【问题标题】:How to force a Func as strongly typed dependency injection in .net core 3?如何在.net core 3中强制Func作为强类型依赖注入?
【发布时间】:2020-08-13 12:18:29
【问题描述】:

我在库中公开了处理消息代理的所有机制,客户端需要使用扩展方法来使用它,我需要它提供一组实现 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 接口相关的依赖注入?

【问题讨论】:

    标签: c# asp.net-core generics dependency-injection func


    【解决方案1】:

    没有。没有办法阻止这种情况,因为您只是直接使用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,如果他们这样做,它将失败。

    【讨论】:

    • 确实我是这样开始的,但是因为类型根据定义不是类,所以我不能确定它是在运行时而不是在构建时传递的 IMessageHandler
    【解决方案2】:

    编辑:

    事实上它很容易被“黑”,但我不明白为什么我们能够做到这一点? 在这里,我删除了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 ??

    原帖:

    我终于找到了基于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>();
        }
    }
    

    基类,仅用于客户端声明(你知道有什么方法可以摆脱这个吗?

    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>
                    });
    

    它就像一个魅力!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-23
      • 2020-11-20
      • 1970-01-01
      • 2021-04-17
      • 2016-05-22
      • 1970-01-01
      • 2023-02-24
      • 1970-01-01
      相关资源
      最近更新 更多