65.9K
CodeProject 正在变化。 阅读更多。
Home

创建自定义设置提供程序以在应用程序之间共享设置

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (6投票s)

2010 年 12 月 13 日

CPOL

9分钟阅读

viewsIcon

54727

downloadIcon

1159

本文介绍如何利用 .NET 应用程序设置体系结构,为分布式应用程序提供共享设置的访问权限。

引言

在 .NET 应用程序的上下文中,设置是指程序正常运行所必需的、但又不属于程序主要输入或输出的数据。与业务数据一样,设置也会发生变化。设置的示例包括文件夹路径或 Web 服务 URI。设置通常存储在应用程序配置文件(app.configweb.config)中,以便管理员无需重构和重新编译即可轻松更改其值。此解决方案对单个应用程序来说通常效果良好。但是,有时需要跨多个应用程序重用设置。本文将讨论如何以最少的代码实现这一点。

背景

上一篇文章中,我演示了如何通过设置包装器类的强类型属性,将存储在 machine.config 文件中的设置暴露给多个应用程序。虽然这种方法简单有效,但有两个局限性:

  1. 它仅适用于同一台计算机上的应用程序,并且
  2. 设置无法在运行时更新。

为了克服这些限制,我们需要一个新的计划。

计划

我们的方法将涉及创建一个自定义设置提供程序,该提供程序将读取(并在需要时写入)我们的自定义数据存储。数据存储可以是 XML 文件、关系数据库,几乎可以是任何东西。在演示中,我选择了最常见的方法——将设置存储在数据库中。因此,首先我们将创建一个数据库表并填充一些数据。然后,我们将使用 Visual Studio 快速生成一个具有匹配我们设置的属性的类。为了让设置类能够与数据存储进行通信,我们将创建一个新的提供程序,并指示设置类使用它。在此演示中,提供程序类将使用 LINQ to SQL 来执行数据库读取和更新,但您也可以使用任何数据访问技术:Entity Framework、原始 ADO.NET、第三方 ORM,或任何适合您需求的。为了强调这一点,此方法并不依赖于特定的数据访问技术或特定的后端选择,而是取决于将设置类连接到自定义设置提供程序,我们将在步骤 5-7 中完成此操作。

分步指南

1. 创建数据存储

如前所述,我的数据存储将是一个数据库表。在设计用于存储设置的架构时,我们面临几个决定。我们将所有数据存储在一个 varchar 列中,还是将数据存储在不同的字段甚至不同的表中,具体取决于类型?我喜欢我为本次演示选择的架构的几点。请看下面的 Settings 表。

schema.jpg

为简单起见,我将名称值对存储在一个表中。如果您偏爱规范化,也可以轻松地将它们拆分到单独的表中。这里有趣的部分是 Value 字段的数据类型。如您所见,我使用的是 sql_variant。我选择 sql_variant 是因为,与 varchar 不同,它保留了底层类型(bit、int、date 等)的信息,而无需为可能使用的每种数据类型创建一个字段或表。这是 SQL Server 的优点之一。如果您喜欢它,请使用它。否则,或者如果您使用的是不支持 sql_variant 数据类型的 RDBMS,请选择一个替代方案。

我还添加了一个 Description 字段和一个 Enabled 字段,用于根据需要启用或禁用某个设置。

在创建好表后,用一些设置填充它。这是我的设置:

table.jpg

2. 创建一个新的类库

如果您已经有一个作为解决方案中其他项目核心引用的库,则可以使用它并跳过此步骤。如果没有,请向您的解决方案添加一个新的类库项目。在我的示例中,该项目名为 NetRudder,它也作为其他项目的根命名空间。

3. 添加引用

将以下程序集引用添加到上一步创建的库中:

  • System.Configuration
  • System.Data.Linq

4. 添加数据访问层

如果您的解决方案已包含数据访问层,则可以使用它。在演示中,我只是在我的 NetRudder 项目中添加了一个新的 LINQ to SQL 数据上下文。然后,我创建了一个 Setting 类,该类映射到我们之前创建的 Settings 表。使用 LINQ to SQL,这就像将表从 Server Explorer 拖到设计器表面一样简单。新类如下所示:

Setting_entity.jpg

请注意一个有趣的细节:Value 属性的类型是 Object - 这是 LINQ to SQL 对 sql_variant 的默认映射,并且对我们来说效果很好。

L2S_props.jpg

5. 创建设置类

为了利用 .NET 应用程序设置体系结构,我们需要创建一个继承自 ApplicationSettingsBase 的类。如果您阅读了我上一篇文章,您已经有一个设置类。如果没有,您可以使用 Visual Studio Settings Designer 快速创建一个:

  • 向您的项目添加一个新的 Settings 模板。我将其命名为 NetrudderSettings
  • 打开新的 .settings 文件。Settings Designer 将会显示。
  • settings1.jpg

  • 输入您在第一个步骤的表中输入的相同设置。确保名称完全匹配。为每个设置选择正确的类型,并将 Scope 从 User 更改为 Application。这些值现在并不关键 - 如果数据库中找不到该设置,它们将用作默认值。
  • 将 Access Modifier 更改为 Public,以便我们可以在程序集外部引用生成的类。
  • 保存项目,但暂时不要关闭 Designer。

此时,Visual Studio 已为我们生成了一个包装器类,其属性名称与我们的设置名称完全相同。

