How to ensure that Autofac is calling Dispose() on EF6 DbContext - c#

UPDATE
Found this little gem which helped me with DbContext
Josh Kodroff - Making Entity Framework More Unit-Testable
Original
After doing a lot of research I finally decided to implement IOC using Autofac in my MVC5 EF6 project. Autofac's documentation has been helpful, but I'm still not sure about whether or not I need to call Dispose() either in my Controller or Service Class?
I'm not using an abstracted UOW and Generic Repository, but just relying on DbContext and DbSet<> provided in EF6. Here's a snippet of my classes.
My DbContext
public class ProductContext : DbContext
{
public ProductContext() : base("ProductContext")
{
}
public DbSet<Availability> Availability { get; set; }
public DbSet<Category> Categories { get; set; }
....
}
My Service Class
public class ProductService : IProductService
{
private ProductContext _db;
public ProductService(ProductContext db)
{
_db = db;
}
public List<Product> GetProductsByCategory(string cleanCategory)
{
return _db.Products
.Include(p => p.Options.Select(o => o.OptionGroup))
.Include(p => p.Associations.Select(a => a.AssociatedGroup))
.Include(p => p.Variations).Include(p => p.Manufacturer)
.Where(p => p.Active && p.Category.Name.ToUpper().Equals(cleanCategory)).ToList();
}
.....
}
My Service Interface
public interface IProductService
{
List<Product> GetProductsByCategory(string cleanCategory);
....
}
My Contoller
public class ProductsController : Controller
{
private IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
//GET: Products/
public ActionResult Index(string category)
{
if (String.IsNullOrEmpty(category))
{
return HttpNotFound();
}
string cleanCategory = urlScrubber(category);
var viewModel = new ProductsVM();
viewModel.ProductList = _productService.GetProductsByCategory(cleanCategory);
}
My Autofac Container
var builder = new ContainerBuilder();
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// REGISTER COMPONENTS HERE:
builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();
builder.RegisterType<ProductService>().As<IProductService>().InstancePerRequest();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
I have removed Dispose() from the controller with the understanding that Autofac would handle the disposal of contexts that inherit from IDisposable. Since ProductContext inherits from DbContext which includes a Dispose() Method, this should work.
Do I need to include something like
builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();
or will my current container work as expected calling Dispose?
builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();
Thanks for any help, I'm having a hard time locating documentation using Autofac without a generic repository and UOW on top of DbContext similar to my current pattern.

As per the doucmentation,
Autofac integration libraries standard unit-of-work lifetime scopes will be created and disposed for you automatically. Autofac’s ASP.NET MVC integration, a lifetime scope will be created for you at the beginning of a web request and all components will generally be resolved from there. At the end of the web request, the scope will automatically be disposed - no additional scope creation is required on your part.
So I think if your class implments IDisposable then Dispose() would be automatically called for such objects. So simply,
builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();
Would do the Disposal via object life scope management.

Autofac also supports using Func<> in constructor injection. For example, you can register your data context like normal:
builder.RegisterType<ProductContext>().As<IProductContext>();
and use it as follows in your ProductService:
public class ProductService : IProductService
{
private IProductContext _dbCreator;
public ProductService(Func<IProductContext> dbCreator)
{
_db = db;
}
public List<Product> GetProductsByCategory(string cleanCategory)
{
using (var dbCtx = _dbCreator())
{
return dbCtx.Products
.Include(p => p.Options.Select(o => o.OptionGroup))
.Include(p => p.Associations.Select(a => a.AssociatedGroup))
.Include(p => p.Variations).Include(p => p.Manufacturer)
.Where(p => p.Active && p.Category.Name.ToUpper().Equals(cleanCategory)).ToList();
}
}
.....
}
Basically, your ProductService now has access to a Func<>(_dbCreator) that creates a new instance of your ProductContext based on your autofac registration every time it's called, allowing you to dispose the instance when you deem appropriate.
I realized after I wrote this that you don't have an IProductContext, I would usually recommend using this pattern, however, it isn't too important as far as your question is concerned. You can continue to use your current registration method for ProductContext and then just pass in a Func<ProductContext> instead of an IProductContext, i.e.,
builder.RegisterType<ProductContext>().AsSelf();
and
private ProductContext _dbCreator;
public ProductService(Func<ProductContext> dbCreator)
Sorry if the code doesn't compile, I didn't use an IDE... Hopefully it's close enough for you to get my point!

Related

How to avoid using lots of dbcontexts in .NET using MVVM?

I trying to learn building webapplications in .NET using the MVVM-pattern. I watched some tutorials and there is one single thing I don't understand.
Each ViewModel contains:
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _dbContext;
public IndexModel(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
..
}
It's fine to copy paste this when you have a couple of pages (max 10), but my application is starting to grow and it starts feeling very redundant using this method.
I wasn't able to find another post answering my question, but I am wondering if there is any other way to accomplish using a _dbContext on each ViewModel without having to use this redundancy? I am not very familiar with design patterns, but would a singleton pattern in my startup be an option?
Add a custom base class inherited from PageModel. Then inherit all you Model from your custom base class.
public abstract class MyBasePageModel : PageModel
{
protected readonly ApplicationDbContext _dbContext;
public MyBaseModel(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
}
public class IndexModel : MyBasePageModel
{
public IndexModel(ApplicationDbContext dbContext):base(dbContext)
{
//
}
}
That is not sound design patterns. What you could do is pass a business interface to your viewmodel as an injected dependency using dependency injection (Unity example). Then that injected business service could inject into it a data service interface where the data context is found.
It is considered bad practice to have your data layer in your presentation layer. Here is a sample way on how you can separate your code layers.
Below is simple example of a IDataService (notice I only deal with interfaces and the data context stays in the data service):
public class DataService : ServiceBase, IDataService
{
public DataService(IMapper mapper) : base(mapper) { }
public IList<UserDto> GetUsers(bool runSafeMode = true)
{
Func<IList<UserDto>> action = () =>
{
return GetUsers(_ => true);
};
return ExecutorHandler(action, runSafeMode);
}
...
private IList<UserDto> GetUsers(Expression<Func<User, bool>> predicate, bool runSafeMode = true)
{
Func<IList<UserDto>> action = () =>
{
using (var ymse = YMSEntities.Create())
{
var users = ymse.User
.Include(u => u.UserUserProfile)
.Include(m => m.UserUserProfile.Select(uup => uup.UserProfile))
.Include(m => m.UserUserProfile.Select(uup => uup.User))
.Include(m => m.UserUserProfile.Select(uup => uup.UserProfile.UserProfileModule))
.Where(predicate).OrderBy(u => u.UserName).ToList();
return MappingEngine.Map<IList<UserDto>>(users);
}
};
return ExecutorHandler(action, runSafeMode);
}
}
That gets injected into a business service which in turn is injected into my VM:
public class DocksViewModel : ViewModelBase
{
public DocksViewModel(IConfigService configService, IEventService eventService, INotificationService notificationService)
{
...
}
}
Simple separation of concerns and everything is independently testable. My IDataService in this case is found in the BaseViewModel because depending if my app has internet connection or not I switch implementations between sql server and local json files for data persistence. Here is how you would wire up your dependencies using Unity for example:
var unityContainer = new UnityContainer();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unityContainer));
unityContainer.RegisterType<IServiceLocator, UnityServiceLocator>(new ContainerControlledLifetimeManager());
// automapper
var config = new MapperConfiguration(cfg =>
cfg.AddProfile(new AutoMapperBootstrap())
);
unityContainer.RegisterType<IMapper>(new InjectionFactory(_ => config.CreateMapper()));
// factories
unityContainer.RegisterType<IWelcomeGateViewFactory, WelcomeGateViewFactory>();
unityContainer.RegisterType<ITrailerPictureViewFactory, TrailerPictureViewFactory>();
// services
unityContainer.RegisterType<IDataService, OfflineDataService>("OfflineDataService", new ContainerControlledLifetimeManager(), new InjectionConstructor(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ServiceLocator.Current.GetInstance<IMapper>()));
unityContainer.RegisterType<IDataService, DataService>(new ContainerControlledLifetimeManager());
unityContainer.RegisterType<ITestDataService, TestDataService>(new ContainerControlledLifetimeManager());
...

