Autofac运行时参数

mag*_*guy 6 c# ioc-container inversion-of-control autofac

我是autofac的新手,希望看到将运行时值传递给构造函数的最佳实践.我已经阅读了一堆stackoverflow问题,但是没有一个完全充实.我们应该使用代表,工厂来创建服务等.我知道传递容器并不是实现这一目标的最佳方法.

在我的特定情况下,我有一个访问多个依赖项的服务,比如日志记录,数据提供者等.除了传递的少量服务之外,我还需要捕获运行时参数,比如userid,password.SomeService需要用户标识和密码,并在Web查看器执行特定操作时查找.以下是我的问题,并强调了问题.

public class SomeService : ISomeService
{
    private readonly IDataProvider _dataProvider;
    private readonly ILog _log;
    private readonly string _username;  
    private readonly string _password;

    public SomeService(IDataProvider dataProvider, ILog log,
        string username, string password)
    {
      _dataProvider = dataProvider;
      _log = log;
      _username = username;
      _password = password;
    }
}
Run Code Online (Sandbox Code Playgroud)

数据提供者和日志在autofac中配置

builder.RegisterType<DataProviderService>().As<IDataProvider>()
builder.RegisterType<SomeLogService>().As<ILog>()
Run Code Online (Sandbox Code Playgroud)

这个"SomeService"的大多数功能都需要用户名和密码才能在执行任务之前进行验证,因此最好在创建时传递给构造函数,但从未处理过autofac的运行时要求.我已经回顾了Autofac这个问题- 解决运行时参数而不必传递容器,它似乎接近我需要的东西,但需要更多关于完成此任务的最佳方法的反馈.

Ste*_*ven 7

通常,您应该防止将运行时值传递给构造函数。这将使您的设计和 DI 配置复杂化很多。构造函数用于依赖项和配置值。通过方法参数传递运行时值或注入允许您检索这些运行时值的服务。以IUserContext允许检索当前登录用户的名称的服务为例。


Mat*_*ton 7

AutoFac通过参数化实例化的概念支持使用运行时参数解析服务.

在具有特定运行时参数的服务的依赖关系的客户端的构造函数中,将依赖关系声明为Func根据其强类型参数返回该依赖关系.

例如 Func<string, ISomeService> myService

当AutoFac看到Func它创建一个委托时,它充当创建服务的工厂方法.

从文档:

如果在容器中注册了类型T,则Autofac将自动解析对Func的依赖关系,作为通过容器创建T实例的工厂.

在您的依赖项的参数列表中不可能有重复的类型,就像ISomeService您的问题中的情况一样.例如Func<string, string, ISomeService>不会工作.在这种情况下,您需要提供自定义委托工厂.

从文档:

工厂适配器为托管组件提供容器的实例化功能,而不会将容器本身暴露给它们.

实现此方法的一种方法是声明委托类型以及AutoFac将用作工厂方法的类型定义.

例如

public class SomeService : ISomeService
{
    // Factory method
    public delegate SomeService Factory(string userName, string password);

    public SomeService(IDataProvider dataProvider,
        ILog log,
        string username,
        string password)
    {
        // ..
Run Code Online (Sandbox Code Playgroud)

您的ISomeService客户端将如下所示:

public class MyClient
{
    public MyClient(SomeService.Factory serviceFactory)
    {
        // Resolve ISomeService using factory method
        // passing runtime parameters
        _myService = serviceFactory("this", "that");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,容器将继续自动解析服务的所有非运行时参数(在您的情况下为IDataProvider和ILog).