Friday, January 17, 2020

Azure DevOps Server - Portable PDB distribution

As I mentioned yesterday the story of sharing Portable PDB’s using Azure DevOps Server isn’t complete yet. Azure Artifacts on premise doesn’t support Portable PDB’s (yet) and uploading .snupkg files doesn’t work either. I don’t want to switch back to Full PDB’s.

This means that at the moment of writing the only feasible solution would be to still include the PDB in the main NuGet package. Although this significantly increases the size of the package (and this restore time for projects that consume the package), I don’t see a better alternative.

To include the portable PDB in the nuget package, add the following setting to your csproj file:


Thursday, January 16, 2020

Azure DevOps Server 2019–Portable PDB

I’m quite confused about the current state of Portable PDBs in combination with Azure DevOps Server.
If you look around on the Internet, the recommendation from Microsoft is to use SourceLink support. So all my projects reference the Microsoft.SourceLink.AzureDevOpsServer.Git NuGet package and have the following settings in the project file:
I also added a reference to my Azure DevOps server repo:
  <SourceLinkAzureDevOpsServerGitHost Include="server-name" VirtualDirectory="tfs"/>
More information:
Inside the documentation they mention the following.
Including PDBs in the .nupkg is generally no longer recommended as it increases the size of the package and thus restore time for projects that consume your package, regardless of whether the user needs to debug through the source code of your library or not
OK, so it is not a good idea to include the pdb in the NuGet package. So let’s publish to a file share as it is not possible yet to publish symbols to your local Azure Artifacts instance(as part of your Azure DevOps Server).
I added the Index Sources and Publish Symbols task to my build pipeline.
If you leave the Index sources checkbox checked, the task will output the following:
Skipping: D:\b\5\_work\50\s\ExampleApp\bin\Release\netcoreapp2.2\Example.pdb because it is a Portable PDB
This does make sense as the indexing is already done by sourcelink. But when I take a look at the publishing part no files are stored 😒
2020-01-14T08:58:54.0211016Z ##[debug]SYMSTORE: Number of files stored = 0
2020-01-14T08:58:54.0230550Z ##[debug]SYMSTORE: Number of errors = 0
2020-01-14T08:58:54.0250084Z ##[debug]SYMSTORE: Number of files ignored = 123
It seems that it is not able to solve this puzzle yet.
I see 2 possible workarounds:
  1. Switching back to Full PDB files, as we are not running on Linux (yet) this would be a good short term solution
  2. Keeping the Portable PDB files, but include them in the NuGet packages.
We decided to go for workaround #2.

Wednesday, January 15, 2020

Rapid frontend development with GraphQL

As frontend development gets more complex, I see more and more organizations moving to a model where frontend and backend are implemented by different teams. (another nice example of reverse Conway’s law).

Most of these backends are exposed through REST APIs. This leads to the problem that frontend teams that are using the APIs have to wait for the backend team to complete the development of their APIs. The backend team becomes the bottleneck and causes slowness in development for the frontend team.

Let’s bring GraphQL into the mix…

In the GraphQL world, there is a different approach. The frontend and backend teams can develop in parallel, without stalling the development. The frontend teams can work with mock versions of the API, and use libraries like GraphQL Faker to create fake data. Coding can be completely done with mock data and tests can be written too.

I know that in theory a similar approach would be feasible with REST APIs but these APIs tend to be more static by nature. One GraphQL endpoint can handle a multitude of clients each with their own requirements. It is really hard to have the same flexibility with a REST API, most of them are either too generic(what leads to overfetching) or too specific(what leads to underfetching).

More information:

Tuesday, January 14, 2020

Asynchronous streams - Using IAsyncEnumerable in .NET 4.7

Although IAsyncEnumerable is a part of the C# 8 release and C# 8.0 is supported on .NET Core 3.x and .NET Standard 2.1, this doesn’t have to mean that you cannot use this feature in .NET Core 2.x or the full .NET Framework.

We’ll start with the following (failing to compile) code in a .NET 4.7 project and try to make it work:

A .NET Standard 2.0 project doesn’t know the IAsyncEnumerable interface. So the first thing we need to do is to install the compatibility NuGet package Microsoft.Bcl.AsyncInterfaces.

Now the compiler finds the IAsyncEnumerable interface but Visual Studio still complains because we are targeting C# 7.3 and asynchronous streams is a C# 8 feature.

We can fix this but this requires that the following things are installed on our computer:

  • .NET Core SDK 3.0 or MSBuild Tools 2019
  • Visual Studio 2019 or VSCode

If these requirements are met we can update our project file and tell the compiler to use C# 8 as the language version:

  • Unload the project.
  • Add a <LangVersion>8</LangVersion> property to the project file.
  • Reload the project.

Monday, January 13, 2020

ElasticSearch–Pinned queries

One of the nice features of ElasticSearch is the support for Pinned Queries. With Pinned Queries you can promote a set of documents to rank higher than those matching a given query. This is a nice feature if you want to put specific results into the spotlight (for example if you want to promote a specific product or article).

In the organic part you can specify what the query is you want to execute. The Ids part will return the specified documents and put them on top of the search results.

More info:

Friday, January 10, 2020

MassTransit 6–Serilog integration

Before MassTransit 6, separate NuGet packages existed that allowed you to integrate the logging framework of your choice with MassTransit. In our case we were using Serilog and a MassTransit.SerilogIntegration NuGet package to bring the 2 together.

In MassTransit 6 the previous abstraction has been removed and is replaced by Microsoft.Extensions.Logging.Abstractions.

To enable integration you need to call


before configuring the bus or directly pass on the ILogger instance


Integration with Serilog can now be done through the serilog-extensions-logging NuGet package.

More information here;

Thursday, January 9, 2020

People believe in what they can control, not what works

Food for thought:

I especially liked the part about the Dunning Kruger effect and it’s impact on our industry.