Resolve Dependencies using MEF and built-in IoC container of ASP.NET Core
By: Vikas Sharma
Tags: Loosely Coupled, Ioc, Mef, Microsoft, Aspnetcore

INTRODUCTION

You have a ASP.NET Core web project and you are using the built-in IoC container of ASP.NET Core to register and resolve your dependencies. Things looks good and perfect, ASP.NET Core framework makes your life easy by providing its built-in IoC container, all you have to do is reference your contracts project and service project in you web project or web layer and register your dependencies in Startup.cs file, it will inject the dependencies throughout the app wherever you needed.

Registration of the dependency in a service container. ASP.NET Core provides a built-in service container, IServiceProvider. Services are registered in the app’s Startup.ConfigureServices method.

Your Startup.cs file will typically look something like:

The only downside to this approach is that your web project will be referencing your service contracts/abstractions as well as service implementation project and your complete solution becomes tightly coupled. With time list of registration will keep on increasing.

Now, imagine you have multiple microservices. You want to replace one service will some other service keeping the contracts intact but still you would have to modify your dependencies registered in Startup.cs file and hence re-compile your web project.

Ideally, web layer should only know about the contracts and abstractions but not the actual implementations. But by registering your dependencies in Startup.cs, you will have to expose your implementations to web project.

In this article, we will make our web project so loosely coupled that we could replace the old services with new services when needed without re-compiling or changing the existing registered services list by using MEF and built-in IoC container.

Typical coupled architecture

MEF Based Approach

To de-couple our application we will take the help of MEF. The Managed Extensibility Framework or MEF is a library for creating lightweight, extensible applications. MEF can discover the components of our application by dynamically loading the DLLs and reading the attributes of the classes. If you want to dig more about MEF, I would suggest you to visit the official MSDN documentation (https://docs.microsoft.com/en-us/dotnet/framework/mef/).

Getting your hand dirty

I think it would make more sense if we can see things in action. Let’s create an ASP.NET Core application. The project is going to be a sample Web API.

· Create a WEB API project

· Add three class library projects to the solution.

· One will have all the contracts that are required for your application.

· We have divided our services into two different projects.

Solution explorer

· Next, we will add few contracts to our service contracts project.

solution explorer

· Implement the contracts in Service layer.

· Add service implementation in their respective projects.

solution explorer

· Modify the default ‘ValuesController’ by injecting the service contracts in constructor and exposing related endpoints.

Keep in mind we have not registered our dependencies in Startup file yet.

Registering dependencies via MEF

Add a new class library project.

· Add an interface which will expose some wrapper methods of ‘IServiceCollection’

· Add another interface will be used to register dependencies.

· Time to give implementation to IDependencyRegister

IServiceCollection is found in Microsoft.Extensions.DependencyInjection.Abstractions dll.

Now time to see the magic of MEF. Add DependencyLoader class.

LoadDependencies will be used as extension method in Startup file to tell MEF where to load dlls.

solution explorer

Well we are almost there, now all that is left is to resister our dependencies in Service layer itself. To do so we will implement the interface ‘IDependencyResolver’ and use MEF Export attribute to let MEF discover the registration code.

· Add class in ServiceOne project & ServiceTwo project:

solution explorer

One last thing set the project properties of Service projects to compile dlls to web bin folder. Service dlls will be compiled and saved in web bin folder.

In Startup file we will use extension created previously.

Don’t forget to add new entries in appsettings.json.

Path key holds the value of location of service dlls. And ServiceOne holds the name of “ServiceOne.dll” and ServiceTwo holds the name of “ServiceTwo.dll”.

Run the application and hit the URLs:

http://localhost:56121/api/values/data

http://localhost:56121/api/values/strings

output

output

Wow isn’t it beautiful!

solution explorer

Our web layer only contains the reference of Contracts project and totally unaware about the service layer, so loosely coupled.

Story doesn’t get over here, lets see the real magic of all the hard work we just did. We will add a new service project which will also implement the ‘IDummyService1’ and replace the older service with new service without even re-compiling the web project. Services are now pluggable into web layer without any registration in Startup.cs file or re-compiling the project. We will make it configurable by using the appsettings.json.

solution explorer

Build the complete project and the run again.

If you hit the URL (http://localhost:56121/api/values/data) data from DummyService1 will be loaded.

Stop the application and modify the appsettings.json file.

Now, data will be loaded from NewService service without re-compiling or changing anything in any project or Startup file. That’s the magic I was talking about.

Source Code

You can find the source code on GitHub https://github.com/vikas0sharma/sample-for-artice.

Nuget Package

I have also created a Nuget package named ‘vDependencyResolver’ to be directly by services and web projects. You can find the same at https://www.nuget.org/packages/vDependencyResolver/.

Conclusion

We can keep our architecture clean by keeping services abstracted to Web layer.