Dependency Injection pass parameters by constructor

We have a project where we need to use DI and ASP Core.
I'm very new to this and have a question.
I have a controller named HomeController like this:
public class HomeController : BaseController {
private IOrderService _orderService;
public HomeController(IOrderService orderService) {
_orderService = orderService;
}
public IActionResult Index() {
var orders = _orderService.GetMyOrders();
return View(orders);
}
}
The code looks like this:
public class OrderService : BaseService, IOrderService {
public OrderService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public List<Orders> GetMyOrders() {
var orders = // do my code here which works fine!;
// here i need some code do check orders for delivery so
DeliveryService deliveryService = new DeliveryService(_dataContextService);
// update my orders and return these orders
return orders;
}
}
public class DeliveryService : BaseService, IDeliveryService {
public DeliveryService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public void MyMethod() {
}
}
public class BaseService {
protected IDataContextService _dataContextService;
}
Almost all my services have a constructor like the OrderService and DeliveryService. My question is, do I have to pass the _dataContextService every time, or is there a solution within the dependency pattern?
You should keep it the way you have it and asp.net core IoC will inject it for you, but make sure it is injected per request, this will help to insantiate only one context for each request and dispose it after the request is served.
You can register the context and services in the ConfigureServices method inside the Startup class as below
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<HomeController>();
services.AddTransient<IOrderService , OrderService >();
services.AddTransient<IDeliveryService, DeliveryService>();
services.AddScoped<IDataContextService , YourDataContextService >();
}
The AddScoped method will create only one instance of the object for each HTTP request
If I understand correctly what you are asking, you are looking for an IoC container. .NET Core has built in support for dependency injection. Basically, you just indicate which implementation should be provided when an interface is requested. Then the container will instantiate the types for you. See for example https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection.
Hope that helps

