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.
Related
We have a project where we need to use DI and ASP Core.
I'm very new to this and have a question.
I have a controller named HomeController like this:
public class HomeController : BaseController {
private IOrderService _orderService;
public HomeController(IOrderService orderService) {
_orderService = orderService;
}
public IActionResult Index() {
var orders = _orderService.GetMyOrders();
return View(orders);
}
}
The code looks like this:
public class OrderService : BaseService, IOrderService {
public OrderService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public List<Orders> GetMyOrders() {
var orders = // do my code here which works fine!;
// here i need some code do check orders for delivery so
DeliveryService deliveryService = new DeliveryService(_dataContextService);
// update my orders and return these orders
return orders;
}
}
public class DeliveryService : BaseService, IDeliveryService {
public DeliveryService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public void MyMethod() {
}
}
public class BaseService {
protected IDataContextService _dataContextService;
}
Almost all my services have a constructor like the OrderService and DeliveryService. My question is, do I have to pass the _dataContextService every time, or is there a solution within the dependency pattern?
You should keep it the way you have it and asp.net core IoC will inject it for you, but make sure it is injected per request, this will help to insantiate only one context for each request and dispose it after the request is served.
You can register the context and services in the ConfigureServices method inside the Startup class as below
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<HomeController>();
services.AddTransient<IOrderService , OrderService >();
services.AddTransient<IDeliveryService, DeliveryService>();
services.AddScoped<IDataContextService , YourDataContextService >();
}
The AddScoped method will create only one instance of the object for each HTTP request
If I understand correctly what you are asking, you are looking for an IoC container. .NET Core has built in support for dependency injection. Basically, you just indicate which implementation should be provided when an interface is requested. Then the container will instantiate the types for you. See for example https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection.
Hope that helps
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!
I'm working on web application (web form). I want to be able to change EntityFrameworkRepositoryFactory to NHibernateRepositoryFactory in the future.
IRepositoryFactory
public interface IRepositoryFactory
{
IProductRepository GetProductRepository();
}
ProductRepository
public class ProductRepository : IProductRepository
{
ExDbContext _db;
public ProductRepository(ExDbContext dbContext)
{
_db = dbContext;
}
public IList<Product> ListProductsByCategoryId(int categoryId)
{
List<Product> productsByCategoryId = _db.Products.Where(x => x.ProductCategoryId == categoryId).ToList();
return productsByCategoryId;
}
}
And there is EntityFrameworkRepositoryFactory.
class EntityFrameworkRepositoryFactory:IRepositoryFactory
{
ExDbContext _db;
public EntityFrameworkRepositoryFactory(ExDbContext dbContext)
{
_db = dbContext;
//
// TODO: Add constructor logic here
//
}
public IProductRepository GetProductRepository()
{
return new ProductRepository(_db);
}
}
How can i make easy for changing this in future ? I want use ninject for access EntityFrameworkRepositoryFactory but I'm stuck. Is there any example for this ?
Thanks.
We will add Ninject to your web application, fix your repository classes and add some Ninject modules to configure dependency injection:
Install Ninject. You can do this easily using the Package Manager Console: Install-Package Ninject.Web -dependencyVersion Highest
Remove your RepositoryFactory. Delete IRepositoryFactory and EntityFrameworkRepositoryFactory. You don't need them. Ninject will create a Repository and provide the dependencies as soon as your application asks for them. You need factories only to have better control of an object's lifetime.
Fix the repository. Let's make things more conventional and use an IEnumerable<Product> to return a read-only collection of products as result of our query. We also use Get as a prefix, as most repository patterns do:
public interface IProductRepository
{
IEnumerable<Product> GetProductsByCategoryId(int categoryId);
}
class EfProductRepository : IProductRepository
{
private readonly ExDbContext db;
public EfProductRepository(ExDbContext dbContext)
{
this.db = dbContext;
}
public IEnumerable<Product> GetProductsByCategoryId(int categoryId)
{
var productsByCategoryId = this.db
.Products
.Where(x => x.ProductCategoryId == categoryId)
.ToArray();
return productsByCategoryId;
}
}
Create a Ninject module. We need to bind our repository implementation to its interface. The Entity Framework DbContext uses the "Unit of Work" pattern, so we also need to make sure that our entity context instances are going to be disposed as soon as a request ends. We could do this using a context factory and the using directive, but we can also use the "Request Scope" of Ninject as it's easier:
public class EfRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<EfProductRepository>();
this.Bind<ExDbContext>().ToSelf().InRequestScope();
}
}
At first, we bind IProductRepository to our concrete implementation. Thereby, whenever a component needs a product repository, Ninject will create an instance of EfProductRepository and use that.
Then we tell Ninject to bind ExDbContext to itself and use the request scope. All dependencies on ExDbContext will be served by one single instance of this class during a request, and this instance is going to be disposed when the request ends.
Load the module. In App_Start/NinjectWebCommon.cs update the following method:
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}
Add dependencies to your pages. In every page where you need to show products, add the following property:
[Inject]
public IProductRepository ProductRepository { get; set; }
We need to use property injection or method injection here, because Web Pages doesn't support constructor injection (which should usually be favored). The Inject attribute tells Ninject that we have a dependency here that we want to be injected.
Add a module for NHibernate later on.
public class NHibernateRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<NHibernateProductRepository>();
// Bind whatever else you need when working with NHibernate
}
}
// NinjectWebCommon
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}
I try to access my repository from a class for RSS service. So I used dependency injection for that.
Here is what I do in the NinjectControllerFactory:
ninjectKernel.Bind<IPostRepositoryFactory>().To<NinjectPostRepositoryFactory>().InSingletonScope();
Here is my IPostRepositoryFactory class:
public interface IPostRepositoryFactory
{
IPostRepository GetRepository();
}
public class NinjectPostRepositoryFactory : IPostRepositoryFactory
{
private readonly IKernel kernel;
public NinjectPostRepositoryFactory(IKernel kernel)
{
if (kernel == null)
throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
public IPostRepository GetRepository()
{
return kernel.Get<IPostRepository>();
}
}
Here is the call from my controller:
public ActionResult Feed(int? page = 1)
{
var mgr = new SyndicationManager();
return mgr.GetFeedResult(page);
}
Here is the SyndicationManager class:
public class SyndicationManager
{
[Inject]
public IPostRepositoryFactory m_PostRepositoryFactory { get; set; }
private SiteConfiguration m_SiteConfiguration;
public SyndicationManager()
{
m_SiteConfiguration = SiteManager.CurrentConfiguration;
}
public ActionResult GetFeedResult(int? page = 1)
{
IPostRepository repository = m_PostRepositoryFactory.GetRepository();
var feed = new SyndicationFeed(m_SiteConfiguration.Name,
m_SiteConfiguration.Description,
new Uri(SiteManager.GetBaseUrl()));
So I started debugging from my Feed action controller. Then accessing GetFeedResult and there is the problem: error is that my m_PostRepositoryFactory is always null.
Any help is greatly appreciated.
Why aren't you using constructor injection? It makes it easier to find dependencies of your classes and all resolves will fail directly if any of the dependencies are missing.
Just use the ninject.mvc3 nuget package to configure ASP.NET MVC to use dependency injection for the controllers.
And I don't see the use of a singleton factory to find the repository? Why can't you resolve the repository interface directly?
#Jehof is correct. ninject will not resolve any dependencies when you create objects yourself. But as I said: Don't use the kernel directly, configure MVC3+NInject correctly instead.
http://nuget.org/packages/Ninject.MVC3/2.2.2.0
I´m not an expert on Ninject, but i use Unity as DependencyInjection-Framework. I think the problem is that you instantiate SyndicationManager using its default constructor.
You need to get a reference to the SyndicationManager by resolving it from the Ninject-Kernel, otherwise the dependencies won´t be injected.
public ActionResult Feed(int? page = 1)
{
IKernel kernel = // get the kernel from somewhere
var mgr = kernel.Get<SyndicationManager>();
return mgr.GetFeedResult(page);
}
I was following this tutorial:
http://blog.johanneshoppe.de/2010/10/walkthrough-ado-net-unit-testable-repository-generator/
And I had this issue:
MVC3 & EF. Interface for TDD
However, now I have my interfaces setup (I am not using ninject due to project restrictions)
I am getting a null error here;
`Public partial class MyEntitiesRepository : MyEntitiesRepository
{
public IEnumerable<userdetails> getAlluserDetails()
{
return this.Context.userDetails.ToList();
}`
Context is null. I am using the exact same structure as the tutorial.
The header in my MVC controller that calls this is:
`
[HandleError]
public class HomeController : Controller
{
private MyEntitiesRepository _repository;
...
...
public HomeController() : this(new externalEntities(), new MyEntitiesRepository ()){}
public HomeController(externalEntities external, MyEntitiesRepository repository)
{
_repository = repository;
_ContextExt = external;
}
`
EDIT:
context is from:
[System.CodeDom.Compiler.GeneratedCode("ADO.NET Unit Testable Repository Generator", "0.5")]
public partial class MyEntitiesRepository
{
/// <summary>
/// Gets or sets the specialised object context
/// </summary>
/// <value>object context</value>
#if !DO_NOT_USE_UNITY
[Dependency]
#endif
public IMyEntities Context { get; set; }
}
}
I am guessing that in the example they pass the Context in the constructor. They can do this because they are using dependency injection and it will create that instance for you. Since you are not using Ninject, you will more than likely need to construct this Context yourself.
If you are unable to use Ninject or any other IoC container then you need to do a better job convincing your bosses to let you. If they still don't let you then you can do poor man's dependency injection I suppose:
public class MyEntitiesRepository
{
private MyDbContext context;
public MyEntitiesRepository() : this(new MyDbContext())
{ }
public MyEntitiesRepository(MyDbContext context)
{
this.context = context;
}
}
It's better than nothing I suppose?
Seeing the edit (the Dependency attribute) I guess the project restrictions you are referring to are that instead of Ninject you are to use Microsoft's Unity.
Now you can solve your problem using or not using Unity. To start with the latter: Adjust your HomeController and MyEntitiesRepository classes a little:
public HomeController() :
this(new externalEntities(),
new MyEntitiesRepository (new MyEntities()))
{
}
public HomeController(externalEntities external, MyEntitiesRepository repository)
{
_repository = repository;
_ContextExt = external;
}
public partial class MyEntitiesRepository
{
public MyEntitiesRepository(IMyEntities context)
{
this.Context = context;
}
public IMyEntities Context { get; private set; }
}
Here I made the assumption that you have a class MyEntities implementing the interface IMyEntities.
You could also use Unity. To get to know that framework a little better you could start at MSDN. I don't have any experience with Unity, but some things I noticied are that you need to create MyEntityRepository using a UnityContainer object:
IUnityContainer container = new UnityContainer();
...
MyEntityRepository repository = container.Resolve<MyEntityRepository>();
Before that works you need to register a mapping of MyEntities to IMyEntities:
container.RegisterType<IMyEntities, MyEntities>();
If you choose to try Unity I suggest you give it a try and ask a new question if you get stuck.