ASP.NET Core Dependency Injection – Registering Implementations Using Delegates Using the delegate implementation factory extension methods with Microsoft.Extensions.DependencyInjection

Today I want to continue my series (see links at the end of this post) of posts focusing on the Microsoft dependency injection library included by default in new ASP.NET Core projects. In this post I wanted to dive into another lesser known capability of the default DI library.

I was recently reviewing some code where the developer had brought in StructureMap as the container for an ASP.NET Core application. My colleague was using it in place of the Microsoft.Extensions.DependencyInjection package since he wanted to take advantage of some more advanced registrations. StructureMap extends the abstractions for DI provided by Microsoft and so can be easily swapped in as the DI container.

However, when reviewing the code I noticed that we could actually achieve the required registrations using the built in DI instead, removing the extra dependency on StructureMap. Also, from some performance benchmarks I’ve seen, I believe that the Microsoft DI is performing pretty well when compared to StructureMap. NOTE: I can’t seem to locate the source I’d previously read. If/when I track it down I’ll update this post with a link.

The exact example I was looking at is a bit too complicated to explain and demonstrate here. Instead I have put together a simpler example based loosely on the real-world case. In our application we were taking a dependency on an internal library that at this point we didn’t want to modify. One of the classes we wanted to use and resolve via DI looked a little like this…

We wanted to be able to register the IIndexNameProvider type, with the implementation returning this external WeekBasedElasticIndexNameProvider class. However, this presented a problem, since the constructor expects a string parameter defining the baseIndexName. We weren’t in a position to adjust this class and so my colleague had used StructureMap in order to register it as follows

In this registration the IElasticsearchConfig is loaded from DI and it’s IndexNamePrefix property is used to supply the baseIndexName required by the WeekBasedElasticIndexNameProvider. The IDateTimeProvider is also surfaced via DI and passed into the constructor for the WeekBasedElasticIndexNameProvider instance.

It turns out that the Microsoft DI is capable of a similar behaviour. There are overloads of the Add extension methods (e.g. AddSingleton) which accept a Func<IServiceProvider, TService> as the implementation factory. This delegate is expected to return an instance of a suitable object for the registration. To achieve the above registration using the Microsoft DI we can use this code to register our service…

The delegate that this extension method takes as a parameter expects us to return an implementation of the IIndexNameProvider interface. It expects an IIndexNameProvider since that is what has been defined in the generic parameter for the AddSingleton method. In the delegate we get access to an IServiceProvider which we can use to access other registered services.

This delegate will be called the first time that an instance of IIndexNameProvider is required as a dependency on any of our other services registered in the DI container. At that point, the delegate is executed; retrieving the IElasticsearchConfig and IDateTimeProvider from the IServiceProvider. It uses the IElasticsearchConfig to get the required IndexNamePrefix value.

Now that we have the IndexNamePrefix value and an IDateTimeProvider, we can construct and return an instance of the WeekBasedElasticIndexNameProvider which implements IIndexNameProvider. Using this pattern we were able to default back to the Microsoft DI.

It’s likely to be fairly infrequent that you’ll need to register services using delegates in this way, but should you need to do so it’s perfectly possible. Using this approach you can use other services registered in DI to configure or control the implementation that the DI container builds.

Other posts in this series

ASP.NET Core Dependency Injection – How to Register Generic Types
ASP.NET Core Dependency Injection – Registering Multiple Implementations of an Interface

ASP.NET Core Dependency Injection – Registering Multiple Implementations of an Interface

In a previous post I covered registering generic types with Dependency Injection. This is one of the less common (and less documented) ways in which services could be registered with the Microsoft DI library. It turns out that you can do more with the DI available in the Microsoft.Extensions.DependencyInjection package than it may first appear.

Another “advanced” pattern that can be achieved is to register multiple concrete implementations for an interface. These can later be injected as an IEnumerable of that interface. In this post we’ll explore a quick example of how we can do that.

