Generic Repository and Transaction - c#

I have implemented my first Generic repository in MVC app. Works fine but how to put repositories in Transaction scope?
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _db;
public Repository(DataContext db)
{
_db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return _db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
_db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
_db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
_db.SubmitChanges();
}
#endregion
}
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
var connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
kernel.Bind(typeof(DataContext)).ToMethod(context => new DataContext(connectionString));
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
public class AdminController : Controller
{
private readonly IRepository<User> _userRepository;
private readonly IRepository<Order> _orderRepository;
public AdminController(IRepository<User> userRepository, IRepository<Order> orderRepository)
{
_userRepository = userRepository;
_orderRepository = orderRepository;
}
public ActionResult InsertUser(UserViewModel model)
{
//Skip Code
//Do not commit data to database if _orderRepository is failed to save data
_userRepository.Add(user);
_userRepository.Save();
//Skip Code
_orderRepository.Add(order);
_orderRepository.Save();
}
}
What would be best method to wrap repository code with Transaction scope in InsertUser action?

You are missing an abstraction here. You should place all your business logic inside command handlers and create a command handler decorator that implements transaction behavior. This article describes how to do this, but in short:
Define an ICommandHandler<TCommand> interface:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
Create commands that define the contract of a business operation. Commands are simply DTOs (with only data and no behavior). For instance:
public class ShipOrderCommand
{
public int OrderId { get; set; }
public ShippingInfo Info { get; set; }
}
Implement command handlers that will contain the business logic / behavior for those commands:
public class ShipOrderCommandHandler
: ICommandHandler<ShipOrderCommand>
{
private readonly IRepository<Order> repository;
public ShipOrderCommandHandler(
IRepository<Order> repository)
{
this.repository = repository;
}
public void Handle(ShipOrderCommand command)
{
// do some useful stuf with the command and repository.
}
}
Let your MVC Controllers depend on the ICommandHandler<T> abstraction:
public ShipOrderController : Controller
{
private readonly ICommandHandler<ShipOrderCommand> handler;
public ShipOrderController(
ICommandHandler<ShipOrderCommand> handler)
{
this.handler = handler;
}
public void Ship(int orderId, ShippingInfo info)
{
this.handler.Handle(new ShipOrderCommand
{
OrderId = orderId,
Info = info
});
}
}
Define a generic decorator that implements transaction logic:
public TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratedHandler;
public TransactionalCommandHandlerDecorator(
ICommandHandler<TCommand> decoratedHandler)
{
this.decoratedHandler = decoratedHandler;
}
public void Handle(TCommand command)
{
using (var scope = new TransactionScope())
{
this.decoratedHandler.Handle(command);
scope.Complete();
}
}
}
Ensure that each ShipOrderCommandHandler is decorated with a TransactionalCommandHandlerDecorator and injected into ShipOrderController. You can do this with your favorite DI container, or by hand:
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(ShipOrderController))
{
return new ShipOrderController(
new TransactionalCommandHandlerDecorator<ShipOrderCommand>(
new ShipOrderCommandHandler(
new OrderRepository())));
}
return base.GetControllerInstance(requestContext, controllerType);
}
With this in place you can run all your business logic inside a transaction, without the need for the business logic to be aware of that.

There's a pattern called Unit of work. Here's an explanation.

Related

Autofac how to register and resolve generic interface at runtime?

