C# 如何处理在运行时通过依赖项注入加载的配置类?

C# 如何处理在运行时通过依赖项注入加载的配置类?,c#,mvvm,dependency-injection,C#,Mvvm,Dependency Injection,我目前正在尝试依赖注入,到目前为止我很喜欢。但有一件事我真的想不起来,我目前的解决方案似乎是错的 我正在使用WPF、MVVM和我注入的许多类,它们需要一个项目配置类的实例,该实例在用户在应用程序中创建或打开新项目之前不会初始化 因此,我当前的解决方案是使用一个带有load/save方法的“ConfigurationHandler”和一个属性,该属性在加载配置类后保存配置类的实例。我将ConfigurationHandler注入其他类,然后它们可以在加载配置后访问配置。但让从不保存/加载配置的类处

我目前正在尝试依赖注入,到目前为止我很喜欢。但有一件事我真的想不起来,我目前的解决方案似乎是错的

我正在使用WPF、MVVM和我注入的许多类,它们需要一个项目配置类的实例,该实例在用户在应用程序中创建或打开新项目之前不会初始化

因此,我当前的解决方案是使用一个带有load/save方法的“ConfigurationHandler”和一个属性,该属性在加载配置类后保存配置类的实例。我将ConfigurationHandler注入其他类,然后它们可以在加载配置后访问配置。但让从不保存/加载配置的类处理整个“ConfigurationHandler”似乎有些奇怪,它们100%只会使用它访问配置实例,如下所示:

var configuration = configurationHandler.Configuration; 
另一个问题是,如果他们试图在加载配置之前访问配置,他们将得到异常(不应该发生,因为在创建/加载项目之前,您不能做任何事情,但仍然可以)

但我能想到的唯一其他解决方案是在创建/打开项目后使用“初始化”方法,但这似乎同样糟糕

那么你通常如何处理这样的案件呢


Edit:应该添加这个配置类处理项目路径、项目名称等信息,所以和依赖项注入本身无关

>P>而不是构造函数注入,考虑使用<代码>环境上下文< /代码>方法。

我们将讨论的最后一种DI类型是使依赖项可用 通过静态访问器。它也被称为通过注射 环境背景。它用于实现横切关注点

如果需要访问您的配置的类在不同的层或库中具有不同的类型,那么这是一个很好的选择,也就是说,这是一个真正的横切关注点

()


示例,基于[Dependency Injection in.NET][2]中的经典时间提供程序1 用法


可以使用其他方法,但需要对需要它的类进行更改。如果配置是一个交叉关注点,那么环境上下文可能是最合适的

构造函数注入示例

public SomeClass(IConfiguration config)
{
}
财产注入

public SomeClass()
{
   IConfiguration configuration { get; set; }
}
public SomeClass()
{
   public void DoSomethingNeedingConfiguation(IConfiguration config)
   {
   }
}
方法注入

public SomeClass()
{
   IConfiguration configuration { get; set; }
}
public SomeClass()
{
   public void DoSomethingNeedingConfiguation(IConfiguration config)
   {
   }
}

还有服务定位器,但服务定位器(IMO)是一个。

如果您的配置是静态的(读取:它仅在应用程序启动时读取,例如从
project.json
Web.Config
),您还可以在应用程序启动/合成根目录时设置它

新的ASP.NET5大量使用它,并且工作得非常好。基本上,您将拥有一个
IConfiguration
接口和一个POCO类,您可以在应用程序启动期间设置该接口并将其解析/注入到您的服务中

public interface IConfiguration<T> where T : class
{
    T Configuration { get; }
}
然后在作文根中注册它,如

// read Web.Config
Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);

container.AddSingleton<IConfiguration<AppConfiguration>>(new DefaultConfiguration<AppConfiguration>(
    new AppConfiguration
    {
        OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
        OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
    })
);
//读取Web.Config
Configuration rootWebConfig=System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
container.AddSingleton(新的DefaultConfiguration(
新应用程序配置
{
OneOption=rootWebConfig.AppSettings.Settings[“oneSetting”],
OtherOption=rootWebConfig.AppSettings.Settings[“otherSetting”],
})
);
最后,您需要在服务中声明的是

public class MyService : IMyService 
{
    public MyService(IUserRepository, IConfiguration<AppConfiguration> appConfig) 
    {
        ...
        if(appConfig.OneOption=="someValue") {
            // do something
        };
    }
}
公共类MyService:IMyService
{
公共MyService(IUserRepository、IConfiguration appConfig)
{
...
if(appConfig.OneOption==“someValue”){
//做点什么
};
}
}
最后,如果编写一个扩展方法,比如

public static class MyContainerExtension 
{
    public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
    {
        var t = new T();
        config(t);
        container.AddSingelton<IConfiguration<T>>(t);
    }
}
公共静态类MyContainerExtension
{
publicstaticvoidconfigure(这个IMyContainer容器,actionconfig),其中T:class,new()
{
var t=新的t();
形态(t);
容器。AddSingelton(t);
}
}
那么你需要做的就是

container.Configure<AppConfiguration>(
    config => 
    {
        config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
        config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
    })
);
container.Configure(
配置=>
{
config.OneOption=rootWebConfig.AppSettings.Settings[“oneSetting”],
config.OtherOption=rootWebConfig.AppSettings.Settings[“otherSetting”],
})
);

设置它

哦,这是一个很酷的解决方案,我认为这会起作用。在发布这个问题后,我想到的另一个问题是将“ConfigurationHandler”拆分为多个接口——一个使用load/save方法,另一个使用property(或get方法)。这样,其他类可能只需要具有属性的接口,而从不访问加载/保存。但是环境上下文可能是一个更好的解决方案?你真的不应该使用静态依赖注入取决于你的优先级tbh,在4种主要DI模式中,环境上下文对你的应用程序的“损害”最小,因为它只会在你需要的时候出现。配置也可以被注入。很快将发布一个不使用静态关键字的可能解决方案anywhere@TsengOfc,任何东西都可以注入,这是关于为工作选择正确的工具:-)这是一个很好的工具,但遗憾的是,我的配置没有在应用程序开始时读取。它是在用户创建/打开新项目时读取/创建的(在注入之后),并且可以多次更改。我猜这使得这个解决方案在这种情况下无法使用?基于构造函数的解决方案的良好实现:-)好的,您可以在composition根目录中初始化默认配置,一旦创建项目,您只需更新配置值。因为它注册为singleton,所以配置对象在容器期间将保持活动状态
public static class MyContainerExtension 
{
    public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
    {
        var t = new T();
        config(t);
        container.AddSingelton<IConfiguration<T>>(t);
    }
}
container.Configure<AppConfiguration>(
    config => 
    {
        config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
        config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
    })
);