Effective C# 原則37:使用標準的配置機制(譯)

來源:互聯網
上載者:User

Effective C# 原則37:使用標準的配置機制
Item 37: Use the Standard Configuration Mechanism

我們要尋求一種避免直接寫代碼的應用程式配置和資訊設定方法,我們已經建立了多種不同的策略來儲存配置資訊。而我們是要尋求一種正確的方法,我們要不斷提高和改我們的想法,關於哪裡是放置這些資訊的好地方。INI檔案?這是Windows3.1做的事,配置資訊的結構是受限制的,而且在檔案名稱上可能還會與其它程式程式相衝突。註冊表?是的,是這個正確的想法,但它也有它的限制。亂七八糟的程式可能會通過在註冊表裡寫一些錯誤資訊來嚴重破壞電腦。正因為寫註冊表存在危險,一個應用程式必須有管理員權限來寫註冊表的一部份。你的所有使用者都會是以具有修改註冊表權利的管理員身份在運行嗎?希望不是,如果你使用註冊表,而你的使用者不是以管理員身份啟動並執行,在試圖讀寫註冊表時,將會得到一個異常和錯誤。

謝天謝地,還有很多更好的方法來儲存設定資訊,這樣你的程式可以根據使用者的選擇不同適應不同的行為,例如安裝參數,機器設定,或者其它任何事情。.Net架構提供了一個標準的設定位置,這樣你的程式可以使用它來儲存配置資訊。這些儲存位置是由應用程式特別指定的,而且當程式執行的機器上的使用者被限制了許可權時一樣可以有效工作。

唯讀資訊是屬於設定檔的,XML檔案控制應用程式中不同類型的行為;定義的結構表指明了所有的元素和屬性,而這些都是.NET FCL從設定檔中分析出來的。 這些元素控制一些設定,例如正在使用那個架構版本,支援的調試層級(參見原則36),以及程式集的搜尋路徑。有一個節點你是必須要明白的,那就是appSettings部份,它可以同時應用與web應用程式和傳統型應用程式。運行程式在啟動時讀取這一節點的資訊,它載入所有的關鍵字和值到一個屬於應用程式的名字值集合(NameValueCollection)中。這是你自己程式的一部份,你可以添加任何程式須要的值來控製程序行為。當修改設定檔時,也就修改了程式行為。

對於使用設定檔來說,ASP.Net應用程式比傳統型應用程式的伸縮性稍靈活一點。每個個虛擬目錄可以有一個自己的設定檔,這個檔案被每個虛擬目錄依次讀取,而每個虛擬目錄也就對應一個URL的一部分。The most local wins. 例如,這個URL:http://localhost/MyApplication/SubDir1/SubDir2/file.aspx 可能被4個不同的設定檔所控制。machine.config最先讀取,其次是在MyApplication中的web.config檔案,接著是在SubDir1 和SubDir2中的web.config檔案。而它們每一個都可以修改前一個設定檔設定的值,或者是添加自己鍵/值對。你可以通過這種設定繼承方式,來配置一個全域應用程式的參數選擇,而且可以限制一些私人資源的訪問。web應用程式在不同的虛擬目錄中有不同的配置。

在傳統型應用程式中,對於每個應用程式定義域只有一個應用程式程式設定檔。.Net運行時在載入每個可執行檔時,為它建立一個預設的應用程式定義域,然後讀取一個預先軍定義的設定檔到這個應用程式定義域中。預設的設定檔在與應用程式運行時的同一個目錄中,而且就以<應用程式名稱>.<副檔名>.config來命名的。例如:MyApp.exe可能就有一個名為MyApp.exe.config的設定檔。appsettings部份可以用於建立你自己的鍵/值對到應用程式中。

設定檔是儲存一些控製程序行為的資訊的最好的地方。但你可能很快會發現,應用程式沒有API來寫設定檔資訊。設定檔不是用於儲存任何有序設定的地方。不要急著寫註冊表,也不要自己亂寫。這裡有一個更好的方法讓你配置傳統型應用程式。

