在多个环境中使用的C#类库的配置

时间:2016-03-05 23:12:10

标签: .net configuration

我正在C#.NET Framework 4.6中构建一个类库,它正在整合和简化对各种后端数据源的数据访问。这些数据源是Azure表,Azure Blob,Redis缓存,DocumentDB数据和外部REST API。所有这些数据都被不同平台上的多个系统使用。此时,我们有大量不同的系统,每当其中一个后端数据源发生轻微变化时,都需要单独维护。更改表意味着我们需要更新5到7个代码库中的代码。

问题是这个类库将用于ASP.NET 2& 4,ASP.NET Core 1.0和Windows Forms应用程序。它也有可能在其他环境中使用。

挑战在于每个位置都需要一种方法来设置自己的配置字符串和访问密钥。我希望这只是配置文件的一部分,您可以在其中添加信息。该库将读取密钥并准备就绪,就像许多库一样。

我的问题是,似乎没有通用的方法来访问这些平台上的设置。我宁愿不为每个可以使用的平台创建一个自定义设置访问器。

有人可以给我一个易于实施和维护的简单解决方案。理想情况下,它不需要外部依赖的方式。

作为一个附带问题,我是否应该期待处理这些不同的系统。

2 个答案:

答案 0 :(得分:1)

如果它只是一个需要连接字符串的类,请将连接字符串放在类的构造函数中。该类不应直接从web.config或其他任何地方获取字符串。

像这样:

public class ReadsSomethingFromSql
{
    private readonly string _connectionString;

    public ReadsSomethingFromSql(string connectionString)
    {
        _connectionString = connectionString;
    }

    public void InsertSomethingIntoSql()
    {
        using (var connection = new SqlConnection(_connectionString))
        {
            //Do something with connection string
        }
    }
}

这样,该类不负责从web.config读取。这可能真的令人困惑,因为使用该类的人现在可能知道该类期望连接字符串在web.config中。通过将它放在构造函数中,很明显该类需要一个连接字符串。

如果您没有使用依赖注入,那么您的调用方法可以执行此操作:

var reader = new ReadsSomethingFromSql(
    ConfigurationManager.ConnectionStrings["myConnection"].ConnectionString);

但这可能只会解决问题。如果您正在自己的库中创建该类实例 ,那么您仍然遇到同样的问题 - 您的库直接从web.config读取。

更好的解决方案是使用依赖注入来指定您的类所依赖的所有值。 (这是在这篇文章中扩展的一个重要主题。这是使用Castle Windsor的starting example依赖注入。)

使用它,您可以指定连接字符串的来源,如下所示:

container.Register(
    Component.For<ReadsSomethingFromSql>()
        .DependsOn(Dependency.OnValue("connectionString",
            ConfigurationManager.ConnectionStrings["myConnection"].ConnectionString))
    );

如果它不仅仅是一个连接字符串,可能是您的类需要的许多设置,那么您可以创建一个接口,如下所示:

public interface ISettings
{
    string Setting1 { get; }
    int SomeOtherSetting { get; }
}

并将其放在类的构造函数中,就像上面的连接字符串一样。

public class MyClass
{
    private readonly ISettings settings;

    public MyClass(ISettings settings)
    {
        _settings = settings;
    }

通过这种方式,您的类引用_settings,它是ISettings的一个实例,但它并不“知道”实现的内容。

然后,您可以创建一个实现ISettings的类,该类从配置中获取值,如下所示:

public class Settings : ISettings
{
    public string Setting1 { get { return ConfigurationManager.AppSettings["MyClass:Setting1"]; } }
    public int SomeOtherSetting {
        get
        {
            return Int32.Parse(ConfigurationManager.AppSettings["MyClass:SomeOtherSettings"]);
        }
    } }
}

这将根据配置解决您的课程问题。它不依赖于配置。它取决于ISettings

使用Windsor,你的应用程序会像这样配置:

container.Register(Component.For<ISettings,Settings>());

我并没有真正用这些粗略的例子来做依赖注入。但是我用完全相同的问题开始了完全相同的道路。依赖注入是答案,并且还将以许多其他方式使您受益。

<强>更新 您提到您不希望修改该类的使用者。我想我看到了部分问题 - 你的Core 1.0应用程序没有web.config。

你可以妥协。修改类的构造函数并使参数可选。这样,当您编写新的使用者时,您可以使用依赖注入。老消费者可以像现在一样工作,如下:

public class ReadsSomethingFromSql
{
    private readonly string _connectionString;

    public ReadsSomethingFromSql(string connectionString = null)
    {
        _connectionString = connectionString
            ?? ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
    }

答案 1 :(得分:0)

我不完全确定你想要什么:

1)库配置数据需要位于主项目的配置文件中吗? 2)库需要将所有其他项目的配置数据嵌入到自己的配置中吗?

如果您需要的话是#1,那么它就像使用您的配置文件一样简单。我目前正在制作中,4个使用4个库的webapps,其中2个在使用它的项目上有自定义配置。我使用appSettings webconfig部分。并且库将使用以下方式读取该配置文件:

ConfigurationManager.AppSettings["<CONFIG KEY HERE>"]

如果#2,那么它或多或少相同。只需为库编写自定义配置,然后用它来释放所有数据。但我会更喜欢做第一名。

如果我的问题错了,那就对不起!如果您更详细地解释一下您的情景,那么我很乐意为您提供帮助。

  

作为一个附带问题,是否还有其他问题我应该期待   处理这些不同的系统。

这太糟糕了!我只是有一个相关的问题。查看我的帖子:Is Windows Universal App for me? - UI Migration

框架2和4将为您带来问题,混合平台和特殊的最新微软技术,如aspnet核心和UWA。

我会检查TWICE并进行一些广泛的测试,然后再花时间编写一些不起作用的东西。

干杯