Ninject + ASP.net MVC + Entity Framework - when is my context disposed? - asp.net-mvc

I am using Ninject in my MVC 3 application and one of my dependencies is on Entity Framework:
interface IFooRepository
{
Foo GetFoo(int id);
}
public EFFooRepository : IFooRepository
{
private FooDbContext context;
public EFFooRepository(FooDbContext context)
{
this.context = context;
}
}
I set up a binding like so in Ninject, so if I have more than one dependency and they both need a data context they end up sharing the same context:
Bind<FooDbContext>().ToSelf().InRequestScope();
I am uncertain of when my context will be disposed. Since I am not the one that instantiates it, will it ever get disposed of or will it just get disposed of when it is garbage collected? Does Ninject know to Dispose of anything when it is done with it?

If the FooDbContext implements IDisposable, Ninject will automatically call the Dispose method on it at the end of the request.
Here's how you can verify it:
Create a new ASP.NET MVC 3 application using the default template
Install the Ninject.Mvc3 NuGet package
Have the following:
public interface IFooRepository
{
}
public class FooDbContext: IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}
public class EFFooRepository : IFooRepository
{
private FooDbContext _context;
public EFFooRepository(FooDbContext context)
{
_context = context;
}
}
public class HomeController : Controller
{
private readonly IFooRepository _repo;
public HomeController(IFooRepository repo)
{
_repo = repo;
}
public ActionResult Index()
{
return View();
}
}
Add the following in the RegisterServices method of ~/App_Start/NinjectMVC3.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<FooDbContext>().ToSelf().InRequestScope();
kernel.Bind<IFooRepository>().To<EFFooRepository>();
}
Run the application. As expected at the end of the request, the FooDbContext instance is disposed and the NotImplementedException exception is thrown.

Related

Configuring Autofac with ASP.NET MVC 5

I am trying to implement Dependency Injection with Autofac in an ASP.NET MVC5 Project. But I am getting the following error every time:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyProjectName.DAL.Repository` ........
My Autofac configuration code in App_Start folder as follows:
public static class IocConfigurator
{
public static void ConfigureDependencyInjection()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<Repository<Student>>().As<IRepository<Student>>();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
In Global.asax file:
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
// Other MVC setup
IocConfigurator.ConfigureDependencyInjection();
}
}
Here is my IRepository:
public interface IRepository<TEntity> where TEntity: class
{
IQueryable<TEntity> GelAllEntities();
TEntity GetById(object id);
void InsertEntity(TEntity entity);
void UpdateEntity(TEntity entity);
void DeleteEntity(object id);
void Save();
void Dispose();
}
Here is my Repository:
public class Repository<TEntity> : IRepository<TEntity>, IDisposable where TEntity : class
{
internal SchoolContext context;
internal DbSet<TEntity> dbSet;
public Repository(SchoolContext dbContext)
{
context = dbContext;
dbSet = context.Set<TEntity>();
}
.....................
}
Here is my Student Controller:
public class StudentController : Controller
{
private readonly IRepository<Student> _studentRepository;
public StudentController()
{
}
public StudentController(IRepository<Student> studentRepository)
{
this._studentRepository = studentRepository;
}
....................
}
What's wrong in my Autofac Configuration..Any Help Please??
To inject a dependency you need to have satisfied all of the dependencies for all of the pieces down the chain.
In your case, the Repository constructor cannot be satisfied without a SchoolContext.
So in your registration add:
builder.RegisterType<SchoolContext>().InstancePerRequest();
See http://docs.autofac.org/en/latest/lifetime/instance-scope.html#instance-per-request

How to new up an object independent of the container? [duplicate]

I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.

Web API, odata v4 and Castle Windsor

I have WebApi project with ODataController and I'm trying to inject some dependency into MyController. I was following this blogpost by Mark Seemann.
Consider code below.
Problem is, that when is MyController creating, I got exception inside WindsorCompositionRoot Create method on this line,
var controller = (IHttpController)this.container.Resolve(controllerType);
An exception of type 'Castle.MicroKernel.ComponentNotFoundException'
occurred in Castle.Windsor.dll but was not handled in user code
Additional information: No component for supporting the service
System.Web.OData.MetadataController was found
Any idea how to fix this?
Thank you.
My controller:
public class MyController : ODataController
{
private readonly DataLayer _db;
public PrepravyController(DataLayer db)
{
_db = db;
}
}
CompositonRoot:
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)this.container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => this.container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
Global asax:
var container = new WindsorContainer();
container.Install(new RepositoriesInstaller());
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorCompositionRoot(container));
GlobalConfiguration.Configure(WebApiConfig.Register);
Make sure you're registering all your controllers with the container:
public class ControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestylePerWebRequest())
.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
}
}
Windsor uses installers to encapsulate and partition registration logic. It also includes a helper called FromAssembly, so you don't need to manually instantiate all your installers:
_container = new WindsorContainer();
_container.Install(FromAssembly.This());

Structuremap Constructor injection Unit of Work always null

I am trying to pass my unitofwork into my generic base repository, but when i try and call some of the methods the unitofwork isnt being passed into the base repository.
The scenario: I inject the userRepository below into my UserController all fine, its when it calls the userRepository.Save(user) it fails due to the unitofwork being null. Im not sure why though?
Im using nhibernate and structuremap. I think ive wired everything up correctly but here is some code to double check:
Here is the base repository:
public class BaseRepository<T> : IRepository<T> where T : IAggregateRoot
{
private readonly IUnitOfWork _unitOfWork;
public BaseRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public BaseRepository()
{}
public void Save(T Entity)
{
_unitOfWork.Session.Save(Entity);
}
}
A specific repository:
public class UserRepository : BaseRepository<User>, IUserRepository
{
}
This is my nhibernate structuremap configuration:
public NhibernateRegistry()
{
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For(typeof(IRepository<>)).Use(typeof(BaseRepository<>));
// Nhibernate Session
For<ISession>().HybridHttpOrThreadLocalScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
// Nhibernate SessionFactory
For<ISessionFactory>().Singleton().Use(NhibernateHelper.CreateSessionFactory());
}`
Here is my nhibernate http module:
public class NHibernateModule : IHttpModule
{
private IUnitOfWork _unitOfWork;
public void Init(HttpApplication context)
{
context.BeginRequest += ContextBeginRequest;
context.EndRequest += ContextEndRequest;
}
private void ContextBeginRequest(object sender, EventArgs e)
{
_unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
}
private void ContextEndRequest(object sender, EventArgs e)
{
try { _unitOfWork.Commit(); }
catch { _unitOfWork.Rollback(); }
finally { Dispose(); }
}
public void Dispose()
{
if (_unitOfWork != null)
_unitOfWork.Dispose();
}
}
UserRepository needs a constructor that takes in the IUnitOfWork and passes it to the BaseRepository constructor. Currently, UserRepository is using the parameterless constructor of BaseRepository, so no IUnitOfWork is injected. Get rid of the parameterless constructor, and make sure all derived types pass the IUnitOfWork to the base.