你可能須要定義設定檔的格式,而且把設定檔放到正確的地方。通過在全域設定上定義一些設定結構和添加公用的讀寫屬性,你可以很簡單的儲存和取回這些設定:

[ Serializable( ) ]
public struct GlobalSettings
{
  // Add public properties to store.
}

XML序列化來儲存你的設定:

XmlSerializer ser = new XmlSerializer(
  typeof( GlobalSettings ));
TextWriter wr = new StreamWriter( "data.xml" );
ser.Serialize( wr, myGlobalSettings );
wr.Close( );

使用XML格式就意味著你的設定可以很容易的閱讀,很容易的解析,以及很容易的去調試。如果須要,你可以對這些使用者佈建進行加密儲存。這隻是一個使用XML序列化的例子,不是對象持久序列化(參見原則25)。XML序列化隱藏檔,不是整個對象樹。配置設定以及使用者佈建一般不會包含網狀對象,而且XML序列化是一個簡單的檔案格式。

最後一個問題就是,應該在哪裡儲存這些資訊。你應該在三個不同的地方放置配置資訊檔。選擇哪一個要根據配置的使用方式:全域,單使用者,或者單使用者且單機器。這三個位置可以通過調用System.Environment.GetFolderPath() 而取得。你應該在GetFolderPath()返回的路徑後添加上應用程式的詳細目錄。請格外小心的在所有使用者或者機器範圍上填寫資訊。這樣做要在目標機器是取得一些特權。

Environment.SpecialFolder.CommonApplicationData返回儲存資訊的目錄,這一目錄是被機器上的所有使用者所共用的。如果在一台機上使用的是預設安裝,GetFolderPath(SpecialFolder.CommonApplicationData)會返回 C:\Documents and Settings\All Users\Application Data。儲存在這一目錄的的設定應該是被機器上的所有使用者所使用的。當你要在這裡建立資訊時,讓安裝程式給你做或者以管理員模式進行。不應該在這裡寫一些使用者級(譯註:users級是windows裡的一個使用者組,權利比管理員小。)的程式資料。偶然可能會讓你的應用程式在使用者機上沒有足夠的許可權來訪問。

Environment.SpecialFolders.ApplicationData返回目前使用者的路徑,而且在網路上被所有機器共用的。在預設安裝中,GetFolderPath(SpecialFolders.ApplicationData)返回 C:\Documents and Settings\<使用者名稱>\Application Data。每個使用者有他(或她)自己的應用程式資料目錄。當使用者登入到一個域是,使用這個列舉進入到共用網路上,而且在網路上包含了使用者的全域設定。儲存在這裡的資料只由目前使用者使用,不管是從網路上的哪台機器登入過來的。

Environment.SpecialFolders.LocalApplicationData返回一個特殊的目錄,該目錄隊了儲存設定資訊以外,同時也是一個使用者的私人目錄,它只屬於從這台機器上登入的使用者。一般GetFolderPath(SpecialFolders.LocalApplicationData)返回:C:\Documents and Settings\<使用者名稱>\Local Settings\Application Data

這三個不同的位置可以讓你儲存每個人的設定資訊,給定使用者的資訊,或者是給定使用者並給定機器的資訊。具體的使用哪一個取決於應用程式。但考慮一些明顯的例子:資料庫連結字串是一個全域設定,它應該存在在跨平台 app程式資料(Common Application Data) 目錄中。一個使用者的工作內容應該存在在應用程式資料(Application Data)目錄中,因為它只取決於使用者。視窗的位置資訊應該在本地應用程式資料(Local Application Data)目錄中。因為它們取決於機器上的使用者的屬性(不的機器可能有不同的解析度)。

