使用依赖注入将配置代码保留在逻辑代码之外的方法

时间:2011-09-02 20:25:04

标签: c# configuration dependency-injection structuremap application-settings

如何使用Settings(ApplicationSettingsBase)和依赖注入将所有配置文件代码保留在逻辑代码之外?

配置我指的是客户特定的配置文件。

我是否真的必须在每次需要时注入配置类,还是有其他模式?

获得一些示例代码会很棒!

样品:

静态配置:

public static class StaticConfiguration
{
    public static bool ShouldApplySpecialLogic { get; set; }
    public static string SupportedFileMask { get; set; }
}

public class ConsumerOfStaticConfiguration
{
    public void Process()
    {
        if (StaticConfiguration.ShouldApplySpecialLogic)
        {
            var strings = StaticConfiguration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}

非静态配置:

public interface IConfiguration
{
    bool ShouldApplySpecialLogic { get; set; }
    string SupportedFileMask { get; set; }
}

public class Configuration : IConfiguration
{
    public bool ShouldApplySpecialLogic { get; set; }
    public string SupportedFileMask { get; set; }
}

public class Consumer
{
    private readonly IConfiguration _configuration;

    public Consumer(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Process()
    {
        if (_configuration.ShouldApplySpecialLogic)
        {
            var strings = _configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}

非静态配置的静态上下文:

public static class Context
{
    public static IConfiguration Configuration { get; set; }
}

public class ConsumerOfStaticContext
{
    public void Process()
    {
        if (Context.Configuration.ShouldApplySpecialLogic)
        {
            var strings = Context.Configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}

4 个答案:

答案 0 :(得分:27)

配置类减少了消费者的凝聚力并增加了消费者的耦合。这是因为可能有许多设置与您的类所需的一个或两个无关,但为了实现依赖性,IConfiguration的实现必须为所有访问器提供值,甚至是不相关的。

它还将您的课程与基础知识相结合:“将这些值配置在一起”等详细信息从应用程序配置中渗透到您的类中,从而增加了受不相关系统更改影响的表面区域。

共享配置值的最简单,最灵活的方法是使用构造函数注入值本身,外部化基础结构问题。但是,在对另一个答案的评论中,您表明您害怕拥有大量构造函数参数,这是一个有效的问题。

要认识到的关键点是原始和复杂依赖关系之间没有区别。无论您是依赖于整数还是接口,它们都是您不知道且必须被告知的东西。从这个角度来看,IConfigurationIDependencies一样有意义。大型构造函数表明,无论参数是原始的还是复杂的,类都有太多的责任。

考虑将intstringbool视为与任何其他依赖关系一样。它将使您的课程更清晰,更专注,更耐变,更容易进行单元测试。

答案 1 :(得分:24)

要实现的重要部分是配置只是驱动应用程序行为的几个值源之一。

第二个选项(非静态配置)最好,因为它使您能够完全将消费者与配置值的来源分离。但是,界面不是必需的,因为配置设置通常最好建模为值对象

如果您仍想从配置文件中读取值,可以从应用程序的Composition Root执行此操作。使用StructureMap,它可能看起来像这样:

var config = (MyConfigurationSection)ConfigurationManager.GetSection("myConfig");

container.Configure(r => r
    .For<Consumer>()
    .Ctor<MyConfigurationSection>()
    .Is(config));

答案 2 :(得分:2)

一种方法是注入像你发布的配置界面。以下是其他几种方式。

公开Setter

class Consumer
{
    public bool ShouldApplySpecialLogic { get; set; }

    ...
}

在组合根目录中,您可以读取配置文件或对其进行硬编码。 Autofac示例:

builder.RegisterType<Consumer>().AsSelf()
    .OnActivated(e => e.Instance.ShouldApplySpecialLogic = true);

当你有一个好的默认

时,这可能是唯一可取的

构造函数注入

public class Server
{
    public Server(int portToListenOn) { ... }
}

在作文根目录中:

builder.Register(c => new Server(12345)).AsSelf();

答案 3 :(得分:0)

在我的应用程序中,我使用IoC执行上述操作。也就是说,让我的IoC容器(StructureMap也)在我的类中注入IApplicationSettings

例如,在ASP.NET MVC3项目中,它可能看起来像:

Public Class MyController
    Inherits Controller

    ...
    Private ReadOnly mApplicationSettings As IApplicationSettings

    Public Sub New(..., applicationSettings As IApplicationSettings)
        ...
        Me.mApplicationSettings = applicationSettings
    End Sub

    Public Function SomeAction(custId As Guid) As ActionResult
         ...

         ' Look up setting for custId
         ' If not found fall back on default like
         viewModel.SomeProperty = Me.mApplicationSettings.SomeDefaultValue

         Return View("...", viewModel)
    End Function
End Class

IApplicationSettings的实现从应用的.config文件中提取了大部分内容,并且还有一些硬编码值。

我的例子不是逻辑流程控制(就像你的例子一样),但如果是这样的话就会有相同的效果。

执行此操作的另一种方法是执行服务定位器类型模式,在此模式中,您要求Dependency Injection容器即时获取配置类的实例。服务地点is considered an anti-pattern generally,但可能仍然对您有用。