I am having trouble resolving a generic interface implementation at runtime. I am working with an eventbus that will resolve eventhandlers depending on the type of the event. When I try to resolve the eventhandlers without a generic implementation everything works as expected. I want to implement a generic interface so I could have a base class that handles specific type of events.
I had the following situation before I created a generic implementation:
public interface IEvent
{
Guid EntityId { get; set; }
}
public interface IEventHandler<TEvent> where TEvent : IEvent
{
Task Handle(TEvent #event);
}
public class EventBus
{
private readonly IComponentContext _context;
public EventBus(IComponentContext context)
{
_context = context;
}
public async Task HandleEvent<TEvent>(TEvent #event) where TEvent : IEvent
{
var handler = _context.Resolve<IEventHandler<TEvent>>();
await handler.Handle(#event);
}
}
I register the eventHandlers as follows:
builder.RegisterAssemblyTypes(ThisAssembly).AsClosedTypesOf(typeof(IEventHandler<>));
Example Implementation :
public class FooEventHandler :
IEventHandler<FooArchivedEvent>,
IEventHandler<FooRestoredEvent>,
IEventHandler<FooSomethingElseHappenedEvent>
{
private readonly IRepository<Foo> _repository;
public FooEventHandler(IRepository<Foo> repository)
{
_repository = repository;
}
public async Task Handle(FooArchivedEvent #event)
{
var Foo = await _repository.Get(#event.EntityId);
Foo.Archive();
}
public async Task Handle(FooRestoredEvent #event)
{
var Foo = await _repository.Get(#event.EntityId);
Foo.Restore();
}
public async Task Handle(FooSomethingElseHappenedEvent #event)
{
// do something else with Foo
}
}
public class BarEventHandler :
IEventHandler<BarArchivedEvent>,
IEventHandler<BarRestoredEvent>
{
private readonly IRepository<Bar> _repository;
public BarEventHandler(IRepository<Bar> repository)
{
_repository = repository;
}
public async Task Handle(BarArchivedEvent #event)
{
var Bar = await _repository.Get(#event.EntityId);
Bar.Archive();
}
public async Task Handle(BarRestoredEvent #event)
{
var Bar = await _repository.Get(#event.EntityId);
Bar.Restore();
}
}
When I pass a FooArchivedEvent to the eventbus the eventbus will resolve the required eventhandler. As you can see I have some duplicate code that I want to resolve in a base eventhandler. This is what I tried before I created the generic implementation (which won't compile):
public class BaseEventHandler<TEntity, TArchivedEvent, TRestoredEvent> :
IEventHandler<TArchivedEvent>,
IEventHandler<TRestoredEvent>
where TEntity : class
where TArchivedEvent : IEvent
where TRestoredEvent : IEvent
{
public Task Handle(TArchivedEvent #event)
{
throw new NotImplementedException();
}
public Task Handle(TRestoredEvent #event)
{
throw new NotImplementedException();
}
}
So I created a generic base class that does compile, however I can't figure out how to resolve the generic eventhandler in the eventbus.
Generic base class:
public abstract class BaseEventHandler<TEntity> :
IEventHandler<IArchivedEvent<TEntity>>,
IEventHandler<IRestoredEvent<TEntity>>
where TEntity : Archivable
{
protected readonly IRepository<TEntity> _repository;
public BaseEventHandler(IRepository<TEntity> repository)
{
_repository = repository;
}
public virtual async Task Handle(IArchivedEvent<TEntity> #event)
{
var entity = await _repository.Get(#event.EntityId);
entity.Archive();
}
public async virtual Task Handle(IRestoredEvent<TEntity> #event)
{
var entity = await _repository.Get(#event.EntityId);
entity.Archive();
}
}
My new FooEventHandler will now look like this:
public class FooEventHandler : BaseEventHandler<Foo>,
IEventHandler<FooSomethingElseHappenedEvent>
{
public FooEventHandler(IRepository<Foo> repository) : base(repository)
{
}
public Task Handle(FooSomethingElseHappenedEvent #event)
{
// do something else with Foo
}
}
Now when I pass a FooArchivedEvent to the eventbus the eventbus can't resolve the eventhandler. Is there something I need to do in the registration part or is it not possible to resolve a generic implementation like this ?
I ended up writing a method that checks every interface of a type for a registered handler:
private IEventHandler<TEvent> GetHandler<TEvent>(Type type = null) where TEvent : IEvent
{
object handler;
type = type ?? typeof(TEvent);
if (_container.TryResolve(typeof(IEventHandler<>).MakeGenericType(type), out handler))
{
return (IEventHandler<TEvent>)handler;
}
else
{
foreach (var t in type.GetInterfaces())
{
var h = GetHandler<TEvent>(t);
if (h != null)
return h;
}
}
return null;
}

Circular component dependency detected Repository pattern with autofac dependency injections

I am working on implementing the generic repository pattern with db Context and Autofac DI, and I am using the constructor based on dependency injections.
I have created the three layers repository pattern which are:
Infrastructure layer
Model layer
Services layer
Now, I am using this architecture in MVC web application when I try to pass the IContactService interface in ContactController and run the application.
I am getting the circular dependency detected error. Followings are my project code.
Repository code:
public class Repository<T> : IRepository<T> where T : class
{
private InvoiceBillingDbContext db;
private DbSet<T> dbSet;
public Repository()
{
db = new InvoiceBillingDbContext();
dbSet = db.Set<T>();
}
public IEnumerable<T> GetAll()
{
return dbSet.ToList();
}
public T GetById(object Id)
{
return dbSet.Find(Id);
}
public void Insert(T obj)
{
dbSet.Add(obj);
Save();
}
public void Update(T obj)
{
db.Entry(obj).State = EntityState.Modified;
Save();
}
public void Delete(object Id)
{
T getObjById = dbSet.Find(Id);
dbSet.Remove(getObjById);
}
public void Save()
{
db.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (this.db != null)
{
this.db.Dispose();
this.db = null;
}
}
}
public void AddRange(List<T> obj)
{
dbSet.AddRange(obj);
Save();
}
public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
{
return dbSet.Where(predicate);
}
}
Interface IRepository
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
T GetById(object Id);
IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
void Insert(T obj);
void AddRange(List<T> obj);
void Update(T obj);
void Delete(Object Id);
void Save();
}
My ContactRepository
public class ContactRepository:Repository<Contact>, IContactRepository
{
private IContactRepository _contractRepo;
public ContactRepository(IContactRepository contractRepo)
{
this._contractRepo = contractRepo;
}
}
My ContactRepository Interface
public interface IContactRepository:IRepository<Contact>
{
}
My Contact Service
public interface IContactService
{
void AddContact(Contact contact);
IEnumerable<Contact> GetContactsByTypeId(int typeId);
}
public class ContactService : IContactService
{
private readonly IContactRepository _contactRepository;
public ContactService(IContactRepository contactRepository)
{
this._contactRepository = contactRepository;
}
public void AddContact(Contact contact)
{
_contactRepository.Insert(contact);
}
public IEnumerable<Contact> GetContactsByTypeId(int typeId)
{
return _contactRepository.Get(i => i.TypeID == typeId);
}
}
My Controller
public class ContactController : Controller
{
// GET: Contact
private IContactService _contactService;
public ContactController(IContactService contactService)
{
this._contactService = contactService;
}
public ActionResult Index()
{
return View(new ContactViewModel());
}
public ActionResult AddContact(ContactViewModel contact)
{
if (ModelState.IsValid)
{
var _contactMapper = Mapper.Map<ContactViewModel, Contact>(contact);
_contactService.AddContact(_contactMapper);
ViewBag.Message = "Successfully Saved";
return View("Index",new ContactViewModel());
}
ViewBag.Message = "Error Occur Please try Again!";
return View("Index", new ContactViewModel());
}
}
And Autofac Dependency Injection
public static void ConfigureContainer()
{
var builder = new ContainerBuilder();
// Register all controllers in the Mvc Application assembly
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// Registered Warehouse Reservoir Service
builder.RegisterType<InvoiceRepository>().As<IInvoiceRepository>();
// Registration Service Layer Service
builder.RegisterType<InvoiceService>().As<IInvoiceService>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
// Registered Warehouse Reservoir Service
builder.RegisterType<JournalVoucherRepository>().As<IJournalVoucherRepository>();
// Registration Service Layer Service
builder.RegisterType<JournalVoucherService>().As<IJournalVoucherService>();
// Registered Warehouse Reservoir Service
builder.RegisterType<ContactRepository>().As<IContactRepository>();
// Registration Service Layer Service
builder.RegisterType<ContactService>().As<IContactService>();
// Registration filter
builder.RegisterFilterProvider();
var container = builder.Build();
// Setting Dependency Injection Parser
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
You've only got one implementation of IContactRepository. You've also got a generic IRepository<T>.
Your implementation of IContactRepository gets another IContactRepository injected into it. So you're recursively resolving the same class and injecting it into itself.
public class ContactRepository:Repository<Contact>, IContactRepository
{
private IContactRepository _contractRepo;
// In order to resolve IContractRepository, the container has to
// resolve another IContractRepository to inject into it.
// And another one to inject into that. It's recursive.
public ContactRepository(IContactRepository contractRepo)
{
this._contractRepo = contractRepo;
}
}
Your example doesn't show how ContactRepository uses the IContactRepository that gets inject into it. But this
public interface IContactRepository:IRepository<Contact>
{
}
reveals that it's using the exact same methods found in IRepository<Contact>, because IContactRepository doesn't have any methods other than those.
So you most likely just need to modify ContactRepository to inject IRepository<Contact>, not IContactRepository.
public class ContactRepository:Repository<Contact>, IContactRepository
{
private IRepository<Contact> _contractRepo;
public ContactRepository(IRepository<Contact> contractRepo)
{
this._contractRepo = contractRepo;
}
}
That could be easy to overlook since both interfaces have exactly the same methods.

Unit of Work and Repository Pattern in MVC controller constructor injection using Unity not doing any changes to database

1.) I am a building new MVC application with 3 tier project architecture having:
Common Project with entities
Business/Service holding interfaces and logic classes and
Data holding repositories, interfaces, DbContext and UnitOfWorkclasses. I am using Unity Config to register dependencies, DbContext and UnitOfWork.
2.) I created a repository for each table and one generic repository that does basic CRUD operations.
Example Entity residing in Common Project:
public class MenuSecd
{
[Key, Column(Order = 0)]
public string prg_module { get; set; }
[Key, Column(Order = 1)]
public int prg_numb { get; set; }
[Key, Column(Order = 2)]
public string menu_level { get; set; }
}
My generic Entity Logic Interface residing in Business Project:
public interface IEntityLogic<T> : ILogic where T : class
{
void Create(T entity);
void Delete(T entity);
IEnumerable<T> GetAll();
void Update(T entity);
}
Entity Logic Class:
public abstract class EntityLogic<T> : IEntityLogic<T> where T : class
{
IUnitOfWork _unitOfWork;
IGenericRepository<T> _repository;
public EntityLogic(IUnitOfWork unitOfWork, IGenericRepository<T> repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_unitOfWork.Commit();
}
}
Example Business Logic class for the entity defined in Common Project:
public class MenuSecdLogic : EntityLogic<MenuSecd>, IMenuSecdLogic
{
IUnitOfWork _unitOfWork;
IMenuSecdRepository _repository;
public MenuSecdLogic(IUnitOfWork unitOfWork, IMenuSecdRepository repository) : base(unitOfWork, repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _repository.GetItems(usrgrp_id);
}
}
My Generic Repository in Data Project looks like:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected DbContext _entities;
protected readonly IDbSet<T> _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual T Add(T entity)
{
return _dbset.Add(entity);
}
public virtual T Delete(T entity)
{
return _dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = EntityState.Modified;
}
}
Repository Interface for the same Entity is defined as:
public interface IMenuSecdRepository : IGenericRepository<MenuSecd>
{
List<MenuSecd> GetItems(string usrgrp_id);
}
Repository class for above mentioned interface is:
public class MenuSecdRepository : GenericRepository<MenuSecd>, IMenuSecdRepository
{
public MenuSecdRepository(DbContext context) : base(context)
{
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _dbset.Where(m => m.usrgrp_id == usrgrp_id).ToList();
}
}
My DbContext looks like:
public class DashboardContext : DbContext
{
public DashboardContext() : base("Name=DBEntities")
{
}
public DbSet<MenuSecd> menusecd { get; set; }
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
//future custom implementation like auditing
return base.SaveChanges();
}
}
My UnitOfWork looks like:
public sealed class UnitOfWork : IUnitOfWork
{
private DbContext _dbContext;
public UnitOfWork(DbContext context)
{
_dbContext = context;
}
public int Commit()
{
return _dbContext.SaveChanges();
}
//disposes current object
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//disposes all external resources
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
My controller:
public class DashController : Controller
{
private readonly IMenuSecdLogic _menuSecdLogic;
public DashController(IMenuSecdLogic menuSecdLogic)
{
_menuSecdLogic = menuSecdLogic;
}
public void Save()
{
var menuSecd = new menuSecd();
//populate all fields for entity MenuSecd
_menuSecdLogic.Create(menuSecd);
}
}
My Unity Config in App_Start looks like :
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<DbContext, DashboardContext>();
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
container.RegisterType<IMenuSecdLogic, MenuSecdLogic>();
container.RegisterType<IMenuSecdRepository, MenuSecdRepository>();
}
So when run above project everything builds fine. But when controller calls:
_menuSecdLogic.Create(menuSecd);
It reaches Entity Logic and adds a new entity to _repository at :
_repository.Add(entity);
_unitOfWork.Commit();
But when it hits next line to actually save it to database which is :
return _dbContext.SaveChanges();
in UnitOfWork.cs file.
It comes to dashboardContext where it finally have to save it to database. But it does execute :
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
return base.SaveChanges();
But nothing changes in database. There will be no record in database. To test I have added modifiedEntries to see if it is in context or not. By the time control reaches this point I see no modified entries at all. But in EntityLogic.cs it does add a new entity to local entities in repository.
I am not sure what is happening with UnitOfWork here. I ran SQL Profiler to see if it is hitting database or not. Interestingly it is not hitting database at all. But if my make following changes to EntityLogic like this:
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_repository.Save();
//_unitOfWork.Commit();
}
It hits Database and records gets saved fine. But I am not getting why it is neither tracking changes nor hitting database if I use _unitOfWork.Commit() which I want to do. Please help.
It looks like your issue is the scope of your DbContext. Your UnitOfWork and GenericRepository<T> classes are getting different instances.
Not super familiar with Unity, but it looks like you want to use something like this for your DbContext registration:
container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());
This will create a single DashboardContext for each request, and your UnitOfWork and GenericRepository<T> classes will be working within the same context.

How to dynamically change change DI using autofac?

We are developing windows service, and i want to change dbcontext class dynamically in repositories.
bellow is the scenario.
I have three db context classes
public abstract class Context : DbContext, IUnitOfWork
{
protected Context(string connectionString) : base(connectionString)
{
}
}
public class PlatformContext : Context
{
private readonly string _connectionString;
public PlatformContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class PlatformReplicaContext : Context
{
private readonly string _connectionString;
public PlatformReplicaContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
public class TempContext : Context
{
private readonly string _connectionString;
public TempContext(string connectionString)
: base(connectionString)
{
_connectionString = connectionString;
}
}
and i have repository
public interface ICategoryRepository : IRepository<Category>
{
}
public class CategoryRepository :Repository<Category>, ICategoryRepository
{
public CategoryRepository(Context context) : base(context)
{
}
}
hence im using CQRS i have another three classes
public class CategoryBasicQuery:IRequest<BaseQueryResponse>
{
public int CategoryId { get; set; }
}
public class CategoryBasicQueryHandler : IRequestHandler<CategoryBasicQuery, BaseQueryResponse>
{
private readonly ICategoryRepository _categoryRepository;
private readonly IMapper _mapper;
public CategoryBasicQueryHandler(ICategoryRepository categoryRepository, IMapper mapper)
{
_categoryRepository = categoryRepository;
_mapper = mapper;
}
public async Task<BaseQueryResponse> Handle(CategoryBasicQuery request, CancellationToken cancellationToken)
{
var entry = await _categoryRepository.FindAsync(request.CategoryId);
if (entry == null)
{
return new NotFoundResponse();
}
var response = _mapper.Map<CategoryBasicResponse>(entry);
return response;
}
}
Now here is the issue
Here category repository should be able to execute queries in all 3 types of contexts.
but how should i register classes in using autofac?
then i came up with a solution generating repositories in run time as below
public class RepositoryFactory
{
public static TRepository GetRepositoryInstance<T, TRepository>(
params object[] args)
where TRepository : IRepository<T>
{
return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
}
}
im calling this method inside CategoryBasicQueryHandler class like this
var categoryRepo = RepositoryFactory.GetRepositoryInstance<Category, CategoryRepository>(new PlatformReplicaContext("connectionString"));
but when calling from CQRS
var categoty = new Category();
var command = new CategoryBasicQuery {CategoryId = categoryId};
var result = _mediator.Send(command);
VS give me following error
and my autofac registration as follows
builder.RegisterType<CategoryService>().AsSelf();
builder.RegisterType<ActionRepository>().As<IActionRepository>();
builder.RegisterType<CategoryRepository>().As<ICategoryRepository>();
builder.RegisterType<Mapper>().As<IMapper>();
can anyone help me resolve this or suggest good method to handle this situation.
thanks.
This may give you a good starting point for a possible solution: http://autofaccn.readthedocs.io/en/latest/resolve/relationships.html#keyed-service-lookup-iindex-x-b
builder.RegisterType<PlatformContext>().Keyed<Context>("platform");
builder.RegisterType<PlatformReplicaContext>().Keyed<Context>("replica");
builder.RegisterType<TempContext>().Keyed<Context>("temp");
You mentioned in a comment that there is a variable named action somewhere that will indicate which implementation to use:
public class Class1
{
private readonly IIndex<string, Context> contexts;
public Class1(IIndex<string, Context> contexts)
{
this.contexts = contexts;
}
public void Whatever()
{
string action = ...; // platform, replica or temp
Context context = this.contexts[action];
...
}
}
Of course this needs to be adapted so that it will fit in the rest of your application design. A possible example could be:
Context context = this.contexts[action];
using(ILifetimeScope scope = container.BeginLifetimeScope(builder =>
{
builder.RegisterInstance(context).As<Context>();
}))
{
// Because we are resolving IMediator from the scope, the selected Context will be used in all dependencies
var mediator = scope.Resolve<IMediator>();
mediator.Send(...);
}

MVC DBContext management with ninject

My project is using MVC5, EF6 and Ninject.
I have some service classes wich composes the business layer, and only them are allowed to acces the DbContext, meaning that the controller doesen't have any direct access to the context.
The service classes are like those:
public interface IService1: IDisposable
{
IEnumerable<SomeDataType> GetSomeData(string param);
void SaveData();
}
public class Service1: IService1
{
private MyContext context;
public Maestri(MyContext context)
{
this.context = context;
}
public void Dispose()
{
context.Dispose();
}
public IEnumerable<SomeDataType> GetSomeData(string Param)
{
[...]
}
public void SaveData()
{
[...]
context.SaveChanges()
}
}
public interface IService2: IDisposable
{
IEnumerable<SomeDataType2> GetSomeData(string param);
void SaveData();
}
public class Service2: IService2
{
private MyContext context;
public Maestri(MyContext context)
{
this.context = context;
}
public void Dispose()
{
context.Dispose();
}
public IEnumerable<SomeDataType2> GetSomeData(string Param)
{
[...]
}
public void SaveData()
{
[...]
context.SaveChanges()
}
}
In Ninject CreateKernel are initialized like this:
kernel.Bind<MyContext>().ToSelf().InRequestScope();
kernel.Bind<IService1>().To<Service1>().InRequestScope();
kernel.Bind<IService2>().To<Service2>().InRequestScope();
In the controller:
public class MyController : Controller
{
private readonly IService1 _service1;
private readonly IService2 _service2;
public MyController(IService1 service1, IService2 service2)
{
_service1 = service1;
_service2 = service2;
}
public ActionResult SomeAction()
{
var data1 = _service1.GetSomeData("");
var data2 = _service2.GetSomeData("");
[...]
return View();
}
}
I've noticed that for every request to Controller/SomeAction the MyContext constructor has called only once, but the dispose() will be called twice. This leads me to think about a bad design of mine.
I've tried to remove the context.Dispose(); from the services, but this leads to MyContext.dispose to never get called, but a new instance is generated for every request.
Could someone please point me out what am I doing wrong?
Thanks!

Categories