I have a lot of commands and queries and most of them need same interfaces DI'ed to do different things. Is it possible to some how reduce this clutter that each and every one of my handler needs and it is repeated over and over?
public class GetCoinByIdQueryHandler : IRequestHandler<GetCoinByIdQuery, CoinModel>
{
private readonly EventsContext context;
private readonly ICacheClient cache;
private readonly ILogger logger;
private readonly IMapper mapper;
private readonly Settings settings;
public GetCoinByIdQueryHandler(
EventsContext context, ICacheClient cache, ILogger logger,
IMapper mapper, IOptions<Settings> settings)
{
this.context = context;
this.cache = cache;
this.logger = logger;
this.mapper = mapper;
this.settings = settings.Value;
}
}
This may not be directly related to Mediatr but I am looking for a more elegant way of just reducing all the common ones to maybe ONE DI'ed param.
I am using Autofac as my DI container if it makes any difference.
EDIT: possibly having base class that all the handlers inherit from and in the base class get access to all the interfaces and set them as properties on the base class, but I have no idea how to achieve this.
EDIT 2: Autofac has property injection but that seems like it is not the right approach, so people who are using Mediatr, how are you handling of repeating yourself over and over. Every open source project that uses Mediatr that I have seen, seem to not address the repeating yourself problem.
When I find myself in the situation where several handlers have many common dependencies, I look at 2 things:
whether my handlers are doing too much; and
if it's the case, whether I can refactor some of the behavior in a separate class
As an example, in the handler code you posted, there's a cache client, which could possibly mean your handler does 2 things:
executing the business logic to retrieve the coin; and
doing some logic do return an already cached coin, or caching the one you just retrieved
MediatR has the concept of behaviors which allow you to handle cross-cutting concerns in a single place; this is potentially applicable to caching, logging and exception handling. If you're familiar with ASP.NET Core middlewares, they follow the same concept, as each behavior is given:
the current request (or query in MediatR lingo); and
the next item in the pipeline, which can be either another behavior or the query handler
Let's see how we could extract the caching logic in a behavior. Now, you don't need to follow this example to a T, it's really just one possible implementation.
First, we'll define an interface that we apply to queries that need to be cached:
public interface IProvideCacheKey
{
string CacheKey { get; }
}
Then we can change GetCoinByIdQuery to implement that new interface:
public class GetCoinByIdQuery : IRequest<CoinModel>, IProvideCacheKey
{
public int Id { get; set; }
public string CacheKey => $"{GetType().Name}:{Id}";
}
Next, we need to create the MediatR behavior that will take care of caching. This uses IMemoryCache provided in ASP.NET Core solely because I don't know the definition of your ICacheClient interface:
public class CacheBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IProvideCacheKey, IRequest<TResponse>
{
private readonly IMemoryCache _cache;
public CacheBehavior(IMemoryCache cache)
{
_cache = cache;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
// Check in cache if we already have what we're looking for
var cacheKey = request.CacheKey;
if (_cache.TryGetValue<TResponse>(cacheKey, out var cachedResponse))
{
return cachedResponse;
}
// If we don't, execute the rest of the pipeline, and add the result to the cache
var response = await next();
_cache.Set(cacheKey, response);
return response;
}
}
Lastly, we need to register the behavior with Autofac:
builder
.RegisterGeneric(typeof(CacheBehavior<,>))
.As(typeof(IPipelineBehavior<,>))
.InstancePerDependency();
And there we have it, caching is now a cross-cutting concern, which implementation lives in a single class, making it easily changeable and testable.
We could apply the same pattern for different things and make the handlers only responsible for business logic.
Related
Im learning about generics and was wondering about how a generic controller, service and ef core repo design would look like.
My case: lets say an incomming post request to add Smartphone and keyboard object to smartphone and keyboard tables
My repository setup is
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class, IProductGenericEntities
{
private readonly MyDbContext _db;
public GenericRepository(MyDbContext db)
{
_db = db;
}
public async Task<bool> AddProduct(TEntity entity)
{
try
{
_db.Set<TEntity>().AddAsync(entity);
return (await _db.SaveChangesAsync()) > 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
}
And my service
public class ProductService<TEntity> : IProductService<TEntity>
where TEntity : class
{
private readonly IGenericRepository<TEntity> _repo;
public ProductService(IGenericRepository<TEntity> repo)
{
_repo = repo;
}
public async Task<bool> AddProduct(TEntity entity)
{
return await _repo.AddProduct(entity);
}
}
And my Controller.cs
[ApiController]
[Route("api/[controller]")]
public class ProductController
{
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
public ProductController(IProductService<Keyboards> keyService, IProductService<Smartphones> smartService)
{
_keyService = keyService;
_smartService = smartService;
}
[HttpPost("Post-generated-items")]
public async Task<ActionResult> PostProducts(List<TEntity> entities)
{
foreach(var item in entities)
{
and sort the objects here
}
}
}
is it correct to initialize 2 of IProductServices and sort the incomming objects to their correct DI on the controller?
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
Or is it what im doing plain wrong with a generic service layor?
Ok, so your approach is completely valid, i would not worry about initializing two repositories, since they're essentially empty memory vise since they just take reference to existant DbContext which by default is registered with Scoped lifecycle.
There will be a time when you need to use several repositories to complete task at hand. I would suggest going for NON-generic services approach. This way you could make ProductsService which has all the needed generic repositories injected and can orchestrate their work to achieve use case goal.
You might as well look into UOW (Unit Of Work) pattern for even more complex situations.
Answering your question:
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
You might write some code that would do just that for you using Reflection, but i would suggest against doing so. By initializing your repositories specifically you make yourself less error prone and code becomes more self-documenting.
For example now you have a controller that asks DI for two services and that instantly set's you up for what's going on in this controller. On the other hand if everything would be generic, you would end up with one huge knot of spaghetti that "Does everything".
We have a common architecture for many of our projects, and this architecture requires some amount of boilerplate that is generic for every project. I'm trying to tie all this boilerplate into a single reusable NuGet package to make maintenance easier, but am running into issues with getting the DI to work with me.
Specifically, I'm struggling with the concept of services. In the NuGet, I'll have to define basic service interfaces so I can hook some pipelines to use these services. However, every application that will be using this NuGet will need to be able to extend these services with application specific methods.
Let's go over an example with the "User authentication pipeline", which should answer common questions like "Is this user in role x" and application specific questions like "Can this user modify z based on its owner y".
First, our application layer is structured based on CQRS using a common interface, which is implemented by every Query and Command:
public interface IApplicationRequestBase<TRet> : IRequest<TRet> { //IRequest from MediatR
Task<bool> Authorize(IUserServiceBase service, IPersistenceContextBase ctx);
void Validate();
}
IUserServiceBase is an interface providing access to the current user (I'm skipping the IPersistenceContextBase, which is just an empty interface):
public interface IUserServiceBase {
string? CurrentUserExternalId { get; }
bool IsUserInRole(params string[] roleNames);
...
And in the authentication pipeline
public class RequestAuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IApplicationRequestBase<TResponse> { //MediatR IPipelineBehavior
private readonly IUserServiceBase _userService;
private readonly IPersistenceContextBase _ctx;
public RequestAuthorizationBehaviour(IUserServiceBase userService, IPersistenceContextBase ctx) {
_userService = userService;
_ctx = ctx;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) {
if (await request.Authorize(_userService, _ctx)) {
return await next();
}
throw new UnauthorizedAccessException();
}
}
}
And finally the NuGet DI definition:
public static class DependencyInjection {
public static IServiceCollection AddApplicationInfra(this IServiceCollection services) {
...
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestAuthorizationBehaviour<,>));
return services;
}
}
All well and good in the NuGet side, now the application. This approach has me trying to extend the interfaces directly, and this is the easiest way to visualize what I wish to accomplish.
The application has a bunch of app-specific authorization checks, so we have a custom interface for that:
public interface IUserService : IUserServiceBase {
public string LocalUserIdClaimKey { get; }
Guid CurrentUserLocalId { get; }
/// <summary>
/// Shortcut for checking if the user has any role allowing read access to notifications
/// </summary>
bool CurrentUserCanReadNotifications { get; }
...
The UserService class implements all the functionality required in the IUserService interface, meaning the IUserServiceBase methods as well. It is defined in a different project (Infrastructure) than the interface (Application).
public class UserService : IUserService {
private readonly IHttpContextAccessor _contextAccessor;
public UserService(IHttpContextAccessor contextAccessor) {
_contextAccessor = contextAccessor;
}
public string? CurrentUserExternalId {
get {
var user = _contextAccessor.HttpContext.User;
if (user != null) {
return user.FindFirst(JwtClaimTypes.Subject)?.Value;
}
return null;
}
}
...
And finally, in our Command, where it all should come together:
public class UpdateSubsequentTreatmentFacilitiesCommand : IApplicationRequestBase<int> {
public async Task<bool> Authorize(IUserService service, IPersistenceContext ctx) {
//Application specific authorization check
}
public void Validate() {
}
Now, here we get a build error, stating that 'UpdateSubsequentTreatmentFacilitiesCommand' does not implement interface member 'IApplicationRequestBase<int>.Authorize(IUserServiceBase, IPersistenceContextBase)'. This is probably what I'm encountering here (though I still can't figure out why exactly...).
So, to reiterate:
Goal is to package common project boilerplate to a single NuGet
We need to be able to extend the services defined in the NuGet with application specific functionality
IApplicationRequestBase defines the type of the service parameter as IUserServiceBase, but UpdateSubsequentTreatmentFacilitiesCommand tried to use IUserService. OO programming and inheritance doesn't let you change method signatures.
If you can change IApplicationRequestBase, adding a TService generic parameter will let you get around it:
public interface IApplicationRequestBase<TRet, TService> : IRequest<TRet>
where TService is IUserServiceBase
{
Task<bool> Authorize(TService service, IPersistenceContextBase ctx);
void Validate();
}
public class UpdateSubsequentTreatmentFacilitiesCommand : IApplicationRequestBase<int, IUserService>
{
public async Task<bool> Authorize(IUserService service, IPersistenceContext ctx)
{
// method body
}
// rest of class
}
However, given that IUserService is an interface, if it is the only thing that extends/implements IUserServiceBase, then it sounds like a case of overengineering. There's a saying that perfection is the enemy of good. In other words, attempting to be too generic, too reusable, where it's not actually needed, is just slowing down progress. By all means, strive to have a high quality codebase, but you also need to be pragmatic.
If other apps that use IApplicationRequestBase have their own user service, not the same IUserService as your app, then you'll need to find another approach, given that C# is a strongly typed language. You could just typecast the IUserServiceBase into an IUserService in the method body. Rather than extending the interface, you could have an extension method. If you're creative, you might think of other approaches as well.
However, looking at IUserService, my guess is that it exists only to improve performance of checking certain commonly used roles. If I'm wrong and it's about convenience and not performance, then an extension method should be sufficient. If the concern is performance, then make sure that the implementation of IsUserInRole does caching. Looking up a string still won't be as fast as returning a property's backing field. But changing your software architecture to improve performance for something you haven't profiled to confirm that it is a performance bottleneck is the definition of premature optimization. If IsUserInRole does basic caching, you'll probably find the the performance is good enough, and helper/extension methods solve whatever readability/code quality issue you're trying to solve.
Is it possible to set up injection scopes for the default DI in Asp.Net Core? I mean For example:
services.AddSingleton<IUser, UserService>
services.AddSingleton<IUser, UserService>
And for the second configuration somehow specify that it should be injected into only HomeController. Unlike the first one should be injected to all others. Is it possible with default DI?
I answered a similar question here but using scoped instead of singleton:
How to register multiple implementations of the same interface in Asp.Net Core?
My gut feeling is that this might be what you're trying to achieve, or might be a better approach, and you might be mixing up the User with the UserService. When you have multiple implementations of the same interface DI will add these to a collection, so it's then possible to retrieve the version you want from the collection using typeof.
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(IUserService, UserServiceA);
services.AddScoped(IUserService, UserServiceB);
services.AddScoped(IUserService, UserServiceC);
}
// Any class that uses the service(s)
public class Consumer
{
private readonly IEnumerable<IUserService> _myServices;
public Consumer(IEnumerable<IUserService> myServices)
{
_myServices = myServices;
}
public UserServiceA()
{
var userServiceA = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceA));
userServiceA.DoTheThing();
}
public UserServiceB()
{
var userServiceB = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceB));
userServiceB.DoTheThing();
}
public UseServiceC()
{
var userServiceC = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceC));
userServiceC.DoTheThing();
}
}
Assuming this registration, how should the dependency injection container possibly know which “singleton” (it’s not really a singleton when there are two of them) it should inject into the HomeController, or a different service, when they are all just depend on IUser?
The type the dependency gets registered as, in your case IUser, is the “key” which DI containers use to resolve the dependency. So two services that both depend on IUser will get their dependency resolved in the same way. With a singleton lifetime, this means that both services get the same instance.
Service registrations are also usually replacing. So if you have one registration AddSingleton<X, Y>() and then have another one AddSingleton<X, Z>(), then the latter will replace the former. So all services dependending on X will receive Z.
DI containers, including the default container that ships with ASP.NET Core, do usually support resolving all registrations by depending on IEnumerable<X> instead. But for this example this just means that a services would get both Y and Z.
The closest thing you are looking for are keyed or named dependencies. While these are supported in some DI containers, they are technically not part of dependency injection and as such often deliberately absent from many containers, including the ASP.NET Core one. See this answer for more details on that and for some idea to get around that.
To get back to your use case, you should really think about what you are actually doing there. If you have two “singleton” instances of UserService, you should really think about why that is the case: Why isn’t there just one? And if there is support for multiple, why not register it as transient?
More importantly, what would possibly differ between those two instances? After all, they are both instances of the same implementation, so there isn’t much that they can do differently.
If you can identify that, and also confirm that this is something that actually makes the instances different, then consider splitting this up in the type hierarchy as well. It’s difficult to explain this without having a use case here, but what you should try is to end up with two different interfaces that each do exactly what each dependent service type needs. So HomeController can depend on IUserA, and others can depend on IUserB (please choose better names than this).
I have the similar issue. There is my solution.
On the top level in controller I use custom attribute for the action, where I need specific service implementation (for reports for example):
public class HomeController : ControllerBase
{
private readonly IService _service;
public HomeController(IService service)
{
_service = service;
}
[HttpGet]
[ReportScope]
public IEnumerable<WeatherForecast> Get()
{
_service.DoSomeThing();
}
This attribute is processed by custom middleware:
public class ReportScopeLoggingMiddleware
{
private readonly RequestDelegate _next;
public ReportScopeLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, ReportScopeContext scopeContext)
{
var controllerActionDescriptor = context
.GetEndpoint()
.Metadata
.GetMetadata<ControllerActionDescriptor>();
bool analytical = controllerActionDescriptor.EndpointMetadata.Any(m => m is ReportScopeAttribute);
if (analytical) scopeContext.SetActive();
await _next(context);
}
}
In this middleware I use ReportScopeContext.
public class ReportScopeContext
{
public bool Active { get; private set; } = false;
public void SetActive()
{
Active = true;
}
}
This ReportScopeContext has scoped lifetime in DI and I use it to select an implementation of IService:
services.AddScoped<ReportScopeContext>();
services.AddTransient<Service2>();
services.AddTransient<Service1>();
services.AddTransient<IService>(sp =>
sp.GetRequiredService<ReportScopeContext>().Active
? sp.GetRequiredService<Service1>()
: sp.GetRequiredService<Service2>());
I'm using Drum which provides a generic class `UriMaker:
public class UriMaker<TController>
{
// I need use this one
public UriMaker(UriMakerContext context, HttpRequestMessage request) { }
public UriMaker(Func<MethodInfo, RouteEntry> mapper, UrlHelper urlHelper) { }
}
Used like this:
public class UserController : ApiController
{
public UserController(UriMaker<UserController> urlMaker) {}
}
I've used to register it with Unity:
container.RegisterType(typeof(UriMaker<>),
new InjectionConstructor(typeof(UriMakerContext), typeof(HttpRequestMessage)));
but now migrating to Simple Injector. I already have this:
UriMakerContext uriMaker = config.MapHttpAttributeRoutesAndUseUriMaker();
container.RegisterSingle(uriMakerContext);
So how now register UriMaker<> itself?
Although it is possible to configure Simple Injector to allow injecting an UriMaker<TController> directly into your controllers, I strongly advice against this for multiple reasons.
First of all, you should strive to minimize the dependencies your application takes on external libraries. This can easily be done by defining an application specific abstraction (conforming the ISP).
Second, injecting the UriMaker directly makes your extremely hard to test, since the UriMaker is pulled into your test code, while it assumes an active HTTP request and assumes the Web API route system to be configured correctly. These are all things you don't want your test code to be dependent upon.
Last, it makes verifying the object graph harder, since the UriMaker depends on an HttpRequestMessage, which is a runtime value. In general, runtime values should not be injected into the constructors of your services. You should build up your object graph with components (the stuff that contains the application's behavior) and you send runtime data through the object graph after construction.
So instead, I suggest the following abstraction:
public interface IUrlProvider
{
Uri UriFor<TController>(Expression<Action<TController>> action);
}
Now your controllers can depend on this IUrlProvider instead of depending on an external library:
public class UserController : ApiController
{
private readonly IUrlProvider urlProvider;
public UserController(IUrlProvider urlProvider)
{
this.urlProvider = urlProvider;
}
public string Get()
{
this.urlProvider.UriFor<HomeController>(c => c.SomeFancyAction());
}
}
Under the covers you of course still need to call Drum, and for this you need to define a proxy implementation for IUrlProvider:
public class DrumUrlProvider : IUrlProvider
{
private readonly UriMakerContext context;
private readonly Func<HttpRequestMessage> messageProvider;
public DrumUrlProvider(UriMakerContext context,
Func<HttpRequestMessage> messageProvider)
{
this.context = context;
this.messageProvider= messageProvider;
}
public Uri UriFor<TController>(Expression<Action<TController>> action)
{
HttpRequestMessage message = this.messageProvider.Invoke();
var maker = new UriMaker<TController>(this.context, message);
return maker.UriFor(action);
}
}
This implementation can be registered as singleton in the following way:
container.EnableHttpRequestMessageTracking(config);
UriMakerContext uriMakerContext =
config.MapHttpAttributeRoutesAndUseUriMaker();
IUrlProvider drumProvider = new DrumUrlProvider(uriMakerContext,
() => container.GetCurrentHttpRequestMessage());
container.RegisterSingle<IUrlProvider>(drumProvider);
This example uses the Simple Injector Web API integration package to allow retrieving the current request's HttpRequestMessage using the EnableHttpRequestMessageTracking and GetCurrentHttpRequestMessage extension methods as explained here.
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.