How to handle this scenario in mvc c#? - c#

I am working on a multi-tenant app with asp.net mvc. I have to identify tenant for each request so i have created a class below:
public class TenantProvider
{
public static Tenant Tenant
{
get
{
Tenant tenant = HttpContext.Current.Items["Tenant"] as Tenant;
if (tenant == null)
{
var tenantUsername = HelperUtility.GetCurrentRequestHost();
//The below line of code is my problem
TenantRepository tenantRepository = new TenantRepository(new AppointContext());
tenant = tenantRepository.GetByUsername(tenantUsername);
HttpContext.Current.Items.Add("Tenant", tenant);
}
return tenant;
}
}
}
This class static property returning the Tenant for current request. It will first check for the Tenant in cache, if not found than if will get the Tenant from the database, initialize the cache and return the Tenant.
For getting Tenant form the database i am creating a TenantRepository instance. TenantRepository has a dependency over database context, which i am passing it while creating its instance.
Now when i have to do other database operation on current Tenant than i have to create a new Repository instance at some other place and have to pass new Context, so the actual context with which i have extracted the Tenant and the new Context differ which i think may create the problem.
So my question is how can i handle this scenario, so that same context instance will be used ??

The solution you are looking for is the Unit of Work design pattern. From Martin Fowler:
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
ref: http://martinfowler.com/eaaCatalog/unitOfWork.html
This pattern allows you to enroll multiple transactions into a single context. This is a very common pattern, and here is one possible implementation. First, create a Unit of Work object which will hold a reference to your central context, and which will initialize your repositories with that context (this implementation uses the Entity Framework):
public class UnitOfWork : IUnitOfWork
{
internal EntitiesContext _context = new EntitiesContext ();
private ITenantRepository _tenantRepository;
private IOtherRepository _otherRepository;
public ITenantRepository TenantRepository
{
get
{
if (_tenantRepository== null)
{
_tenantRepository= new TenantRepository(_context);
}
return _tenantRepository;
}
}
public IOtherRepository OtherRepository
{
get
{
if (_otherRepository== null)
{
_otherRepository= new OtherRepository(_context);
}
return _otherRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
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);
}
Note that if you use any repository with this pattern, they will all use the same context.
Your controller should either initializing the Unit of of Work, or even better, have it injected into its constructor:
public TenantController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_tenantRepository = unitOfWork.TenantRepository;
_otherRepository = unitOfWork.OtherRepository;
}
If you need to use the UnitOfWork to another layer, you would typically pass it as an argument to another object's constructor:
public ActionResult Index()
{
TenantProvider provider = new TenantProvider(_unitOfWork);
_otherRepository.DoWork();
_unitOfWork.Save();
}
Now your TenantProvider can do some work with its respective repository, but the Unit of Work's OtherRepository can also do some work using the same context.

In addition to #ChrisHardie, I want to add some MVC specifics: I think it is a very good practice to inject the Unit of Work into the controllers. In order to do so, you can create a custom ControllerFactory that is derived from DefaultControllerFactory and is registered at application startup:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
// Analyze whether instance of controllerType should be created directly or
// whether the Unit of Work should be injected
if (needsUnitOfWork)
return (IController)Activator.CreateInstance(controllerType, unitOfWork);
else
return (IController)Activator.CreateInstance(controllerType);
}
}
In order to discern between controllers that need a Unit of Work and those that do not, you could use reflection (custom attributes or inspecting constructor arguments). Maybe you can also assume that each controller needs a Unit of Work for the moment.
If you are already using an Inversion of Control container, it can support you in creating the instances (IoC containers are usually plugged in in a ControllerFactory in MVC). If not, you might consider to start using one.
You can register the ControllerFactory like this:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// ...
RegisterCustomControllerFactory ();
// ...
}
private void RegisterCustomControllerFactory ()
{
IControllerFactory factory = new CustomControllerFactory();
ControllerBuilder.Current.SetControllerFactory(factory);
}
}
As this answers builds upon the extension points for Dependency Injection in MVC, this link might help.

Related

How do I use Dependency Injection with Unit of Work and Repositories in C#? (Not a web based App)