How to properly inject a DbContext for WebAPI using a ContextFactory and a repository?

I'm trying to safely inject a database context per web request for a repository on the back of a Web API. The consuming class calls the repository in order to retrieve the object, and if it comes back null, then it gets the object from a different data store and saves that in the database for faster access later. This means it's trying to Get from the DB then doing stuff then creating a new record.
Currently I have this repository
public class OrganisationRepository : IOrganisationRepository
{
public Func<IOrganisationDomainDbContext> ContextFactory { get; set; }
public Organisation GetDetailByIdentifier(int id)
{
using (var context = ContextFactory.Invoke())
{
var org = context.Organisations.SingleOrDefault(x => x.Id == id);
return org;
}
}
public void Create(Organisation orgToCreate)
{
using (var context = ContextFactory.Invoke())
{
context.Organisations.Add(orgToCreate);
context.SaveChanges();
}
}
}
and the repository is injected into the consuming class with a transient lifestyle. The DbContext is injected per web request.
Previously, the Repository was injected with a singleton lifestyle, which was breaking on the Create action.
My question is, am I doing a cheap hack by making the Repository transient? Will this cause me problems down the line? If so, how should I be doing this differently?
EDIT: For further information, the DI Container in use is Castle Windsor
EDIT: Relevant parts of the DI Installer
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IOrganisationDomainDbContext>().ImplementedBy<OrganisationDomainDbContext>().LifeStyle.PerWebRequest,
Component.For<Func<IOrganisationDomainDbContext>>().Instance(container.Resolve<IOrganisationDomainDbContext>),
Component.For<IOrganisationRepository>().ImplementedBy<OrganisationRepository>().LifeStyle.Transient,
Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
}
UPDATE: Transient repository did not fix the problem, that was a mistake on my part - I just forgot that the record I was looking at had in fact been committed to the database, and therefore the create action was not being called. My mistake, apologies.
As user jbl pointed out, I didn't need to use using blocks around the context usage - the DI Container disposes of the context as it is used per web request.
Here's the code now:
public class OrganisationRepository : IOrganisationRepository
{
public Func<IOrganisationDomainDbContext> ContextFactory { get; set; }
public Organisation GetDetailByIdentifier(int id)
{
var context = ContextFactory.Invoke()
var org = context.Organisations.SingleOrDefault(x => x.Id == id);
return org;
}
public void Create(Organisation orgToCreate)
{
var context = ContextFactory.Invoke();
context.Organisations.Add(orgToCreate);
context.SaveChanges();
}
}
And the DI container installer:
container.Register(
Component.For<IOrganisationDomainDbContext>().ImplementedBy<OrganisationDomainDbContext>().LifeStyle.PerWebRequest,
Component.For<Func<IOrganisationDomainDbContext>>().Instance(container.Resolve<IOrganisationDomainDbContext>),
Component.For<IOrganisationRepository>().ImplementedBy<OrganisationRepository>().LifeStyle.PerWebRequest,
Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
Hopefully this is the correct answer, debugging shows that the contexts are disposed of after each web request and I'm not running into the exceptions. Thanks for all the help jbl and Mark Seeman.

RepositoryFactory with Ninject

I'm working on web application (web form). I want to be able to change EntityFrameworkRepositoryFactory to NHibernateRepositoryFactory in the future.
IRepositoryFactory
public interface IRepositoryFactory
{
IProductRepository GetProductRepository();
}
ProductRepository
public class ProductRepository : IProductRepository
{
ExDbContext _db;
public ProductRepository(ExDbContext dbContext)
{
_db = dbContext;
}
public IList<Product> ListProductsByCategoryId(int categoryId)
{
List<Product> productsByCategoryId = _db.Products.Where(x => x.ProductCategoryId == categoryId).ToList();
return productsByCategoryId;
}
}
And there is EntityFrameworkRepositoryFactory.
class EntityFrameworkRepositoryFactory:IRepositoryFactory
{
ExDbContext _db;
public EntityFrameworkRepositoryFactory(ExDbContext dbContext)
{
_db = dbContext;
//
// TODO: Add constructor logic here
//
}
public IProductRepository GetProductRepository()
{
return new ProductRepository(_db);
}
}
How can i make easy for changing this in future ? I want use ninject for access EntityFrameworkRepositoryFactory but I'm stuck. Is there any example for this ?
Thanks.
We will add Ninject to your web application, fix your repository classes and add some Ninject modules to configure dependency injection:
Install Ninject. You can do this easily using the Package Manager Console: Install-Package Ninject.Web -dependencyVersion Highest
Remove your RepositoryFactory. Delete IRepositoryFactory and EntityFrameworkRepositoryFactory. You don't need them. Ninject will create a Repository and provide the dependencies as soon as your application asks for them. You need factories only to have better control of an object's lifetime.
Fix the repository. Let's make things more conventional and use an IEnumerable<Product> to return a read-only collection of products as result of our query. We also use Get as a prefix, as most repository patterns do:
public interface IProductRepository
{
IEnumerable<Product> GetProductsByCategoryId(int categoryId);
}
class EfProductRepository : IProductRepository
{
private readonly ExDbContext db;
public EfProductRepository(ExDbContext dbContext)
{
this.db = dbContext;
}
public IEnumerable<Product> GetProductsByCategoryId(int categoryId)
{
var productsByCategoryId = this.db
.Products
.Where(x => x.ProductCategoryId == categoryId)
.ToArray();
return productsByCategoryId;
}
}
Create a Ninject module. We need to bind our repository implementation to its interface. The Entity Framework DbContext uses the "Unit of Work" pattern, so we also need to make sure that our entity context instances are going to be disposed as soon as a request ends. We could do this using a context factory and the using directive, but we can also use the "Request Scope" of Ninject as it's easier:
public class EfRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<EfProductRepository>();
this.Bind<ExDbContext>().ToSelf().InRequestScope();
}
}
At first, we bind IProductRepository to our concrete implementation. Thereby, whenever a component needs a product repository, Ninject will create an instance of EfProductRepository and use that.
Then we tell Ninject to bind ExDbContext to itself and use the request scope. All dependencies on ExDbContext will be served by one single instance of this class during a request, and this instance is going to be disposed when the request ends.
Load the module. In App_Start/NinjectWebCommon.cs update the following method:
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}
Add dependencies to your pages. In every page where you need to show products, add the following property:
[Inject]
public IProductRepository ProductRepository { get; set; }
We need to use property injection or method injection here, because Web Pages doesn't support constructor injection (which should usually be favored). The Inject attribute tells Ninject that we have a dependency here that we want to be injected.
Add a module for NHibernate later on.
public class NHibernateRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IProductRepository>().To<NHibernateProductRepository>();
// Bind whatever else you need when working with NHibernate
}
}
// NinjectWebCommon
private static void RegisterServices(IKernel kernel)
{
kernel.Load<EfRepositoryModule>();
}