應該有一個特殊的目錄,它為所有應用程式的所有使用者佈建儲存,描述頂層的目錄結構。這裡,你須要在頂層目錄結構下建立子目錄。.Net架構的System.Windows.Application類定義了一些屬性,這些屬性可以為你建立一些通用的配置路徑。Application.LocalAppDataPath屬性返回GetFolderPath(SpecialFolders.CommonApplicationData)+"\\CompanyName\\ProductName\\ProductVersion"的路徑。類似的,Application.UserDataPath和Application.LocalUserDataPath產生位於使用者資料和本機資料目錄下的路徑名,這一目錄包括公司,應用程式,以及版本號碼。如果你組合這些位置,你就可以為你自己公司的所有應用程式建立一個配置資訊,或者為某一程式的所有版本,或者是特殊版本。

注意到了,這些目錄中我沒有提到過應用程式目錄,就是在Program Files下的目錄。你決不應該在Program Files或者在Windows 系統目錄以及子目錄裡寫資料。這些目錄要更高的特權,因此你並不能指望你的使用者有權利來寫這些資料。
當在哪裡儲存應用程式的設定資料成為一個很重要的問題,就像每個企業級使用者到家庭使用者所擔心的機器安全問題一樣時,把資訊放在正確的位置就意味著對於使用你的應用程式的使用者來說沒有折衷的辦法。你還是要給使用者提供私人的感覺,用.Net的順序組合正確的位置,這樣可以很容易的給每個使用者一種私人的感覺,而且不用折衷安全問題。
==============================
    

Item 37: Use the Standard Configuration Mechanism
In our quest to avoid hard-coding configuration and settings information, we have created many different strategies for storing configuration information. In our quest to get it right, we kept improving and changing our minds about where to put such information. INI files? That was so Windows 3.1. You were limited in the structure of your configuration information, and you had to contend with filename collisions with other applications. The Registry? Yes, this was a step in the right direction, but it had its limitations as well. Malicious programs could do serious damage to a machine writing the wrong things to the Registry. Because of the dangers inherent in writing to the Registry, a program must have administrative rights to write in parts of the Registry. Are all your users running as admins with the capability to edit the Registry? You hope not. If you use the Registry, users running as nonadmins will get exceptions and errors when they attempt to save or read their settings.

Thankfully, there are much better ways to store settings so that your program can adapt its behavior to your users' preferences, the install parameters, the machine settings, or just about anything else. The .NET Framework provides a standard set of locations that your application can use to store configuration information. These locations are specific to your application and will work when the user has limited privileges on the machine where the code executes.

Read-only information belongs in configuration files, XML files that control various types of behavior in the application. Defined schemas dictate all the elements and attributes that the .NET FCL parses from config files. These elements control settings such as the version of the framework being used, the level of debugging support (see Item 36), and the search path for assemblies. One section you must understand is the appSettings section, which applies to both web and desktop applications. The runtime reads this section when your application starts. It loads all the keys and values into a NameValueCollection owned by your application. This is your section. You add any values that your application needs to control its behavior. If you modify the config file, you modify the application's behavior.

ASP.NET applications have a little more flexibility than desktop applications do with respect to config files. Each virtual directory can have its own config file. The files are read in order for each virtual directory that is part of the URL. The most local wins. For example, the URL http://localhost/MyApplication/SubDir1/SubDir2/file.aspx could be controlled by four different config files. The machine.config file gets read first. Second is the web.config file in the MyApplication directory. Following is the web.config files in SubDir1 and SubDir2, in that order. Each can change values set by a previous config file or add its own key/value pairs. You can use this configuration inheritance to set up global application preferences and limit access to some private resources. Web applications can have different configurations for different virtual directories.

On the desktop, there is only one application configuration file for each app domain. The .NET runtime creates a default application domain for each executable that it loads, and reads one predefined config file into that domain. This default configuration file is located in the same directory as the executable and is called <applicationname>.<ext>.config. For example, MyApp.exe would have a config file named MyApp.exe.config. The appsettings section can be used to create your own key/value pairs for your application.

Config files are great to store information that controls the behavior of your application at runtime. But you will quickly notice that there are no APIs to write configuration information from your application. Configuration files are not the place for user settings of any sort. Don't go running for the Registry yet. Don't write your own from scratch. There is a better way for your .NET desktop applications.