I see a lot of questions and answers on this topic, however the vast majority are dealing with ASP.Net or other web based applications and something called .InRequestScope. I have yet to find this method in Ninject with a Windows Application.
I have the usual Unit of Work (UoW) and Repository (Repo) classes and Interfaces, but I am wanting to inject the same DbContext into both, each time a UoW is run from the DIContainer. My code looks like this;
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly FinancialContext _context;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get { return _accountRepository; }
}
UnitOfWork(IMyContext context, IAccountRepository accountRepository)
{
_context = context;
_accountRepository = accountRepository;
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
public class AccountRepository : Repository<Account>, IAccountRepository
{
public AccountRepository(IMyContext context) : base(context) { }
}
The DIContainer holds the following associations;
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<IUnitOfWorkFactory>().ToFactory();
Bind<IMyContext>().To<MyContext>().InSingletonScope();
Bind<IAccountTypeRepository>().To<AccountTypeRepository>().InTransientScope();
I'll come back to the .InSingletonScope();
The way I have seen people do this normally has been in the UoW Properties for each Repo to have code to this effect;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get
{
if(_accountRepository = null)
{
_accountRepository = new AccountRepository(_context);
}
return _accountRepository;
}
}
And remove the injected repositories from the Constructor, there by ensuring that each instance of a repository using the same _context.
However in my mind this breaks the Dependency Injection for this class. Is there a way to do this where each creation of a UoW like so;
public TestUnitOfWork(IUnitOfWorkFactory unitOfWork)
{
using (var UoW = unitOfWork.Create())
{
Work done on UoW...
}
}
Currently the .InSingletonScope allows this, but is this keeping an instance of the context always open? Introducing the errors associated with not disposing a context properly?
Or is it better to create a Factory for the Repositories and give them a context parameter, then in the properties initialise it like so;
private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
get
{
if(_accountRepository = null)
{
_accountRepository = RepositoryFactory.CreateAccountRepository(_context);
}
return _accountRepository;
}
}
Thanks in advance for any help!
The solution is the use Ninject's Extensions.Factory class and pass in an IAccountFactory.Create() to initialise a new object. This then uses the DI Container to resolve its dependencies and doesn't break the DI approach.

WebApi: Per Request Per Action DbSession using IoC, how?

