ASP.NET Core – adding controllers directly from integration tests

1. Introduction

From time to time it might happen, that you need to test certain parts of your ASP.NET Core configuration without hitting publicly visible business-related controllers. For instance, in my case, I wanted to make sure that my ASP.NET Core API behavior is consistent with the original API written in Nancy. As you might expect there are quite a lot of differences between both of the frameworks, so let’s focus on testing one thing, namely non-nullable reference type handling. Long story short, in order to have the same behavior in ASP.NET Core as in Nancy I had to add the following line of configuration

This one prevents ASP.NET Core from marking non-nullable reference type properties in request as required. Having that configuration ready, I wanted to test it with an end to end test. Because there was no business-related logic yet, I needed to figure out the way of adding API controllers to my application directly from the integration tests. Here is how you can achieve that.

2. Accessing ApplicationPartManager from integration tests

ASP.NET Core is able to compose your API from different parts thanks to ApplicationPartManager. By default, you don’t use it directly but rather with IMvcBuilder AddApplicationPart extension method while setting up your application

However, there is no easy way of getting IMvcBuidler from the integration tests(at least I didn’t find a proper way of doing that without tampering too much with the original application pipeline) so we need to access ApplicationPartManager directly. Inspecting the source code of the framework you will find that ApplicationPartManager can be retrieved directly from IServiceCollection with following code

Applying similar code to the WebApplicationFactory will allow us to add controllers directly from tests

3. Handling private controllers

The solution presented below works nice, however it has couple of drawbacks. First of all, it only discovers public non-nested controllers. Second of all, it will always add all controllers from given assembly – which potentially might affect other integration tests. In order to get rid of these drawbacks, we need to tell ApplicationPartManager to include only selected controllers. We can achieve that by adding additional IApplicationFeatureProvider<ControllerFeature> to the list of FeatureProviders.

Putting it all together and applying some refactoring we will end up with following code

Source code for this post can be found here

ASP.NET Core – adding controllers directly from integration tests

Running ASP.NET Core together with Nancy

1. Introduction

Our current API runs on Nancy which in my opinion is past its prime. Recent news from the GitHub issue tracker seems to confirm that thesis, that is why we started looking for a migration path from Nancy based API to ASP.NET Core. Because the codebase is quite large we didn’t want to do a Big Bang Rewrite but instead of that, we wanted to gradually replace old API with a new one, so both of them can coexist next to each other.

2. Legacy API

Before I jump into implementation, here is a sample Nancy API with two endpoints – products and variants

The goal is to replace products endpoint with ASP.NET Core implementation while variants endpoint should still be served by Nancy

3. Combining Nancy with ASP.NET Core

The solution is based on branching the pipeline feature which is available starting from ASP.NET Core 2.1. Long story short – it is possible to configure different pipelines for different route paths thanks to

method. Having that in mind we can Map products path to run through ASP.NET Core pipeline whereas the rest would go through Nancy.

At this point we are almost there, however running request through Map pipeline will remove the path prefix, meaning that our controller would be accessible under / path instead of products. In order to bypass this limitation we have to restore original prefix with RewriteMiddleware. Once we put it all together, now we are able to replace multiple Nancy endpoints with ASP.NET Core ones using following piece of code

Source code for this post can be found here

Running ASP.NET Core together with Nancy

ASP.NET Core – custom ILogger<T> and Nlog callsite layout renderer issue

1. Introduction

In my current project, we use Microsoft.Extensions.Logging.ILogger<T> default implementation as our logging mechanism. This basically comes with the ASP.NET Core 2.0 package and it was working fine so far. However recently we decided to switch the default implementation with a custom one, due to the fact that we wanted to have some additional logic applied for all of the logging providers.

2. Implementation

The custom implementation itself is very similar to the original one, we came up with something like that

and we replaced the default logger with this code

As you can see we basically wanted to add information from custom exceptions to the message. Due to the fact that this is added in here, we don’t have to modify all of our existing logging providers.

3. NLog call site renderer issue

Once we run the application all of the providers were working fine and were producing expected output apart from NLog provider. Originally NLog provider for the following code

was producing this output

However, after introducing new implementation of ILogger<T>, it started appending wrong caller member name

