I am attempting to refactor some code in an MVC application using Autofac Aggregate services. One of the services I am attempting to inject is an log4net.ILog that is using the type of a specific controller. edit
Per suggestion, I am using the publicly available LoggingModule from the Autofac example on modules. Leaving that out of the question as it's the same as posted:
var builder = new ContainerBuilder();
builder.RegisterAggregateService<IHomeControllerDependencies>();
//other service registrations
builder.RegisterModule<LoggingModule>();
builder.RegisterType<HomeController>().InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Next, in my aggregate service, I am using the following (leaving out the other services for brevity):
public interface IHomeControllerDependencies
{
ILog Logger { get; }
//other services
}
public class HomeControllerDependencies : IHomeControllerDependencies
{
public HomeControllerDependencies(IComponentContext context)
{
Logger = context.Resolve<ILog>();
//other services
}
public ILog Logger { get; }
//other services
}
I then inject the dependencies object in my HomeController as follows:
public class HomeController : Controller
{
private readonly IHomeControllerDependencies _dependencies;
public HomeController(IHomeControllerDependencies dependencies)
{
_dependencies = dependencies;
}
...
}
I still get the error that 'log4net.ILog' has not been registered.
edit
The interesting thing here is that when I use the Logger explicitly in the Controller's constructor, and take it out of the aggregate service without modifying registrations, it works and gets the logging instance correctly, even correctly typed as the HomeController Logger:
public class HomeController : Controller
{
public ILog Logger { get; }
public HomeController(IHomeControllerDependencies dependencies, ILog logger)
{
_dependencies = dependencies;
Logger = logger;
}
...
}
Aggregate:
public interface IHomeControllerDependencies
{
//other services
}
public class HomeControllerDependencies : IHomeControllerDependencies
{
public HomeControllerDependencies(IComponentContext context)
{
//other services
}
//other services
}
I guess I could keep it this way, but the main reason why I'm using aggregate services is to have a one parameter constructor.
Thanks
Related
I am building the asp.net WebAPI project and have used Autofac as IOC. Now i am doing constructor based injection and calls the various methods of the business class from the controller class.
Now i want to pass some additional data into the business class via the public property IncomingUser such as this one :-
My interface looks like this :-
public interface IUserManager
{
string IncomingUser { set; get; }
Task<List<String>> GetUserPofiles(string Name);
}
This readonly property IncomingUser will be used inside various methods defined under the class UserManager.
public class UserManager : IUserManager
{
public string IncomingUser { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public async Task<List<String>> GetUserPofiles(string Name)
{
......Business Logic for the method......
}
}
From the API controller, i am setting the DI like this :-
public class myAPIController : ApiController
{
IUserManager _Manager;
public myAPIController(IUserManager Mang)
{
_Manager = Mang;
}
}
Please suggest, how should i set the property IncomingUser from the API controller class with the help of autofac DI or another way.
i have XMLProductRepository and SQLProductRepository. now how could i switch between them dynamically. i am new in DI. so searching google for the same and found a link which discuss a bit. but still do not understand on what basis the repository will be changed and how. here is the code
public interface IProductRepository
{
IEnumerable<Product> GetAll();
Product Get(int id);
Product Add(Product item);
void Remove(int id);
bool Update(Product item);
}
public class XMLProductRepository : IProductRepository
{
public XMLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
public class SQLProductRepository : IProductRepository
{
public SQLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
Unity.Mvc3 is using as Di
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//Register the repository
container.RegisterType<IProductRepository, SQLProductRepository>();
return container;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
}
public class HomeController : Controller
{
private readonly IProductRepository productRepository;
public HomeController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
i understand the code that dynamically SQLProductRepository instance is getting injecting into controller. so my question is how to inject XMLProductRepository ?
i want to design something in such a way based on url dependency will be injected.
how to achieve it. looking for guide line. thanks
One possible solution is to inject an IProductRepositoryFactory instead of IProductRepository itself. It would look like this:
interface IProductRepositoryFactory
{
IProductRepository GetRepository(string url);
}
Then your HomeController would look like this:
public class HomeController : Controller
{
private readonly IProductRepositoryFactory productRepositoryFactory;
public HomeController(IProductRepositoryFactory productRepositoryFactory)
{
this.productRepositoryFactory = productRepositoryFactory;
}
}
This way, you'll be able to get required implementation of IProductRepository in your controller action at runtime — all you need is to implement the required logic in the IProductRepositoryFactory.GetRepository(url) method.
Here's a controller action example (note that getting current request URL in such a way makes this method less testable):
public Product Get(string id)
{
return productRepositoryFactory
.GetRepository(Request.Url.ToString())
.GetById(id);
}
UPD: The following is an example implementation of IProductRepositoryFactory. Just implement your own decision-making logic that returns an appropriate instance of IProductRepository based on the URL:
public class ProductRepositoryFactory : IProductRepositoryFactory
{
public IProductRepository GetRepository(string url)
{
if (url.Contains("xml")) { return new XMLProductRepository(); }
if (url.Contains("sql")) { return new SQLProductRepository(); }
throw new ArgumentException("url");
}
}
I don't know where you got the code from, perhaps this question, but the two implementations of IProductRepository that you show have two purposes.
SQLProductRepository will read and write data from and to the database.
XMLProductRepository can read XML and maybe write files.
When running code in a unit test, you generally don't want to connect to a database, but you do sometimes want to use data in a unit test. That's where the XML repository comes in handy. You prepare a data set in XML files that you can commit to version control, you inject another implementation of the requested interface - namely one that reads the XML file - and you don't need a database anymore.
That's why you configure your DI container to inject the SQLProductRepository, while in unit tests you or the DI container will provide an XMLProductRepository when the application requests an IProductRepository.
Now if you say that your controller, your business logic, is to choose SQLProductRepository for one particular request, based on the URI, and XMLProductRepository for the other, then using IProductRepository for that purpose is wrong. That is a problem that should not be solved using your DI container.
Introduce two new interfaces instead and apply those to the repositories:
public interface ISqlProductRepository : IProductRepository
{
}
public interface IXmlProductRepository : IProductRepository
{
}
SQLProductRepository : ISqlProductRepository
XMLProductRepository : IXmlProductRepository
And register and inject those:
// Application startup
container.RegisterType<ISqlProductRepository, SQLProductRepository>();
container.RegisterType<IXmlProductRepository, XMLProductRepository>();
// Controller
private readonly ISqlProductRepository _sqlProductRepository;
private readonly IXmlProductRepository _xmlProductRepository;
public HomeController(ISqlProductRepository sqlProductRepository, IXmlProductRepository xmlProductRepository)
{
_sqlProductRepository = sqlProductRepository;
_xmlProductRepository = xmlProductRepository;
}
public ActionResult SqlMethod1()
{
// use _sqlProductRepository
}
public ActionResult XmlMethod2()
{
// use _xmlProductRepository
}
Of course now you can't inject XMLProductRepository for SQLProductRepository anymore, but that's a problem easily solved using mocking.
Anyway based on your current streak of questions, you're trying to learn something about unit testing and dependency injection. Please pick up a decent book and stop tying pieces together from blog posts, which hardly ever explain everything you need to know.
I have this (simplified) controller setup:
[CustomAuthorizeAttribute]
public class MainController : Controller {}
public class AccountController : MainController
{
private IService _iService;
public AccountController()
{
_service = DependencyFactory.Resolve<IService>(SessionManager.ServiceKey)
}
public AccountController(IService service)
{
_service = service;
}
}
And CustomAuthorizeAttribute looks something like:
public CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool serviceKeyIsGood = CheckServiceKey(SessionManager.ServiceKey);
return serviceKeyIsGood;
}
}
The goal is to only have the account controller run if the user is authenticated, as defined by the presence of a "good" service key.
The problem I'm having is that the constructor for AccountController runs before OnAuthorize runs which causes the service to blow up (by design) since its service key is bad.
What's the best way to manage this? I'd like to take advantage of the simplicity of the CustomAuthorizeAttribute, and I have to avoid re-architecting the way our services are instantiated. (And the dependency factory is necessary as MVC complains about now having parameterless constructors.)
You can use injection of factorymethod instead of service itself:
[CustomAuthorizeAttribute]
public class MainController : Controller
public class AccountController : MainController
{
private Func<IService> _serviceFactory;
public AccountController()
{
_serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)
}
public AccountController(Func<IService> serviceFactory)
{
_serviceFactory= serviceFactory;
}
}
and use: to get service: service = _serviceFactory() when you need it.
PS: I recommend you to use standard methods for DI in MVC (controller factory or internal dependency resolver) to avoid code such _serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)
Previously I have had parameterless repositories being injected into my MVC controllers:
ProjectRepository implementation:
public class ProjectRepository : EntityFrameworkRepository<Project>, IProjectRepository
{
public ProjectRepository()
{ }
}
UnityConfig.cs dependency resolution:
container.RegisterType<IProjectRepository, ProjectRepository>();
MVC Controller:
private IProjectRepository _projectRepository { get; set; }
public ProjectController(IProjectRepository projectRepository)
{
_projectRepository = projectRepository;
}
This worked great.
Now I have implemented a Unit of Work pattern into my repository classes so that I can commit transactional changes to data (especially when changes are being made to more than one repository).
The new ProjectRepository implementation accepts a IUnitOfWork in its constructor:
public class ProjectRepository : EntityFrameworkRepository<Project>, IProjectRepository
{
public ProjectRepository(IUnitOfWork unitOfWork): base(unitOfWork)
{ }
}
This means that multiple repositories can share the same IUnitOfWork and changes can be collectively committed using UnitOfWork.SaveChanges().
QUESTION:
How do I now use dependency injection to instantiate the repository with an instance of IUnitOfWork?
public ProjectController(IProjectRepository projectRepository, IUnitOfWork unitOfWork)
{
_projectRepository = projectRepository;
_unitOfWork = unitOfWork;
}
There could also be more than one repository injected into the controller. How can these all be instantiated with the same IUnitOfWork?
When you register your IUnitOfWork instance, use PerResolveLifetimeManager, this will ensure every dependency of IUnitOfWork within a single IUnityContainer.Resolve gets provided the same instance.
For example:
public class SomeDependency
{
}
public class Service
{
public Service(SomeDependency someDependency, SomeDependency someDependency2)
{
Console.WriteLine(someDependency == someDependency2);
}
}
public static void Main()
{
using(var container = new UnityContainer())
{
container.RegisterType<SomeDependency>(new PerResolveLifetimeManager());
container.Resolve<Service>();
}
}
This will output True to the Console.
See the page for Understanding Lifetime Managers for further details.
In a MVC3-application with Ninject.MVC 2.2.0.3 (after merge), instead of injecting repostories directly into controllers I'm trying to make a service-layer that contain the businesslogic and inject the repostories there. I pass the ninject-DependencyResolver to the service-layer as a dynamic object (since I don't want to reference mvc nor ninject there). Then I call GetService on it to get repositories with the bindings and lifetimes I specify in NinjectHttpApplicationModule. EDIT: In short, it failed.
How can the IoC-container be passed to the service-layer in this case? (Different approaches are also very welcome.)
EDIT: Here is an example to illustrate how I understand the answer and comments.
I should avoid the service locator (anti-)pattern and instead use dependency injection. So lets say I want to create an admin-site for Products and Categories in Northwind. I create models, repositories, services, controllers and views according to the table-definitions. The services call directly to the repositories at this point, no logic there. I have pillars of functionality and the views show raw data. These bindings are configured for NinjectMVC3:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICategoryRepository>().To<CategoryRepository>();
kernel.Bind<IProductRepository>().To<ProductRepository>();
}
Repository-instances are created by ninject via two layers of constructor injection, in the ProductController:
private readonly ProductsService _productsService;
public ProductController(ProductsService productsService)
{
// Trimmed for this post: nullchecks with throw ArgumentNullException
_productsService = productsService;
}
and ProductsService:
protected readonly IProductRepository _productRepository;
public ProductsService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
I have no need to decouple the services for now but have prepared for mocking the db.
To show a dropdown of categories in Product/Edit I make a ViewModel that holds the categories in addition to the Product:
public class ProductViewModel
{
public Product Product { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
The ProductsService now needs a CategoriesRepository to create it.
private readonly ICategoryRepository _categoryRepository;
// Changed constructor to take the additional repository
public ProductsServiceEx(IProductRepository productRepository,
ICategoryRepository categoryRepository)
{
_productRepository = productRepository;
_categoryRepository = categoryRepository;
}
public ProductViewModel GetProductViewModel(int id)
{
return new ProductViewModel
{
Product = _productRepository.GetById(id),
Categories = _categoryRepository.GetAll().ToArray(),
};
}
I change the GET Edit-action to return View(_productsService.GetProductViewModel(id)); and the Edit-view to show a dropdown:
#model Northwind.BLL.ProductViewModel
...
#Html.DropDownListFor(pvm => pvm.Product.CategoryId, Model.Categories
.Select(c => new SelectListItem{Text = c.Name, Value = c.Id.ToString(), Selected = c.Id == Model.Product.CategoryId}))
One small problem with this, and the reason I went astray with Service Locator, is that none of the other action-methods in ProductController need the categories-repository. I feel it's a waste and not logical to create it unless needed. Am I missing something?
You don't need to pass the object around you can do something like this
// global.aspx
protected void Application_Start()
{
// Hook our DI stuff when application starts
SetupDependencyInjection();
}
public void SetupDependencyInjection()
{
// Tell ASP.NET MVC 3 to use our Ninject DI Container
DependencyResolver.SetResolver(new NinjectDependencyResolver(CreateKernel()));
}
protected IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NhibernateModule(),
new ServiceModule(),
new RepoModule()
};
return new StandardKernel(modules);
}
So in this one I setup all the ninject stuff. I make a kernal with 3 files to split up all my binding so it is easy to find.
In my service layer class you just pass in the interfaces you want. This service class is in it's own project folder where I keep all my service layer classes and has no reference to the ninject library.
// service.cs
private readonly IRepo repo;
// constructor
public Service(IRepo repo)
{
this.repo = repo;
}
This is how my ServiceModule looks like(what is created in the global.aspx)
// ServiceModule()
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IRepo>().To<Repo>();
}
}
Seee how I bind the interface to the repo. Now every time it see that interface it will automatically bind the the Repo class to it. So you don't need to pass the object around or anything.
You don't need worry about importing .dll into your service layer. For instance I have my service classes in their own project file and everything you see above(expect the service class of course) is in my webui project(where my views and global.aspx is).
Ninject does not care if the service is in a different project since I guess it is being referenced in the webui project.
Edit
Forgot to give you the NinjectDependecyResolver
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IResolutionRoot resolutionRoot;
public NinjectDependencyResolver(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
return resolutionRoot.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return resolutionRoot.GetAll(serviceType);
}
}