动态属性介绍 (Visual Studio)

更新:2007 年 11 月

说明:

自 Visual Studio 2005 开始,已移除动态属性的用户界面。但是,仍支持动态属性。如果从 Visual Studio 的早期版本导入一个项目,动态属性设置将保留在代码中并在运行时工作。建议您改用“项目设计器”来指定应用程序设置。有关更多信息,请参见 “项目设计器” ->“设置”页管理应用程序设置

动态属性使您得以配置应用程序,从而使它的部分或全部属性值存储在外部配置文件中,而不是在应用程序的编译代码中。通过向管理员提供更新属性值的方法(这些属性值在一段时间后可能需要更改),就能够在应用程序已部署后,降低维护该应用程序的总开销。例如,假设您正在生成一个在开发过程中使用测试数据库的应用程序,而在部署时需要更换为生产数据库。如果您把属性值存储在应用程序内部,你就必须在部署前手动更改所有的数据库设置,然后重新编译源代码。如果您把这些值存储在外部,您就只需在外部文件中进行更改,应用程序会在下次运行时获取新值。

安全说明:

存储在配置文件中的属性值是不安全的。敏感数据(如密码和信用卡信息)不应存储为动态属性。

可以在编译为 .exe 文件的任何应用程序中使用动态属性。编译 DLL 的项目无法直接使用动态属性;但是可通过引用 .dll 的 .exe 动态设置 DLL 属性。虽然这些应用程序中的任何组件、窗体或控件的属性都可以动态处理,但是某些属性相对于其他属性而言,是更好的动态属性候选对象。通常情况下,您将存储和检索的属性所连接的是可能会更改的外部资源,包括数据库、事件日志或性能计数器。这些属性中的许多个都标识为动态属性的默认候选对象。

说明:

此主题中的示例代码依赖于 SqlConnection 对象和配置文件是否存在;如果它们不存在,则会导致编译错误。

动态属性和配置文件

当把属性设置为可配置时,它的值被写入配置文件,代码被插入该类,以便指示该属性值应从此外部资源中检索。配置文件根据应用程序的类型不同而不同;基于 Web 的应用程序使用 Web.config 文件,而基于 Windows 的应用程序则使用扩展名为 .config 的类似文件。一个应用程序中的所有窗体和组件都使用一个配置文件。不能在单个应用程序内切换到不同的配置文件或使用多个文件。

在配置文件内部,属性通过使用 XML 保持。例如,假设您指示数据连接的 ConnectionString 属性应存储在配置文件中。您将在代码编辑器中看到如下代码,指示该值存储在外部:

Me.SqlConnection1.ConnectionString = _
  System.Configuration.ConfigurationManager. _
  AppSettings.Get("SqlConnection1.ConnectionString")
     this.sqlConnection1.ConnectionString = 
          System.Configuration.ConfigurationManager.
          AppSettings.Get("SqlConnection1.ConnectionString");
安全说明:

有关创建安全数据连接的更多信息,请参见保护连接信息 (ADO.NET)

在配置文件中,此属性的值将用在窗体代码中指示的键通过 XML 存储:

<configuration>

<appSettings>

<add key="sqlConnection1.ConnectionString" value="data source=myserver;initial catalog=Apps;Integrated Security=SSPI;packet size=4096" />

</appSettings>

</configuration>

配置文件中的每个值都分配有一个键,用于存储和检索该值。键的起始部分指示该值从中产生的组件。例如,这两个键指示在一个应用程序内的两个不同数据连接上的 ConnectionString 属性:

<configuration>

<appSettings>

<add key="sqlConnection1.ConnectionString" value="data source=myserver;initial catalog=Apps;Integrated Security=SSPI;packet size=4096" />

<add key="sqlConnection2.ConnectionString" value="data source=myserver;initial catalog=Apps;Integrated Security=SSPI;packet size=4096" />

</appSettings>

</configuration>

可以直接修改配置文件,以便在应用程序内动态更新属性值。应用程序下次启动时将更新这些值。

从某种意义上来说,配置文件类似于资源文件;它们都用于在已编译的应用程序外部存储值,它们都使用 XML 存储信息。但是,资源文件的用途和配置文件有很大差别。资源文件是出于翻译的目的用来存储字符串和其他可本地化的资源,而配置文件(就动态属性而言)是用于更新属性值。资源文件中的值是要翻译的,但通常不会更改,而配置文件中的动态属性值可以根据需要更改。此外,可以将多个资源文件与一个项目关联,但应用程序只能有一个配置文件。有关资源文件的更多信息,请参见用于本地化的资源的分层组织

