This has got to be a solved problem, I just can't seem to find an answer...
I have a WPF front-end in a class library that uses Ninject IoC container; each View uses a ViewModel that gets a Model constructor-injected, and the Model receives a class derived from DbContext, also in its constructor.
As I type these words it occurs to me that I could solve this problem by injecting a factory that creates a class derived from DbContext, but I'll just finish putting the problem in context here.
This setup makes each window own a unit of work - which is exactly what I want. The problem is that on one of these windows I want a discard changes command that reloads all entities from the context.
I read the only reliable way to do this is to Dispose the context and reinstantiate it.
Q1: How is this supposed to play well with Dependency Injection?
I might have something like this:
public class SomeModel : ISomeModel
{
private readonly SomeContext _context;
public SomeModel(SomeContext context)
{
_context = context;
}
/* some methods acting upon entities in _context */
}
What I'm thinking of is something like this:
public class SomeModel : ISomeModel
{
private readonly IContextFactory<SomeContext> _factory;
private SomeContext _context;
public SomeModel(IContextFactory<SomeContext> factory)
{
_factory = factory;
_context = _factory.Create();
}
public void DiscardChanges()
{
_context.Dispose();
_context = _factory.Create();
}
/* some methods acting upon entities in _context */
}
Q2: Are there any known issues/pitfalls to this approach?
Right now I'm binding DbContext like this, using Ninject's Conventions extension:
_kernel.Bind(t => t.From(_dataLayerAssembly)
.SelectAllClasses()
.Where(type => type.Name.EndsWith("Context"))
.BindDefaultInterface()
.Configure(config => config.InCallScope()));
If I go with the above approach, I don't need this configuration anymore (besides I'm not 100% sure the context gets disposed when I think it does) and I gain full control over the context's timeline and disposal... but I feel like I'm breaking something in the pattern - not that I care much about breaking a pattern (not a "purist"), though I'm curious to see how a MVVM+DI "purist" would approach this.
Also I know Ninject has a Factory extension which could probably eliminate the need for factory classes, but last time I used it, it broke - the class library must be usable by a VB6 ActiveX DLL, and the factory extension doesn't seem to like that.
Related
In the code I am working on I have a structure where some portions of the code depend on the current software session. Software session contains multiple helper objects which are dependency injected by composition.
One example is IRepository injected to it, which contains access to the data repository. And the IRepository contains a DatabaseContext which writes to a database, via IDbContext again which is injected.
SoftwareSession is the only injected common infrastructure for accessing all the way to the database, acting as a gateway. This means when I want to write an object to database, for instance WriteCar I will have to implement 3 interfaces, 2 functions delegating to composed objects and 1 function with implementation. It is clarified in the code fragment below. The WriteCar signatures are defined the same in 3 interfaces (IRepository, ISoftwareSession, IDbContext), 2 places where it is not implemented (Repository, SoftwareSession) which simply calls composited objects related functions and 1 place of actual implementation (IDbContext)
This means when I want to refactor, move code, add functionality or change function signatures I will always have to change 6 places for one function.
I think this provides the best environment for improving testability and it follows best practices where software session wraps access to repository and repository wraps access to data contexts - yet I still am questioning if we can have some better way of writing it once, or do I have a misunderstanding of some concept in the code below?
What is the architecturally more maintainable way of implementing this? Maybe even using some clever way of lambdas or delegates to reduce the amount of code written for each new functionality? Or even some libraries (like automapper simplifies DTOs) or tools to ease generation of this code from some kind of templating mechanism using Visual Studio, Resharper, etc?
Please let me know if I am having some confusion of concepts here. I know some my colleagues have similar views, in which case it may be helpful to clarify misunderstandings of others as well.
public class SoftwareSession : ISoftwareSession
{
...
IRepository repository;
public void WriteCar(Car car){
repository.WriteCar(car);
}
...
}
public interface ISoftwareSession{
...
void WriteCar(Car car);
...
}
public class Repository : IRepository{
...
IDbContext context;
public void WriteCar(Car car){
context.WriteCar(car);
}
...
}
public interface IRepository{
...
void WriteCar(Car car);
...
}
public class MyDbContext : IDbContext{
...
public void WriteCar(Car car){
//The Actual Implementation here.
...
}
...
}
public interface IDbContext{
...
void WriteCar(Car car);
...
}
For one thing, your IDbContext and IRepository are the same. You would probably like to remove IDbContext, or at least to remove methods declared in IRepository from it.
Then, both MyDbContext and Repository would implement IRepository and Repository class would just be a wrapper around MyDbContext.
Then, if Repository is only forwarding calls to MyDbContext, then you probably don't need that class either.
Furthermore, I don't see that you are doing anything in the SoftwareSession apart from forwarding the call to the contained repository. Do you really need SoftwareSession, or would it make sense to pass IRepository directly to whoever is calling the session object?
Bottom line is that this implementation is swarming with duplication and forwarding. Remove that, and your entire model would become simple.
Without seeing your composition root, I'm not entirely sure how your implementation works, but I'd suggest looking into using an Inversion of Control (IoC) container. Since your ISoftwareSession implementation only depends on an IRepository instance, you only need to inject that in the class' constructor. The same goes for your IRepository implementation: you only need to inject your IDbContext into the constructor.
With the IoC container, you "register", i.e. wire up your interfaces to your implementation at application startup (in the composition root), and the container takes care of creating the required instances when you resolve the dependencies. Then all you have to do is get the instance of SoftwareSession from the container, and away you go.
So, you could change your SoftwareSession implementation like this:
public class SoftwareSession : ISoftwareSession
{
IRepository repository;
public SoftwareSession(IRepository repository)
{
this.repository = repository;
}
public void WriteCar(Car car)
{
repository.WriteCar(car);
}
}
And your Repository implementation like this:
public class Repository : IRepository
{
IDbContext context;
public Repository(IDbContext dbContext)
{
context = dbContext;
}
public void WriteCar(Car car)
{
context.WriteCar(car);
}
}
Then here is your composition root:
var ioc = new MyIocContainer();
// register your interfaces and their associated implementation types with the IoC container
ioc.Register<ISoftwareSession, SoftwareSession>();
ioc.Register<IRepository, Repository>();
ioc.Register<IDbContext, MyDbContext>();
// resolve the IoC container
ioc.Resolve();
// get your `ISoftwareSession` instance
var session = ioc.GetConcrete<ISoftwareSession>();
var newCar = new Car();
session.WriteCar(newCar);
I've been gifted having had to work with an already set up Ninject DI based application which I have grown and added to considerably over the development of an application I'm working on.
I now find a problem that I would like to correct. I've managed to work around it using inheritance but would like a more cleaner solution.
I have two connections required to be injected into different services and repositories. I then need the repositories to also be correctly linked to the correct service having the same UnitOfWork.
I think I might be asking something that is not possible without inheritance and specialisation but that is why I am asking.
I managed to resolve this by creating a sub class of the main Repository and UnitOfWork classes but does nothing apart from implementing the base class.
I just don't like the idea of a sub class that is fully dependant on the super class functionality with basically empty braces apart from constructor, to me this doesn't seem true OOP just to resolve this problem. So I sought for a better solution utilising a one class solution if possible in DI.
So if you can ignore the solution I have spoken about because I completely reverted the change this is what I am left with:
Looking at the code below you can see what is the objective.
...
public class UnitOfWork : IUnitOfWork
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger("UnitOfWork");
public DbContext DataContext { get; set; }
public UnitOfWork(string connectionString)
{
DataContext = new DbContext(connectionString);
}
public void Commit()
{
...
}
}
...
public class Repository<T> : IRepository<T> where T : class
{
public IUnitOfWork unitOfWork { get; set; }
private readonly IDbSet<T> dbSet;
//private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Repository");
public Repository(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
dbSet = this.unitOfWork.DataContext.Set<T>();
}
...
}
...
public class IPOPDataModules : NinjectModule
{
public override void Load()
{
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();
}
}
...
public class DataModules : NinjectModule
{
public override void Load()
{
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString);
Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InRequestScope();
}
}
...
public class QuoteService : IQuoteService
{
private IUnitOfWork unitOfWork;
private IRepository<Data.Quote> quoteRepository;
public QuoteService(IUnitOfWork unitOfWork, IRepository<Data.Quote> quoteRepository)
{
...
}
}
...
public class IPOPService : IIPOPService
{
private IUnitOfWork unitOfWork;
private IRepository<Data.tOrder> tOrderRepository;
public IPOPService(IUnitOfWork unitOfWork, IRepository<Data.tOrder>)
{
...
}
}
What I want to know is, is it possible to share the same UnitOfWork and Repository objects by two different connections and have them injected as different instances to the respective services (IPOPService for IPOP_BE_TEST connection, QuoteService for IPOP_BAP connection)
Again the code above doesn't achieve want I want but this is the sort of architecture I would like to play around to get this to work.
What you're looking for are Ninject binding scopes. Whenever you declare a binding Ninject will provide a delegate to that binding that the activation process uses to determine if it should create a new instance of that service, or if it should return a previously constructed instance.
So, if you want to implement a singleton in Ninject, you simply declare a binding that looks like this:
Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InSingletonScope();
InSingletonScope() and InRequestScope() are simply sugar (or in the case of InRequestScope an extension method) on IBindingInSyntax<T> for the InScope(Func<Ninject.Activation.IContext, object> scope) method though. Any time you want to ensure that Ninject returns the same instance of a service in a given situation, all you need to do is implement a custom scope.
If I understand your question correctly, you want to ensure that when a request hits your application the same instances of Repository<T> and IUnitOfWork will be injected into all the services in your application. In this case you would simply have to write bindings like this:
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();
However, your problem appears to be that you have two separate modules, with two separate bindings. I would suggest that you need to use a single module with contextual binding to determine which connection string should be provided to which part of the system. So your one module might look like this:
Bind<IUnitOfWork>()
.To<UnitOfWork>()
.WhenInjectedInto<IIPOPService>()
.InRequestScope()
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
Bind<IUnitOfWork>()
.To<UnitOfWork>()
.WhenInjectedInto<IQuoteService>()
.InRequestScope()
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString);
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();
This way you can be sure that when Ninject is resolving IIPOPService it will create an instance of UnitOfWork initialized with the "IPOP_BE_TESTEntities" connection string, and when resolving IQuoteService, it will use the "IPOP_BAPSEntities" connection string, but otherwise, across that request scope, only a single instance will be constructed by Ninject.
Hope this helps.
Your question is not completely clear for me. But check the documentation for the following two scopes, which might be interesting for your scenario.
InCallScope will result that only one instance will be created per resolution tree. I usually use this scope on desktop applications for a unit of work. See the documentation here. You'll need the Ninject.Extensions.NamedScope extension for this.
InRequestScope will result that in a web application, only one instance will be created per HTTP request. I usually use this scope for a unit of work. See the documentation here. You'll need the Ninject.Web.Common package for this.
I'm creating a Web API and I'm using dependency inject wit Ninject.
I have:
IRTWRepository
IModelFactory
I'm injecting those 2 into my controllers like this.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRTWRepository>().To<RTWRepository>();
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();
kernel.Bind<IModelFactory>().To<ModelFactory>();
}
My RTWRepository constructor looks like this
public class RTWRepository :IRTWRepository
{
private RTWAPIContext _context;
public RTWRepository(RTWAPIContext context)
{
_context = context;
}}
My ModelFactory constructor looks like this
public class ModelFactory : IModelFactory
{
private IRTWRepository _repo;
public ModelFactory(IRTWRepository repo)
{
_repo = repo;
}
}
I have a Controller that looks like this:
public MaterialsController(IRTWRepository repository,IModelFactory modelFactory)
: base(repository,modelFactory)
{
}
Now, my question is : Is Ninject creating 2 separate contexts when creating an instance of my RTWRepository and also when creating an instance of ModelFactory?.
The reason that I'm asking that is because I'm having a problem when I try to save an entity that has a dependency to another object which was previously retrieve from the db.
I'm saving the entity in my controller but I'm creating it in my model factory along with is dependency.
public class RecycleCenter
{
public RecycleCenter()
{
}
public int MyProperty { get; set; }
[Required]
public virtual Address Address { get; set; }
}
The code above is for the entity Recycle Center which has an Address, this recycle center entity is created in my model factory and then in my controller I try to save it but when my repository execute this line
_context.RecycleCenters.Add(entity);
I'm getting this error
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
So, somewhere in my code I'm using 2 context instead of 1 and I think is when creating the ModelFactory and RTWRepository, is this assumption correct?, if so how do I fix it?
TL;DR;
You probably need to change this line:
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();
to
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InRequestContext();
Explanation:
When you define a binding in Ninject, you also specify how that object's lifecycle should be handled.
If you don't explicitly define it, Ninject's default lifecycle is Transient. Transient means that each time an instance is required, it will create a new one. In your case, you need to two instances: one for the RTWRepository of the ModelFactory and one for the RTWRepository of the MaterialsController.
You can modify the lifestyle to one of these options:
Singleton ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InSingleTonScope();
Request ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InRequestScope();
Thread ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InThreadScope();
Named, Call, Parent, Custom
In your case, I think you need InRequestScope, but you have to check the necessary lifecycle as it depends on the application.
For further information please check out the documentation here: https://github.com/ninject/ninject/wiki/Object-Scopes
Most probably, it is. There's no annotation that is telling to Ninject "Hey, stop, when you have created the instance once, reuse it". You should agree that in most cases, you would want multiple instances of an object and that it is a rare case, where you want it only once.
If you want to reuse the instance, use the singleton pattern. Ninject is familiar with it, so you can bind the object mapping to a method
kernel.Bind<RTWAPIContext>().ToMethod(c => RTWAPIContext.GetInstance());
There is also a ToSingleton binding, but I bet you cannot make your context constructor private and implement C# specific singleton due to other ASP.NET problems (e.g. ASP.NET Identity will try to invoke the context's method for object creation).
I have scoured the web looking for a good implementation of the Repository/Unit of Work pattern using Entity Framework. Everything I've come across is either tightly coupled at some point in the abstraction or assumes that the DbContext used by the Unit of Work and Repositories is shared and should live for the entire HTTP request (instance per request via dependency injection).
For example, assuming you are consuming repositories from the service layer, a service constructor might look like this:
public DirectoryService(IUnitOfWork unitOfWork, ICountryRepository countryRepo, IProvinceRepository provinceRepo)
{
/* set member variables... */
}
The unit of work constructor might look like:
public UnitOfWork(IDbContext context)
{
_context = context;
}
And a repository constructor might look like:
CountryRepository(IDbContext context)
{
_context = context;
}
This solution makes the blind assumption that the Dependency injection is setting up the Unit of Work and Repositories to share the same IDbContext using instance per request. Is that really a safe assumption to make?
If you are using dependency injection with instance per request, the same IDbContext will be injected into multiple units of work. The unit of work is no longer atomic, is it? I might have pending changes in one service that are then committed in another service because the context is shared across multiple units of work.
To me it seems to make more sense to set up a IDbContextFactory and get a fresh database context with each unit of work.
public interface IDbContextFactory
{
IDbContext OpenContext();
}
public class UnitOfWork
{
private IDbContextFactory _factory;
private IDbContext _context;
UnitOfWork(IDbContextFactory factory)
{
_factory = factory;
}
internal IDbContext Context
{
get { return _context ?? (_context = _factory.OpenContext()); }
}
}
The problem then becomes, how do I make my Unit of Work implementation available to the injected repositories? I don't want to assume instance per request because then I'm right back in the same boat I started in.
The only thing I can think of is to follow Entity Framework's lead and make the repositories (IDbSet<T>) part of the unit of work (DbContext).
So then I might have units of work that look like this:
public class DirectoryUnitOfWork : IDirectoryUnitOfWork
{
private IDbContextFactory _factory;
private IDbContext _context;
public DirectoryUnitOfWork(IDbContextFactory factory)
{
_factory = factory;
}
protected IDbContext Context
{
get { return _context ?? (_context = _factory.OpenContext()); }
}
public ICountryRepository CountryRepository
{
get { return _countryRepo ?? (_countryRepo = new CountryRepository(Context)); }
}
public IProvinceRepository ProvinceRepository
{
get { return _provinceRepo ?? (_provinceRepo = new ProvinceRepository(Context)); }
}
void Commit()
{
Context.SaveChanges();
}
}
Then my Directory service starts to look like this
public class DirectoryService : IDirectoryService
{
private IDirectoryUnitOfWork _unitOfWork;
public DirectoryService(IDirectoryUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public GetCountry(int id)
{
return _unitOfWork.CountryRepository.GetById(id);
}
public GetProvince(int id)
{
return _unitOfWork.ProvinceRepository.GetById(id);
}
public void AddProvince(Province province)
{
_unitOfWork.ProvinceRepository.Create(province);
Country country = GetCountry(province.CountryId);
country.NumberOfProvinces++; // Update aggregate count
_unitOfWork.Commit();
}
/* ... and so on ... */
}
It seems like a lot of work, but using this method leaves everything loosely coupled and unit testable. Am I missing an easier way, or is this a good way to do it if I am going to abstract away Entity Framework?
You should never abstract an ORM (itself an abstraction), but you should abstract the Persistence. The only UoW I'm using is a db transaction and that's a persistence detail. You don't need to use UoW and Repository together. You should think if you really need all this stuff.
Personally, I'm using the repository by default because Persistence is the last thing I do in an app. I don't care about patterns per se , I do care about decoupling my BL or the UI from DAL. Your upper layers (everything except DAL, which is the lowest layer from a dependency point of view) should always know about an abstraction, so that you can go as wild as you want in the DAL implementation.
One trick a lot of devs don't know is that design patterns (especially architectural ones) should be treated as a high level principle first and as a technical know-how second. Simply put, the thing that matters the most is the benefit a pattern is trying to achieve (the principle, the bigger picture), not its actual implementation (the "low level" details).
Ask yourself why should the BL know about a UoW in the first place. The BL only knows about an abstraction dealing with business objects. And you never work with the whole BL as once, you're always in a specific BL context. Your DirectoryService seems to be doing way to much for its own good. Updating stats doesn't look like it belongs to the same context as adding a new Province. Also why do you need UoW for queries?
One mistake I see a lot is devs rushing to write whatever code (with a design pattern attached) when they aren't doing the most important part: the design itself. When you have the improper design, problems appear and you start looking for workarounds. One of them is this UoW with Repository properties, which require a high layer like BL to know more than business concerns. Now the BL needs to know that you're using a UoW, a lower level pattern which is great for the DAL, not so great for the BL.
Btw, UoW never makes sense for quering as you're dealing with a 'read' situation, UoW is only for 'writes'. I don't mention EF or any ORM because they don't really matter, your BL service (Directory Service) is already corrupted by an infrastructural detail required by improper design. Note that sometimes you do need to compromise in order to implement a solution, but this is not the case.
Proper design means you know about your bounded context (yeah, DDD concept you can apply it regardless how much DDD you want to do) and don't put everything that might use the same data in one place. You have specific contexts for use cases and counting provinces (a presentation/reporting detail) is really a different use case than adding Province.
Adding the province and then publishing an event which signals to a handler to update stats is a more elegant, maintainable solution. No UoW required either.
Your code would look like this
public class DirectoryService : IDirectoryService
{
public DirectoryService(IProvinceRepository repo, IDispatchMessage bus)
{
//assign fields
}
/* other stuff */
//maybe province is an input model which is used by the service to create a business Province?
public void AddProvince(Province province)
{
_repo.Save(province);
_bus.Publish( new ProvinceCreated(province));
}
}
public class StatsUpdater:ISubscribeTo<ProvinceCreated> /* and other stat trigger events */
{
public void Handle(ProvinceCreated evnt)
{
//update stats here
}
}
In a way it simplifies things, in other way you might thing it complicates stuff. Actually, this is a maintainable approach, because the stats updater can subscribe to many events but the logic stays in one class only. And the DirectoryService does only the things that are assumed it does (what part of the name AddProvince hints you that the method also updates stats?).
In conclusion, you need to design the BL better before rushing to complicate your life with UoW, DbContext, Repositories as properties etc
or assumes that the DbContext used by the Unit of Work and Repositories is shared and should live for the entire HTTP request
This is clearly wrong. Assuming that the context is shared between the UoW and Repositories doesn't mean that the context lifetime should depend on the HTTP request. Rather - you can create new instances of the context and the UoW that use it whenever you want. This is only a convenience to have a default UoW that lives for the HTTP request but creating new, local units of work could be handy.
On the other hand, if repositories are exposed from the UoW:
public class UnitOfWork
{
...
public IUserRepository UserRepo
{
get { ... }
}
public IAccountRepository AccountRepo
{
get { ... }
}
then not sharing the same context between repos could have unexpected results:
UoW uow = ....
var u1 = uow.User.FirstOrDefault( u => u.ID == 5 );
var u2 = uow.Account.FirstOrDefault( a => a.ID_USER == 5 ).User;
You would definitely expect these two to return the same instance of the user of the id 5 and what's more, sharing the same context would mean that the second query could retrieve the user from the 1st level cache. On the other hand, two different contexts for two repos means that you get two different instances.
This also means that this would not be possible
var u1 = uow.User.FirstOrDefault( u => u.ID == 5 );
var a1 = uow.Account.FirstOrDefault( a => a.ID == 177 );
a1.User = u1; // oops!
as mixing entites from different contexts would just raise an exception. But the above scenario is a common one!
The conclusion from these observations is that you should share the context between repos. But, if you need a fresh instance, you just create a local, fresh instance of the context, inject it into the UoW, from where it gets injected into repos, and dispose it at will.
I'm out of ideas how to configure right Windsor container for use with repositories in Windows app.
I have generic repository implementation Repository, where T is entity type, it has a dependency IDatacontextProvider, which provides datacontext for it:
public class Repository<T> : IRepository<T> where T : class
{
protected DataContext DataContext;
public Repository(IDataContextProvider dataContextProvider) {
DataContext = dataContextProvider.DataContext;
}
....
}
And for simple things everything works ok with following configuration:
container.Register(
Component.For<IDataContextProvider>()
.ImplementedBy<DataContextProvider>()
.Lifestyle.Transient,
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.Lifestyle.Transient, ....
Problems occur, when i try to join different entities from several repositories, as long as each repository instance has different data context instance.
For example i have simple service:
public class SimpleService : ISimpleService {
public SimpleService(IRepository<Order>, IRepository<OrderLine>) {
....
}
}
I could make IDataContextProvider as Singleton, but i think that would bring even bigger problems.
I could pass IDataContextProvider to SimpleService, and try to resolve repository instances there, but that would require additional code to make service easy testable and would require additional dependencies.
May be somebody has a better idea how to solve this?
update:
following advice, I've created repository factory (it's little bit different from proposed in answer, it does not have direct dependency to datacontext, but idea is very same):
public interface IRepositoryFactory
{
IRepository<T> GetRepository<T>() where T:class;
}
public class RepositoryFactory : IRepositoryFactory
{
private readonly IDataContextProvider dataContextProvider;
public RepositoryFactory(IDataContextProvider dataContextProvider)
{
this.dataContextProvider = dataContextProvider;
}
public IRepository<T> GetRepository<T>() where T : class
{
return new Repository<T>(dataContextProvider);
}
}
What about having another layer in between, such as a RepositoryFactory? That one could have a transient lifestyle. All repositories created from the factory would share the same DataContext instance. You would also need to change your repository classes so they take a DataContext instance instead of a DataContextProvider.
public class RepositoryFactory : IRepositoryFactory
{
protected DataContext dataContext;
public RepositoryFactory(IDataContextProvider provider)
{
dataContext = dataContextProvider.DataContext;
}
public IRepository<T> GetRepository<T>()
{
return new Repository<T>(dataContext);
}
}
public class SimpleService : ISimpleService {
public SimpleService(IRepositoryFactory factory) {
....
}
}
IDatacontextProvider sounds like a factory interface and these are usually defined as singletons in the dependency injection. I see several potential paths to a solution:
I don't know about particulars of your application, but maybe you can write your own lifestyle manager for IDatacontextProvider (since you say neither singleton nor transient suits you).
If you want to ensure the same IDatacontextProvider is passed among repositories, maybe you should think about providing it explicitly as a method parameter, instead of an injected dependency.
#Can's answer is also a possible solution, I've used that one myself once.
Your problem is in the configuration of the lifestyle. I had the same issues. You have to configure your repositories with an PerWebRequest lifestyle. This gave me an nice performance boost and reducing my errors from dozens to zero.
On my blog you can find an simple example http://marcofranssen.nl of dependency injection in combination with mvc3 and EF Code first.