Is it a good design to inject services as factories?

I have been reading Mark Seemann's excellent book on DI and hope to implement it in my next WPF project. However I have a query regarding object lifetime. So far, most examples seem to explain the repository pattern per request for MVC applications. In WPF there isn't really an alternative to this (I think). Seeing as the object graph of the entire application is constructed in the composition root, how can I make sure that my unit-of-work stuff is working properly. For example:
public class ContextFactory : IContextFactory
{
DBContext context;
public ContextFactory()
{
context = new MyDBContext();
}
public DBContext GetContext()
{
return context;
}
}
public class ItemOneRepository() : IItemOneRepository
{
DBContext context;
public ItemOneRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItems()
{
return context.ItemOnes;
}
}
public class ItemTwoRepository() : IItemTwoRepository
{
DBContext context;
public ItemTwoRepository(IContextFactory contextFactory)
{
this.context = contextFactory.GetContext();
}
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
public class ThingService : IThingService
{
IItemOneRepository itemOneRepo;
IItemTwoRepository itemTwoRepo;
public ThingService(
IItemOneRepository itemOneRepository,
IItemTwoRepository itemTwoRepository)
{
itemOneRepo = itemOneRepository;
itemTwoRepo = itemTwoRepository;
}
public IEnumerable Things GetThing()
{
var ItemOnes = itemOneRepo.GetItems();
return ItemOnes.Select(i =>
new Thing(
i.FieldOne,
i.FieldFour,
itemRepoTwo.GetItemsByItemOneID(i.ID)
)
);
}
}
In this case the MyDBContext instance is created through ContextFactory in the composition root. ItemOneRepository and ItemTwoRepository are using the same unit-of-work (MyDBContext), but so is the rest of the application which is plainly wrong. What if I changed the repositories to accept a DBContext instead of ContextFactory and added a ThingServiceFactory class like:
public ThingServiceFactory : IThingServiceFactory
{
IContextFactory contextFactory;
public ThingServiceFactory(IContextFactory factory)
{
contextFactory = factory;
}
public IThingService Create()
{
MyDBContext context = contextFactory.Create();
ItemOneRepository itemOneRepo = new ItemOneRepository(context);
ItemOneRepository itemTwoRepo = new ItemTwoRepository(context);
return new ThingService(itemOneRepo, itemTwoRepo);
}
}
This is better as I can now pass the ThingServiceFactory to my ViewModels instead of an instance of ThingService (complete with DBContext). I can then create a unit-of-work whenever I need one and instantly dispose of it when I’ve finished. However, is this really the correct approach. Do I really need to write a factory for every unit-of-work operation I need? Surely there is a better way...
There's IMO only one good solution to this problem and that is to apply a command-based and query-based application design.
When you define a single ICommandHandler<TCommand> abstraction to define business transactions, you can inject closed versions of that interface into any form that needs this. Say for instance you have a "move customer" 'command' operation:
public class MoveCustomer
{
public Guid CustomerId;
public Address NewAddress;
}
And you can create a class that will be able to execute this command:
public class MoveCustomerHandler : ICommandHandler<MoveCustomer>
{
private readonly DBContext context;
// Here we simply inject the DbContext, not a factory.
public MoveCustomerHandler(DbContext context)
{
this.context = context;
}
public void Handle(MoveCustomer command)
{
// write business transaction here.
}
}
Now your WPF Windows class can depend on ICommandHandler<MoveCustomer> as follows:
public class MoveCustomerWindow : Window
{
private readonly ICommandHandler<MoveCustomer> handler;
public MoveCustomerWindows(ICommandHandler<MoveCustomer> handler)
{
this.handler = handler;
}
public void Button1Click(object sender, EventArgs e)
{
// Here we call the command handler and pass in a newly created command.
this.handler.Handle(new MoveCustomer
{
CustomerId = this.CustomerDropDown.SelectedValue,
NewAddress = this.AddressDropDown.SelectedValue,
});
}
}
Since MoveCustomerWindow lives for quite some time, it will drag on its dependencies for as long as it lives. If those dependencies shouldn't live that long (for instance your DbContext) you will be in trouble and Mark Seemann calls this problem Captive Dependency.
But since we now have a single ICommandHandler<TCommand> abstraction between our presentation layer and our business layer, it becomes very easy to define a single decorator that allows postponing the creation of the real MoveCustomerHandler. For instance:
public class ScopedCommandHandlerProxy<TCommand> : ICommandHandler<TCommand>
{
private readonly Func<ICommandHandler<TCommand>> decorateeFactory;
private readonly Container container;
// We inject a Func<T> that is able to create the command handler decoratee
// when needed.
public ScopedCommandHandlerProxy(
Func<ICommandHandler<TCommand>> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Handle(TCommand command)
{
// Start some sort of 'scope' here that allows you to have a single
// instance of DbContext during that scope. How to do this depends
// on your DI library (if you use any).
using (container.BeginLifetimeScope())
{
// Create a wrapped handler inside the scope. This way it will get
// a fresh DbContext.
ICommandHandler<TCommand> decoratee =this.decorateeFactory.Invoke();
// Pass the command on to this handler.
decoratee.Handle(command);
}
}
}
This sounds a bit complex, but this completely allows you to hide the fact that a new DbContext is needed from the client Window and you hide this complexity as well from your business layer; you can simply inject a DbContext into your handler. Both sides know nothing about this little peace of infrastructure.
Of course you still have to wire this up. Without a DI library you do something like this:
var handler = new ScopedCommandHandlerProxy<MoveCustomerCommand>(
() => new MoveCustomerCommandHandler(new DbContext()),
container);
How to register this in a DI library is completely depending on the library of choice, but with Simple Injector you do it as follows:
// Register all command handler implementation all at once.
container.Register(
typeof(ICommandHandler<>),
typeof(ICommandHandler<>).Assembly);
// Tell Simple Injector to wrap each ICommandHandler<T> implementation with a
// ScopedCommandHandlerProxy<T>. Simple Injector will take care of the rest and
// will inject the Func<ICommandHandler<T>> for you. The proxy can be a
// singleton, since it will create the decoratee on each call to Handle.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ScopedCommandHandlerProxy<>),
Lifestyle.Singleton);
This is just one of the many advantages that this type of design gives you. Other advantages is that it makes much easier to apply all sorts of cross-cutting concerns such as audit trailing, logging, security, validation, de-duplication, caching, deadlock-prevention or retry mechanisms, etc, etc. The possibilities are endless.
ItemOneRepository and ItemTwoRepository are using the same
unit-of-work (MyDBContext), but so is the rest of the application
which is plainly wrong.
If your factory is registered with a transient lifecycle, you will get a new instance every time it's injected, which will be a new DBContext each time.
However, I would recommend a more explicit unit of work implementation:
public DBContext GetContext() //I would rename this "Create()"
{
return new MyDBContext();
}
And:
public IEnumerable GetItemsByItemOneID(int itemOneID)
{
using (var context = contextFactory.Create())
{
return context.ItemTwos.Where(i => i.itemOneID == itemOneID);
}
}
This gives you fine-grained control over the unit of work and transaction.
You might also ask yourself if the repositories are gaining you anything vs. just using the context directly via the factory. Depending on the complexity of your application, the repositories may be unnecessary overhead.

Categories

Resources