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

Interested in Dependency Injection? You may want to check out my Pluralsight course – Dependency Injection in ASP.NET Core.

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 its 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 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

 

If you found this post useful, you may want to check out my Pluralsight course – Dependency Injection in ASP.NET Core.

Steve Gordon

Steve Gordon is a Microsoft MVP, Pluralsight author, senior developer and community lead based in Brighton. He works for Madgex developing and supporting their data products built using .NET Core technologies. Steve is passionate about community and all things .NET related, having worked with ASP.NET for over 15 years. Steve is currently developing cloud-native services, using .NET Core, ASP.NET Core and Docker. He enjoys sharing his knowledge through his blog, in videos and by presenting at user groups and conferences. Steve is excited to be a part of the .NET community and founded .NET South East, a .NET Meetup group based in Brighton. He enjoys contributing to and maintaining OSS projects, most actively helping save lives with open source software and the Humanitarian Toolbox (www.htbox.org). You can find Steve online at his blog www.stevejgordon.co.uk and on Twitter as @stevejgordon