Let’s first discuss when and why you might want to do this. The example I have is based on a service I’ve been involved with previously. This service is responsible for reading messages from a Amazon SQS queue, enriching them and then saving them to ElasticSearch. Based on the property values in the message it conditionally enriches the data. Initially we only had a couple of possible enrichers, but over time we’ve added more.

The way we decided to implement this was to define an IEnricher interface. That interface looks a little like this:

There are two methods on the interface. The first is called CanEnrich and this will take the message object and determine if this enricher can do enrichment on the message. The second method, Enrich, then performs the actual enrichment of the message.

We can define zero or more implementations of this interface for the different enriching activities we may want to perform.

Here’s example of an enricher:

This enricher tries to lookup the city for any failed login messages coming through our queue. It can only do this if the IP Address is present.

And here’s another :

This enricher populates a DayOfWeek property, which is then used for aggregating in ElasticSearch. It can only do this if the incoming message contains a Date.

Both of are quite basic and contrived examples. The functionality isn’t that important here though.

The enrichers can now be registered with the ServiceCollection wherever that happens in your application:

It’s worth making it clear that the implementations will be added in the order they are registered. They will be returned in that same order when injected into calling code. Depending on your requirements, this may be useful and important. For this example we don’t really care what order we get them in.

To make use of these enrichers we can have them injected wherever we require them and DI is available. Since we’ve registered more than one instance, we ask the DI framework for an IEnumerable<IEnricher> which we can then enumerate over to access all implementations.

A simplified example of this in a caller would look like this:

Here I filter to only the enrichers which can enrich the message we are processing. Then I call the Enrich method on each one in turn.

Where this pattern proves particularly useful is if we imagine we now want to add another enricher. All we have to do is create a class which implements the interface and then ensure it is registered with DI. Now when our caller runs, that enricher will be included in the IEnumerable<IEnricher> which is injected. Our consuming code will make use of the new enricher without any further code changes.

The ASP.NET Core framework uses this same pattern in a number of places. One which I’ve covered in the past is the IHostedService interface. This allows you to define one or more “background” services to run whilst you application is alive. As with my enricher example, all you have to do is create a class implementing IHostedService and then register it with DI. When the application starts it will fire up any registered IHostedService instances in order.

Other posts in this series

ASP.NET Core Dependency Injection – How to Register Generic Types
ASP.NET Core Dependency Injection – Registering Implementations Using Delegates

ASP.NET Core Dependency Injection – How to Register Generic Types Exploring how generic types can be registered with the built-in Microsoft DI container

Since its release, ASP.NET Core has shipped with a “basic” Dependency Injection (DI) container included. This supports the functionality required to run the framework which was built from the ground up to support the use of DI throughout.

The ASP.NET documentation describes some general information about the use of DI in ASP.NET Core.

The documentation for the DI container (ServiceProvider) claims that its quite basic and not a replacement for more fully featured containers such as AutoFac or StructureMap for example. In my experience, for many of my requirements it has proved quite sufficient. In this short post I want to explore a less common registration requirement that may exist for some developers.

Imagine a scenario where you want to register a generic interface and a generic implementation with the ASP.NET Core DI container. In ASP.NET Core itself, an example of this use case is the ILogger<T> interface. We can ask for an ILogger<T> in constructors of our Controllers for example, where T is the Type that the logger will be logging for.

To put this more concretely; if we have a ValuesController and we want to log caught errors from our Actions, we can require an ILogger<ValuesController> in our constructor for the ValuesController. When the controller is constructed by the framework it will receive an implementation of the generic Logger<T> for our provided Type parameter. Under the covers the ILoggerFactory will use the type name to return the appropriate Logger. Messages logged via that logger will then include the full name of the Type (Namespace.ValuesController) when logged to the console for example.

A common way to register services with the ServiceCollection is using the generic extension methods. To add a Singleton registration for an interface and it’s concrete type for example we can call…

serviceCollection.AddSingleton<IService, MyService>();

