问题
I'm trying to setup a dependency which I want to be injected in the resolution scope of a base interface (of MediatR handlers):
container.Register<DbContext, Model1>(reuse: Reuse.InResolutionScopeOf(typeof(IAsyncRequestHandler<,>)));
However, this interface is being setup with a few decorators, which have a dependency on a IActionHandler which, in turn, depends on the DbContext:
public class Decorator<TRequest, TResponse> : IAsyncRequestHandler<TRequest, TResponse>
{
public Decorator(IActionHandler handler, IAsyncRequestHandler<TRequest, TResponse> inner);
}
I'm getting an exception trying to resolve the implementation of that IActionHandler, because it can't inject the DbContext, as it doesn't seem to be available in the scope.
I've tried to set the IActionHandler to be the target of InResolutionScopeOf, but then the DbContext can't be resolved in my IAsyncRequestHandler<,>.
I need for each DbContext instance to be available across any Decorators or IActionHandler originated from the resolution of a IAsyncRequestHandler<,>, and that instance should also be injected in the IAsyncRequestHandler<,> implementation.
Any ideas as to how I can achieve this type of injection?
Thanks
回答1:
Update:
The fix to enable this code is available since DryIoc 2.8.4
Old answer:
DryIoc as of latest version 2.8.3 does not support specifying the resolution scope reuse with open-generic type. Like so Reuse.InResolutionScopeOf(typeof(IAsyncRequestHandler<,>)
.
Specifying as concrete closed type works fine. Check the sample below (live):
using System;
using DryIoc;
public class Program
{
public static void Main()
{
var c = new Container();
c.Register<IActionHandler, SomeActionHandler>();
c.Register<IAsyncRequestHandler<string, string>, SomeRequestHandler>();
// works with closed-generic spec.
c.Register<DbContext, Model1>(reuse: Reuse.InResolutionScopeOf(typeof(IAsyncRequestHandler<string, string>)));
// Error: not working with open-generic type in reuse spec
// c.Register<DbContext, Model1>(reuse: Reuse.InResolutionScopeOf(typeof(IAsyncRequestHandler<,>)));
c.Register(typeof(IAsyncRequestHandler<,>), typeof(Decorator<,>), setup: Setup.Decorator);
var result = c.Resolve<IAsyncRequestHandler<string, string>>();
Console.WriteLine("decorator: " + result);
Console.WriteLine("decorator.DbContext is the same as action handler's: " +
(result.DbContext == ((Decorator<string, string>)result).ActionHandler.DbContext));
}
public interface IAsyncRequestHandler<TRequest, TResponse>
{
DbContext DbContext { get; }
}
public interface IActionHandler
{
DbContext DbContext { get; }
}
public class DbContext {}
public class Model1 : DbContext {}
public class Decorator<TRequest, TResponse> : IAsyncRequestHandler<TRequest, TResponse>
{
public DbContext DbContext { get { return _decorated.DbContext; } }
IAsyncRequestHandler<TRequest, TResponse> _decorated;
public readonly IActionHandler ActionHandler;
public Decorator(IActionHandler handler, IAsyncRequestHandler<TRequest, TResponse> inner)
{
ActionHandler = handler;
_decorated = inner;
}
}
public class SomeRequestHandler : IAsyncRequestHandler<string, string>
{
public DbContext DbContext { get; private set; }
public SomeRequestHandler(DbContext dbContext)
{
DbContext = dbContext;
}
}
public class SomeActionHandler : IActionHandler
{
public DbContext DbContext { get; private set; }
public SomeActionHandler(DbContext context)
{
DbContext = context;
}
}
}
I have created an issue to add the support into the next version.
As alternative, you may use the key without type as following:
container.Register<DbContext, Model1>(reuse: Reuse.InResolutionScopeOf(serviceKey: blah));
But then you need to register you IAsyncRequestHandler
with the key as well.
来源:https://stackoverflow.com/questions/40244178/dryioc-decorator-and-inresolutionscopeof