You need to define the format for your configuration information and put that configuration information in the right location. You can easily store and retrieve these settings by defining a settings structure and adding public read/write properties for the global settings:

[ Serializable( ) ]
public struct GlobalSettings
{
  // Add public properties to store.
}

 

Use the XML serializer to save your settings:

XmlSerializer ser = new XmlSerializer(
  typeof( GlobalSettings ));
TextWriter wr = new StreamWriter( "data.xml" );
ser.Serialize( wr, myGlobalSettings );
wr.Close( );

 

Using XML format means that your settings will be easy to read, easy to parse, and easy to debug. You can use encrypted storage for these user settings, if necessary for your application. This example uses the XML serializer, not the object serializer for persistence (see Item 25). The XML serializer stores documents, not entire object trees. Configuration settings and user settings typically do not contain webs of objects, and the XML serializer is a simpler file format.

The only question remaining is where to store the information. You should put settings information in three different locations. Which you choose depends on when it should be used: Globally, per user, or per user and machine. All three locations are returned by different calls to by the System.Environment.GetFolderPath() method. You should append your application-specific directories on the end of the path returned by GetFolderPath(). Be extremely careful about writing information in the all-user or machine-wide directories. Doing so requires more privileges on the target machine.

Environment.SpecialFolder.CommonApplicationData returns the directory for storing information that is shared by all users on all machines. On a machine with a default installation, GetFolderPath (SpecialFolder.CommonApplicationData) returns C:\Documents and Settings\All Users\Application Data. Settings stored under this location should be used by all users, on all machines. When you create information that should go here, write it with the installer or an admin module. Avoid writing data here in your user programs. Chances are, your application does not have the necessary access rights on users' machines.

Environment.SpecialFolders.ApplicationData returns the directory for this user, shared by all machines in the network. On a default installation, GetFolderPath(SpecialFolders.ApplicationData) gives you C:\Documents and Settings\<username>\Application Data. Each user has his or her own application data directory. When the user logs into a domain, using this enumeration points to the network share that contains the user's global settings. Settings stored under this location are used by the current user, no matter what machine in the network he has logged in from.

Environment.SpecialFolders.LocalApplicationData returns the directory for storing information that is personal for this userand only when logged in on this machine. A typical value returned by GetFolderPath(SpecialFolders.LocalApplicationData) is C:\Documents and Settings\<username>\Local Settings\Application Data.

These three different locations let you store settings that should apply to everyone, the given user, or the given user on the given machine. Exactly which you use depends on the application. But consider some obvious examples: The database connection is a global setting. It should be stored in the Common Application Data directory. A user's working context should be stored in the Application Data directory because it depends only on the user. Window locations should be in the Local Application Data directory because they depend on the user and properties of the machine (different machines might have different screen resolutions).

These special folders describe the top-level directory structure for user settings stored by all applications. In all cases, you should create subdirectories underneath these top-level structures. The .NET Framework's System.Windows.Application class defines properties that build common configuration paths for you. The Application.LocalAppDataPath property returns the path for GetFolderPath(SpecialFolders.CommonApplicationData)+"\\CompanyName\\ProductName\\ProductVersion". Similarly, Application.UserDataPath and Application.LocalUserDataPath produce pathnames underneath the user's data and local data directories for this company, application, and version. If you combine these locations, you can create configuration information for all your company's applications, for this application across all versions, and for this specific version.

Note that nowhere in those directories did I mention the application directory, under Program Files. You should not ever write data in any directory under Program Files or in the Windows system directory. Those locations require more security privileges, so you should not expect your users to have permission to write in them.

Where you store your application's settings has become more important as everyone from enterprise users to home users worries about the security of machines. Putting the information in the right location means that it is easier for your users to work with your application without compromising security. You can still provide your users with a personalized experience. Combine the right location with .NET serialization, and it's easy to have your application provide a personalized appearance for each user without compromising security.

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.