将多个属性设置为同一个键

在配置文件中,多个属性可以引用同一个键值对。例如,如果类中有三个组件都访问同一个数据库,您可以在同一个键值对中存储每个组件的 ConnectionString 属性。这意味着如果数据库有更改,您只要在设置文件中更新一个值就能把更改应用到全部三个组件。只需将每个属性设置为同一个键即可,就像这样:

Me.SqlConnection1.ConnectionString = _
  System.Configuration.ConfigurationManager. _
  AppSettings.Get("SqlConnection1.ConnectionString")

Me.SqlConnection2.ConnectionString = _
  System.Configuration.ConfigurationManager. _
  AppSettings.Get("SqlConnection1.ConnectionString")

Me.SqlConnection3.ConnectionString = _
  System.Configuration.ConfigurationManager. _
  AppSettings.Get("SqlConnection1.ConnectionString")
     this.sqlConnection1.ConnectionString = 
          System.Configuration.ConfigurationManager.
          AppSettings.Get("SqlConnection1.ConnectionString");

        this.sqlConnection2.ConnectionString = 
          System.Configuration.ConfigurationManager.
          AppSettings.Get("SqlConnection1.ConnectionString"); 

        this.sqlConnection3.ConnectionString = 
          System.Configuration.ConfigurationManager.
          AppSettings.Get("SqlConnection1.ConnectionString"); 

请注意,尽管所使用的组件不同,它们都引用 sqlConnection1.ConnectionString 的键。

当为多个属性选择同一个键时,配置文件中只生成一项。存储的初始值来自赋予该键的第一个属性。

数据类型和动态属性

XML 把一切都作为字符串存储。如果要存储的属性值不是字符串,您将在代码编辑器中看到指示该属性值的数据类型的其他信息。例如,假设您要动态存储 Timer 组件的 IntervalEnabled 属性的值。在配置文件中,该属性的存储方式如下:

<appSettings>

<add key=timer1.Interval" value="100" />

<add key=timer1.Enabled" value="True" />

</appSettings>

在代码编辑器中,您会看见下列代码,这说明检索到的值需要更改为 Double 数据类型 (Visual Basic)

Me.Timer1.Enabled = (New System.Configuration. _
AppSettingsReader()).GetValue("timer1.Enabled", GetType(Boolean))

Me.Timer1.Interval = (New System.Configuration. _
AppSettingsReader()).GetValue("Timer1.Interval", GetType(Double))
     this.timer1.Enabled = (bool)(new System.Configuration.
          AppSettingsReader().GetValue("timer1.Enabled", typeof(bool)));

        this.timer1.Interval = (System.Double)(new System.Configuration.
          AppSettingsReader().GetValue("timer1.Interval", typeof(System.Double)));
说明:

有两个计时器,一个用于 Windows 窗体,一个用于基于服务器的应用程序,二者在编程模型上略有差异。本示例使用基于服务器的计时器。有关两个可用计时器的更多信息,请参见基于服务器的计时器介绍

关于动态属性的性能和安全性问题

在使用动态属性时,可能有两点值得考虑。首先,动态属性存储和检索可能会对应用程序的性能有一定程度的影响。从已编译的应用程序内部检索属性值比从配置文件中检索属性值更快。如果应用程序是首次访问某个配置文件值,应用程序读取文件时性能会受到轻微影响。但这种影响是极小的,并不显著。此后对该属性或其他属性的检索对于性能的影响更是小得多,这类似于从哈希表中读取值。

其次,如果您要将诸如用户 ID 和密码之类的属性值存储到外部文件,您将需要控制谁能够访问该文件及其包含的值。完成此任务的方法之一是用 Windows 访问控制列表 (ACL) 来确保文件的安全。访问控制列表指定对于特定文件和目录,不同的用户可以执行的操作。此外,如果您正在使用基于 Web 的应用程序,您可以利用由 Windows、Internet 信息服务 (IIS) 和 SQL Server 提供的集成安全性选项。在该模型中,用户在本地网络的身份验证凭据也用于访问数据库资源,并且在连接字符串中不使用任何显式用户名或密码。

有关安全性的更多信息,请参见 Windows 文档或以下页:

请参见

其他资源

使用动态属性配置应用程序