6. 将设置类连接到使用自定义设置提供程序

让我们回顾一下。我们现在已具备以下组件:

  • 一个已填充数据的 Settings 表
  • 一个映射到 Settings 表的 LINQ to SQL Setting 实体
  • 一个公开各个设置作为属性的设置类(NetrudderSettings

缺少的类是介于数据访问层和设置类之间的类。所以,让我们来创建它。

在 Settings Designer 中,单击“View Code”。如您所见,NetrudderSettings 是一个部分类。如果您想手动添加属性而不是使用 Settings Designer,可以在此处进行。如果您需要属性是可写的(请参阅下面的注释),这将特别有用。现在,我们只需要用以下属性来装饰我们的类:

<SettingsProvider(GetType(LinqSettingsProvider))> _
Partial Public NotInheritable Class NetrudderSettings

通过添加属性,我们指示设置类使用我们将要编写的自定义提供程序。没有这个属性,NetrudderSettings 将使用 LocalFileSettingsProvider,这是默认的提供程序类,它知道如何“与” .NET 配置文件(machine.configapp.configweb.config)“对话”,但不能与数据库或其他任何东西“对话”。

我们还没有创建 LinqSettingsProvider 类,因此您会在类名下看到一条波浪线。将光标放在名称上以调出错误更正菜单,选择让 Visual Studio 为您创建该类。(如果您因为使用的是 VS Express 而没有此选项,只需手动创建该类即可。)

使设置可写

默认情况下,当您使用 Settings Designer 添加设置时,Visual Studio 创建的用于公开这些设置的属性将被标记为 ReadOnly。如果您的某些设置需要可写,您必须手动创建这些属性。没什么大不了的。使用 Settings Designer,删除您希望可写的任何设置。打开您在此步骤中修改的部分类,并按照以下模式添加您希望可写的属性:

<Global.System.Configuration.ApplicationScopedSettingAttribute()> _
Public Property Year() As Integer
    Get
        Return CType(Me("Year"), Integer)
    End Get
    Set(ByVal value As Integer)
        Me("Year") = value
    End Set
End Property

7. 让自定义设置提供程序发挥作用

设置提供程序是我们解决方案中唯一直接与数据访问层通信的部分。如何做到这一点取决于我们。首先,确保您的提供程序类继承自 SettingsProvider。此时,您应该看到一个类似以下的存根:

Public Class LinqSettingsProvider
    Inherits SettingsProvider

    Public Overrides Property ApplicationName() As String
        Get

        End Get
        Set(ByVal value As String)

        End Set
    End Property

    Public Overrides Function GetPropertyValues(ByVal context As _
           System.Configuration.SettingsContext, ByVal collection _
           As System.Configuration.SettingsPropertyCollection) _
           As System.Configuration.SettingsPropertyValueCollection

    End Function

    Public Overrides Sub SetPropertyValues(ByVal context As _
           System.Configuration.SettingsContext, ByVal collection _
           As System.Configuration.SettingsPropertyValueCollection)

    End Sub
End Class

Initialize 方法中添加以下行:

MyBase.Initialize(Me.ApplicationName, col)

ApplicationName 属性的 Getter 中添加以下代码(将 Setter 留空):

ApplicationName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name

GetPropertyValues 方法添加代码,该方法将值从数据存储读取到 SettingsPropertyValueCollection 中。为节省空间,此处不粘贴代码,您可以在包含的演示中查看所有代码。当然,如果您没有使用 LINQ to SQL,与数据访问层交互的代码部分将有所不同。

SetPropertyValues 方法添加代码,该方法获取更新后的设置并将其持久化到数据库(请参阅附加的项目)。

8. 添加“快捷方式”模块

我们快完成了。最后一步是创建一个方便的快捷方式,指向我们设置类的同步实例,从而更易于使用。将以下代码粘贴到一个新模块中,并用您的根命名空间替换 NetRudder

<Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Public Module PublicSettingsProperty
    Public ReadOnly Property Settings() As Netrudder.My.MySettings
        Get
            Return Netrudder.My.MySettings.Default
        End Get
    End Property
End Module

编译项目。完成!

访问设置

为了测试设置,我创建了一个新的控制台项目并引用了 NetRudder 程序集。您可以使用不同类型的应用程序执行相同的基本测试。以下代码从数据库读取我的设置并将其输出到控制台。它还更新了 Year 属性,该属性是我之前设置为可写的。请注意,要将更新持久化到数据存储,您需要调用设置类继承自 ApplicationSettingsBaseSave 方法。

With Netrudder.Settings
    Console.WriteLine("Copyright {0} {1}", .Year, .Copyright)
    Console.WriteLine("Lat/Lng: {0},{1}", .Lattitude, .Longitude)

    .Year = 2009
    'Persist the settings change
    .Save()
End With

合并方法

仅仅因为您有一个自定义设置提供程序,并不意味着您不能像以前那样将某些设置存储在 .config 文件中。还记得在步骤 6 中我们是如何指示我们的设置类使用自定义设置提供程序的吗?好吧,您可以为单个属性覆盖此行为。因此,如果您有一个设置的值可能因每个应用程序而异,则可以将该属性的提供程序设置为 LocalFileSettingsProvider,并将其值存储在 app.config/web.config 中。请查看下面的 MSDN 链接上的 SettingsProvider,了解更多关于混合使用提供程序的信息。

延伸阅读

© . All rights reserved.