Winforms DbContext Per Form - c#

I am working on a WindowsForms application. I am using Repository, UoW, DI and EntityFramework. The best practice in such applications is to use a DbContext per windows form.
My problem is that when i resolve a form IoC, the form is injected with my business services. This should by default create a new DbContext instance, which is fine. When i open a sub-form from the same form, even though there are new business services injected into this sub-form, the same DbContext instance is used.
Even if i open a new form, the same DbContext instance is used, unless i release the resolved form.
Shouldn't be the case that whenever i resolve an component, and that component has several dependencies, then new instances from all will be created, especially since i am using Transient life style.
Below is short implementation of the code i use. I have included the important parts.
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private DbContextBase context = null;
/// <summary>
/// Constructer
/// </summary>
public UnitOfWork(DbContextBase context)
{
this.context = context;
}
/// <summary>
/// Gets current context.
/// </summary>
public DbContextBase UoWContext
{
get { return context; }
}
}
UnitOfWorkManager:
public class UnitOfWorkManager
{
private static IUnitOfWork _unitOfWork { set; get; }
private UnitOfWorkManager()
{
}
public static IUnitOfWork Current
{
get
{
if (_unitOfWork != null)
return _unitOfWork;
else
{
_unitOfWork = Create();
return _unitOfWork;
}
}
set
{
_unitOfWork = value;
}
}
private static IUnitOfWork Create()
{
return IoCManager.IoC.Resolve<IUnitOfWork>();
}
}
Repository:
public class Repository<TEntity, TKey> : IRepository<TEntity, TKey>
where TEntity : class
{
public Repository()
{
}
private DbContextBase Context
{
get
{
return UnitOfWorkManager.Current.UoWContext;
}
}
private DbSet<TEntity> DbSet
{
get
{
return Context.Set<TEntity>();
}
}
}
Business Service:
{
public class BusinessService<TEntity, TKey> : IBusinessService<TEntity, TKey>
where TEntity : IEntity
{
protected IRepository<TEntity, TKey> _repository;
public BusinessService(IRepository<TEntity, TKey> repository)
{
_repository = repository;
}
}
DI Registration using Castle-Windsor:
IoCManager.IoC.Register<DbContextBase, PMDbContext>(IoCLifeStyle.Transient);
IoCManager.IoC.Register<IEFUnitOfWork, EFUnitOfWork>(IoCLifeStyle.Transient);
IoCManager.IoC.Register<IRepository>(typeof(IRepository).Assembly, IoCLifeStyle.Transient);
IoCManager.IoC.Register<BusinessServiceInterceptor>(IoCLifeStyle.Singelton);
IoCManager.IoC.Register<IBusinessService, BusinessServiceInterceptor>(typeof(IBusinessService).Assembly, IoCLifeStyle.Transient, typeof(BusinessServiceInterceptor));
//Forms
IoCManager.IoC.Register<frm_Main>(PM.Common.Enums.IoCLifeStyle.Transient);
IoCManager.IoC.Register<frm_Calander>(PM.Common.Enums.IoCLifeStyle.Transient);
IoCManager.IoC.Register<frm_Calanders>(PM.Common.Enums.IoCLifeStyle.Transient);

You have to change your design little bit:
public class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class
{
private readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
private DbContextBase Context
{
get
{
return _unitOfWork.UoWContext;
}
}
private DbSet<TEntity> DbSet
{
get
{
return Context.Set<TEntity>();
}
}
}
Then whenever a new form is requested
new service is injected
which gets a new repository
which gets a new
unitOfWork
which gets a new dbContext
Each call to the service within the same form will result in call to the same underlying -service -> repository -> unitOfWork -> context.
In case you have more services within the form which should share the same instance of uow:
Container.Register(Component.For<IUnitOfWork>()
.ImplementedBy<UnitOfWork>()
.LifestyleBoundToNearest<frmBase>());
(https://github.com/castleproject/Windsor/blob/master/docs/lifestyles.md)
Then uow and its context would be scoped only to the nearest form.

Related

MOQ SetupGet dbContext with constructor parameters

Situation
Here I am, trying to write some unit tests for my GroupService with the use of MOQ.
To create an instance of my GroupService, I mocked 4 interfaces that needed to be passed through the constructor. Now on one of the mocks (IGroupRepository) a property called Context is called and my idea was to SetupGet this property and just simply return a fake list of GroupUser. But I keep getting errors, whatever I try.
Code
public class GroupServiceTests
{
private readonly GroupService _groupService;
private readonly Mock<AppDbContext> _dbContext;
private readonly Mock<IGroupRepository> _groupRepository;
private readonly Mock<IComponentService> _componentService;
private readonly Mock<IUserContextService> _userContextService;
private readonly Mock<IModelEntityMapper<Group, Core.DbContexts.Entities.Group>> _mapper;
public GroupServiceTests()
{
var groupUsersMock = CreateDbSetMock(GetFakeListOfGroupUsers());
_dbContext = new Mock<AppDbContext>(new DbContextOptions<AppDbContext>());
_dbContext.SetupGet(x => x.GroupUser).Returns(groupUsersMock.Object);
_groupRepository = new Mock<IGroupRepository>();
_groupRepository.SetupGet(repo => repo.Context).Returns(_dbContext.Object);
_componentService = new Mock<IComponentService>();
_userContextService = new Mock<IUserContextService>();
_mapper = new Mock<IModelEntityMapper<Group, Core.DbContexts.Entities.Group>>();
_groupService = new GroupService(_groupRepository.Object, _componentService.Object, _userContextService.Object, _mapper.Object);
}
}
In the GroupService this line is called:
// _repository reffers to IGroupRepository
userIdsForContextReset.AddRange(_repository.Context.GroupUser.Where(x => groupIds.Contains(x.GroupId)).Select(x => x.UserId));
And the GroupRepository and EntityRepository look like this:
public interface IGroupRepository : IEntityRepository<AppDbContext, Group>
{
List<GroupPermission> GetInheritedGroupPermissions(int groupId);
}
public class GroupRepository : EntityRepository<AppDbContext, Group>, IGroupRepository
{
public GroupRepository(AppDbContext dbContext) : base(dbContext)
{
}
public List<GroupPermission> GetInheritedGroupPermissions(int groupId)
{
// Removed for brevity
}
}
public class EntityRepository<TDbContext, TEntity> : EntityRepository<TDbContext, TEntity, int>, IEntityRepository<TDbContext, TEntity>
where TDbContext : DbContext
where TEntity : class, IEntity<int>
{
public EntityRepository(TDbContext dbContext) : base(dbContext)
{
}
}
public class EntityRepository<TDbContext, TEntity, TId> : IEntityRepository<TDbContext, TEntity, TId>
where TDbContext : DbContext
where TEntity : class, IEntity<TId>
where TId : IComparable
{
public EntityRepository(TDbContext context)
{
Context = context;
}
public TDbContext Context { get; }
}
And last but not least, the AppDbContext and SqlDbContext:
public class AppDbContext : Shared.DbContexts.SqlDbContext
{
public virtual DbSet<GroupUser> GroupUser { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
}
public class SqlDbContext : DbContext
{
public SqlDbContext(DbContextOptions options) : base(options)
{
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
ChangeTracker.StateChanged += ChangeTracker_StateChanged;
}
}
Error
The error that I am getting is inside the SqlDbContext on the 1st line inside the constructor and says the following:
System.InvalidOperationException: 'No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.'
What am I doing wrong?
When you mock an implementation it creates the object using the constructor matching the parameters provided; it runs that code.
Additionally, anything not able to be mocked (not virtual or abstract) will run as is. In this case, you're passing in DbContextOptions and you haven't specified a provider, and something needs that.
This can be an opinionated topic, however to solve your problem there are a number of ways you could do it:
Add a parameterless constructor to your DbContext for testing. I wouldn't recommend this as I follow the mantra of not changing your SUT for a test.
Use an in-memory provider; EF Core In-Memory Database Provider or SQLite EF Core Database Provider are two that I have used. They do have limitations but for the OP usage would probably be fine and addresses Microsofts notes about how you shouldn't mock the DbContext.
Use an existing library such as EntityFrameworkCore.Testing (disclaimer, I am the author) which will extend in-memory providers to address their limitations.

Getting ninject to dispose of resources InRequestScope

I have a project that I'm working with and I'm trying to integrate ninject into. The way I have it set up is I have several service classes that inherit from two similar base classes AbstractService & AbstractReadableService, from which give them access to the data layer through my unit of work. The main dependency I want to be disposed is the DataContext which is held by the UnitOfWork which is in turn injected by ninject.
The way I have all these components set up is, I have the ServiceFactory put into the controller, which gets the needed dependencies from ninject. Then whenever I need a service I use the GetService method which sets the needed dependencies for that service drawn from the ServiceFactory’s copy and returns a copy of that service ready to use. However when I navigate to a new page or do any other action the Dispose method on the UnitOfWork is never called.
My thought was that the ServiceFactory and it's dependencies would be created on each request and that each time I set a new request the UnitOfWork would dispose of the database context. However I'm not hitting the dispose method and was hoping someone could point me in the right direction.
AbstractService:
AbstractReadableService holds the unit of work.
public abstract class AbstractService : AbstractReadableService
{
/// <summary>
/// Gets the current user id all lowercase at run time
/// </summary>
protected string UserId; //TODO: Change, to a more complete object, ex: We can resolve the employee number at startup time and get all that from an object returned by ICustomPrincipalService
public AbstractService() { }
/// <summary>
/// Constructor for abstract service that we can use to create a new service inside of other services
/// </summary>
/// <param name="user"></param>
/// <param name="unitOfWork"></param>
public AbstractService(ICustomPrincipalService user, IUnitOfWork unitOfWork)
{
if (base._unitOfWork == null || this.UserId == null)
{
this.UserId = user.GetUser();
base._unitOfWork = unitOfWork;
}
}
public void SetDependencies(ICustomPrincipalService user, IUnitOfWork unitOfWork)
{
if (base._unitOfWork == null || this.UserId == null)
{
this.UserId = user.GetUser();
base._unitOfWork = unitOfWork;
}
else
{
// Throw some really nasty error
}
}
}
Unit of work class
public class UnitOfWork : IUnitOfWork
{
private DataContext _dataContext;
public UnitOfWork(DataContext dataContext)
{
//Misc
_dataContext = dataContext;
ISomeRepo SomeRepo { get; private set; }
//Repositories
SomeRepo = new SomeRepo(dataContext);
}
public void SaveChanges(string userId)
{
RecordAuditProperties(userId);
_epmsContext.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_dataContext.Dispose();
}
}
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Service factory
public class ServiceFactory : IServiceFactory
{
private IUnitOfWork _unitOfWork;
private ICustomPrincipalService _userInfo;
private IEmployeeCredentialService employeeCredentials;
public ServiceFactory(IUnitOfWork unitOfWork, ICustomPrincipalService userInfo, IEmployeeCredentialService employeeCredentials)
{
_unitOfWork = unitOfWork;
_userInfo = userInfo;
}
public T GetService<T>() where T : AbstractService, new()
{
T svc = new T();
svc.SetDependencies(_userInfo, _unitOfWork);
return svc;
}
public T GetReadOnlyService<T>() where T : AbstractReadableService, new()
{
T svc = new T();
svc.SetDependencies(_unitOfWork);
return svc;
}
}
Ninject bindings:
private void AddBindings()
{
// Binding context to ensure only one context is used in the lifetime of the request
kernel.Bind<DataContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
//Deals with pulling the current HTTP context user id into the services
kernel.Bind<ICustomPrincipalService>().To<CustomPrincipalService>().InRequestScope();
kernel.Bind<IHttpContextFactory>().To<HttpContextFactory>().InRequestScope();
kernel.Bind<IEmployeeCredentialService>().To<EmployeeCredentialService>().InRequestScope();
//Disposible dependencies are passed here
kernel.Bind<IServiceFactory>().To<ServiceFactory>().InRequestScope();
}
Everything was correct, I was able to get it working after I installed the Ninject MVC4 solution from nuget

ASP.NET MVC UnitOfWork and Business Services / Layer

need you help implementing UnitOfWork for my business layer.
Want to wrap multiple different business service calls into a single transaction.
Let's assume I use Entity Framework as my repository layer and I have an additional business layer for validation and other business rules. In this example just very very simple.
public class MyDbContext
{
public DbSet<User> Users;
public DbSet<Contract> Contracts;
}
public class UserService
{
public UserService(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public void AddUser(User user)
{
_dbContext.Users.Add(user);
_dbContext.SaveChanges();
}
}
public class ContractService
{
public ContractService(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public void AddContract(Contract contract)
{
_dbContext.Contracts.Add(contract);
_dbContext.SaveChanges();
}
}
In my controller:
userService.AddUser(user);
contractService.AddContract(contract);
... The add user calls already save changes but i want to save changes after add contract.
So can I do the following?? Or is this somehow bad design?!
Create UnitOfWork class:
public class UnitOfWork
{
public UnitOfWork(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public MyDbContext DbContext => _dbContext;
public void SaveChanges()
{
_dbContext.SaveChanges();
}
}
Change my services to:
public class UserService
{
public UserService(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void AddUser(User user)
{
_unitOfWork.DbContext.Users.Add(user);
}
}
public class ContractService
{
public ContractService(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void AddContract(Contract contract)
{
_unitOfWork.DbContext.Contracts.Add(contract);
}
}
And then in my controller I do:
userService.AddUser(user);
contractService.AddContract(contract);
unitOfWork.SaveChanges();
Is this a valid approach?! Really need your help and thoughts on this...
Thanks!!!!
Your 'UnitOfWork' should contain methods that reflect your use cases. So I would have a method like 'CreateContract' which actually adds the 'user' and 'contract' and commits the transaction and just call this method from the controller.
public void CreateContract(User user,Contract contract)
{
this.dbContext.Users.Add(user);
this.dbContext.Contracts.Add(contract);
this.dbContext.SaveChanges();
}
This way you can encapsulate any transactional code within this method. Ex - if adding a user and contract are not simply EF calls but calls to different services, you can have a distributed transaction or other code to rollback the transaction.

How to write custom methods when using generic repository

I am still struggling to make good data access layer for asp mvc application and as always something is missing :)
I have created separate assembly for DAL and I am using repository pattern and ninject for IOC.
Problem is that now I don't know how to write custom methods (methods out of generic CRUD methods).
This is implementation:
Context class:
public class MainContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IMainContext
{
public MainContext()
: base("DefaultConnection")
{
}
...
public DbSet<Country> Countries { get; set; }
...
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
Repository:
public interface ICountryRepository : IGenericRepository<Country>...
Generic Repository:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly IMainContext _context;
private readonly IDbSet<TEntity> _dbSet;
public GenericRepository(IMainContext context)
{
this._context = context;
this._dbSet = context.Set<TEntity>();
}
...
Generic Repository Interface:
public interface IGenericRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "");
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
And this is try to add custom method in repository class:
public virtual IEnumerable<Country> GetByLocation(float location)
{
var data = from c in _context...
return data;
}
But I don't have a context.
I don't know how to implement getting data now.
Should I inject it somehow or make instance by new keyword (but I guess this is wrong)
How to implement custom method now?
Your implementation of ICountryRepository should inherit the GenericRepository. The GenericRepository has a reference to the db context which you can use for your custom queries. For your Generic Repository constructor is will be much easier to take MainContext instead of an IMainContext which is ok if you keep injecting it down through you layers. With Ninject you will want to bind your MainContext like this:
kernel.Bind<MainContext>().ToSelf().InRequestScope();
and the rest of your interfaces to the concrete implementation. So each of your repositories will have the context through the GenericRepository which has a reference to your db context which you can make custom queries off of in the repository. If you had a service layer, inject the interface of the repository:
private readonly ICountryRepository _repository;
public SomeServie(ICountryRepository repository){
_repository = repository;
}
public void DoSomething(float locationId){
_repository.GetByLocation(locationId);
}
HERE IS THE OTHER CODE YOU NEED:
public class CountryRepository : GenericRepository<Country>, ICountryRepository
{
public CountryRepository(MainContext mainContext) : base(mainContext) { }
public IEnumerable<Country> GetByLocation(float location)
{
return this.Context.Countries.ToList();
}
.....
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
public MainContext Context { get; set; }
public IDbSet<TEntity> DbSet { get; set; }
public GenericRepository(MainContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
.......
Also, your GetCountries does not need to be virtual.
The main changes here are that you need to pass the context through the country repository constructor to base, and the context and countries db set need to be public, even when inherited. See this article: Are private members inherited in C#?

MVC 4 Autofac and Generic Repository pattern

I am utilizing the Unit Of Work and Generic Repository pattern in my MVC 4 app. The problem I am trying to solve is creating Repository stubs for every entity in my system. In order to utilize the Autofac Ioc I am having to create a repository class and interface for every entity so that I can register it in Autofac.
app start...
builder.RegisterType<SchoolDetailRepository>().As<ISchoolDetailRepository>().InstancePerHttpRequest();
Repository class
public class SchoolDetailRepository : RepositoryBase<SchoolDetail>, ISchoolDetailRepository
{
public SchoolDetailRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
}
Interface
public interface ISchoolDetailRepository : IRepository<SchoolDetail>
{
}
It seems like a lot of extra work.
Is there a way to register the generic repository of Type rather than creating all these empty classes?
Then in my service class I can just have the generic type passed into the constructor via Ioc like...
public class SchoolService : ISchoolService
{
private readonly IRepository<SchoolDetail> _schoolRepository;
private readonly IUnitOfWork _unitOfWork;
public SchoolService(IRepository<SchoolDetail> schoolRepository, IUnitOfWork unitOfWork)
{
this._schoolRepository = schoolRepository;
this._unitOfWork = unitOfWork;
}
}
Container config
// Autofac iOC
var builder = new ContainerBuilder();
// register controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// register services
builder.RegisterType<MembershipService>().As<IMembershipService>().InstancePerHttpRequest();
builder.RegisterType<SchoolService>().As<ISchoolService>().InstancePerHttpRequest();
builder.RegisterType<StudentService>().As<IStudentService>().InstancePerHttpRequest();
builder.RegisterType<ClassRoomService>().As<IClassRoomService>().InstancePerHttpRequest();
builder.RegisterType<CourseService>().As<ICourseService>().InstancePerHttpRequest();
builder.RegisterType<SchoolYearService>().As<ISchoolYearService>().InstancePerHttpRequest();
builder.RegisterType<EnrollmentService>().As<IEnrollmentService>().InstancePerHttpRequest();
builder.RegisterType<TeacherService>().As<ITeacherService>().InstancePerHttpRequest();
// register data infrastructure
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerHttpRequest();
// register repositories
builder.RegisterType<SchoolRepository>().As<ISchoolRepository>().InstancePerHttpRequest();
builder.RegisterType<TeacherRepository>().As<ITeacherRepository>().InstancePerHttpRequest();
builder.RegisterType<MembershipRepository>().As<IMembershipRepository>().InstancePerHttpRequest();
builder.RegisterType<RoleRepository>().As<IRoleRepository>().InstancePerHttpRequest();
builder.RegisterType<ProfileRepository>().As<IProfileRepository>().InstancePerHttpRequest();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerHttpRequest();
builder.RegisterType<StudentRepository>().As<IStudentRepository>().InstancePerHttpRequest();
builder.RegisterType<ClassRoomRepository>().As<IClassRoomRepository>().InstancePerHttpRequest();
builder.RegisterType<CourseRepository>().As<ICourseRepository>().InstancePerHttpRequest();
builder.RegisterType<EnrollmentRepository>().As<IEnrollmentRepository>().InstancePerHttpRequest();
builder.RegisterType<SchoolYearRepository>().As<ISchoolYearRepository>().InstancePerHttpRequest();
builder.RegisterType<GradeLevelRepository>().As<IGradeLevelRepository>().InstancePerHttpRequest();
//builder.RegisterType<SchoolDetailRepository>().As<ISchoolDetailRepository>().InstancePerHttpRequest();
builder.RegisterGeneric(typeof(RepositoryBase<SchoolDetail>)).As(typeof(IRepository<SchoolDetail>));
// build and setup resolver
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
the exception is coming from the above code where the expression you gave me runs..
builder.RegisterGeneric(typeof(RepositoryBase<SchoolDetail>)).As(typeof(IRepository<SchoolDetail>));
RepositoryBase
public abstract class RepositoryBase<T> where T : class
{
private LearningCompactPilotContext _dataContext;
private readonly IDbSet<T> _dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected LearningCompactPilotContext DataContext
{
get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
}
... more code
}
You need the open generics feature of Autofac:
builder.RegisterGeneric(typeof(RepositoryBase<>))
.As(typeof(IRepository<>));
Then you use your repositories exactly as you described:
public class SomeService
{
private readonly IRepository<SomeEntity> _repository;
public SchoolService(IRepository<SomeEntity> repository)
{
this._repository= repository;
}
}

Categories