Ninject doesn't call Dispose on objects when out of scope

I was surprised to find that at least one of my objects created by Ninject is not disposed of at the end of the request, when it has been defined to be InRequestScope
Here's the object I'm trying to dispose:
Interface:
public interface IDataContext : IDisposable
{
MessengerEntities context { get; set; }
}
MessengerEntities is Entity Framework's implementation of ObjectContext -- my context object.
Then I create a concrete class like so:
public class DataContext : IDataContext
{
private MessengerEntities _context = new MessengerEntities();
public MessengerEntities context
{
get
{
return _context;
}
set
{
_context = value;
}
}
#region IDisposable Members
public void Dispose()
{
context.Dispose();
}
#endregion
}
And then I have a Ninject controller factory like so (this is modeled on the Steve Sanderson MVC 2 book):
public class NinjectControllerFactory : DefaultControllerFactory
{
// a Ninject "kernel" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new MessengerServices());
// ASP.NET MVC calls this to get the controller for each request
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class MessengerServices : NinjectModule
{
public override void Load()
{
Bind<IDataContext>().To<DataContext>().InRequestScope();
Bind<IArchivesRepository>().To<ArchivesRepository>().InRequestScope();
Bind<IMessagesRepository>().To<MessagesRepository>().InRequestScope();
}
}
}
Now, when I put a breakpoint at the call to context.Dispose() in the DataContext object and run the debugger, that code never gets executed.
So, the evidence suggests that Ninject does not dispose of objects when they go out of scope, but simply creates new objects and relies on the garbage collector to get rid of them at a time of its choosing.
My question is: should I be concerned about this? Because I am -- I would think Ninject would dispose of any object that implements IDisposable.
UPDATE: I downloaded the Ninject Mvc extensions (for MVC 3) and this is now how I'm doing the MvcApplication and the binding, and it does seem to be disposing of my context object.
In global.asax:
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
and
public class EFBindingModule : NinjectModule
{
public override void Load()
{
Bind<IDataContext>().To<DataContext>().InRequestScope();
Bind<IArchivesRepository>().To<ArchivesRepository>().InRequestScope();
Bind<IMessagesRepository>().To<MessagesRepository>().InRequestScope();
}
}
Everything else remains the same.
Ninject will dispose your objects as soon as the request object is collected by the GC. But normally this takes some time. But there is a way to force early disposal after the request ended. The best way is to use Ninject.Web.MVC http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/ instead of implementing your own ControllerFactory. The other way is to configure your application to use the OnePerRequestModule.

Resources