UnitOfWork for different DbContext - c#

I have something like following
//Following is the Constructor
public UnitOfWork(IEmployeeContext context)
{
this._context = context;
}
#endregion
public void Dispose()
{
this._context.Dispose();
}
public void Commit()
{
this._context.SaveChanges();
}
public IEmployeeRepository EmployeeRepository
{
{
return _employeeRepository??
(_employeeRepository= new EmployeeRepository(_context));
}
}
Now the Problem is i have another repository which is not based on IEmployeeContext. Lets call that context IOfficeContext so it will be like
get
{
return _officeRepository??
(_officeRepository= new OfficeRepository(_context));
}
The Context passed to OfficeRepository is IOfficeContext . Should i have two separate UnitOfWork for them? or some other clever thing can be done over here?

You could have a common interface:
public interface IContext
{
void Dispose();
void SaveChanges();
}
And have both IEmployeeContext and IOfficeContext inherit from it. Then UnitOfWork could know only about IContext and will be able to handle both.

Related

How can I implement a transaction for my repositories with Entity Framework?

I am trying to utilize the repository design pattern in my application for 2 reasons
I like to de-couple my application from Entity in case I decide to not use Entity Framework at some point
I want to be able reuse the logic that interacts with the model
I successfully setup and used the repository pattern. However, I have one complexity to deal with which is a transaction.
I want to be able to use transaction so that I can make multiple calls to the repository and then commit or rollback.
Here is my repository interface
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Support.Repositories.Contracts
{
public interface IRepository<TModel> where TModel : class
{
// Get records by it's primary key
TModel Get(int id);
// Get all records
IEnumerable<TModel> GetAll();
// Get all records matching a lambda expression
IEnumerable<TModel> Find(Expression<Func<TModel, bool>> predicate);
// Get the a single matching record or null
TModel SingleOrDefault(Expression<Func<TModel, bool>> predicate);
// Add single record
void Add(TModel entity);
// Add multiple records
void AddRange(IEnumerable<TModel> entities);
// Remove records
void Remove(TModel entity);
// remove multiple records
void RemoveRange(IEnumerable<TModel> entities);
}
}
Then I create an implementation for Entity Framework like so
using Support.Repositories.Contracts;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace Support.Repositories
{
public class EntityRepository<TEntity> : IRepository<TEntity>
where TEntity : class
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(int id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public void Add(TEntity entity)
{
DbSet.Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
DbSet.AddRange(entities);
}
public void Remove(TEntity entity)
{
DbSet.Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
DbSet.RemoveRange(entities);
}
}
}
Now, I create a IUnitOfWork to interact with repository like so
using System;
namespace App.Repositories.Contracts
{
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
IAddressRepository Addresses { get; }
}
}
Then I implemented this interface for Entity Framework like this:
using App.Contexts;
using App.Repositories.Contracts;
using App.Repositories.Entity;
namespace App.Repositories
{
public class UnitOfWork : IUnitOfWork
{
private readonly AppContext _context;
public IUserRepository Users { get; private set; }
public IAddressRepository Addresses { get; private set; }
public UnitOfWork(AppContext context)
{
_context = context;
Users = new UserRepository(_context);
Addresses = new AddressRepository(_context);
}
public UnitOfWork() : this(new AppContext())
{
}
public int Save()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
}
I am able to use the repository like this
using(var repository = new UnitOfWork())
{
repository.Users.Add(new User(... User One ...))
repository.Save();
repository.Addresses(new Address(... Address For User One ...))
repository.Save();
repository.Users.Add(new User(... User Two...))
repository.Save();
repository.Addresses(new Address(... Address For User Two...))
repository.Save();
}
Now, I want to be able to use database transaction so only when everything is good then commit otherwise rollback.
My first take is to add a new method called BeginTransaction() to my UnitOfWork class. But will couple my code to Entity Framework only.
Now, I am thinking to create a new interface that provides BeginTransaction(), Commit() and Rollback() method which will allow me to write an implementation for any ORM.
i.e.
namespace Support.Contracts
{
public IRepositoryDatabase
{
SomethingToReturn BeginTransaction();
void Commit();
void Rollback();
}
}
The question is how would I tie IRepositoryDatabase back to my UnitOfWork so I can implement correctly? And what would BeginTransaction() needs to return?
I think I figured out the way to do it. (I hope I did it the right way)
Here is what I have done, I hope this helps someone looking to do the same thing.
I created a new Interface like so
using System;
namespace Support.Repositories.Contracts
{
public interface IDatabaseTransaction : IDisposable
{
void Commit();
void Rollback();
}
}
Then I implemented IDatabaseTransaction for Entity framework like so
using Support.Repositories.Contracts;
using System.Data.Entity;
namespace Support.Entity.Repositories
{
public class EntityDatabaseTransaction : IDatabaseTransaction
{
private DbContextTransaction _transaction;
public EntityDatabaseTransaction(DbContext context)
{
_transaction = context.Database.BeginTransaction();
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
}
public void Dispose()
{
_transaction.Dispose();
}
}
}
Then, I added a new method called BeginTransaction() to my IUnitOfWork contract like so
using System;
namespace App.Repositories.Contracts
{
public interface IUnitOfWork : IDisposable
{
IDatabaseTransaction BeginTransaction();
IUserRepository Users { get; }
IAddressRepository Addresses { get; }
}
}
Finally, following is my UnitOfwork implementation for Entity
using App.Contexts;
using App.Repositories.Contracts;
using App.Repositories.Entity;
using Support.Repositories;
namespace App.Repositories
{
public class UnitOfWork : IUnitOfWork
{
private readonly AppContext _context;
public IUserRepository Users { get; private set; }
public IAddressRepository Addresses { get; private set; }
public UnitOfWork(AppContext context)
{
_context = context;
Users = new UserRepository(_context);
Addresses = new AddressRepository(_context);
}
public UnitOfWork() : this(new AppContext())
{
}
public int Save()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
public IDatabaseTransaction BeginTransaction()
{
return new EntityDatabaseTransaction(_context);
}
}
}
And here is how I consume the UnitOfWork implementation from my controller
using(var unitOfWork = new UnitOfWork())
using(var transaction = new unitOfWork.BeginTransaction())
{
try
{
unitOfWork.Users.Add(new User(... User One ...))
unitOfWork.Save();
unitOfWork.Addresses(new Address(... Address For User One ...))
unitOfWork.Save();
unitOfWork.Users.Add(new User(... User Two...))
unitOfWork.Save();
unitOfWork.Addresses(new Address(... Address For User Two...))
unitOfWork.Save();
transaction.Commit();
}
catch(Exception)
{
transaction.Rollback();
}
}
In EF Core, Although UnitOfWork pattern is implemented internally, you can simply use IDbContextTransaction interface as follow (supposing that you use Dependency Injection):
public interface IUnitOfWork
{
int SaveChanges();
Task<int> SaveChangesAsync();
IDbContextTransaction BeginTransaction();
Task<IDbContextTransaction> BeginTransactionAsync();
IUserRepository Users { get; }
IAddressRepository Addresses { get; }
}
and the implementation:
public class UnitOfWork : IUnitOfWork, IDisposable
{
private bool _disposed;
private readonly AppDbContext _context;
public UnitOfWork(AppDbContext context,
IUserRepository userRepositpry, IAddressRepository addressRepository)
{
_context = context;
Users = userRepositpry;
Addresses = addressRepository;
}
public IUserRepository Users { get; }
public IAddressRepository Addresses { get; }
public int SaveChanges()
{
return _context.SaveChanges();
}
public async Task<int> SaveChangesAsync()
{
return await _context.SaveChangesAsync();
}
public IDbContextTransaction BeginTransaction()
{
return _context.Database.BeginTransaction();
}
public async Task<IDbContextTransaction> BeginTransactionAsync()
{
return await _context.Database.BeginTransactionAsync();
}
protected void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Usage:
public class FooService
{
private readonly IUnitOfWork _unitOfWork;
public FooService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void Bar()
{
using (var transaction = _unitOfWork.BeginTransaction())
{
try
{
_unitOfWork.Users.Add(new UserModel("dummy username"));
_unitOfWork.SaveChanges();
_unitOfWork.Addresses.Add(new AddressModel("dummy address"));
_unitOfWork.SaveChanges();
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
}
}
While comments by Sir Rufo are correct, you did said that wanted an EF independent solution and although usually abstracting away from the ORM is an overkill, if you are still set on handling the transaction yourself you can use TransactionScope (which was apparently the way to achieve control over the transaction before having BeginTransaction in the context.Database).
Please see the following article for details: https://msdn.microsoft.com/en-us/data/dn456843.aspx
Relevant bits are that you can enclose all the calls in a TransactionScope (this will actually work out of the box in other ORMs as well):
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;
namespace TransactionsExamples
{
class TransactionsExample
{
static void UsingTransactionScope()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
using (var conn = new SqlConnection("..."))
{
conn.Open();
var sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.CommandText =
#"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'";
sqlCommand.ExecuteNonQuery();
using (var context =
new BloggingContext(conn, contextOwnsConnection: false))
{
var query = context.Posts.Where(p => p.Blog.Rating > 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
}
}
scope.Complete();
}
}
}
}
But do need to mind the following caveats:
There are still some limitations to the TransactionScope approach:
Requires .NET 4.5.1 or greater to work with asynchronous methods
It cannot be used in cloud scenarios unless you are sure you have one and only one connection (cloud scenarios do not support distributed transactions)
It cannot be combined with the Database.UseTransaction() approach of the previous sections
It will throw exceptions if you issue any DDL (e.g. because of a Database Initializer) and have not enabled distributed transactions through the MSDTC Service
Aside all the solutions above I did it the easy way I know most of the sollutions are handy but I'm sharing it maybe it can help somebody.
First in IUnitOfWork I set a rule as:
DatabaseFacade DbTransaction();
And in the implementation I just used:
public DatabaseFacade DbTransaction()
{
return _myContext.Database;
}
Now anywhere in my code I can use it easily and I can call it and simplicity enable me to keep track of things and remember what I have coded.
Calling process:
var transaction = _unitOfWork.DbTransaction().BeginTransaction();
Try{
//Any operations you like
transaction.Commit();
}catch(Exception E){
//handling Exception
}

Call different methods, from different repositories, in same transaction using Unit of work

I am still learning UnitOfWork pattern and I am not comfortable with this yet. I found many examples but nothing is clear enough for my problem.
I want use UnitOfWork with Ado.Net.
I have many repositories. I want call different methods from different repositories in same transaction using Unit of work.
For example a have this 2 repositories.
public class FirstRepository : IFirstRepository
{
private readonly ILogger logger;
private readonly IImportConfiguration configuration;
public FirstRepository(ILogger logger, IImportConfiguration configuration)
{
this.logger = logger;
this.configuration = configuration;
}
public int Save()
{
//Save to DB with Ado.Net
return 1;
}
}
public class SecondRepository : ISecondRepository
{
private readonly ILogger logger;
private readonly IImportConfiguration configuration;
public SecondRepository(ILogger logger, IImportConfiguration configuration)
{
this.logger = logger;
this.configuration = configuration;
}
public int Update()
{
//Update in DB with Ado.Net
return 1;
}
}
I want call functions Save() and Update() in same transaction.
using (var uow = UnitOfWorkFactory.Create())
{
firstRepository.Save();
secondRepository.Update();
_unitOfWork.SaveChanges();
}
Problem is how to use same UnitOfWork in both repositories ? Only thing I can see is add additional parameter to functions
//in first repository
Save(IUnitOfWork uow)
//in second repository
Update(IUnitOfWork uow)
//****************************
using (var uow = UnitOfWorkFactory.Create())
{
firstRepository.Save(uow);
secondRepository.Update(uow);
_unitOfWork.SaveChanges();
}
This is ugly solution, because i must have this parameter in all functions that work with DB.
I am using Dependency injection. ILogger and IImportConfiguration are injected with AutoFac. Maybe would be good to register all repositories in UnitOfWork? But how to do that? I cant have just one instance injected in all repositories.
Any idea?
public class UnitOfWork
{
public DbSet<Company> Companies { get; set; }
public int SaveChanges()
{
underlyingContext.SaveChanges();
}
}
public class UnitOfWorkFactory
{
public UnitOfWork Create()
{
// real creation logic
return new UnitOfWork();
}
}
public class CompanyRepository
{
private readonly UnitOfWork uow;
public CompanyRepository(UnitOfWork uow)
{
uow = uow;
}
public void Add(Company company)
{
uow.Companies.Add(company);
}
}
public class CompanyRepositoryFactory
{
public Create(UnitOfWork uow)
{
new CompanyRepository(uow);
}
}
Tying it all together:
var uow = new UnitOfWorkFactory().Create();
var companyRepository = new CompanyRepositoryFactory().Create(uow);
So to use DI, you need to create interfaces for all these.
The unit of work is based round some Data Layer connection, for example EF uses DbContext which you would use in the underlying UnitOfWork class.
Other things you can do is make IUnitOfWork (the interface) inherit IDisposable so you use the using().
To make it so you don't have a hundred repository classes (although not really a bad thing) you can make it Generic, so IRepository<T> and Repository<T>
So for a generic repo and unit of work using EF.
public class UnitOfWork : IUnitOfWork
{
ProjectDbContext context;
public UnitOfWork() {
context = new ProjectDbContext();
}
public IQueryable<T> Query<T>(Expression<Func<bool, t>> predicate)
{
return context.Set<T>().Where(predicate);
}
public void Add<T>(T entity)
{
context.Set<T>().Add(entity);
}
public int SaveChanges()
{
return context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public class UnitOfWorkFactory
{
Lazy<UnitOfWork> lazyUOW = new Lazy<UnitOfWork>(() => new UnitOfWork());
public UnitOfWork Create()
{
// having the DI initialise as Singleton isn't enough.
return lazyUOW.Value;
}
}
public class Repository<T> : IRepository<T>
{
private readonly IUnitOfWork uow;
public Repository(IUnitOfWork uow)
{
uow = uow;
}
public void Add(T entity)
{
uow.Add(entity);
}
public List<T> AllBySomePredicate(Expression<Func<bool, T>> predicate)
{
return uow.Query(predicate).ToList();
}
}
public class RepositoryFactory : IRepositoryFactory
{
public Create<T>(UnitOfWork uow)
{
new Repistory<T>(uow);
}
}
Usage:
public class CompanyController : Controller
{
private readonly IUnitOfWorkFactory uowFactory;
private readonly IRepositoryFactory repoFactory;
public CompanyController (
IUnitOfWorkFactory uowFactory,
IRepositoryFactory repoFactory)
{
uowFactory = uowFactory;
repoFactory = repoFactory;
}
public ActionResult Index()
{
using(var uow = uowFactory.Create())
{
var companyRepo = repoFactory.Create<Company>(uow);
return View(companyRepo.AllBySomePredicate(x => x.CompanyJoined == DateTime.Now.AddMonths(-2)));
}
}
}

Cordinate between my repository classes and controller classes to be using the same Context object

I am working on an asp.net mvc web application. now i have created multiple repositories classes, for example i have the following abstract repository classes:-
public interface ISkillRepository : IDisposable
{//code goes here..
&
public interface IStaffRepository : IDisposable
{//code goes here
and the model Repositories:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
//code goes here
&
public class StaffRepository : IStaffRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
now inside y controller i am intializing and creating the repo as follow:-
public class SkillController : Controller
{
private ISkillRepository skillRepository;
public SkillController() : this(new SkillRepository()) {}
public SkillController(ISkillRepository repository)
{
skillRepository = repository;
}
but currently i got the following error inside my application:
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
and the problem is that i need to be passing the same context accross the repos and controllers. so can anyone adivce on this:-
how i can inside one model repo to reference another repo using the same context class. for example inside the Staff repositoryto referecne the skill repository?
how i can inside a controller class to refer multiple repos , but at the same time pass the same context object among them , so if i issue a save() it will wrap all the statements inside one transaction. for example insie my skillController to reference both the skill & staff repos using the same context object ?
Thanks
Edit
I have created the following Unit of work class:-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
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);
}
}
}
and then inside my repo i did the following:-
public class SecurityRoleRepository : ISecurityRoleRepository , IDisposable
{
private SkillManagementEntities context;// = new SkillManagementEntities();
public SecurityRoleRepository(SkillManagementEntities context)
{
this.context = context;
and on the controller class i will be referencing the UnitOfWork as follow:-
public class SecurityRoleController : Controller
{
private UnitOfWork unitOfWork = new UnitOfWork();
public async Task<ActionResult> Index(string filter = null, int page = 1, int pageSize = 20, string sort = "Name", string sortdir = "ASC")
{
try
{
var records = new PagedList<SecurityRole>();
ViewBag.filter = filter;
records.Content = await unitOfWork.SecurityRoleRepository.GetSecurityRoleForGrid(filter, page, pageSize, sort, sortdir).ToListAsync();
now i am facing a problem is that how i can referecne a repo from another Repo ? for example how i can reference the Skill repo inside the SecurityRole repo ?
EDIT Final
i did the following steps:-
1. i install
Install-Package Ninject.MVC5
2. then i created the following dependency class:-
public class YourDependencyResolverClass : IDependencyResolver
{
private IKernel kernel;
public YourDependencyResolverClass()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<ISkillRepository>().To<SkillRepository>();
kernel.Bind<IStaffRepository>().To<StaffRepository>();
kernel.Bind<ISecurityRoleRepository>().To<SecurityRoleRepository>();
kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
kernel.Bind<ISkillVersionHistoryRepository>().To<SkillVersionHistoryRepository>();
}
}
}
3.now inside my SkillRepository class i will be referencing the StaffRepository as follow:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context ;
private IStaffRepository staffrepo = (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository));
public SkillRepository(SkillManagementEntities context)
{
this.context = context;
}
Finally inside my action method i will be calling the Uiteofwork class as follow:-
public class StaffController : Controller
{
//private SkillManagementEntities db = new SkillManagementEntities();
UnitOfWork unitofwork = new UnitOfWork();
public async Task<ActionResult> AutoComplete(string term)
{
var staff = await unitofwork.StaffRepository.GetAllActiveStaff(term).Select(a => new { label = a.SamAccUserName }).ToListAsync();
return Json(staff, JsonRequestBehavior.AllowGet);
and the unite of work class is :-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
private CustomerRepository customerRepository;
private SkillVersionHistoryRepository SVH;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public CustomerRepository CustomerRepository
{
get
{
if (this.customerRepository == null)
{
this.customerRepository = new CustomerRepository(context);
}
return customerRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.securityroleRepository == null)
{
this.securityroleRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public SkillVersionHistoryRepository SkillVersionHistoryRepository
{
get
{
if (this.SVH == null)
{
this.SVH = new SkillVersionHistoryRepository(context);
}
return SVH;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
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);
}
}
So can you adivce if my approach of using unitefwork and DI will guarantee that all my statements will be warped inside a single DB transaction ? thnaks?
We handle this by sharing a context using a singleton that is scoped to the request using HttpContext:
public MyContext GetContext()
{
if (System.Web.HttpContext.Current.Items["MyScopedContext"] == null)
{
System.Web.HttpContext.Current.Items["MyScopedContext"] = new MyContext();
}
return (MyContext)System.Web.HttpContext.Current.Items["MyScopedContext"];
}
The context object (repository) itself essentially houses a Unit of Work. The code I added above just gives you a way to share a single repository across all code running within a request. If your repository classes are defined in the scope of a web application, you can just replace your direct instantiation of SkillManagementEntities() with a call to a GetContext() method.
On the other hand if your repositories are defined in a layer shared by heterogeneous applications, you may need to get your context from a factory object that you can inject as needed. Either way, creating a new context object per repository is what's causing your issue.
Not an answer: this "use DI" suggestion answers a bit different question - OP is looking for "unit-of-work" pattern - while basic case (lifetime of unit of work matches lifetime of request/controller) can easily be solved with any DI framework, managing multiple units of work or units of work with longer lifetime is much harder and dedicated "unit of work factory" (sample usage) is likely the solution.
Usually when you go that far with interfaces/repositories and constructor dependency injection you have some Dependency Injection framework. There is a good chance that one you are using already provides "per HTTP request" resolution or allows to easily add one.
I.e. if you using Unity there is PerRequestLifetime lifetime manager that makes all .Resolve calls for the same interface/object to return the same instance for given request. See more info in DI with Unity MSDN article.
Approximate sample:
container.RegisterType<ISkillRepository, SkillRepository>();
container.RegisterType<IOtherRepository, OtherRepository>();
container.RegisterType<TheContext, TheContext>(new PerRequestLifetime());
With such registration and assuming you've configured ASP.Net MVC to use Unity to resolve types when controller is created it will get necessary dependencies (new instances as registered with default lifetime), but both will share the same context (assuming each depends on TheContext class either via constructor or property injection).

Getting Generic Repository + Child repository + UnitOfWork inside my asp.net mvc web application

I am working on an asp.net vmc5 web application that uses Entity framework 6.
Now I am trying to get these working :-
Define a generic repository.
For each DBSet type to create a dedicated repository which will be derived from the generic repository.
Create an interface for each of the dedicated repository.
Use UnitOfwork class so that calling multiple repository classes will result in a single transaction generated.
I have a DbSet of type SkillType.
So I created the following interface:-
namespace SkillManagementp.DAL
{
public interface ISkillTypeRepository {
}
Then the following generic Repository:-
namespace SkillManagement.DAL
{
public class GenericRepository<TEntity> where TEntity : class
{
internal SkillManagementEntities context;
internal DbSet<TEntity> dbSet;
public GenericRepository(SkillManagementEntities context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}//code goes here...
The following SkillTypeRepository:-
namespace SkillManagement.DAL
{
public class SkillTypeRepository : GenericRepository<SkillType> : ISkillTypeRepository
{
private SkillManagementEntities db = new SkillManagementEntities();
public void Dispose()
{
db.Dispose();
}
public void Save()
{
db.SaveChanges();
}
}
}
And finally I created the following UnitOfWork class:-
namespace SkillManagement.DAL
{
public class UnitOfWork : IDisposable
{
private SkillManagementEntities db = new SkillManagementEntities();
private SkillTypeRepository skillTypeRepository;
public SkillTypeRepository SkillTypeRepository
{
get
{
if (this.skillTypeRepository == null)
{
this.skillTypeRepository = new SkillTypeRepository();
}
return skillTypeRepository;
}
}
public void Save()
{
db.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
But I am getting these errors:-
I can not define two derived classes for my SkillManagmentRepositry class.
Also I am getting this error inside the SkillTypeRepository:- SkillManagement.DAL.GenericRepository' does not contain a constructor that takes 0 arguments
Rewrite SkillTypeRepository to this:
public class SkillTypeRepository : GenericRepository<SkillType>, ISkillTypeRepository
{
public SkillTypeRepository() : base(new SkillManagementEntities())
{
}
//rest of code etc
}
As mentioned in my comment, your SkillTypeRepository does not have a constructor, but the GenericRepository does, as the base class has a constructor you need to provide one in the derived class and call :base(params) see here for more details.
You can then simply call base.context to obtain a reference to the SkillManagementEntities.

Passing Windsor Castle Injected Dependency to a Parallel Thread - Dispose() problem

I'm using ASP.NET MVC with Castle Windsor as my IoC container with the component lifestyle set to PerWebRequest. My repository (which is the dependency that's injected) creates an instance of Entity Framework's ObjectContext in the constructor and I store that in a private instance variable. My repository implements IDisposable and inside my Dispose method, I dispose the ObjectContext. I think all of this is pretty standard and here's a simplified illustration:
Repository:
public class Repository : IRepository {
private MyContext _dc; // MyContext inherits from ObjectContext
public Repository() {
_dc = new MyContext();
}
public void Dispose() {;
_dc.Dispose();
}
}
To ensure that there's no memory leak and that my Repository's Dispose() is called, I override DefaultControllerFactory's ReleaseController method to release Windsor's container:
public class WindsorControllerFactory : DefaultControllerFactory {
IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container) {
_container = container;
// Do stuff to register all controller types
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
// Do stuff to resolve dependency
}
public override void ReleaseController(IController controller) {
// by releasing the container, Windsor will call my Dispose() method on my repository
_container.Release(controller);
base.ReleaseController(controller);
}
}
I think all of this is pretty standard. However, I'd like to spin off a parallel thread, and inside that parallel thread utilize the IRepository dependency. My problem is that my repository will have already been disposed by the time I use it:
public class HomeController : Controller {
IRepository _repository;
public HomeController(IRepository repository) {
_repository = repository;
}
public ActionResult Index() {
var c = _repository.GetCompany(34);
new Task(() => {
System.Threading.Thread.Sleep(2000); // simulate long running task
// will throw an error because my repository (and therefore, ObjectContext) will have been disposed.
var c2 = _repository.GetCompany(35);
}).Start();
return Content(c.Name, "text/plain");
}
}
How do other people solve this problem? How do you pass your dependencies to a parallel thread?
Thanks in advance.
Create a new Repository instance. ObjectContexts are inexpensive to construct.
OR, you could attach the responsibility of disposing the Repository to the long running thread. I messed around with it, I think these alterations to your code will solve your problem:
In your WindsorControllerFactory
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
IController controller;
// Do stuff to resolve dependency
if(controller is LongTaskController)
{
((LongTaskController) controller).CompleteLongTask += (sender, args) => _container.Release(controller);
}
}
public override void ReleaseController(IController controller)
{
// by releasing the container, Windsor will call my Dispose() method on my repository
if(!(controller is LongTaskController && ((LongTaskController)controller).HasLongTask)
{
_container.Release(controller);
}
base.ReleaseController(controller);
}
In HomeController
public class HomeController : LongTaskController
{
private readonly IRepository _repository;
public HomeController(IRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var c = _repository.GetCompany(34);
DoLongTask(() =>
{
Thread.Sleep(200);
var c2 = _repository.GetCompany(35);
});
return Content(c.Name, "text/plain");
}
}
And the new base controller
public abstract class LongTaskController: Controller,IHasLongTask
{
private bool _hasLongTask;
public bool HasLongTask { get { return _hasLongTask; } }
public event EventHandler CompleteLongTask;
void IHasLongTask.DoLongTask(Action action) { DoLongTask(action); }
protected void DoLongTask(Action action)
{
_hasLongTask = true;
if (CompleteLongTask == null)
{
throw new NullReferenceException("Controller.CompleteLongTask cannot be null when Controller does a long running task.");
action += () => CompleteLongTask(this, EventArgs.Empty);
}
new Task(action).Start();
}
}
public interface IHasLongTask
{
bool HasLongTask { get; }
void DoLongTask(Action action);
event EventHandler CompleteLongTask;
}

Categories

Resources