Our existing database deployment has a single 'master' and a read-only replica. Using ASP.NET's Web API2 and an IoC container I want to create controller actions whose attribute (or lack there of) indicate which database connection is to be used for that request (See Controller and Services usage below)...
public MyController : ApiController
{
public MyController(IService1 service1, IService2 service2) { ... }
// this action just needs the read only connection
// so no special attribute is present
public Foo GetFoo(int id)
{
var foo = this.service1.GetFoo(id);
this.service2.GetSubFoo(foo);
return foo;
}
// This attribute indicates a readwrite db connection is needed
[ReadWrteNeeded]
public Foo PostFoo(Foo foo)
{
var newFoo = this.service1.CreateFoo(foo);
return newFoo;
}
}
public Service1 : IService1
{
// The dbSession instance injected here will be
// based off of the action invoked for this request
public Service1(IDbSession dbSession) { ... }
public Foo GetFoo(int id)
{
return this.dbSession.Query<Foo>(...);
}
public Foo CreateFoo(Foo newFoo)
{
this.dbSession.Insert<Foo>(newFoo);
return newFoo;
}
}
I know how to setup my IoC (structuremap or Autofac) to handle per request IDbSession instances.
However, I'm not sure how I would go about making the type of IDbSession instance for the request to key off the indicator attribute (or lack there of) on the matching controller's action. I assume I will need to create an ActionFilter that will look for the indicator attribute and with that information identify, or create, the correct type of IDbSession (read-only or read-write). But how do I make sure that the created IDbSession's lifecycle is managed by the container? You don't inject instances into the container at runtime, that would be silly. I know Filters are created once at startup (making them singleton-ish) so I can't inject a value into the Filter's ctor.
I thought about creating an IDbSessionFactory that would have 'CreateReadOnlyDbSession' and 'CreateReadWriteDbSession' interfaces, but don't I need the IoC container (and its framework) to create the instance otherwise it can't manage its lifecycle (call dispose when the http request is complete).
Thoughts?
PS During development, I have just been creating a ReadWrite connection for every action, but I really want to avoid that long-term. I could also split out the Services methods into separate read-only and read-write classes, but I'd like to avoid that as well as placing GetFoo and WriteFoo in two different Service implementations just seems a bit wonky.
UPDATE:
I started to use Steven's suggestion of making a DbSessionProxy. That worked, but I was really looking for a pure IoC solution. Having to use HttpContext and/or (in my case) Request.Properties just felt a bit dirty to me. So, if I had to get dirty, I might as well go all the way, right?
For IoC I used Structuremap and WebApi.Structuremap. The latter package sets up a nested container per Http Request plus it allows you to inject the current HttpRequestMessage into a Service (this is important). Here's what I did...
IoC Container Setup:
For<IDbSession>().Use(() => DbSession.ReadOnly()).Named("ReadOnly");
For<IDbSession>().Use(() => DbSession.ReadWrite()).Named("ReadWrite");
For<ISampleService>().Use<SampleService>();
DbAccessAttribute (ActionFilter):
public class DbAccessAttribute : ActionFilterAttribute
{
private readonly DbSessionType dbType;
public DbAccessAttribute(DbSessionType dbType)
{
this.dbType = dbType;
}
public override bool AllowMultiple => false;
public override void OnActionExecuting(HttpActionContext actionContext)
{
var container = (IContainer)actionContext.GetService<IContainer>();
var dbSession = this.dbType == DbSessionType.ReadOnly ?
container.GetInstance<IDbSession>("ReadOnly") :
container.GetInstance<IDbSession>("ReadWrite");
// if this is a ReadWrite HttpRequest start an Request long
// database transaction
if (this.dbType == DbSessionType.ReadWrite)
{
dbSession.Begin();
}
actionContext.Request.Properties["DbSession"] = dbSession;
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var dbSession = (IDbSession)actionExecutedContext.Request.Properties["DbSession"];
if (this.dbType == DbSessionType.ReadWrite)
{
// if we are responding with 'success' commit otherwise rollback
if (actionExecutedContext.Response != null &&
actionExecutedContext.Response.IsSuccessStatusCode &&
actionExecutedContext.Exception == null)
{
dbSession.Commit();
}
else
{
dbSession.Rollback();
}
}
}
}
Updated Service1:
public class Service1: IService1
{
private readonly HttpRequestMessage request;
private IDbSession dbSession;
public SampleService(HttpRequestMessage request)
{
// WARNING: Never attempt to access request.Properties[Constants.RequestProperty.DbSession]
// in the ctor, it won't be set yet.
this.request = request;
}
private IDbSession Db => (IDbSession)request.Properties["DbSession"];
public Foo GetFoo(int id)
{
return this.Db.Query<Foo>(...);
}
public Foo CreateFoo(Foo newFoo)
{
this.Db.Insert<Foo>(newFoo);
return newFoo;
}
}
I assume I will need to create an ActionFilter that will look for the indicator attribute and with that information identify, or create, the correct type of IDbSession (read-only or read-write).
With your current design, I would say an ActionFilter is the way to go. I do think however that a different design would serve you better, which is one where business operations are more explicitly modelled behind a generic abstraction, since you can in that case place the attribute in the business operation, and when you explicitly separate read operations from write operations (CQS/CQRS), you might not even need this attribute at all. But I'll consider this out of scope of your question right now, so that means an ActionFilter is the the way to go for you.
But how do I make sure that the created IDbSession's lifecycle is managed by the container?
The trick is let the ActionFilter store information about which database to use in a request-global value. This allows you to create a proxy implementation for IDbSession that is able to switch between a readable and writable implementation internally, based on this setting.
For instance:
public class ReadWriteSwitchableDbSessionProxy : IDbSession
{
private readonly IDbSession reader;
private readonly IDbSession writer;
public ReadWriteSwitchableDbSessionProxy(
IDbSession reader, IDbSession writer) { ... }
// Session operations
public IQueryable<T> Set<T>() => this.CurrentSession.Set<T>();
private IDbSession CurrentSession
{
get
{
var write = (bool)HttpContext.Current.Items["WritableSession"];
return write ? this.writer : this.reader;
}
}
}