After some digging, it turned out that the issue lies in the (indirect)configuration of NLog’s callsite layout renderer. Long story short, when you add NLog provider to your logger providers, under the hood it adds Microsoft.Extensions.Logging.Abstractions assembly(among others) to something called hidden assembly collection. Once the NLog tries to figure out what is the caller member name, it crawls the stack trace to find a method name. If the method in current frame comes from a hidden assembly, logger skips it and continues iteration. As we changed the Logger<T> to our custom one, it is no longer part of Microsoft.Extensions.Logging.Abstractions assembly, so the NLog reports Log method from our custom logger as a caller member name.

4. The fix

In order to restore previous behavior you have to add custom logger assembly to the hidden assembly collection. You can do it via

Of course, if the logger is located in the same assembly as rest of your code, this might not be the perfect solution – as this will impact the way the callsite is rendered for other parts of your code in this assembly. In that case, you might consider moving the logging piece to separate assembly or resign from using callsite layout renderer at all. We decided to replace it with logger layout renderer as callsite layout renderer, either way, wouldn’t be used in production environments.

Source code for this post can be found here

ASP.NET Core – custom ILogger<T> and Nlog callsite layout renderer issue

ASP.NET Core – make sure IOptions<T> is initialized

1. Introduction

As most people know IOptions<T> is a convenient way of handling configuration options in your application. Even though I’ve been using it for quite some time, last week I was unpleasantly surprised by a production bug caused by wrong usage of this mechanism.

2. Problem

Let’s say we have a simple controller which depends on two instances of IOptions<T>

Then we add only IOptions in Startup class – IOptions<PaymentOptoins>

Now, when we run the app and hit one of the endpoints in ValuesController I was expecting to get an exception, as I didn’t register IOptions<NotificationOptions>. Surprisingly for me, the application was running normally and IOptions<NotificationOptions> was created with the new instance of NotificationOptions class(with all the properties defaulted).

In order to find out why it behaves like that we have to take a look how services responsible for handling IOptions<T> are registered in the container.

As you can see AddOptions method registers open generics for (among others) IOptions<> which means that you don’t have to register specific types of IOptions<T>, however, you are responsible for its configuration with

I was always convinced that services.Configure registers and configure IOptions<T> but apparently, I was wrong.

3. Ensuring initialization

As these kind of errors are rather difficult to catch(at least in case of our application) I wanted to minimize the risk of doing the same bug again. The idea was to make sure that at least one IConfigureOptions<T> or IPostConfigureOptions<T> service is registered in the container (as these are the services which are responsible for setting the values of T class). My first approach was to replace default OptionsFactory<T> with a custom one

This method works fine (although probably needs smarter TOptions filter)

however I got to conclusion that there is no point to do validation in a runtime, and the integration test might be a better choice. I came up with following code (I am assuming that all configuration options are stored in the same assembly, as this is convention in my project)

Running the test shows that NotificationOptions was not configured

Source code for this post can be found here

ASP.NET Core – make sure IOptions<T> is initialized

ASP.NET Core – passing command-line arguments to Startup class

1. Introduction

I usually pass configuration to my web API via JSON files, but recently I needed to pass them also via command-line arguments. As the solution for ASP.NET Core 2.x is quite different than for ASP.NET Core 1.x I decided to describe both methods in here.

2. ASP.NET Core 2.x

For the newest version of ASP.NET Core, the solution is pretty straightforward as IConfiguration is injected by default to the Startup class. All we have to do is to add CommandLineConfigurationSource to IConfigurationBuilder when configuring IWebHost. CommandLineConfigurationSource is part of the Microsoft.Extensions.Configuration.CommandLine package and can be easily used by AddCommandLine extension method

Now we can access our command-line arguments just like any other configuration

3. ASP.NET Core 1.x

The solution for ASP.NET Core 1.x requires a bit more work but it is possible to achieve the same result. We still will be using CommandLineConfigurationSource from Microsoft.Extensions.Configuration.CommandLine package, however this time we have to manually create IConfiguration object and register it in the container before the Startup class is created. This is possible because the WebHostBuilder exposes ConfigureServices method.

Having our service registered now we can easily access IConfiguration object in our application

Source code for this post can be found here

ASP.NET Core – passing command-line arguments to Startup class