I have one project functioning perfectly using Unity. I try switching to use Simple Injector instead and now NO changes ever get saved in my database. I believe it has to do with the lifetime of the registered components. Here is the Unity container registration:
private IUnityContainer GetUnityContainer()
{
IUnityContainer container = new UnityContainer()
.RegisterType<IDatabaseFactory, DatabaseFactory>(
new HttpContextLifetimeManager<IDatabaseFactory>())
.RegisterType<IUnitOfWork, UnitOfWork>(
new HttpContextLifetimeManager<IUnitOfWork>())
.RegisterType<ICategoryRepository, CategoryRepository>(
new HttpContextLifetimeManager<ICategoryRepository>())
.RegisterType<ICategoryService, CategoryService>(
new HttpContextLifetimeManager<ICategoryService>());
return container;
}
And here is the new Simple Injector registration.
container.Register<IDatabaseFactory, DatabaseFactory>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Register<ICategoryRepository, CategoryRepository>();
container.Register<ICategoryService, CategoryService>();
I'm not sure how the HttpContextLifetimeManager
comes into play with Simple Injector. MVC is the client for the unity example, but I'm changing to a WPF project and Simple Injector. Any suggestions are much appreciated. Thanks.
@Steven. Thanks for your comment. I just discovered that since my RepositoryBase and my UnitOfWork inject an IDatabaseFactory in their constructors that I needed to use container.RegisterSingle<IDatabaseFactory, DatabaseFactory>()
. This resolved one issue. I still have a problem with lifetime though. Since my consuming app is WPF, how will the RegisterPerWebRequest work?
My project has a DataLayer >> BusinessLayer >> WcfService >> WPF Front end. Simple Injector is set on the WcfService project and the business layer has Boostrapper to register items there. As of now, my WPF client will GetAllCountries() and display in a grid. If I change the name of one and try to update, I get the "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." error. I've done some debugging and find that after the GetCountries service call in the WPF client, when I go back to try to update, I see ALL of the countries are attached to the context via dbContext.ChangeTracker.Entries(). At this point I should have NO entities being tracked as my context should have been disposed after the first unit of work.
In an MVC app the RegisterPerWebRequest fixes that, but what is the equivalent for WPF? I'm going to install the extension now and try it anyway but I have a feeling it isn't the solution I'm looking for.. or is it? Thanks again for the help.
OK. I did a bit more digging and found a solution that works. I'm just not sure if it's the correct one. Anyway, now in my BLL where there is a bootstrapper to register things, I can register like this:
container.RegisterPerWcfOperation<IDatabaseFactory, DatabaseFactory>();
container.RegisterPerWcfOperation<IUnitOfWork, UnitOfWork>();
container.RegisterPerWcfOperation<ICountryRepository, CountryRepository>();
That gives me what I was looking for. Only a single instance of DatabaseFactory is ever created and thus my repository and unit of work share it like they should. Also, after GetCountries() on the client, when I do my second call to the service to perform and update, I check the dbContext.ChangeTracker.Entries() and see that there are NO entities being tracked, which is correct. I can now attach, set to modify, and call SaveChanges without getting the duplicate key error. Does this seem ok? Thanks.