How far does Dependency Injection reach? - asp.net-mvc

My web app solution consists of 3 projects:
Web App (ASP.NET MVC)
Business Logic Layer (Class Library)
Database Layer (Entity Framework)
I want to use Ninject to manage the lifetime of the DataContext generated by the Entity Framework in the Database Layer.
The Business Logic layer consists of classes which reference repositories (located in the database layer) and my ASP.NET MVC app references the business logic layer's service classes to run code. Each repository creates an instance of the MyDataContext object from the Entity Framework
Repository
public class MyRepository
{
private MyDataContext db;
public MyRepository
{
this.db = new MyDataContext();
}
// methods
}
Business Logic Classes
public class BizLogicClass
{
private MyRepository repos;
public MyRepository
{
this.repos = new MyRepository();
}
// do stuff with the repos
}
Will Ninject handle the lifetime of MyDataContext despite the lengthy dependency chain from the Web App to the Data Layer?

EDIT
I has some problems with it some time ago, but now it seems to work:
Bind<CamelTrapEntities>().To<CamelTrapEntities>().Using<OnePerRequestBehavior>();
Instead of using HttpModule, you can use OnePerRequestBehavior and it will take care of handling context in current request.
EDIT 2
OnePerRequestBehavior needs to be registered in web.config, because it depends on HttpModule too:
In IIS6:
<system.web>
<httpModules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</httpModules>
</system.web>
With IIS7:
<system.webServer>
<modules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</modules>
</system.webServer>
PREVIOUS ANSWER
It is your responsibility to dispose context when it is not needed. Most popular way in ASP.NET is to have one ObjectContext per request. I do it by having HttpModule:
public class CamelTrapEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
((CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
HttpContext.Current.Items[#"CamelTrapEntities"] = new CamelTrapEntities();
}
}
This is injection rule:
Bind<CamelTrapEntities>().ToMethod(c => (CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]);
My Repository takes ObjectContext in constructor:
public Repository(CamelTrapEntities ctx)
{
_ctx = ctx;
}

Just want to mention that Autofac with the ASP.Net integration have the request lifetime support built-in. Resolve instances in the RequestContainer and they will be disposed (if implementing IDisposable) at the end of the request.
You should make your classes DI friendly though:
public class MyRepository
{
private MyDataContext db;
public MyRepository(MyDataContext context)
{
this.db = context;
}
// methods
}
public class BizLogicClass
{
private MyRepository repos;
public BizLogicClass(MyRepository repository)
{
this.repos = repository;
}
// do stuff with the repos
}

Related

Entity Framework DbContext Lifetime in ASP.NET MVC Using Ninject?

I have the following unit of work pattern set up for an MVC 5 application using Entity Framework. The unit of work has all the repos defined as follows so that they are all using the same dbcontext and it has one save method to co-ordinate the transaction using the same context:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public IProductRepository ProductRepository { get; private set; }
public ICustomerRepository CustomerRepository { get; private set; }
// Other reposistories
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
ProductRepository = new ProductRepository(_context);
CustomerRepository = new CustomerRepository(_context);
// Other reposistories
}
public void Complete()
{
_context.SaveChanges();
}
}
This is an example of my repo. The reason for using repos is for code re-use so that I'm not duplicating queries inside different controllers.
public class ProductRepository : IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context)
{
_context = context;
}
public Product GetProduct(int productId)
{
return _context.Ticket.SingleOrDefault(p => p.Id == productId);
}
public void Add(Product product)
{
_context.Product.Add(product);
}
// Other methods
}
I inject the unit of work class in my controller as follows using Ninject:
public class ProductsController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly IFileUploadService _FileUploadService;
public ProductsController(IUnitOfWork unitOfWork,
IFileUploadService fileUploadService)
{
_unitOfWork = unitOfWork;
_FileUploadService = fileUploadService;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateEditProductViewModel viewModel)
{
var product = new Product
{
// Do stuff
};
_unitOfWork.ProductRepository.Add(product);
// Call file upload service
_fileUploadService.Upload();
_unitOfWork.Complete();
}
}
This unit of work set up works fine if all I'm using are repos that are defined in the unit of work class. But now I want to use a service class to process some additional application logic and then the unit of work is committed in the controller action. If I define the class as follows it will be using a different instance of the context, In which case how would you co-ordinate a transaction where the service layers is ending up with a different context?
public class FileUploadService : IFileUploadService
{
private readonly IUnitOfWork _unitOfWork;
public FileUploadService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public uploadResult Upload()
{
// Some stuff
var uploadedFile = new UploadedFile
{
//some stuff
};
_unitOfWork.UploadedFileRepository.Add(uploadedFile);
}
}
I've done quite a bit of research online and I'm unable to find any resource that provides a practical example to solve this problem. I've read quite a bit of stuff on ditching unit of work and repos and simply using entity frameworks dbset. However as explained above the purpose of using
repos is to consolidate queries. My questions is how do I co-ordinate the unit of work with a service class.
I would like the service to use the same context so that it can access the repositories it needs to work with, and let the controller (client code) commit the operation when it see fits.
* UPDATE *
In my DI Container I resolve all interfaces using the following snippet:
private static IKernel CreateKernel()
{
RegisterServices(kernel);
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
// default binding for everything except unit of work
kernel.Bind(x => x.FromAssembliesMatching("*")
.SelectAllClasses()
.Excluding<UnitOfWork>()
.BindDefaultInterface());
return kernel;
}
Would adding the line kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); ensure that no more than one ApplicationDbContext is created, even if the request ends up hitting multiple controllers or service layers that all require an IUnitOfWork (ApplicationDbContext)?
If you are using MVC, then your unit of work is your web request. If I were you I'd ditch the UOW implementation and just make sure you dbcontext is instantiated in the Application_BeginRequest. Then I'd stuff it into the HttpContext for safe keeping. On Application_EndRequest, I dispose of the DbContext.
I would move the save to your repository.
I'd create a [Transaction] attribute that would maintain a TransactionScope something like this:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
private TransactionScope Transaction { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Transaction = new TransactionScope( TransactionScopeOption.Required);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
Transaction.Complete();
return;
}
Transaction.Dispose();
}
}
You can then just tag your controller methods with [Transaction].
I'm just spitballing here, but I do something similar with NHibernate instead of EF and it works out nicely for me.
The InRequestScope() will create a new instance of the bound type on every new web request, and at the end of that web request, it will Dispose that instance if it is disposable.
I am not sure how are you passing the ApplicationDbContext into your UnitOfWork. I am assuming that you use Ninject for this injection too. Just make sure that you bind your ApplicationDbContext using the InRequestScope()Bind.To().InRequestScope();.
This way, your ApplicationDbContext instance will be created once per request and disposed at the end.
Also, the use of InRequestScope is for types that are disposable, so you can also release resoruces in the Dispose method of your UnitOfWork method too.