Create instance of interface with dependency injection

I have a base controller and before every page load I want to get the current user. I originally had a constructor in my BaseController that looked like this
public BaseController(ISystemUserCommand command)
{
_systemUserCommand = command
}
The problem with this then is that every controller that inherits from the BaseController would have to contain the ISystemUserCommand in its constructor, which I don't think would be good.
Instead I tried to create just an instance of the service class (shown below - it's the commented line under var sid...) but I need to pass in user service. How would I pass in the user service here or is this a bad way of doing it?
public abstract class BaseController : Controller
{
public SystemUserViewModel CurrentUser { get; set; }
private readonly ISystemUserCommand _systemUserCommand;
public SystemUserViewModel GetCurrentUser()
{
if (HttpContext == null || HttpContext.User == null) return null;
if (CurrentUser != null) return CurrentUser;
var sid = System.Web.HttpContext.Current.Request.LogonUserIdentity.User.ToString();
//var command = new SystemUserCommand();
CurrentUser = _systemUserCommand.GetUser(sid);
return CurrentUser;
}
public void SetUserInformation(SystemUserViewModel currentUser)
{
ViewBag.UserId = currentUser.SystemUserId;
ViewBag.FullName = string.Format("{0} {1}", currentUser.FirstName, currentUser.LastName);
ViewBag.FirstName = currentUser.FirstName;
ViewBag.LastName = currentUser.LastName;
ViewBag.CurrentUser = currentUser;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var currentUser = GetCurrentUser();
if (currentUser != null)
{
if (currentUser.IsActive)
{
SetUserInformation(currentUser);
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
base.OnActionExecuting(filterContext);
}
}
public class SystemUserCommand : ISystemUserCommand
{
private readonly ISystemUserBusiness _systemUserBusiness;
public SystemUserCommand(ISystemUserBusiness systemUserBusiness)
{
_systemUserBusiness = systemUserBusiness;
}
...
}
You could use property injection instead of constructor injection, via the base class, eg using unity:
public abstract class BaseController : Controller
{
[Dependency]
public ISystemUserCommand SystemUserCommand { get; set; }
}
This would mean the interface reference is only on the base class.
See here for the full examples.
EDIT, Autofac example:
You don't need property attributes on the dependency,
public abstract class BaseController : Controller
{
public ISystemUserCommand SystemUserCommand { get; set; }
}
Just to register the properites to auto resolve on the autofac builder:
builder.RegisterControllers(typeof(MvcApplication).Assembly).Where(t => t.IsAssignableFrom(typeof(BaseController))).PropertiesAutowired();
See autofac property injection here.
First of all, it does not seem a good idea to have OnActionExecuting override in the controller. You can use filters, that are specially designed for this purpose. And it seems that is the main reason you created the BaseController at all.
Regarding the problem with injecting the system command in all the required service, I would do so, but without inheriting from a base class, since I generally prefer aggregation to inheritance. That would mean that each controller that needs to work with the service will get it.
Another option that I have used few times to abstract some operations is to create a UserSerivce that will provide the required operations to the controllers. It will have ISystemUserCommand and HttpContext injected inside so that all of your controllers won't have to do the job. You can either use HttpContext.Current as static or abstract it away if you need testability.
Moreover I would not recommend property injection since it is more obscure than constructor injection that should be preferred if possible.
You can read more about filters here. Unfortunately if you use filters it's not that easy to inject in filters themselves and mostly done with property injection or ServiceLocator pattern (which is not good usually). It's possible to do better with some amount of voodoo though. I think that SimpleInjector has a lot of examples and tutorials on how to apply DI to filters in MVC, maybe they even have a nuget package now to ahieve that.

Using Ninject with Owin and InRequestScope

We are trying to use Ninject within an Owin with WebAPI pipeline. We have everything setup according to this documentation, but we cannot get InRequestScope() to work.
Here's the significant part of the startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
// Ninject Setup
app.UseNinjectMiddleware(NinjectConfig.CreateKernel);
app.UseNinjectWebApi(config);
}
}
NinjectConfig looks something like this:
public sealed class NinjectConfig
{
public static IKernel CreateKernel()
{
var kernel = new StandardKernel();
INinjectModule[] modules =
{
new ApplicationModule()
};
instance.Load(modules);
// Do we still need to do this wtih Owin?
instance.Bind<IHttpModule>().To<OnePerRequestHttpModule>();
}
}
Our ApplicationModule lives in a separate infrastructure project with access to all of our different layers, for handling DI & Mapping:
public class ApplicationModule: NinjectModule
{
public override void Load()
{
// IUnitOfWork / EF Setups
Bind<ApplicationContext>().ToSelf().InRequestScope();
Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<ApplicationContext>()});
Bind<ApplicationContext>().ToMethod(ctx => ctx.Kernel.Get<ChromLimsContext>()}).WhenInjectedInto<IDal>();
// other bindings for dals and business objects, etc.
}
}
Then we have a couple interfaces:
public interface IUnitOfWork()
{
void SaveChanges();
Task SaveChangesAsync();
}
and
public interface IDal()
{
// Crud operations, Sync and Async
}
then our actual classes using these:
public class SomeBusinessObject
{
private IUnitOfWork _uow;
private IDal _someDal;
public SomeBusinessObject(IUnitOfWork uow, IDal someDal)
{
_uow = uow;
_someDal = someDal;
}
public Task<SomeResult> SaveSomething(Something something)
{
_someDal.Save(something);
_uow.SaveChanges();
}
}
Some Dal
public class SomeDal : IDal {
private ApplicationContext _applicationContext;
public SomeDal(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public void Save(Something something)
{
_applicationContext.Somethings.Add(something);
}
}
Our EF DbContext
public class ApplicationContext : DbContext, IUnitOfWork
{
// EF DBSet Definitions
public void SaveChanges()
{
base.SaveChanges();
}
}
The expectation is that for every request, a single instance of ApplicationContext is created and injected into the business objects as an IUnitOfWork implementation and into the IDals as an ApplicationContext.
Instead what is happening is that a new instance of ApplicationContext is being created for every single class that uses it. If I switch the scope from InRequestScope to InSingletonScope, then (as expected) exactly 1 instance is created for the entire application, and injected properly into the specified classes. Since that works, I'm assuming this isn't a binding issue, but instead an issue with the InRequestScope extension.
The only issue I could find similar to what I'm experiencing is this one, but unfortunately the solution did not work. I'm already referencing all of the packages he specified in both the WebApi and Infrastructure projects, and I double checked to make sure they are being copied to the build directory.
What am I doing wrong?
Edit:
Some additional information. Looking at the Ninject source code in both Ninject.Web.WebApi.OwinHost and Ninject.Web.Common.OwinHost, it appears that the Owin Middleware adds the OwinWebApiRequestScopeProvider as the IWebApiRequestScopeProvider. This provider is then used in the InRequestScope() extension method to return a named scope called "Ninject_WebApiScope". This will be present until the target class that being injected into switches. The named scope then disappears, and a new scope is created. I think this may be what #BatteryBackupUnit was referring to in their comment, but I don't know how to correct it.
This thread is related to this issue...
https://github.com/ninject/Ninject.Web.WebApi/issues/17
I've found that behavior of InRequestScope seems to change depending on how you inject them. For example...
public ValuesController(IValuesProvider valuesProvider1, IValuesProvider valuesProvider2)
{
this.valuesProvider1 = valuesProvider1;
this.valuesProvider2 = valuesProvider2;
}
Ninject will create and inject the same instance of IValuesProvider. However if the method were written as...
/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// </summary>
/// <param name="valuesProvider">The values provider.</param>
public Values2Controller(IKernel kernel)
{
this.valuesProvider1 = kernel.Get<IValuesProvider>();
this.valuesProvider2 = kernel.Get<IValuesProvider>();
}
...this will create two new instances.
Based on the information in the link in #Mick's post I ended up adding my own extension method like this. I am not sure about the downsides.
public static class CustomRequestScope
{
public static Ninject.Syntax.IBindingNamedWithOrOnSyntax<T> InCustomRequestScope<T>(this Ninject.Syntax.IBindingInSyntax<T> syntax)
{
return syntax.InScope(ctx => HttpContext.Current.Handler == null ? null : HttpContext.Current.Request);
}
}
I do consider switching to another container because of this issue.

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