如何在 .net core 3 中强制 Func 作为强类型依赖注入?
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);
}
以及库中我的扩展方法的原型:
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
,如果他们这样做,它将失败。
编辑:
事实上它很容易做到 "hacked",但我不明白为什么我们能够做到这一点?
在这里,我删除了 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>
});
但为什么我可以使用不尊重委托原型的承诺?
委托中的 TService : class, IMessageHandler
和静态方法中的 TService : where TService : class
??
原文post:
我终于找到了一个基于 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>
});
它就像一个魅力!
我在库中公开了处理消息代理的所有机制,客户端需要使用扩展方法来使用它,我需要它来提供实现 IMessageHandler
接口的处理程序集合将处理每个订阅频道。
它有效,但我的原型只需要通过 Func
进行依赖注入,我希望它是强类型的,以强制客户端提供预期的接口依赖注入。
消息处理界面如下:
public interface IMessageHandler
{
void HandleMessageAsync(object sender, MyEventArgs e);
}
以及库中我的扩展方法的原型:
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
,如果他们这样做,它将失败。
编辑:
事实上它很容易做到 "hacked",但我不明白为什么我们能够做到这一点?
在这里,我删除了 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>
});
但为什么我可以使用不尊重委托原型的承诺?
委托中的 TService : class, IMessageHandler
和静态方法中的 TService : where TService : class
??
原文post:
我终于找到了一个基于 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>
});
它就像一个魅力!