The signature for the AddSingleton method is…

public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection serviceswhere TService : class where TImplementation : class, Tservice

This works well for most scenarios but doesn’t work if we want to register generic services.

For a slightly contrived example, let’s say we have an interface like this…

And an implementation like this…

We want to be able to ask for an IThing<SomeType> in the constructor of a consumer which will get the correct GenericThing<SomeType> injected.

In this case we can use a different extension method on the ServiceCollection that accepts the types as parameters. Our registration would then look like this…

We now have our generic interface and implementation registered correctly. We can now consume this via DI wherever we need it injected.

Other posts in this series

ASP.NET Core Dependency Injection – Registering Multiple Implementations of an Interface
ASP.NET Core Dependency Injection – Registering Implementations Using Delegates

Migrating from .NET Framework to .NET Core The journey of re-targeting an ASP.NET Core application onto .NET Core

What better way to start the new year than with some coding? In my case I’d found a bit of time during the end of my Christmas vacation to tackle an issue on allReady I’d been wanting to work on for a while. Before getting into the issue, if you want to read more about what allReady is you can read my earlier blog post where I cover contributing to it in greater detail.

allReady was first created during the early beta’s of ASP.NET Core (at which point it was known as ASP.NET 5). At that time, due to some dependencies which did not yet support .NET Core, the application was built on top of the full .NET framework 4.6.

The first thing to discuss briefly is why and how we can run ASP.NET Core on the full traditional .NET framework. While it might be reasonable to assume that ASP.NET Core naturally needs to run on the new .NET Core framework, remember that .NET Core ultimately includes a subset of the larger full .NET framework API. Because of this, it is perfectly possible to run ASP.NET Core on the original 4.x version of the .NET framework. This is an advantage to those that want to make use of the new features and optimizations within ASP.NET Core, while also still utilising the libraries they know and love. This is a perfectly reasonable way to run ASP.NET Core but with an important limitation. By targeting the .NET framework you are not able to develop or host the ASP.NET application outside of Windows.

For the allReady project this had started to become a bit of a limitation. We had Mac users who were keen to contribute to the project, but were unable to do so without installing and running a Windows VM on their device. As we were getting to the end of some complex requirements for allReady’s v1 milestone, I took the opportunity to spend some time looking at retargeting the application to run on .NET Core. This turned out to be a bit more involved that I had first anticipated. However, we have succeeded and the code base has been proven to build and run on both Mac and Linux devices.

Updating the Solution

The first part of the process was to update the project.json file inside the web solution. The main update here was changing the framework specification to netcoreapp from net46.

project.json before:

project.json after:

We had decided as a team to continue to track the .NET Core 1.0.x LTS support stream. In short, this is a stable version of the framework, under full Microsoft support. New minor patch releases are appearing to fix major bugs or security issues, but otherwise the changes are expected to be quite limited. Our project was already targeting the latest 1.0.3 SDK and latest 1.0.x libraries for each of the components.

You’ll see above that as well as changing the framework moniker I’ve added an imports section as well. This was required in our case as we have some dependencies on some libraries which don’t yet specify a dotnet Target Moniker or .NET Standard version. It’s essentially there for backwards compatibility until the ecosystem settles down.

Handling Dependencies

Upon making the required changes to project.json, it became apparent that some of the packages we depend on could no longer be restored. The first thing I did was to use Nuget Package Manager to update all of the dependencies to their latest versions to see if any of those had been updated to support .NET Core. This helped in some of the cases but still left me with a few that were not compatible. For the time being I commented those out as well as commenting out any code using those dependencies. In our case this included the following main libraries we had issues with…

  • XZing which was being used in one place to generate a QR code image for use within the allReady phone application. This had its own dependency on System.Drawing which is not part of .NET Core.
  • LinqToTwitter which was being used in one area of the application to query for a user’s information after a sign in via Twitter.
  • GeoCoding.net which was used in a few places in order to take an address and geo code it to latitude and longitude coordinates.