Ninject.MVC3, Pass DependencyResolver to service-layer?

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);
}
}

Ninject Kernel Injection of a provider

I'm trying to use the [Inject] attribute on a BasicRoleProvider : RoleProvider provider.
In my provider, I did:
public class BasicRoleProvider : RoleProvider
{
[Inject]
private IAuthenticationService authenticationService;
/*Other stuff here*/
}
My Global.asax.cs file is as follows:
public class MvcApplication : NinjectHttpApplication
{
/* Other stuff here */
#region Inversion of Control
protected override IKernel CreateKernel()
{
return Container;
}
static IKernel _container;
public static IKernel Container
{
get
{
if (_container == null)
{
_container = new StandardKernel(new SiteModule());
}
return _container;
}
}
internal class SiteModule : NinjectModule
{
public override void Load()
{
//Set up ninject bindings here.
Bind<IAuthenticationService>().To<AuthenticationService>();
this.Kernel.Inject(Roles.Provider);
}
}
#endregion
}
Whenever a method in the BasicRoleProvider gets executed and is using the authenticationService, its null. I think my problem lies in the Global.ascx.cs file. Am I doing the injection right?
It seems possible that you are using Ninject in an unsupported way.
From https://github.com/ninject/ninject/wiki/Changes-in-Ninject-2
Things that were in Ninject 1.x that are not in Ninject 2:
Field injection: This is a bad
practice, and has been cut for
minimization.
Because you tagged your question MVC 3, I assume you are linking to Ninject 2. As far as I know, Ninject 1 in an MVC 3 app would be a dead end.
The Inject attribute still exists, and fields must still be a valid target for it, which is why you do not get a compile time error.
But Ninject 2 will happily ignore that Inject attribute on the fields, which is why it is null for you.

Ninject with MembershipProvider | RoleProvider

