【问题标题】:ASP.NET 5 DI app setting outside controller控制器外部的 ASP.NET 5 DI 应用程序设置
【发布时间】:2016-08-22 14:21:35
【问题描述】:

我可以像这样在控制器中设置应用程序

 private IOptions<AppSettings> appSettings;
 public CompanyInfoController(IOptions<AppSettings> appSettings)
 {
     this.appSettings = appSettings;
 }

但是如何像这样在我的自定义类中进行 DI

  private IOptions<AppSettings> appSettings;
  public PermissionFactory(IOptions<AppSettings> appSetting)
  {
      this.appSettings = appSettings;
  }

我在 Startup.cs 中的注册是

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

【问题讨论】:

    标签: asp.net asp.net-mvc asp.net5


    【解决方案1】:

    “正确”的方式

    在 DI 中注册你的自定义类,就像在 ConfigureServices 方法中注册其他依赖一样,例如:

    services.AddTransient<PermissionFactory>();
    

    (您可以使用AddScoped 或您需要的任何其他生命周期来代替AddTransient

    然后将此依赖项添加到控制器的构造函数中:

    public CompanyInfoController(IOptions<AppSettings> appSettings, PermissionFactory permFact)
    

    现在,DI 知道PermissionFactory,可以对其进行实例化并将其注入到您的控制器中。

    如果您想在Configure 方法中使用PermissionFactory,只需将其添加到它的参数列表中即可:

    Configure(IApplicationBuilder app, PermissionFactory prov)
    

    Aspnet 会发挥神奇的作用并在那里注入类。

    “讨厌”的方式

    如果你想在你的代码深处实例化PermissionFactory,你也可以用一种有点讨厌的方式来做——在Startup类中存储对IServiceProvider的引用:

    internal static IServiceProvider ServiceProvider { get;set; }
    
    Configure(IApplicationBuilder app, IServiceProvider prov) {
       ServiceProvider = prov;
       ...
    }
    

    现在您可以像这样访问它:

    var factory = Startup.ServiceProvider.GetService<PermissionFactory>();
    

    同样,DI 将负责将IOptions&lt;AppSettings&gt; 注入PermissionFactory

    Asp.Net 5 Docs in Dependency Injection

    【讨论】:

    • 我想将 AppSetting 注入 PermissionFactory 而不是将 PermissionFactory 添加到 CompanyInfoController
    • 问题是:你想在哪里访问这个PermissionFactory类。如果某个类B 使用它,你应该将PermissionFactory 添加到B 的构造函数中,依此类推,直到你到达某个“入口点”,这可能是一个控制器。
    • 但是......条目不是控制器......所以我说“外部控制器”
    • 重要的是“控制器外”的类也由DI容器解析。所以如果你有一个控制器,并且控制器依赖于 A,A 依赖于 B 和 C,C 依赖于 D、E 和 F 等,当容器解析控制器。这是最有可能的入口点,但它也可能是一个过滤器。
    • 代码以令人讨厌的方式不起作用。 "非泛型方法 'IServiceProvider.GetService(Type)' 不能与类型参数一起使用"
    【解决方案2】:

    我建议不要通过AppSettings。一个类不应该依赖于模糊的东西——它应该完全依赖于它需要的东西,或者接近它。 ASP.NET Core 使摆脱依赖AppSettings 的旧模式变得更加容易。如果您的类依赖于AppSettings,那么您无法从构造函数中真正看到它依赖于什么。它可能取决于任何键。如果它依赖于一个更具体的接口,那么它的依赖就更清晰、更明确,并且您可以在单元测试时模拟该接口。

    您可以使用您的类需要的特定设置(或不太具体但不太宽泛的设置)和实现它的类创建一个接口 - 例如,

        public interface IFooSettings
        {
            string Name { get; }
            IEnumerable Foos { get; }
        }
    
        public interface IFoo
        {
            string Color { get;  }
            double BarUnits { get;  }
        }
    
        public class FooSettings : IFooSettings
        {
            public string Name { get; set; }
            public List<Foo> FooList { get; set; }
    
            public IEnumerable Foos
            {
                get
                {
                    if (FooList == null) FooList = new List<Foo>();
                    return FooList.Cast<IFoo>();
                }
            }
        }
    
        public class Foo : IFoo
        {
            public string Color { get; set; }
            public double BarUnits { get; set; }
        }
    

    然后添加一个.json文件,fooSettings.json:

        {
          "FooSettings": {
            "Name": "MyFooSettings",
            "FooList": [
              {
                "Color": "Red",
                "BarUnits": "1.5"
              },      {
                "Color": "Blue",
                "BarUnits": "3.14159'"
              },      {
                "Color": "Green",
                "BarUnits": "-0.99999"
              }
            ]
          }
        }
    

    然后,在 Startup()(在 Startup.cs 中)中,我们指定 Configuration 中的内容,添加 fooSettings.json:

        var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
            .AddJsonFile("config.json")
            .AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
            .AddJsonFile("fooSettings.json");
    

    最后,在 ConfigureServices()(也在 Startup.cs 中)告诉它加载 FooSettings 的实例,将其转换为 IFooSettings(因此属性显示为只读)并为所有用户提供该单个实例依赖IFooSettings:

        var fooSettings = (IFooSettings)ConfigurationBinder.Bind<FooSettings>(
            Configuration.GetConfigurationSection("FooSettings"));
        services.AddInstance(typeof (IFooSettings), fooSettings);
    

    现在您的类 - 控制器、过滤器或由 DI 容器创建的任何其他内容 - 可以依赖于 IFooSettings,它将由 .json 文件提供。但是您可以模拟 IFooSettings 进行单元测试。

    Original blog post - 这是我的,所以我没有抄袭。

    【讨论】:

      【解决方案3】:

      您也可以在非控制器类中进行依赖注入。

      在您的 startup 班级中,

      public class Startup
      {
        public IConfigurationRoot Configuration { get; set; }
      
        public Startup(IHostingEnvironment env)
        {
              // Set up configuration sources.
           var builder = new ConfigurationBuilder()
                   .AddJsonFile("appsettings.json")
                   .AddEnvironmentVariables();
           Configuration = builder.Build();
        }
        public void ConfigureServices(IServiceCollection services)
        {
           // register other dependencies also here
           services.AddInstance<IConfiguration>(Configuration);     
        }
      }
      

      现在在您的自定义类中,让构造函数接受 IConfiguration 的实现

      private IConfiguration configuration;
      public PermissionFactory(IConfiguration configuration)
      {
        this.configuration = configuration;
      }
      public void SomeMethod()
      {
        var someSection = this.configuration.GetSection("SomeSection");
        var someValue= this.configuration.Get<string>("YourItem:SubItem");
      }
      

      【讨论】:

      • so...如果我在 project.json 中更改了部分名称,那么我需要检查使用该部分的洞项目吗?
      • 所以如果我想在控制器以外的地方实例化 PermissionFactory 我可以调用var pf = new PermissionFactory() 它会自动工作吗?如果我也想将手动参数传递给该构造函数会怎样?
      • 不要new 实例!在您的代码中随处使用 DI。
      • 你的意思是不要new实例?没有初始化实例就不能使用该类。
      【解决方案4】:

      如果您想 DI 到操作过滤器参考 Action filters, service filters and type filters in ASP.NET 5 and MVC 6 服务过滤器部分。

      【讨论】:

        猜你喜欢
        • 2016-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多