With those taken care of for now (if only commenting out code was considered “fixing”), the last remaining issue for the web project was a dependency on a separate library project in our solution which contains some shared models. This library is used by both our web application and also in some Azure web jobs we have defined. As a result it needed to support both .NET Core and the .NET Framework. The solution here was to convert it to a .NET standard library. In my case I chose the lowest standard version I could find which gave me the API surface I needed, while supporting my dependent projects. This was the .NET Standard 1.3 version. The project.json for this library was changed as follows.

Before:

After:

With this done, I also had to update our test library project.json in a similar way in order to support .NET Core by changing the frameworks section and updating to the latest versions of our dependencies as with the main web project. The changes in this file were very similar to what I’ve already shown, so I won’t repeat the code here.

Wrapping missing dependencies

With the package restore now succeeding for the web project, test project and our .NET standard project my next goal was to find solutions to the libraries we could no longer use.

XZing was an easy decision as currently the phone application project is a bit stale and it was decided that we could simply remove the QRCode endpoint and this dependency as a result.

When I reviewed the use of LinqToTwitter it was only really abstracting one API call to Twitter behind a more fluent Linq syntax. We were using it to request a Twitter user’s profile information. The option I chose here was to write our own small service to wrap the call to the Twitter REST API which using HttpClient. There are some hoops to jump through in order to establish the authentication with Twitter but this ultimately didn’t prove too difficult. I won’t go into the exact details here since this post is intended to cover the general “migration” process.

The final dependent library that wasn’t able to support .NET Core was GeoCoding.net. We were using this library to perform address to coordinate lookups via Google. On review of the usages, it was again clear that we had a whole dependency for what amounted to a single call to a Google endpoint. We were already calling another part of the Google REST API directly from a custom service class, so again, the decision was to wrap up the geocoding functionality in our own code, calling the API directly. Again, the exact details are beyond my scope here, but I may cover this in a future blog post if there’s interest.

Handling API Differences

With the problem packages removed I tried to compile the solution. I was immediately hit by a wall of errors. This was initially a little daunting, but after looking through them I could see that many were quite similar and due to changes to the .NET Core API surface.

Reflection

The first of which was where we’d been using reflection. We have a couple of places in the web app that rely on reflection for wiring up our IoC container and also in some of the test classes. In .NET Core the Object.GetType() method no longer returns full type detail information, instead it returns just the type name. In order to access the full type information there is a new extension method called GetTypeInfo(). It returns TypeInfo which is similar to what Type used to return.

Before:

After:

In this example you can see that the only change is adding in the GetTypeInfo call.

Date Formatting

We also had some code calling ToLongDateString on dates. This is no longer avaiable so I switched to formatting the date using the ToString method instead.

Before:

After:

Exceptions

In a couple of places we were throwing ApplicationException which also seems to have been removed. I switched to a general Exception in this case.

Before:

After:

Final Tweaks

Once all of the compile errors were fixed we were nearly there. In order to enable the site to be run under the non IIS mode of Kestrel I updated the profiles in launchSettings.json

Before:

After:

This new profile basically tell VS to run the project (i.e. via dotnet.exe) – launching it on port 5000. Within Visual Studio you can choose whether to start via IIS Express or directly into the project via the dotnet.exe. New projects targeting .NET core include these two profiles automatically, so updating it in our project felt sensible, to make the developer experience familiar.

Conclusion

With the above steps completed the project was now compiling, tests were running and the site worked as expected. Quite a few hours of work went into the process. The longest time was spent building the new service wrappers around the 3rd party REST APIs so that I could get rid of incompatible dependencies. The actual project and code changes weren’t too painful and it was just a case of working out the API changes so I knew how to modify our code.

It was an interesting experience and once we had it tested on a Mac and Linux during the NDC London code-a-thon it was very exciting to see it working. This has made it much easier for non-Windows developers to contribute to the allReady project and is just one of the great new benefits of working with .NET Core and ASP.NET Core.