I have three types of users in my application, let's say Type1, Type2 and Type3.
Then i want to create one service implementation for each type, let's say i have a service to get photos, i would have three services : Type1PhotosService, Type2PhotosService and Type3PhotosService, each of them implementing IPhotosService.
In the web api, i would inject IPhotosService :
IPhotosService _service;
public PhotosController(IPhotosService service){
_service = service;
}
The web api uses token authentication with claims. So what i want to achieve, is for each user, depending on the claim he has : type1 or type2 or type3, the correct implementation of the service will be automatically injected rather than injecting a single service in the startup file.
What i want to avoid, is having one service, with a bunch of switch and if statements to return the correct data depending on user type and the roles he has.
EDIT:
some comments were wondering what's the point of three implementations, so here are more details to give it a little more sense.
The service is a job finder service, and the application has three different profiles : candidate, employer and administration. Each of these profiles need a proper implementation. So rather than having three methods GetCandidateJobs, GetEmployerJobs and GetAdministrationJobs inside the same service and switch on the user type, i preferred to have one implementation per profile type, then depending on the profile type, use the correct implementation.
Without Using a Separate IoC Container
Here's an approach that's way easier than configuring your app to use another IoC container and then configuring that container. After working through this with Windsor this solution seems a whole lot easier.
This approach is simplest if you can use a singleton instance of each service implementation.
We'll start with an interface, some implementations, and the factory we can inject which will return an implementation selected at runtime based on some input.
public interface ICustomService { }
public class CustomServiceOne : ICustomService { }
public class CustomServiceTwo : ICustomService { }
public class CustomServiceThree : ICustomService { }
public interface ICustomServiceFactory
{
ICustomService Create(string input);
}
Here's a really crude implementation of the factory. (Didn't use string constants, or polish it at all.)
public class CustomServiceFactory : ICustomServiceFactory
{
private readonly Dictionary<string, ICustomService> _services
= new Dictionary<string, ICustomService>(StringComparer.OrdinalIgnoreCase);
public CustomServiceFactory(IServiceProvider serviceProvider)
{
_services.Add("TypeOne", serviceProvider.GetService<CustomServiceOne>());
_services.Add("TypeTwo", serviceProvider.GetService<CustomServiceTwo>());
_services.Add("TypeThree", serviceProvider.GetService<CustomServiceThree>());
}
public ICustomService Create(string input)
{
return _services.ContainsKey(input) ? _services[input] : _services["TypeOne"];
}
}
This assumes that you've already registered CustomServiceOne, CustomServiceTwo, etc. with the IServiceCollection. They would not be registered as interface implementations, since that's not how we're resolving them. This class will simply resolve each one and put them in a dictionary so that you can retrieve them by name.
In this case the factory method takes a string, but you could inspect any type or multiple arguments to determine which implementation to return. Even the use of a string as the dictionary key is arbitrary. And, just as an example, I provided fallback behavior to return some default implementation. It might make more sense to throw an exception instead if you can't determine the right implementation to return.
Another alternative, depending on your needs, would be to resolve the implementation within the factory when it's requested. To the extent possible I try to keep most classes stateless so that I can resolve and reuse a single instance.
To register the factory with the IServiceCollection at startup we would do this:
services.AddSingleton<ICustomServiceFactory>(provider =>
new CustomServiceFactory(provider));
The IServiceProvider will be injected into the factory when the factory is resolved, and then the factory will use it to resolve the service.
Here's the corresponding unit tests. The test method is the identical to the one used in the Windsor answer, which "proves" that we can transparently replace one factory implementation with another and change other stuff in the composition root without breaking stuff.
public class Tests
{
private IServiceProvider _serviceProvider;
[SetUp]
public void Setup()
{
var services = new ServiceCollection();
services.AddSingleton<CustomServiceOne>();
services.AddSingleton<CustomServiceTwo>();
services.AddSingleton<CustomServiceThree>();
services.AddSingleton<ICustomServiceFactory>(provider =>
new CustomServiceFactory(provider));
_serviceProvider = services.BuildServiceProvider();
}
[TestCase("TypeOne", typeof(CustomServiceOne))]
[TestCase("TypeTwo", typeof(CustomServiceTwo))]
[TestCase("TYPEThree", typeof(CustomServiceThree))]
[TestCase("unknown", typeof(CustomServiceOne))]
public void FactoryReturnsExpectedService(string input, Type expectedType)
{
var factory = _serviceProvider.GetService<ICustomServiceFactory>();
var service = factory.Create(input);
Assert.IsInstanceOf(expectedType, service);
}
}
As in the Windsor example, this is written to avoid any reference to the container outside of the composition root. If a class depends on ICustomServiceFactory and ICustomService you could switch between this implementation, the Windsor implementation, or any other implementation of the factory.
Using Windsor
I'm going to sidestep the questions about whether or not this makes sense in this case and just attempt to answer the question as asked:
.NET Core's IoC container isn't built particularly well for this sort of scenario. (They acknowledge this in their documentation.) You can work around it by adding another IoC container like Windsor.
The implementation ended up looking way more complicated than I would have liked, but once you get past the setup it's not bad and you get access to Windsor's features. I'm going to provide another answer that doesn't include Windsor. I had to do all of this work to see that I probably like the other approach better.
In your project, add the Castle.Windsor.MsDependencyInjection NuGet package.
Interfaces and Implementations for Testing
For testing, I added some interfaces and implementations:
public interface ICustomService { }
public interface IRegisteredWithServiceCollection { }
public class CustomServiceOne : ICustomService { }
public class CustomServiceTwo : ICustomService { }
public class CustomServiceThree : ICustomService { }
public class RegisteredWithServiceCollection : IRegisteredWithServiceCollection { }
The intent is to create a factory that will select and return an implementation of ICustomService using some runtime input.
Here's an interface which will serve as a factory. This is what we can inject into a class and call at runtime to get an implementation of ICustomService:
public interface ICustomServiceFactory
{
ICustomService Create(string input);
}
Configure the Windsor Container
Next is a class which will configure an IWindsorContainer to resolve dependencies:
public class WindsorConfiguration : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<ICustomService, CustomServiceOne>().Named("TypeOne"),
Component.For<ICustomService, CustomServiceTwo>().Named("TypeTwo"),
Component.For<ICustomService, CustomServiceThree>().Named("TypeThree"),
Component.For<ICustomService, CustomServiceOne>().IsDefault(),
Component.For<ICustomServiceFactory>().AsFactory(new CustomServiceSelector())
);
}
}
public class CustomServiceSelector : DefaultTypedFactoryComponentSelector
{
public CustomServiceSelector()
: base(fallbackToResolveByTypeIfNameNotFound: true) { }
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (string) arguments[0];
}
}
Here's what's going on in here:
The TypedFactoryFacility will enable us to use Windsor's typed factories. It will create an implementation of our factory interface for us.
We're registering three implementations of ICustomService. Because we're registering more than one implementation, each must have a name. When we resolve ICustomService we can specify a name, and it will resolve the type according to that string.
For illustration I registered another implementation of ICustomService without a name. That will enable us to resolve a default implementation if we try to resolve using an unrecognized name. (Some alternatives are just throwing an exception, or returning a "null" instance of ICustomService or creating a class like UnknownCustomService that throws an exception.)
Component.For<ICustomServiceFactory>().AsFactory(new CustomServiceSelector()) tells the container to create a proxy class to implement ICustomServiceFactory. (More on that in their documentation.)
CustomServiceSelector is what takes the argument passed to the factory's Create method and returns the component name (TypeOne, TypeTwo, etc.) that will be used to select a component. In this case we're expecting that the argument passed to the factory will be the same as the registration name we've used. But we could replace this with other logic. Our factory could even take arguments of other types which we could inspect and determine which string to return.
Configure Your App To Use the Windsor Container
Now, in StartUp, modify ConfigureServices to return IServiceProvider instead of void and create an IServiceProvider that combines services registered directly with the IServiceCollection with those registered with the Windsor container:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var container = new WindsorContainer();
container.Install(new WindsorConfiguration());
return WindsorRegistrationHelper.CreateServiceProvider(container, services);
}
container.Install(new WindsorConfiguration()) allows WindsorConfiguration to configure our container. We could just configure the container right in this method, but this is a nice way to keep our container configurations organized. We can create numerous IWindsorInstaller implementations or our own custom classes to configure the Windsor container.
WindsorRegistrationHelper.CreateServiceProvider(container, services) creates the IServiceProvider that uses container and services.
Does It Work?
I wouldn't post all this without finding out first. Here's some NUnit tests. (I usually write some basic tests for DI configuration.)
The setup creates an IServiceProvider similar to what would happen in the application startup. It creates a container and applies the WindsorConfiguration. I'm also registering a service directly with the ServiceCollection to make sure that the two play well together. Then I'm combining the two into an IServiceProvider.
Then I'm resolving an ICustomerServiceFactory from the IServiceProvider and verifying that it returns the correct implementation of ICustomService for each input string, including the fallback when the string isn't a recognized dependency name.
I'm also verifying that the service registered directly with ServiceCollection is resolved.
public class Tests
{
private IServiceProvider _serviceProvider;
[SetUp]
public void Setup()
{
var services = new ServiceCollection();
services.AddSingleton<IRegisteredWithServiceCollection, RegisteredWithServiceCollection>();
var container = new WindsorContainer();
container.Install(new WindsorConfiguration());
_serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(container, services);
}
[TestCase("TypeOne", typeof(CustomServiceOne))]
[TestCase("TypeTwo", typeof(CustomServiceTwo))]
[TestCase("TYPEThree", typeof(CustomServiceThree))]
[TestCase("unknown", typeof(CustomServiceOne))]
public void FactoryReturnsExpectedService(string input, Type expectedType)
{
var factory = _serviceProvider.GetService<ICustomServiceFactory>();
var service = factory.Create(input);
Assert.IsInstanceOf(expectedType, service);
}
[Test]
public void ServiceProviderReturnsServiceRegisteredWithServiceCollection()
{
var service = _serviceProvider.GetService<IRegisteredWithServiceCollection>();
Assert.IsInstanceOf<RegisteredWithServiceCollection>(service);
}
}
Is All of This Worth It?
Now that I've figured it out, I'd probably use it if I really needed this sort of functionality. It looks worse if you're trying to assimilate both using Windsor with .NET Core and seeing it's abstract factory implementation for the first time. Here's another article with some more information on Windsor's abstract factory without all the noise about .NET Core.
I am going to go out on a limb here and say that the attempt to utilize dependency injection for this purpose is sub-optimal. Normally this would be handled by a Factory pattern that produces service implementations using the dreaded if and switch statements. A simple example is:
public interface IPhotoService {
Photo CreatePhoto(params);
}
public class PhotoServiceFactory {
private readonly IPhotoService _type1;
private readonly IPhotoService _type2;
private readonly IPhotoService _type3;
public PhotoServiceFactory(IDependency1 d1, IDependency2 d2, ...etc) {
_type1 = new ConcreteServiceA(d1);
_type2 = new ConcreteServiceB(d2);
_type3 = new ConcreteServiceC(etc);
}
public IPhotoService Create(User user) {
switch(user.Claim) {
case ClaimEnum.Type1:
return _type1;
case ClaimEnum.Type2:
return _type2;
case ClaimEnum.Type3:
return _type3;
default:
throw new NotImplementedException
}
}
}
Then in your controller:
public class PhotosController {
IPhotoServiceFactory _factory;
public PhotosController(IPhotoServiceFactory factory){
_factory = factory;
}
public IHttpActionResult GetPhoto() {
var photoServiceToUse = _factory.Create(User);
var photo = photoServiceToUse.CreatePhoto(params);
return Ok(photo);
}
}
Alternately just use the concrete classes as arguments in the constructor and follow a similar logic as to the above.
Here is one solution, i have created inside asp.net core console application.
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace CreationalPattern
{
class Program
{
static void Main(string[] args)
{
// Add dependency into service collection
var services = new ServiceCollection()
.AddTransient<FordFigoFactory>()
.AddTransient<AudiQ7Factory>();
/* Create CarServiceFactory as singleton because it can be used across the application more frequently*/
services.AddSingleton<ICarServiceFactory>(provider => new CarServiceFactory(provider));
// create a service provider from the service collection
var serviceProvider = services.BuildServiceProvider();
/* instantiate car*/
var factory = serviceProvider.GetService<ICarServiceFactory>();
var audiCar = factory.Create("audi").CreateACar("Blue");
Console.Read();
}
}
public interface ICarServiceFactory
{
ICreateCars Create(string input);
}
public class CarServiceFactory : ICarServiceFactory
{
private readonly Dictionary<string, ICreateCars> _services
= new Dictionary<string, ICreateCars>(StringComparer.OrdinalIgnoreCase);
public CarServiceFactory(IServiceProvider serviceProvider)
{
_services.Add("ford", serviceProvider.GetService<FordFigoFactory>());
_services.Add("audi", serviceProvider.GetService<AudiQ7Factory>());
}
public ICreateCars Create(string input)
{
Console.WriteLine(input + " car is created.");
return _services.ContainsKey(input) ? _services[input] : _services["ford"];
}
}
public interface ICreateCars
{
Car CreateACar(string color);
}
public class FordFigoFactory : ICreateCars
{
public Car CreateACar(string color)
{
Console.WriteLine("FordFigo car is created with color:" + color);
return new Fordigo { Color = color};
}
}
public class AudiQ7Factory : ICreateCars
{
public Car CreateACar(string color)
{
Console.WriteLine("AudiQ7 car is created with color:" + color);
return new AudiQ7 { Color = color };
}
}
public abstract class Car
{
public string Model { get; set; }
public string Color { get; set; }
public string Company { get; set; }
}
public class Fordigo : Car
{
public Fordigo()
{
Model = "Figo";
Company = "Ford";
}
}
public class AudiQ7 : Car
{
public AudiQ7()
{
Model = "Audi";
Company = "Q7";
}
}
}
Explanation:
To understand better try to read the program from bottom to top. We have 3 sections:
Car (Car, Fordigo, AudiQ7)
CarFactory (ICreateCars, FordFigoFactory, AudiQ7Factory)
CarService (ICarServiceFactory, CarServiceFactory)
In this Dependency injection is registered as transient for Factory classes FordFigoFactory and AudiQ7Factory. And Singleton for CarServiceFactory.
I have a WebApi project using Entity Framework 6.0, Autfac for DI and CQRS architecture. The problem I have that DbContext isn't disposing how it supposed to. The action I take:
I run two quick requests, e.g. send request from Postman to one endpoint, runtime stops on breakpoint in controller method, I send second request to another endpoint in different controller.
Resume Runtime
if the second request finished before the first one is done, the first one throws and error that dbcontext was disposed and it cannot run whatever it was supposed to do
Originally problem appeared when I posted and patched from frontend one after another.
It seems like lifetime scope is not really per-request. It seems like all dbcontexts are disposed on one of the request's end. The other one does not have anything to work with.
How is it configured?
Starting from the highest layer - controller:
public class UsersController : BaseController, IUsersApi
{
private readonly IUserService _userService;
public UsersController(IUserService userService, ILogging logging) : base(logging)
{
_userService = userService;
}
[HttpGet]
[Route("api/users")]
public IList<UserDto> GetUsers()
{
try
{
return _userService.GetAllUsers();
}
catch (Exception e)
{
_logger.Error(e);
_logger.Trace(e);
throw;
}
}
[HttpPatch]
[Route("api/users/")]
public IHttpActionResult EditUsers(ICollection<UserEditDto> model)
{
try
{
_userService.EditUsers(model);
return Ok();
}
catch (Exception e)
{
_logger.Error(e);
_logger.Trace(e);
return BadRequest("Error");
}
}
}
Service layer:
public class UserService : IUserService
{
private readonly IServiceTools _serviceTools;
private readonly IUserQuerier _userQuerier;
public UserService(IServiceTools serviceTools, IUserQuerier userQuerier)
{
_serviceTools = serviceTools;
_userQuerier = userQuerier;
}
public void EditUsers(ICollection<UserEditDto> model)
{
var mapper = _serviceTools.AutoMapperConfiguration.Configure().CreateMapper();
var userEditCommands = mapper.Map<ICollection<UserEditDto>, ICollection<EditUserCommand>>(model);
foreach (var command in userSaveCommands)
{
_serviceTools.CommandBus.SendCommand(command);
CacheHelper.Clear(command.Id.ToString());
}
}
public IList<UserDto> GetAllUsers()
{
var allUsers = _userQuerier.GetAllUsers();
var result = allUsers.Select(x => new UserDto()
{
...
}).ToList();
return result;
}
}
Service Tools interface where command bus sits:
public interface IServiceTools
{
ICommandBus CommandBus { get; }
IAutoMapperConfiguration AutoMapperConfiguration { get; }
IIdentityProvider IdentityProvider { get; }
}
public class ServiceTools : IServiceTools
{
public ServiceTools(ICommandBus commandBus, IAutoMapperConfiguration autoMapperConfiguration, IIdentityProvider identityProvider)
{
CommandBus = commandBus;
AutoMapperConfiguration = autoMapperConfiguration;
IdentityProvider = identityProvider;
}
public ICommandBus CommandBus { get; }
public IAutoMapperConfiguration AutoMapperConfiguration { get; }
public IIdentityProvider IdentityProvider { get; }
}
And whatever handler for command:
public class EditUserHandler : IHandleCommand<EditUserCommand>
{
private readonly ICommandsContext _commandsContext;
public SaveUserHandler(ICommandsContext commandsContext)
{
_commandsContext = commandsContext;
}
public void Handle(EditUserCommand command)
{
... using dbcontext here...
}
}
}
For DI I use Autofac, all resources are set to per-request lifetime, split into modules, e.g. module for data access
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AppNameDbContext>().As<ICommandsContext>().InstancePerRequest();
builder.RegisterType<AppNameDbContext>().As<IQueryContext>().InstancePerRequest();
base.Load(builder);
}
}
The difference between both interfaces is that IQueryContext cannot change entity states and use SaveChagnes() method. IQueryContext have all DbSets in it, while ICommandsContext inherits from it and adds SettingState methods (added, modified, deleted) and SaveChanges() method.
IQueryContext is injected into queries and ICommandsContext into commands as seend in example aboove.
Now the Autofac config for command bus looks like that:
public class InfrastractureModule : Module
{
private ICommandsContext _commandsContext;
private ITranslationsCommandsContext _translationsCommandsContext;
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AutoMapperConfiguration>().
As<IAutoMapperConfiguration>().InstancePerRequest();
builder.RegisterType<ServiceTools>().As<IServiceTools>().InstancePerRequest();
builder.Register(c =>
{
_commandsContext = c.Resolve<ICommandsContext>();
_translationsCommandsContext = c.Resolve<ITranslationsCommandsContext>();
return new CommandBus(CreateHandlersFactory);
})
.As<ICommandBus>().InstancePerRequest();
base.Load(builder);
}
private IHandleCommand CreateHandlersFactory(Type type)
{
if (type == typeof(XXXCommand))
{
return new XXXHandler(_commandsContext);
}
}
While the command bus looks like that
public class CommandBus : ICommandBus
{
private readonly Func<Type, IHandleCommand> _handlersFactory;
public CommandBus(Func<Type, IHandleCommand> handlersFactory)
{
_handlersFactory = handlersFactory;
}
public void SendCommand<T>(T command) where T : ICommand
{
var handler = (IHandleCommand<T>) _handlersFactory(typeof(T));
handler.Handle(command);
}
}
There is completely separate context used for translations for the app, but I do not thing that is important here.
I did not find any posts with similar problem. It only occurs when where two requests processed at the same time. I do not know if the configuration is wrong or Autofac messes things up, because it should not technically dispose dbcontext which was allocated for another request.
Sorry for the wall of text ;) I hope someone can help with that.
Obiously changing dbcontext's lifetime to SingleInstance fixed the problem, but we do not want that :)
SOLUTION EDIT:
As #ZeljkoVujaklija noticed CommandsDbContext declarations in InfrastractureModule seemed strange. I removed whole CommandBus registration from InfrastractureModule. Instead I created CommandsModule in the assembly where all the commands sit. It looks like that:
public class CommandsModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(x => x.IsAssignableTo<IHandleCommand>())
.AsImplementedInterfaces();
builder.Register<Func<Type, IHandleCommand>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(IHandleCommand<>).MakeGenericType(t);
return (IHandleCommand)ctx.Resolve(handlerType);
};
});
builder.RegisterType<CommandBus>()
.AsImplementedInterfaces();
}
}
Not only it fixes the problem but also gets rid of huge factory.
If you are running within ASP.NET Core you should run InstancePerLifetimeScope instead of InstancePerRequest
Use InstancePerLifetimeScope instead of InstancePerRequest. In previous ASP.NET integration you could register a dependency as InstancePerRequest which would ensure only one instance of the dependency would be created per HTTP request. This worked because Autofac was in charge of setting up the per-request lifetime scope. With the introduction of Microsoft.Extensions.DependencyInjection, the creation of per-request and other child lifetime scopes is now part of the conforming container provided by the framework, so all child lifetime scopes are treated equally - there’s no special “request level scope” anymore. Instead of registering your dependencies InstancePerRequest, use InstancePerLifetimeScope and you should get the same behavior. Note if you are creating your own lifetime scopes during web requests, you will get a new instance in these child scopes.
http://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html#differences-from-asp-net-classic
public class ActionFilterVersionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Any(x => x.Key == "SetInternalVersion"))
{
// determine somehow that the **InternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
else
{
// determine somehow that the **ExternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
base.OnActionExecuting(actionContext);
}
}
I have ExternalSystem/InternalSystem with the ISystem interface.
How can I tell autofac to inject the ExternalSystem or InternalSystem into the instantiated controller as ISystem instance depending on the string value I pass in the ActionFilter or maybe message handler.
I know I can do stuff like:
builder.RegisterType<InternalSystem>().As<ISystem>().Keyed<ISystem>("Internal");
where I can use a func<string,ISystem> factory to resolve the class during runtime but this is not what I want to do.
Actually I need to register the ISystem within the the action filter, but then I would need somehow to pass the container into the filter, but that is not what I want...and prolly its also not possible.
// Action: returns external or internal value
public string Get()
{
return resolvedISystem.Get();
}
Of course I could resolve the ISystem depending on the func factory within each single action or put behavior into a base controller where I check for the header, but I really would prefer the action filter as it can be just globally registerd ONE time, but for each new controller I have to subclass the base controller.
Base controller sample with pseudo code , because the base.Request is null which needs another workaround/fix...
public class BaseController : ApiController
{
public BaseController(Func<string, ISystem> dataServiceFactory)
{
string system = base.Request.Headers.Any(x => x.Key == "SetInternalVersion") ? "internal" : "external";
System = dataServiceFactory(system);
}
public ISystem System { get; set; }
}
UPDATING the container is also marked as OBSOLETE by the Autofac author.
Thus I do not want to add registrations in my filter/handler and update/build the container again.
I think you should not use ActionFilter at all. You have a controller dependency which should be resolved properly based on the information coming from request. Here is a possible solution. You can use a static HttpContext.Current property in order to extract request header.
System classes:
public interface ISystem { }
public class ExternalSystem : ISystem { }
public class InternalSystem : ISystem { }
SystemKeyProvider:
public enum SystemKey
{
External,
Internal
}
public interface ISystemKeyProvider
{
SystemKey GetSystemKey();
}
public class SystemKeyProvider : ISystemKeyProvider
{
private const string HeaderKey = "SetInternalVersion";
private readonly HttpRequest _request;
public SystemKeyProvider(HttpRequest request)
{
_request = request;
}
public SystemKey GetSystemKey()
{
return (_request.Headers[HeaderKey] != null) ?
SystemKey.Internal :
SystemKey.External;
}
}
Controller constructor: ValuesController(ISystem system)
Autofac container registration:
var builder = new ContainerBuilder();
builder.Register(c => HttpContext.Current.Request).As<HttpRequest>().InstancePerRequest();
builder.RegisterType<SystemKeyProvider>().AsImplementedInterfaces();
// service registration
builder.RegisterType<ExternalSystem>().Keyed<ISystem>(SystemKey.External);
builder.RegisterType<InternalSystem>().Keyed<ISystem>(SystemKey.Internal);
builder.Register(c =>
c.ResolveKeyed<ISystem>(c.Resolve<ISystemKeyProvider>().GetSystemKey()))
.As<ISystem>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(builder.Build());
In this solution I created a SystemKeyProvider wrapper class which is responsible for providing appropriate key in order to resolve ISystem.
Demo:
When no SetInternalSystem header is present.
Then the dependency is resolved as ExternalSystem.
When SetInternalSystem header is present.
Then the dependency is resolved as InternalSystem.
I read the following article .NET Junkie - Meanwhile... on the command side of my architecture which was suggested by another stackoverflow user that outlines the command pattern and provides a strategy for how to use it with DI at the end of the article.
This has helped immensely but the one thing I'm missing, let's say I create a new class called CheckoutCustomerCommandHandler.
Now, let's say I need to inject this command and the MoveCustomerCommandHandler into a controller for whatever reason via the constructor. How does this affect the DI container setup and the constructor?
At the core, they both implement the same interface. It seems like this would result in a lookup issue for the DI container. In the article example, here is their sample injector setup:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
// Exactly the same as before, but now with the interface.
public class MoveCustomerCommandHandler
: ICommandHandler<MoveCustomerCommand>
{
private readonly UnitOfWork db;
public MoveCustomerCommandHandler(UnitOfWork db,
[Other dependencies here])
{
this.db = db;
}
public void Handle(MoveCustomerCommand command)
{
// TODO: Logic here
}
}
// Again, same implementation as before, but now we depend
// upon the ICommandHandler abstraction.
public class CustomerController : Controller
{
private ICommandHandler<MoveCustomerCommand> handler;
public CustomerController(
ICommandHandler<MoveCustomerCommand> handler)
{
this.handler = handler;
}
public void MoveCustomer(int customerId,
Address newAddress)
{
var command = new MoveCustomerCommand
{
CustomerId = customerId,
NewAddress = newAddress
};
this.handler.Handle(command);
}
}
using SimpleInjector;
using SimpleInjector.Extensions;
var container = new Container();
// Go look in all assemblies and register all implementations
// of ICommandHandler<T> by their closed interface:
container.RegisterManyForOpenGeneric(
typeof(ICommandHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
// Decorate each returned ICommandHandler<T> object with
// a TransactionCommandHandlerDecorator<T>.
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(TransactionCommandHandlerDecorator<>));
// Decorate each returned ICommandHandler<T> object with
// a DeadlockRetryCommandHandlerDecorator<T>.
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(DeadlockRetryCommandHandlerDecorator<>));
Here's what your class declarations would look like...
public class CheckoutCustomerCommandHandler :
ICommandHandler<CheckoutCustomerCommand> {...}
public class MoveCustomerCommandHandler :
ICommandHandler<MoveCustomerCommand> {...}
These may look like they implement the same interface, but they actually compile to two different interfaces because the generics arguments are different. Your DI framework will be able to distinguish between them.
I have a Presenter that takes a Service and a View Contract as parameters in its constructor:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}
I resolve my service with Autofac:
private ContainerProvider BuildDependencies() {
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
return new ContainerProvider(builder.Build());
}
In my ASPX page (View implementation):
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
// this is straightforward but not really ideal
// (IoCResolve is a holder for how I hit the container in global.asax)
this.presenter = new FooPresenter(this, IoCResolve<IFooService>());
// I would rather have an interface IFooPresenter so I can do
this.presenter = IoCResolve<IFooPresenter>();
// this allows me to add more services as needed without having to
// come back and manually update this constructor call here
}
}
The issue is FooPresenter's constructor expects the specific Page, not for the container to create a new one.
Can I supply a specific instance of the view, the current page, to the container for just this resolution? Does that make sense to do, or should I do this another way?
The way to solve passing what I like to call data parameters when resolving dependencies in Autofac is by using generated factories.
(Update: this question discusses the same problem and my article shows how you can avoid large amounts of factory delegates).
The solution to your problem will look something like this:
First, declare a factory delegate thath only accepts the data parameters:
public delegate IFooPresenter FooPresenterFactory(IFooView view);
Your presenter goes unchanged:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}
Next the Autofac container setup:
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
builder.Register<FooPresenter>().As<IFooPresenter>().FactoryScoped();
builder.RegisterGeneratedFactory<FooPresenterFactory>();
Now in your page you can in two lines of code resolve the presenter by first getting the factory and then calling the factory to do the resolution for you:
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
var factory = IoCResolve<FooPresenterFactory>();
this.presenter = factory(this);
}
}
I actually solved this exact problem and built a framework around it. I used Autofac parameters to pass existing views to the presenter resolution call.
First, I defined a custom resolution interface derived from Autofac's:
public interface IMvpContext : IContext
{
T View<T>();
}
which allowed me to register a presenter which resolves the view:
builder.RegisterPresenter(c => new FooPresenter(
c.View<IFooView>(),
c.Resolve<IFooService>()));
using an extension method which wraps Autofac's IContext in an implementation of IMvpContext:
public static IConcreteRegistrar RegisterPresenter<T>(
this ContainerBuilder builder,
Func<IMvpContext, T> creator)
{
return builder
.Register((context, parameters) => creator(new MvpContext(context, parameters)))
.FactoryScoped();
}
I defined a parameter type representing the view parameter:
public class MvpViewParameter : NamedParameter
{
public static readonly string ParameterName = typeof(MvpViewParameter).AssemblyQualifiedName;
public MvpViewParameter(object view) : base(ParameterName, view)
{}
}
It uses its own assembly-qualified type name as the parameter name. This has a very low likelihood of conflicting with legitimate parameters.
MvpContext passes all standard resolution calls to the base context. For the view, it resolves the parameter with the well-known name:
public sealed class MvpContext : IMvpContext
{
private IContext _context;
private IEnumerable<Parameter> _resolutionParameters;
public MvpContext(IContext context, IEnumerable<Parameter> resolutionParameters)
{
_context = context;
_resolutionParameters = resolutionParameters;
}
#region IContext
// Pass through all calls to _context
#endregion
#region IMvpContext
public T View<T>()
{
return _resolutionParameters.Named<T>(MvpViewParameter.ParameterName);
}
#endregion
}
The call to resolve the presenter provides the view parameter:
public partial class Foo : Page, IFooView
{
private readonly FooPresenter presenter;
public Foo()
{
this.presenter = IoCResolve<IFooPresenter>(new MvpViewParameter(this));
}
}