CCI am writing a facade to get data from different sources, normalize, and format it. I am new to using asp.net 5 and giving dependency injection a go but I am having an issue. I want to know how to resolve dependencies based on runtime input. Based on the route I want to instantiate the correct repository. For instance if I get passed Toyota I have want to instantiate a ToyotaRepository, if I get passed Ford I want to instantiate a FordRepository. Those repositories also have dependencies that are unique to each repository. All the repositories share the same ICarRepository Interface, and depend on the same interfaces but different concrete implementations. I thought about using a factory to create the repositories but then the dependencies of each repository would have to be injected into the factory, and that just doesn't feel right. As the number of repositories grow so with the number of dependencies that will need to be injected. Currently I am just newing up the repositories and their dependencies in the factory which also feels wrong, not very SOLID. Maybe there is an issue with my architecture?
[Route("api/v1/[controller]")]
public class CarsController : Controller
{
private IDataFormatter<Product> _formatter;
private ILogger _logger;
private ICarRepositoryFactory _repositoryFactory;
public CarssController(ILogger<CarsController> logger, IProductRepositoryFactory repositoryFactory, IDataFormatter<Car> formatter)
{
_logger = logger;
_repositoryFactory = repositoryFactory;
_formatter = formatter;
}
[HttpGet("{carType}")]
public async Task<IEnumerable<Car>> GetCars(string carType)
{
var repository = _repositoryFactory.Create(carType);
var cars = await repository.GetAll();
foreach(var car in cars)
{
_formatter.Format(car);
}
return cars;
}
}
public class CarRepositoryFacotry : ICarRepositoryFactory
{
private Dictionary<string, Func<ICarRepository>> _carRepositories = new Dictionary<string, Func<ICarRepository>>();
private ILogger<ICarRepository> _logger;
private IOptions<WebOptions> _webOptions;
private IOptions<DisplayInfoOptions> _displayOptions;
public CarRepositoryFacotry(ILogger<ICarRepository> logger, IOptions<WebOptions> webOptions, IOptions<DisplayInfoOptions> displayInfoOptions)
{
_logger = logger;
_webOptions = webOptions;
_displayInfoOptions = displayInfoOptions;
_carRepositories.Add("toyota", () => new ToyotaRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new ToyotaMapper(), _options));
_carRepositories.Add("ford", () => new FordRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new FordMapper(), _options));
}
public ICarRepository Create(string carType)
{
Func<ICarRepository> repo;
_carRepositories.TryGetValue(carType, out repo);
return repo.Invoke();
}
}
I am currently using the builtin dependency framework in asp.net 5 but Im willing to use autofac if it makes things eaisier. Any help or comments would be a big help.
Using factory with all repositories injected is feasible approach ( and much better than temporary "new-ing" dependencies )
example
public interface IVehicleRepository
{
bool CanHandle(string vendor); // example how to deal with choosing appropriate repository
IEnumerable<Vehicle> GetAll();
}
public class VehicleFactory
{
private readonly IVehicleRepository[] repositories;
public VehicleFactory(IVehicleRepository[] repositories)
{
this.repositories = repositories;
}
public IVehicleRepository Create(string vendor) {
return repositories.Single(r => r.CanHandle(vendor));
}
}
usage:
[Route("api/v1/[controller]")]
public class CarController : Controller
{
private readonly VehicleFactory factory;
public CarController(VehicleFactory factory)
{
this.factory = factory;
}
[HttpGet("{vehicleType}")]
public IEnumerable<Vehicle> GetVehicles(string vehicleType)
{
var repository = factory.Create(vehicleType);
var vehicles = repository.GetAll();
foreach (var vehicle in vehicles)
{
// Process(vehicle)
}
return vehicles;
}
}
I see it in that way:
Your CarsController take ICarRepository as a constructor parameter
and work with it
You have to wright and register your own
IControllerFactory which will analyze route parameters and create
concrete instance of Controller with concrete repository
First link at Google. May be not the best, but good.
http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be
My team uses Castle Windsor, an IoC container that can resolve all our dependencies with ease. (Should be similar to Autofac, but I've seen Castle Windsor more often in enterprise apps)
In your case, you can
1. Register FordRepository like this:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly(),
Component.For<DisplayInfoRepository>().ImplementedBy<DisplayInfoRepository>
.DependsOn(Dependency.OnValue("_displayInfoOptions", displayInfoOptionsObject)),
// whatever property name you have in DisplayInfoRepository
Component.For<ICarRepository>().ImplementedBy<FordRepository>().Named("Ford")
.DependsOn(Dependency.OnComponent(typeof(Logger), nameof("Logger")))
.DependsOn(Dependency.OnComponent(typeof(DisplayInfoRepository), nameof(DisplayInfoRepository)))
.DependsOn(Dependency.OnComponent(typeof(FordMapper), nameof(FordMapper)))
.DependsOn(Dependency.OnValue("_option", optionObject)),
// what ever property name you have in FordRepository
);
}
}
2. Start up the container:
// application starts...
var container = new WindsorContainer();
container.Install(FromAssembly.This());
// clean up, application exits
container.Dispose();
3. Get your car repositories based on strings like this
var carRepo = container.Resolve<ICarRepository>("Ford");
Let me know if any questions! Upvotes are greatly appreciated!
Related
I am creating an Azure Function App in Visual Studio with C# and .NET 6.
I have a service I created (CosmosDBService) that implements the interface ICosmosDBService:
public class CosmosDbService : ICosmosDbService
{
private Container? _container = null;
public CosmosDbService(
CosmosClient cosmosDbClient,
string databaseName,
string containerName)
{
_container = cosmosDbClient.GetContainer(databaseName, containerName);
}
I want to pass two different instances of this service into the Function App. Each service instance would represent a different container.
How would I set this up in Startup:FunctionsApp class using the FunctionsHostBuilder?
Default DI container does not support named such scenarios so you have next options - either create separate interfaces and implementations (and register/resolve them) for each databaseName-containerName pair or create a factory and use it to generate desired CosmosDbService instance:
public interface ICosmosDbServiceFactory
{
ICosmosDbService Create(string databaseName, string containerName);
}
class CosmosDbServiceFactory : ICosmosDbServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public CosmosDbServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ICosmosDbService Create(string databaseName, string containerName) => new CosmosDbService(
_serviceProvider.GetRequiredService<CosmosClient>(),
databaseName,
containerName
);
}
Register it with appropriate lifetime and inject it into corresponding class and use it in the constructor to resolve required ICosmosDbService instances.
You can do this, but I wouldn't recommend it. For instance in your start up if you had the following code:
services.AddSingleton<ICosmosDbService, CosmosDbService>();
services.AddSingleton<ICosmosDbService, OtherCosmosDbService>();
both instances would be registered in the Di container. If you had a class that depends on this interface, the following constructor would result in OtherCosmosDbService being injected:
public class SomeClass {
private readonly ICosmosDbService _service;
public SomeClass(ICosmosDbService service){
_service = service; // This would be OtherCosmosDbService
}
}
Both would be registered and in this instance, the last one registered "wins". If you wanted to get both then you could change the constructor to this:
public SomeClass(IEnumerable<ICosmosDbService> services){
// Write logic to handle finding which one you want
}
Honestly, I would go with Guru Stron's suggestion of creating separate interfaces for each container and registering them separately.
I think your design needs to be more granular - trying to access multiple containers (possibly in multiple COSMOS databases) with one interface/class goes against the SOLID principle of single responsibilty. Think about your domain and work from there 'downwards'
public interface ICustomers
{
public IEnumerable<Customer> GetCustomers();
}
public interface IProducts
{
public IEnumerable<Product> GetProducts();
}
public class CustomersInCosmosDatabase : ICustomers
{
private readonly CosmosClient cosmosClient;
public CustomersInCosmosDatabase(CosmosClient cosmosClient)
{
this.cosmosClient = cosmosClient;
}
public IEnumerable<Customer> GetCustomers()
{
var container = cosmosClient.GetContainer("customerDatabaseId", "customerContainerId");
return container.GetItemLinqQueryable<Customer>();
}
}
public class ProductsInCosmosDatabase : IProducts
{
private readonly CosmosClient cosmosClient;
public ProductsInCosmosDatabase(CosmosClient cosmosClient)
{
this.cosmosClient = cosmosClient;
}
public IEnumerable<Product> GetProducts()
{
var container = cosmosClient.GetContainer("productDatabaseId", "prodcutContainerId");
return container.GetItemLinqQueryable<Product>();
}
}
and your registrations become:
serviceCollection.AddAzureClients(clientBuilder =>
{
clientBuilder.AddClient<CosmosClient, CosmosClientOptions>((o) =>
new CosmosClient("connectionString", new DefaultAzureCredential()));
});
serviceCollection.AddTransient<ICustomers, CustomersInCosmosDatabase>();
serviceCollection.AddTransient<IProducts, ProductsInCosmosDatabase>();
You are then in the business of injecting Customer collections and Product collections everywhere NOT CosmosDBServices.
MVC application using Identity and EF.
I want to implement dependency injection using Unity.
I have installed Unity in the project (both Unity and Unity.mvc5), but now I am lost at how to implement it...
As of now, (before changing anything) I instantiate dbcontext in every controller, then in controller constructor I create service instances with new xxxx(db).
My controllers are like this:
public class SomeController : Controller {
private ApplicationDbContext db = new ApplicationDbContext("DefaultConnection");
private XxService xxService;
public SomeController() {
this.xxService = new XxService(db);
}
public ActionResult Index() {
string name = xxService.Foo(5);
return View();
}
}
then I have my Services:
public class XxService {
private ApplicationDbContext db;
private YyService yyService;
public XxService(ApplicationDbContext db) {
this.db = db;
this.yyService = new YyService(db);
}
public string Foo(int id) {
Customer customer = yyService.Bar(id);
return customer.Name;
}
}
public class YyService {
private ApplicationDbContext db;
public YyService(ApplicationDbContext db) {
this.db = db;
}
public Customer Bar(int id) {
return db.Customers.Find(id);
}
}
and the unity config:
public static class UnityConfig {
public static void RegisterComponents() {
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
//container.RegisterType<XxService>(new Unity.Injection.InjectionConstructor());
}
}
I dont really understand what and how should I register in Unity config, and/or what interfaces should I create...
Should I register the Services? the dbcontext? both? and... how? some code would be great, this is driving me nuts...
Yes, you have to put every registration of the interface\concrete implementation pair inside of RegisterComponents(). I assume you defined interface for you DbContext class. So you have done pretty much everything except registering services:), like this:
var container = new UnityContainer();
container.RegisterType<IService1, Service1>(new PerRequestLifetimeManager());
container.RegisterType<IService2, Service2>(new SingletonLifetimeManager());
container.RegisterType<IMyDbContext, MyDbContext>(new PerRequestLifetimeManager(),
new InjectionConstructor("name=MyDbConnection");
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Unity Container / Microsoft Dependency Injection
https://github.com/unitycontainer/microsoft-dependency-injection
Using Autofac, given multiple interfaces in constructor parameters which is not what I want to achieve, let's say I have;
public class SomeController : ApiController
{
private readonly IDomainService _domainService;
private readonly IService1 _service1;
private readonly IService2 _service2;
private readonly IService3 _service3;
public SomeController(IDomainService domainService,
Iservice1 service1,
IService2 service2,
IService2 service3, ...)
{
_domainService = domainService;
_service1 = service1;
_service2 = service2;
_service3 = service3;
...
}
}
Or, we may do one interface and has multiple properties, e.g.;
public interface IAllServices
{
IDomainService DomainService { get; set; }
IService1 Service1 { get; set; }
IService2 Service2 { get; set; }
IService3 Service3 { get; set; }
}
public class SomeController : ApiController
{
private readonly IAllServices _allServices;
public SomeController(IAllServices allServices)
{
_allServices = allServices;
var domainService1 = _allServices.DomainService;
var service1 = _allServices.Service1;
etc...
}
}
However, I would like to have a list of services, and this code works for me, i.e.;
public interface IMyApp
{
IEnumerable<dynamic> Services { get; set; }
}
public class SomeController : ApiController
{
private readonly IMyApp _myapp;
public SomeController(IMyApp myapp)
{
_myapp = myapp;
foreach (var item in _myapp.Services)
{
if (item is IService1) { // do something... }
if (item is IService2) { // do something... }
if (item is IWhatever) { // do whatever something... }
}
}
}
But, I don't have a better best practice how to create the module, here is my module;
public class MainModule : Autofac.Module
{
private readonly string[] _serviceNames;
private readonly IDomainService _domainService;
public MainModule(IDomainService domainService, params string[] serviceNames)
{
_serviceNames = serviceNames;
_domainService = domainService;
}
protected override void Load(ContainerBuilder builder)
{
List<dynamic> _services = new List<dynamic>();
_services.Add(_domainService);
foreach (var serviceName in _serviceNames)
{
switch (serviceName)
{
case "MyService1":
IService1 service1 = new Service1();
_modules.Add(service1);
break;
case "MyService2":
IService2 service2 = new Service2();
_modules.Add(service2);
break;
case "SomeWhateverService":
IWhatever whateverService = new WhateverService();
_modules.Add(whateverService);
break;
}
}
builder.RegisterType<MyApp>()
.As<IMyApp>()
.WithParameter(new TypedParameter(typeof(IEnumerable<dynamic>), _services));
}
}
So, this code works, but I would like to make my DomainService and all of the Services registered in the container as well. That is, I want to replace whatever inside the switch statement without new keyword.
IService1 service1 = new Service1();
_modules.Add(service1);
And I would like to register the domain service as well. So, inside my Bootstrapper is like this;
public static class Initializer
{
public static IContainer BuildContainer(
HttpConfiguration config, Assembly assembly, IDomainService domainService, params string[] services)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(assembly);
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule(new MainModule(domainService, services));
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
}
}
And what happen is, I need to create the domain service in the startup, i.e.;
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
MyDomainService domainService = new MyDomainService();
var container =
Initializer.BuildContainer(
GlobalConfiguration.Configuration,
Assembly.GetExecutingAssembly(),
domainService,
"MyService1", "MyService2", "SomeWhateverService");
}
}
You can see that I have to create the domain service first, which is not using IoC;
MyDomainService domainService = new MyDomainService();
and add to the module.
The big question, how to do this in proper way using Autofac. My Bootstrapper is in another project and all of the interfaces are in other project as well.
Many thanks for the help. And sorry for the long question.
Solution:
After testing several model, it seems the best way is to use domain events model for this type of scenario instead of injecting the services into the domain.
The proper way of doing dependency injection is using Constructor Injection. Constructor Injection should always your preferred choice, and only under high exception, you should fall back to another method.
You proposed property injection as an alternative, but this causes Temporal Coupling which means that classes can be initialized while a required dependency is missing, causing null reference exceptions later on.
The method where you inject a collection containing all services where the constructor is responsible of getting the dependencies it needs, is a variation of the Service Locator pattern. This pattern is littered with problems and is considered to be an anti-pattern.
Grouping dependencies into a new class and injecting that is only useful in case that class encapsulates logic and hides the dependencies. This pattern is called Facade Service. Having one big service that exposes the dependencies for others to use can be considered a form of the Service Locator anti-pattern, especially when the number of services that this class exposes starts to grow. It will become the common go-to object for getting services. Once that happens, it exhibits the same downsides as the other form of Service Locator does.
Extracting dependencies into a different class while allowing the consumer to use those dependencies directly doesn't help in reducing complexity of the consumer. That consumer will keep the same amount of logic and the same number of dependencies.
The core problem here seems that your classes get too many dependencies. The great thing about constructor injection though is that it makes it very clear when classes have too many dependencies. Seeking other methods to get dependencies doesn't make the class less complex. Instead of trying other methods of injection, try the following:
Apply the Single Responsibility Principle. Classes should have one reason to change.
Try extracting logic with its dependencies out of the class into a Facade Service
Remove logic and dependencies that deals with cross-cutting concerns (such as logging and security checks) from the class and place them in infrastructure (such as decorators, interceptors or depending on your framework into handlers, middleware, message pipeline, etc).
After testing several model, it seems the best way is just use domain events pattern for this type of scenario instead of injecting the services into the domain.
I refer to Udi Dahan article on domain events:
http://udidahan.com/2009/06/14/domain-events-salvation/
I have been reading Mark Seemann's excellent book on DI and hope to implement it in my next WPF project. However I have a query regarding object lifetime. So far, most examples seem to explain the repository pattern per request for MVC applications. In WPF there isn't really an alternative to this (I think). Seeing as the object graph of the entire application is constructed in the composition root, how can I make sure that my unit-of-work stuff is working properly. For example:
public class ContextFactory : IContextFactory
{
DBContext context;
public ContextFactory()
{
context = new MyDBContext();
}
public DBContext GetContext()
{
return context;
}
}
public class ItemOneRepository() : IItemOneRepository
{
DBContext context;
public ItemOneRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItems()
{
return context.ItemOnes;
}
}
public class ItemTwoRepository() : IItemTwoRepository
{
DBContext context;
public ItemTwoRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
public class ThingService : IThingService
{
IItemOneRepository itemOneRepo;
IItemTwoRepository itemTwoRepo;
public ThingService(
IItemOneRepository itemOneRepository,
IItemTwoRepository itemTwoRepository)
{
itemOneRepo = itemOneRepository;
itemTwoRepo = itemTwoRepository;
}
public IEnumerable Things GetThing()
{
var ItemOnes = itemOneRepo.GetItems();
return ItemOnes.Select(i =>
new Thing(
i.FieldOne,
i.FieldFour,
itemRepoTwo.GetItemsByItemOneID(i.ID)
)
);
}
}
In this case the MyDBContext instance is created through ContextFactory in the composition root. ItemOneRepository and ItemTwoRepository are using the same unit-of-work (MyDBContext), but so is the rest of the application which is plainly wrong. What if I changed the repositories to accept a DBContext instead of ContextFactory and added a ThingServiceFactory class like:
public ThingServiceFactory : IThingServiceFactory
{
IContextFactory contextFactory;
public ThingServiceFactory(IContextFactory factory)
{
contextFactory = factory;
}
public IThingService Create()
{
MyDBContext context = contextFactory.Create();
ItemOneRepository itemOneRepo = new ItemOneRepository(context);
ItemOneRepository itemTwoRepo = new ItemTwoRepository(context);
return new ThingService(itemOneRepo, itemTwoRepo);
}
}
This is better as I can now pass the ThingServiceFactory to my ViewModels instead of an instance of ThingService (complete with DBContext). I can then create a unit-of-work whenever I need one and instantly dispose of it when I’ve finished. However, is this really the correct approach. Do I really need to write a factory for every unit-of-work operation I need? Surely there is a better way...
There's IMO only one good solution to this problem and that is to apply a command-based and query-based application design.
When you define a single ICommandHandler<TCommand> abstraction to define business transactions, you can inject closed versions of that interface into any form that needs this. Say for instance you have a "move customer" 'command' operation:
public class MoveCustomer
{
public Guid CustomerId;
public Address NewAddress;
}
And you can create a class that will be able to execute this command:
public class MoveCustomerHandler : ICommandHandler<MoveCustomer>
{
private readonly DBContext context;
// Here we simply inject the DbContext, not a factory.
public MoveCustomerHandler(DbContext context)
{
this.context = context;
}
public void Handle(MoveCustomer command)
{
// write business transaction here.
}
}
Now your WPF Windows class can depend on ICommandHandler<MoveCustomer> as follows:
public class MoveCustomerWindow : Window
{
private readonly ICommandHandler<MoveCustomer> handler;
public MoveCustomerWindows(ICommandHandler<MoveCustomer> handler)
{
this.handler = handler;
}
public void Button1Click(object sender, EventArgs e)
{
// Here we call the command handler and pass in a newly created command.
this.handler.Handle(new MoveCustomer
{
CustomerId = this.CustomerDropDown.SelectedValue,
NewAddress = this.AddressDropDown.SelectedValue,
});
}
}
Since MoveCustomerWindow lives for quite some time, it will drag on its dependencies for as long as it lives. If those dependencies shouldn't live that long (for instance your DbContext) you will be in trouble and Mark Seemann calls this problem Captive Dependency.
But since we now have a single ICommandHandler<TCommand> abstraction between our presentation layer and our business layer, it becomes very easy to define a single decorator that allows postponing the creation of the real MoveCustomerHandler. For instance:
public class ScopedCommandHandlerProxy<TCommand> : ICommandHandler<TCommand>
{
private readonly Func<ICommandHandler<TCommand>> decorateeFactory;
private readonly Container container;
// We inject a Func<T> that is able to create the command handler decoratee
// when needed.
public ScopedCommandHandlerProxy(
Func<ICommandHandler<TCommand>> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Handle(TCommand command)
{
// Start some sort of 'scope' here that allows you to have a single
// instance of DbContext during that scope. How to do this depends
// on your DI library (if you use any).
using (container.BeginLifetimeScope())
{
// Create a wrapped handler inside the scope. This way it will get
// a fresh DbContext.
ICommandHandler<TCommand> decoratee =this.decorateeFactory.Invoke();
// Pass the command on to this handler.
decoratee.Handle(command);
}
}
}
This sounds a bit complex, but this completely allows you to hide the fact that a new DbContext is needed from the client Window and you hide this complexity as well from your business layer; you can simply inject a DbContext into your handler. Both sides know nothing about this little peace of infrastructure.
Of course you still have to wire this up. Without a DI library you do something like this:
var handler = new ScopedCommandHandlerProxy<MoveCustomerCommand>(
() => new MoveCustomerCommandHandler(new DbContext()),
container);
How to register this in a DI library is completely depending on the library of choice, but with Simple Injector you do it as follows:
// Register all command handler implementation all at once.
container.Register(
typeof(ICommandHandler<>),
typeof(ICommandHandler<>).Assembly);
// Tell Simple Injector to wrap each ICommandHandler<T> implementation with a
// ScopedCommandHandlerProxy<T>. Simple Injector will take care of the rest and
// will inject the Func<ICommandHandler<T>> for you. The proxy can be a
// singleton, since it will create the decoratee on each call to Handle.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ScopedCommandHandlerProxy<>),
Lifestyle.Singleton);
This is just one of the many advantages that this type of design gives you. Other advantages is that it makes much easier to apply all sorts of cross-cutting concerns such as audit trailing, logging, security, validation, de-duplication, caching, deadlock-prevention or retry mechanisms, etc, etc. The possibilities are endless.
ItemOneRepository and ItemTwoRepository are using the same
unit-of-work (MyDBContext), but so is the rest of the application
which is plainly wrong.
If your factory is registered with a transient lifecycle, you will get a new instance every time it's injected, which will be a new DBContext each time.
However, I would recommend a more explicit unit of work implementation:
public DBContext GetContext() //I would rename this "Create()"
{
return new MyDBContext();
}
And:
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
using (var context = contextFactory.Create())
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
This gives you fine-grained control over the unit of work and transaction.
You might also ask yourself if the repositories are gaining you anything vs. just using the context directly via the factory. Depending on the complexity of your application, the repositories may be unnecessary overhead.
I am reasonably new to Autofac and have come up against a problem when injecting dependencies that have arguments that are only known at runtime. (the code below is an example of the problem I am trying to describe).
Here is where I setup my container (which gets called in Global.asax)
public class Bootstrapper
{
public static void Config()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<PersonService>().As<IPersonService>().InstancePerHttpRequest();
builder.RegisterType<PersonRepository>().As<IPersonRepository>().InstancePerHttpRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Here are the types.
public class PersonService : IPersonService
{
private readonly IPersonRepository _repository;
public PersonService(IPersonRepository repository)
{
_repository = repository;
}
public Person GetPerson(int id)
{
return _repository.GetPerson(id);
}
}
public interface IPersonRepository
{
Person GetPerson(int id);
}
public class PersonRepository : IPersonRepository
{
private readonly int _serviceId;
public PersonRepository(int serviceId)
{
_serviceId = serviceId;
}
public Person GetPerson(int id)
{
throw new System.NotImplementedException();
}
}
Then the controller takes the PersonService in the constructor
public class HomeController : Controller
{
private readonly IPersonService _service;
public HomeController(IPersonService service)
{
_service = service;
}
public ActionResult Index()
{
return View();
}
}
Obviously this will fall over due to the container expecting the ServiceId argument on the constructor of PersonRepository with the following exception "Cannot resolve parameter 'Int32 serviceId'"
I can get the serviceId once I know HttpContext.Request.Current.Url, however this is not known at the time of creating the Container.
I have looked at many articles, forums etc but don't seem to be getting anywhere.
Could anyone point me in the right direction. Your help will be much appreciated.
Thanks
I know you use autofac but in our project we use Unity and it definitely can insert primitive types to type registration like this:
container.RegisterTypeWithParams<INewsRepository, NewsRepository>("ConnectionString", typeof(ILoggedUser));
Look at this
In general, you don't want to do this as you've modeled it (your PersonRepository). DI is used to resolve service dependencies, and what you have is a stateful component.
The way to model this is to use an abstract factory. Mark Seemann has an excellent blog post on this exact subject.
As you noted in your comment, passing the value via method injection is also an option, but can be ugly if it needs to be passed down through multiple dependencies.