[英]How to force a Func as strongly typed dependency injection in .net core 3?
我在库中公开了处理消息代理的所有机制,客户端需要使用扩展方法来使用它,我需要它提供一组实现IMessageHandler
接口的处理程序,这些处理程序将处理每个订阅通道。 它可以工作,但我的原型只需要通过我希望被强类型化的Func
进行依赖注入,以强制客户端提供预期的接口依赖注入。
这是消息处理的接口:
public interface IMessageHandler
{
void HandleMessageAsync(object sender, MyEventArgs e);
}
以及我在lib中的扩展方法的原型:
public static IServiceCollection UseTheSuperMessageBroker(
this IServiceCollection services,
IConfiguration config,
params Func<IServiceCollection>[] handlers)
然后客户端可以像这样使用扩展方法:
services.UseTheSuperMessageBroker(Configuration,
handlers: new Func<IServiceCollection>[] {
() => services.AddSingleton<IMessageHandler, myMessageHandler1>(),
() => services.AddSingleton<IMessageHandler, myMessageHandler2>()
});
但是没有什么能阻止客户端提供任何与IMessageHandler
接口无关的依赖注入,实际上最后一个参数让我们这样做:
services.UseTheSuperMessageBroker(
Configuration,
handlers: new Func<IServiceCollection>[] {
() => services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(),
() => services.AddSingleton(typeof(IMongoRepository<>), typeof(MongoRepository<>))
});
这是编译但不是预期的。
那么有什么机制可以用来强制Func
使用仅与IMessageHandler
接口相关的依赖注入?
不,没有办法阻止这种情况,因为您只是直接使用IServiceCollection
。 实际上,这里的代码甚至没有使用 lambda 本地,而是包含方法的本地,即services
。 本质上,任何事情都可以在这里完成,只要在ConfigureServices
中存在这样做的方法。
如果这是您的要求,最好简单地获取IMessageHandler
类型的集合,然后在方法中注册这些类型,而不是使用Func
的集合。
public static IServiceCollection UseTheSuperMessageBroker(
this IServiceCollection services,
IConfiguration config,
params Type[] handlers)
services.UseTheSuperMessageBroker(Configuration,
handlers: new[] {
typeof(myMessageHandler1),
typeof(myMessageHandler2)
});
然后,在该方法中:
foreach (var handler in handlers)
{
services.AddSingleton(typeof(IMessageHandler), handler);
}
从技术上讲,这不会阻止他们添加不实现IMessageHandler
的类型,但是因为您明确绑定到IMessageHandler
,如果他们这样做,它将失败。
我事实上它很容易被“黑客攻击”,但我不明白为什么我们能够做到这一点? 在这里,我删除了TService
泛型参数的IMessageHandler
接口要求,因此我可以使用任何接口来实现它。
public class DelegateHandler
{
public delegate void MyMessagebrokerDelegateHandler<TService, TImplementation>(IServiceCollection services)
where TService : class, IMessageHandler
where TImplementation : class, TService, new();
public static void MyMessagebrokerHandlerSupplier<TService, TImplementation>(IServiceCollection services)
where TService : class //, IMessageHandler <== REMOVED !!!
where TImplementation : class, TService, new()
{
services.AddSingleton<TService, TImplementation>();
}
}
所以我能够做到:
services.UseTheSuperMessageBroker(Configuration,
handlers: new MyMessagebrokerDelegateHandler<IMessageHandler, BaseMessageHandler>[] {
MyMessagebrokerHandlerSupplier<IHttpContextAccessor, HttpContextAccessor>, // <== HACKED !
MyMessagebrokerHandlerSupplier<IMessageHandler, myMessageHandler2>
});
但是为什么我可以使用不尊重委托原型的 promise 呢? TService: class, IMessageHandler
in delegate and TService: where TService: class
in the static method??
我终于找到了基于generic delegates
的解决方案,我不知道是否也可以使用Func
完成同样的事情。 这是我的新扩展方法:
public static IServiceCollection UseTheSuperMessageBroker<TService, TImplementation>(this IServiceCollection services, IConfiguration config, params MyMessagebrokerDelegateHandler<TService, TImplementation>[] handlers)
where TService : class, IMessageHandler
where TImplementation : class, TService, new()
{
handlers.ToList().ForEach(h =>
{
// Resolve the promise
h.Invoke(services);
});
...
我的通用处理程序:
public class DelegateHandler
{
public delegate void MyMessagebrokerDelegateHandler<TService, TImplementation>(IServiceCollection services)
where TService : class, IMessageHandler
where TImplementation : class, TService, new();
public static void MyMessagebrokerHandlerSupplier<TService, TImplementation>(IServiceCollection services)
where TService : class, IMessageHandler
where TImplementation : class, TService, new()
{
services.AddSingleton<TService, TImplementation>();
}
}
基础 class,仅用于客户端声明(您知道有什么方法可以摆脱这个吗? )
public sealed class BaseMessageHandler : IMessageHandler
{
public Subscribers _sub { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public void HandleMessageAsync(object sender, BasicDeliverEventArgs e)
{
throw new NotImplementedException();
}
}
最后客户调用:
services.UseTheSuperMessageBroker(Configuration,
handlers: new MyMessagebrokerDelegateHandler<IMessageHandler, BaseMessageHandler>[] {
MyMessagebrokerHandlerSupplier<IMessageHandler, myMessageHandler1>,
MyMessagebrokerHandlerSupplier<IMessageHandler, myMessageHandler2>
});
它就像一个魅力!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.