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.
Related
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
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.
I've been looking at a few blog posts to try and create an appropriate solution for the following requirements but I can't seem to piece them together. Hope fully someone can help.
I've been using Repository pattern with interfaces using Automapper...here's a trimmed down example:
public class BookingRepository : IBookingRepository
{
Entities context = new Entities();
public IEnumerable<BookingDto> GetBookings
{
get { return Mapper.Map<IQueryable<Booking>, IEnumerable<BookingDto>>(context.Bookings); }
}
public BookingDto GetBookingWithProduct(Guid bookingId)
{
return Mapper.Map<BookingDto>(context.Bookings.Include(c => c.Products).SingleOrDefault(c => c.BookingId == bookingId));
}
public void Update(BookingDto bookingDto)
{
var booking = Mapper.Map<Booking>(bookingDto);
context.Entry(booking).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IBookingRepository : IDisposable
{
IEnumerable<BookingDto> GetBookings { get; }
BookingDto GetBooking(Guid bookingId);
void Update(BookingDto bookingDto);
void Save();
}
With a seperate Repository for a different Entity, for example
public class ProductRepository : IProductRepository
{
Entities context = new Entities();
public IEnumerable<ProductDto> GetProducts
{
get { return Mapper.Map<IQueryable<Product>, IEnumerable<ProductDto>>(context.Products); }
}
public ProductDto GetProductWithDesign(int productId)
{
return Mapper.Map<ProductDto>(context.Products.Include(c => c.Designs).SingleOrDefault(c => c.ProductId == productId));
}
public void Update(ProductDto productDto)
{
var product = Mapper.Map<Product>(productDto);
context.Entry(product).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IProductRepository : IDisposable
{
IEnumerable<ProductDto> GetProducts { get; }
ProductDto GetProduct(int productId);
void Update(ProductDto productDto);
void Save();
}
Then in my Controller I'm using the repositories as so:
public class HomeController : Controller
{
private readonly IBookingRepository bookingRepository;
private readonly IProductRepository productRepository;
public HomeController() : this(new BookingRepository(), new ProductRepository()) { }
public HomeController(IBookingRepository bookingRepository, IProductRepository productRepository)
{
this.bookingRepository = bookingRepository;
this.productRepository = productRepository;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && this.bookingRepository != null)
this.bookingRepository.Dispose();
if (disposing && this.productRepository != null)
this.productRepository.Dispose();
}
}
So now I'm hoping to create a Unit Of Work to abstract these repositories and share the context and also create a generic repository for the duplicated actions (Save and Update) bearing in mind I'm passing in Dtos and Mapping to Entity objects. I'm having difficulty understanding how to knit it all together.
Additionally, I've seen this post
Repository pattern with generics and DI
which states "You should not have other repository interfaces besides your generic repository" and that custom queries "deserve their own (generic) abstraction:" which is adding another complication to my overworked brain as my repositories will have custom queries that return complex linked objects using Include Statements as Lazy Loading is disabled.
So I'm prepared to be shot down and told that I'm going about this the wrong way but would be grateful for any direction given.
Thanks in advance.
Don't use generic repositories. They are all leaky abstractions. Ask yourself, what benefit to you get by using an abstraction that doesn't really abstract away something? You could use your OR/M directly in those cases.
What I means is that anything that exposes IQueryable<T> forces the user to learn about the weaknesses that the underlying OR/M has. Examples: How do the orm handle lazy loading? How do I eagerly load related entities? How do I create a IN clause?
If you truly want to use the repository pattern either use it together with the specification pattern (you can keep on using a generic repository then) or create repositories that are specific for each root aggregate.
I've blogged about it: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
What I usually do in this case is to create a Base abstract Repository class like this:
public abstract class BaseRepository<T> : IRepository<T>
{
Entities context = new Entities();
public virtual T GetAll()
{
return context.Set<T>();
}
// Add base implementation for normal CRUD here
}
If you don't need special queries then you don't need to create special interface and classes (but you can of course, to improve readability). So you will use, for example:
var bookingsRepo = new BaseRepository<BookingsDto>();
var allBookings = bookingsRepo.GetAll();
If you need some special queries, you create an interface that extends the base interface:
public interface IProductRepository : IRepository<Product>
{
Product GetSpecialOffer();
}
Then create your class:
public class ProductRepository : BaseRepository<Product>, IProductRepository
{
public Product GetSpecialOffer()
{
// your logic here
}
}
That way you only specify a minimal number of special cases while relying on the Base abstract implementation for all things normal.
I added virtual to the base methods because I always like to give derived class the ability to override stuff...
Using Ninject in a MVC4 application with the MVC3 Ninject Extension, when binding to a repository (a DbContext), I want to use InRequestScope for Controllers, and InSingletonScope when the same repository is used within a custom MembershipProvider.
I want to do this:
kernel.Bind<IRepo>().To<Repo>().InRequestScope();
kernel.Bind<IRepo>().To<Repo>().WhenInjectedInto<MembershipHelper>()
.InSingletonScope();
So that each web request to a controller gets a fresh instance of the repo, while the MembershipProvider maintains a re-usable connection to the repo.
This appears to work ok in a development environment, but how do I know which binding is being used? Is there a way to test that the scope is working correctly?
Yes, this is fine. Here's a very easy way to test it:
public interface IRepo { }
public class Repo : IRepo { }
public class MembershipHelper
{
private readonly IRepo _repo;
public MembershipHelper(IRepo repo)
{
_repo = repo;
}
public string GetId()
{
return _repo.GetHashCode().ToString();
}
}
public class HomeController : Controller
{
private readonly IRepo _repo;
private readonly MembershipHelper _helper;
public HomeController(IRepo repo, MembershipHelper helper)
{
_repo = repo;
_helper = helper;
}
public ActionResult Index()
{
return Content(_repo.GetHashCode().ToString() + " " + _helper.GetId());
}
}
Now navigate to /home/index and observe the 2 hashcodes. The first changes on each request whereas the second remains the same.
This might be a strange case but I want to sometimes reuse the same instance when getting exports with MEF and sometimes create a new.
Basicly I have a WCF service class the is instance per call. Each instance imports a RepositoryFactory which will also be new instance per service class. I return a Repository in the Factory and a repository gets a IDbContext injected.
I want each instance of the Factory to inject the same instance of IDbContext but have seperate instances between Factory instances.
So:
1) Factory1 is created
2) Factory1 creates Repository1-1 that gets IDbContext1 injected
3) Factory1 creates Repository1-2 that gets IDbContext1 injected
4) Factory2 is created
5) Factory2 creates Repository2-1 that gets IDbContext2 injected
6) Factory2 creates Repository2-2 that gets IDbContext2 injected
This should ensures that Repositories created from the same factory share a Unit of Work.
But being new to MEF I'm not sure how I would go about doing that.
EDIT
This is what I got:
public class RepositoryFactory
{
private readonly CompositionContainer _container;
[Import(RequiredCreationPolicy=CreationPolicy.NonShared)]
private readonly IDbContext _context;
public IRepository<T> CreateRepository<T>() where T : class, IEntity
{
//Somehow add the _context instance into the Repository import
return _container.GetExportedValue<EntityRepository<T>>();
}
}
and then
public class EntityRepository<T> : IRepository<T> where T : class, IEntity
{
// Perhaps a contract name might help!!
[Import(RequiredCreationPolicy=CreationPolicy.Shared)]
protected readonly IDbContext _context;
You cannot accomplish this with MEF; no matter what you do the MEF container will not act correctly as a Unit of Work manager for you, it just isn't made for this.
You should attempt to explicitly code a Unit of Work infrastructure for your DAL to consume. Your repositories should explicitly ask the a Unit of Work Manager to provide a current Unit of Work and with it the appropriate context.
Take a look at the code in NCommon https://github.com/riteshrao/ncommon; you can refactor the Unit of Work features to serve your needs.
OK here is a solution I came up with but haven't tried. It's somewhat simple and actually works around MEF but doesn't really break it, at least not in my case.
Add to IRepository class the following method:
void SetContext(IDbContext context);
or better yet
IDbContext context { set; }
and in the factory:
public class RepositoryFactory
{
private readonly CompositionContainer _container;
[Import(RequiredCreationPolicy=CreationPolicy.NonShared)]
private readonly IDbContext _context;
public IRepository<T> CreateRepository<T>() where T : class, IEntity
{
IRepository<T> repo = _container.GetExportedValue<EntityRepository<T>>();
repo.context = _context;
return repo;
}
}
And the rest should be self explanatory:
public class EntityRepository<T> : IRepository<T> where T : class, IEntity
{
protected IDbContext _context;
IDbContext context
{
set { _context = value; }
}
public virtual IQueryable<T> GetQuery()
{
return _context.Set<T>();
}
public virtual T GetById(Guid id)
{
return _context.Set<T>().Find(id);
}
public virtual void SaveOrUpdate(T entity)
{
if (_context.Set<T>().Find(entity.Id) == null)
{
_context.Set<T>().Add(entity);
}
_context.SaveChanges();
}
public virtual void Delete(T entity)
{
_context.Set<T>().Remove(entity);
_context.SaveChanges();
}
}
If you are using it in the same way as I am I can't really see a problem with this implementation. The factory is responsible for creating the class so It can be responsible for setting the context. The CreationPolicy should ensure that each Factory gets it's own instance of DbContext that it then relegates to it's Repositories so they share a context.