如何在 .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>
                });

它就像一个魅力!