I'm using ninject as my IoC and I wrote a role provider as follows:
public class BasicRoleProvider : RoleProvider
{
private IAuthenticationService authenticationService;
public BasicRoleProvider(IAuthenticationService authenticationService)
{
if (authenticationService == null) throw new ArgumentNullException("authenticationService");
this.authenticationService = authenticationService;
}
/* Other methods here */
}
I read that Provider classes get instantiated before ninject gets to inject the instance. How do I go around this? I currently have this ninject code:
Bind<RoleProvider>().To<BasicRoleProvider>().InRequestScope();
From this answer here.
If you mark your dependencies with [Inject] for your properties in your provider class, you can call kernel.Inject(MemberShip.Provider) - this will assign all dependencies to your properties.
I do not understand this.
I believe this aspect of the ASP.NET framework is very much config driven.
For your last comment, what they mean is that instead of relying on constructor injection (which occurs when the component is being created), you can use setter injection instead, e.g:
public class BasicRoleProvider : RoleProvider
{
public BasicRoleProvider() { }
[Inject]
public IMyService { get; set; }
}
It will automatically inject an instance of your registered type into the property. You can then make the call from your application:
public void Application_Start(object sender, EventArgs e)
{
var kernel = // create kernel instance.
kernel.Inject(Roles.Provider);
}
Assuming you have registered your role provider in the config. Registering the provider this way still allows great modularity, as your provider implementation and application are still very much decoupled.

Unity 2.0 Web.config settings with MVC

I am trying to use Unity 2.0 for my current project with MVC and having trouble configuring paramter injection in the web.config file.
Here's what I have:
1) A Home Controller:
public class HomeController : Controller
{
IRepository repository = null;
public HomeController()
{
// Always calls this constructor. Why?
// Should be calling the constructor below that takes IRepository.
}
public HomeController(IRepository repository)
{
// Should be calling this constructor!!!
this.repository = repository;
}
public ActionResult Index()
{
List<int> intList = this.repository.GetInts();
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
A basic controller with two constructors. The 1st one takes no arguments, and the 2nd one takes IRepository as an argument (that's supposed to be injected by Unity)
2) SQL Repository
public class SQLRepository : IRepository
{
private string connectionString = null;
public SQLRepository(string connectionString)
{
this.connectionString = connectionString;
}
#region IRepository Members
public List<int> GetInts()
{
return new List<int>() { 1, 2, 3, 4, 5 };
}
#endregion
}
A future to be SQL repository, but for now it just implements 1 member of the IRepository interface, namely GetInts() and returns a list of integers.
3) IRepository Interace
public interface IRepository
{
List<int> GetInts();
}
An interface.
4) Application_Start() Event in my Global.asax file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
This is used to read the Unity 2.0 configuration from the web.config file in order to register and map types etc.
6) The Unity 2.0 Configuration Section in web.config
<unity>
<typeAliases>
<typeAlias alias="string" type="System.String, mscorlib" />
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="IRepository" type="NewMVCApp.Interfaces.IRepository, NewMVCApp" />
<typeAlias alias="SQLRepository" type="NewMVCApp.Repository.SQLRepository, NewMVCApp" />
</typeAliases>
<containers>
<container name="Default">
<types>
<type type="IRepository" mapTo="SQLRepository">
<lifetime type="singleton" />
<constructor>
<param name="connectionString">
<value value="ApplicationServices" />
</param>
</constructor>
</type>
</types>
</container>
</containers>
This is Unity 2.0 configuration section that I use. As you can see It typeAlias for both my IRepository and my SQLRepository classes and then maps IRepository to SQLRepository. So that anytime IRepository is requested, SQLRepository instance will be supplied. Also, I want to pass a connection string via the constructor to my SQLRepository.
5) So, what am I trying to do?
I am trying to use Unity 2.0 to pass in the instance of IRepository (SQLRepository) to my HomeController. But for some reason the default, parameterless constructor, for the HomeController() gets invoked. But HomeController(IRepository repository) never gets called. I am pretty sure that I did not set things up properly in the web.config file. But I am not sure how do set things up properly so the correct constructor on the HomeController gets called. Please help:)
&Thank you:)
Your Unity configuration looks fine. The problem is that you haven't hooked up Unity to the MVC framework, so the framework isn't using the container to create your controller, instead MVC is using the default logic, which calls the default constructor.
You need two things. First, an implementation of IControllerFactory. I usually use this one:
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if(controllerType != null)
return container.Resolve(controllerType) as IController;
return base.GetControllerInstance(requestContext, controllerType);
}
}
Second, you need to tell the MVC framework to use this controller factory instead of it's default one. You do this in your Application_Start handler. Do this:
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container));
Once you've done that, your controllers will be created through the container and everything should start working.
Thank you so much Chris!! That was it! Here's the how the Application_Start() event should look like in MVC2 using Unity 2.0:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
IControllerFactory controllerFactory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
// Do the line below only if you want to Register IoC programatically
//container.RegisterType<IRepository, SQLRepository>(new ContainerControlledLifetimeManager());
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
Try with Unity.Mvc nuget packages. You can use container.LoadConfiguration(); in UnityConfig class.
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.LoadConfiguration();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Then you can update web.config as below.
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity configSource="unity.config" />
Complete article can be found # MVC 5 with Unity for Dependency Injection.

Resources