Oct 15, 2018

IoC - Dependecy injection - StructureMap - ASP.NET Core 2.1 - Using factory to inject all type implementations


There are different implementations of IApplicationContext:
- MyContext1
- MyContext2
Also in future we may add new implementations.
We want to use this context in generic class repository like this:

class MyRepository<T, C> : IRepository<T, C> where T : Entity<T> where C : IApplicationContext

So far everything is straightforward. Repository will know two dependencies - entity and repository.
Consumer classes will reference repository like this:

private IRepository<MyEntity, MyContext1> myRepo1;

But how to obtain instance of MyContext1 inside our MyRepository ?

We could write something like:

var context = new C();

It would work but we could not write unit tests for such class since we create explicit instance inside our method which breaks dependecy injection effort.

Alternative is quite elegant and supported by StructureMap IoC container.

First step is to explicitly scan for all instances of our context like this:

Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
scan.AddAllTypesOf<IApplicationContext>();
});

Then comes the magic touch :)
We create new Factory class. 

Array of contexts is populated with all known implementations of IApplicationContext.

And lastly the requested one is selected from that list through simple generic method:

public class ApplicationContextFactory : IApplicationContextFactory

{

private readonly IApplicationContext[] _applicationContexts;

public ApplicationContextFactory(IApplicationContext[] applicationContexts)
{
_applicationContexts = applicationContexts ?? throw new ArgumentNullException(nameof(applicationContexts));

}

public IApplicationContext GetContext<T>() where T : IApplicationContext
{

return _applicationContexts.SingleOrDefault(c => c is T);

}
}

Factory is then used in our repository generic class to resolve in simple way our instance required by type that called repository:

_applicationContext = _applicationContextFactory.GetContext<C>();

No comments:

Post a Comment