2012年2月8日 星期三

組態設定

組態設定

認識組態檔

系統開發時,一定會使用組態檔,來記錄一些可能會變動的資訊,以避免因 hard-code 所造成的不方便。 .NET底下的 System.Configuration 命名空間所提供的類別,就是用來管理組態設定用的,讓開發者可以更輕鬆的存取這些資訊。

底下是開發系統常會使用到的組態檔

  • 應用程式組態檔( XXXX.exe.config ):這個檔一般與執行檔放在同一層目錄。
  • 電腦組態檔( Machine.config ):包含套用於整個電腦的設定值。這個檔案位於 %system32%\Microsoft.NET\Framework\[版本號]\Config 目錄。
  • Web 組態檔( Web.config ):這個檔是使用在網站專案的組態檔。

組態檔是一個 XML 文件,其中包含了許多的項目,詳情結構可參考.NET Framework 的組態檔結構描述。 雖然這個 XML 文件也可以透過 XmlSerializer 以取得資訊內容,不過, 針對組態檔,直接使用 System.Configuration 命名空間所提供的 Configuration 、 ConfigurationManager 類別,就可以快速方便讀取組態檔中的設定值。

Configuration 的屬性和方法

Configuration 這個類別是用來記載描述電腦中特定的組態檔類別

屬性

方法

ConfigurationManager 的屬性和方法

這個類別是用來管理操作組態檔的類別

屬性

方法

如何開啟組態檔

加入 System.Configuration 參考

因為 Visual Studio 的預設參考不包含 System.Configuration 組件,所以使用這個類別之前,必須先手動加入參考,才可以引用的到 System.Configuration 命名空間。

//開啟應用程式組態檔     //同 XXXX.exe 目錄
Configuration config1 = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

//開啟特定的應用程式組態檔
string ExeFileName = @"C:\App1.config";
Debug.Assert(File.Exists(ExeFileName),"file is miss");   //判斷檔案是否存在

ExeConfigurationFileMap MyMap = new ExeConfigurationFileMap();
MyMap.ExeConfigFilename = ExeFileName;
Configuration config2 = ConfigurationManager.OpenMappedExeConfiguration(MyMap, ConfigurationUserLevel.None);

//開啟電腦組態檔  //%system32%\Microsoft.NET\Framework\[版本號]\Config 目錄。
Configuration config3 = ConfigurationManager.OpenMachineConfiguration();

//開啟特定的電腦組態檔
Configuration config4 = ConfigurationManager.OpenMappedMachineConfiguration(MyMap);

通用設定

什麼是通用設定

前面提過,整個組態檔包含了許多項目,而「通用設定」指的是其中幾項與決定應用程式如何執行有關的組態設定項目。例如:

1.<supportedRuntime>:若開發專案的.NET版本與執行環境的版本不同,可以在這個區段指定RunTime的版本。
2.<developmentMode>:在開發階段將某組件設定成共用組件。
3.<codeBase>:指定某個組件的位置與版本。
4.<appSettings>:與應用程式設定相關的區塊
5.<connectionStrings>:與資料庫連線設定相關的區塊

下面這些例子,示範了上面幾項設定內容:

指定Runtime版本

依 <supportedRun> 中指定的版本啟用 Framework 版本。

<startup>
    <supportedRuntime version="v2.0.50727"/>
  </startup>

指定使用組件位置:

1.加入一個名為 DEVPATH 的環境變數,並指定組件位置。
2.將 developmentMode 的值設為 true。

<runtime>
    <developmentMode developerInstallation="true"/>
  </runtime>

使用 <codeBase> 同時指定組件的位置與版本

<configuration>
    <runtime>
      <assemblyBinding xmlns="schemaname">
        <dependentAssembly>
          <assemblyIdentity name="myprogram" publicKeyToken="xxxxxxxxx" culture="en-us"/>
          <assemblyIdentity name="assembly name" publicKeyToken="xxxxxxxxx" culture="en-us"/>
          <codeBase version="x.0.0.0" href="http://www.adatum.com/myprogram.dll"/>
        </dependentAssembly>
      </assemblyBinding>
    </runtime>
  </configuration>

使用 <appSettings>

<appSettings>
    <add key="ConnString" value="Data Source=localhost; Initial Catalog=DBNAME; User ID=sa; Password=Password"/>
    <add key="DBAssemblyName" value="DBProvider"/>
    <add key="DBClassName" value="SqlDBObject"/>
  </appSettings>

使用 <connectionStrings>

<connectionStrings>
    <clear/>
    <add name="AdventureWorksString" 
        providerName="System.Data.SqlClient" 
        connectionString="Data Source=localhost; Initial Catalog=DBNAME; User ID=sa; Password=Password; Integrated Security=true"/>
  </connectionStrings>

上面資訊中,比較特別的是<appSettings>與<connectionStrings>這二個區段:

底下示範如何操作組態檔

如何讀取組態檔中 appSettings 區段的項目

透過 ConfigurationManager.AppSettings 方法就可以取得 AppSettings 區段下的所有設定項目,其回傳值是一個 NameValueCollection 型別的集合。

//0) 已過時用法
string ConnString = ConfigurationSettings.AppSettings["ConnString"];

//1) 取得單一個項目
string ConnString = ConfigurationManager.AppSettings["ConnString"];

//2) 取得整個<appSettings>區段
NameValueCollection AllAppSett ings = ConfigurationManager.AppSettings;
ConnString = AllAppSettings["ConnString"];

//3) 列舉<appSettings> 區段
foreach (string key in AllAppSettings) 
    Console.WriteLine("Key/Value:{0} = {1}", key, AllAppSettings[key]);  //由 key 取 value

如何修改組態檔中 appSettings 區段的項目

要修改組態設定值,必須先開啟組態檔,再透過 Configuration.AppSettings 這個屬性回傳 AppSettingsSection 型別的組態區段資料,再使用其 Settings 方法,就可新增修改刪除區段中的項目。步驟如下:

//開啟組態檔
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

//取得 AppSettings 區段的組態設定值
KeyValueConfigurationCollection appSettings = config.AppSettings.Settings;

//新增或變更 AppSettings 區段的項目
appSettings["key1"].Value = "value 111";    //修改
appSettings.Add("key2", "value2");          //新增

//儲存到 AppSettings 區段 (要注意使用者的存取權限)
config.Save();   

PS.
當在 Visual Studio 中執行 debug 模式,此時使用的組態檔是 /bin/Debug/XXXX.vshost.exe.config,
而且,即使執行了 Save() 動作,設定值也是不會變更的。

如何讀取組態檔中 connectionStrings 區段的項目

透過 ConfigurationManager.ConnectionStrings 可以取得 connectionStrings 區段下的所有設定項目,其回傳值是一個 ConnectionStringSettingsCollection 型別的集合,集合內的元素則是由 ConnectionStringSettings 物件組成。 透過 ConnectionStringSettings 物件就可以取出設定項目中 name 、 connectionString 、 providerName 三個屬性值。

//1) 取得單一個項目
ConnectionStringSettings myConn = ConfigurationManager.ConnectionStrings["AdventureWorksString"];

//2) 取得整個<connectionStrings> 區段
ConnectionStringSettingsCollection MyConnections = ConfigurationManager.ConnectionStrings;

// 由集合中取出一個項目
ConnectionStringSettings myConnSetting = MyConnections["AdventureWorksString"];
String ConnString = myConnSetting.ConnectionString;

//3) 列舉<connectionStrings> 區段
if (MyConnections != null)
{
    StringBuilder sb = new StringBuilder();
    foreach (ConnectionStringSettings ConnSetting in MyConnections)
    {
        sb.AppendLine("ConnectionString = " + ConnSetting.ConnectionString);
        sb.AppendLine("Name             = " + ConnSetting.Name);
        sb.AppendLine("ProviderName     = " + ConnSetting.ProviderName);
    }
    Console.WriteLine(sb.ToString());
}

如何修改組態檔中 connectionStrings 區段的項目

  1. 開啟組態檔。
  2. 透過 Configuration.ConnectionStrings.ConnectionStrings 取得 connectionStrings 區段的集合物件。
  3. 新增或修改集合中的資料。
  4. 透過 Configuration.Save 方法回存資料到 connectionStrings 區段。
//開啟組態檔
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

//取得 connectionStrings 區段的組態設定值
ConnectionStringSettingsCollection Connections = config.ConnectionStrings.ConnectionStrings;

//新增或變更項目
Connections["Conn1"].ConnectionString = "Data Source=localhost; Initial Catalog=DBNAME1;...";               //修改
Connections.Add(new ConnectionStringSettings("Conn2", "Data Source=localhost; Initial Catalog=DBNAME;"));   //新增

//儲存
config.Save();

如何讀取 Web 應用程式的組態檔

如果是 Web 應用程式的話,可改用 WebConfigurationManager 來管理組態資訊,用法幾乎是一樣的:

Console.SetOut(Response.Output);  

//1)直接取得<appSettings>底下,Key="ConnString"這個項目的設定值
string ConnString = WebConfigurationManager.AppSettings["ConnString"];

//2)取得整個<appSettings>區段
NameValueCollection AllAppSettings = WebConfigurationManager.AppSettings;

//3)列舉<appSettings>區段
IEnumerator SettingsEnumerator = AllAppSettings.Keys.GetEnumerator();
while (SettingsEnumerator.MoveNext())
{
    Response.Write(string.Format("Item: {0}  Value: {1} <BR>", SettingsEnumerator.Current, AllAppSettings[(string)SettingsEnumerator.Current]));
}

//1)直接取得<connectionStrings>底下,Name="AdventureWorksString"這個項目的設定值
ConnectionStringSettings myConn = WebConfigurationManager.ConnectionStrings["AdventureWorksString"];

//2)取得<connectionStrings>區段
ConnectionStringSettingsCollection MyConnections = WebConfigurationManager.ConnectionStrings;

//3)列舉<connectionStrings>區段
if (MyConnections != null)
{
    StringBuilder sb = new StringBuilder();
    foreach (ConnectionStringSettings ConnSetting in MyConnections)
    {
        sb.AppendLine("Full Connection String: " + ConnSetting.ConnectionString + "<BR>");
        sb.AppendLine("Section Name: " + ConnSetting.Name + "<BR>");
        sb.AppendLine("Provider Name: " + ConnSetting.ProviderName + "<BR>");
    }
    Response.Write(sb.ToString());
}

應用程式設定

什麼是應用程式設定

「應用程式設定」指的是套用到整個應用程式的組態設定項目,例如,專案名稱,公司名稱,Web Service的URL等等的變數。

使用應用程式設定,除了快速方便之外,另一個好處是,這些設定值是支援強型別的。

ApplicationSettingsBase :這個類別是這個機制的主要核心物件。 透過設定檔設計工具可以方便管理這些設定值,因為系統會自動建立這些設定值的類別,這個類別會就是繼承自 ApplicationSettingsBase 。 若我們要自已手寫一個類別以讀取應用程式設定檔,也只須繼承這個類別即可。

應用程式設定值有一個屬性,稱為使用範圍,可以有2種設定:一是 Application ,另一個是 User

  • Application:
    指的是整個應用程式的所有使用者共用的資訊,例如存放專案名稱、公司名稱等。這個區段的設定值是唯讀的。 這個範圍的設定值會存放在 <applicationSettings> 區段內。
  • User:
    指的是整個各別使用者使用的資訊,例如存放使用者姓名、喜好設定等。這個區段的設定值可供讀寫。 這個範圍的設定值會存放在 <userSettings> 區段內。

如何設定預設的應用程式設定檔

在專案的 Properties 目錄底下,預設會有一個設定檔 (Settings.settings),只要點擊這個檔案,或者在專案的 Property 項目上,按右鍵,選擇開啟,就可以開啟編輯工具,進行維護。操作步驟如下:

開啟設定檔

設定屬性名稱、型別、範圍

如何讀取預設的應用程式設定檔

假設我們在預設的應用程式設定檔中,加入下列項目:

系統會自動幫我們產生 Settings 這個類別,透過以下的方法,就可以直接以物件導向的方法取得各個設定值。

//讀取應用程式設定檔 Settings 這個設定檔,是系統預設的設定檔類別
Console.WriteLine(Settings.Default.Setting1);
Console.WriteLine(Settings.Default.Setting2);
Console.WriteLine(Settings.Default.Setting3);
Console.WriteLine(Settings.Default.Setting4);
//abc123
//abc456
//公司名稱
//系統名稱

如何新增自建的應用程式設定檔

應用程式設定檔可以多個,也不一定要放在專案的 Property 項目底下。你可以自行新增自訂的應用程式設定檔,如下圖所示:

新增設定檔

設定檔不一定要在 Properties 目錄底下

如何讀取自建的應用程式設定檔

同樣的,當新增一個應用程式設定檔時,系統也會自動幫我們建立這個設定檔類別,透過以下的方法,就可以直接存取設定檔中的設定值。假設設定內容如下:

有二種方式存取。你可以新增一個設定檔類別的實體去存取設定值,或者是使用 Default 這個 static instance 取得屬性值。

//讀取應用程式設定檔,SampleApp 這個設定檔,是透過設計工具幫我們建立的類別
SampleApp sa = new SampleApp();
Console.WriteLine(sa.myName);
Console.WriteLine(sa.myBirthday.ToString());
Console.WriteLine(sa.myEmail);
Color c = sa.sysColor;
Console.WriteLine(sa.sysProjectName);

//若不想建立類別實體,也可以使用Default這個static instance取得屬性值
Console.WriteLine(SampleApp.Default.myName);
Console.WriteLine(SampleApp.Default.myBirthday.ToString());
Console.WriteLine(SampleApp.Default.myEmail);
Color c2 = SampleApp.Default.sysColor;
Console.WriteLine(SampleApp.Default.sysProjectName);

如何自行撰寫自訂應用程式設定檔類別

前面提過, ApplicationSettingsBase 是應用程式設定檔的基底類別,若要自行撰寫設定檔類別,首先就要繼承這個類別。

下列示範如何自行撰寫繼承自 ApplicationSettingsBase 類別,以讀取應用程式設定檔

//讀取應用程式設定檔 SampleApp2這個設定檔,是自行撰寫繼承自ApplicationSettingsBase的類別
SampleApp2 sa2 = new SampleApp2();
Console.WriteLine(sa2.myName);
Console.WriteLine(sa2.myBirthday.ToString());
Console.WriteLine(sa.myEmail);
Color c3 = sa2.sysColor;
Console.WriteLine(sa2.sysProjectName);

class SampleApp2 : ApplicationSettingsBase
{
    [UserScopedSetting()]                   //將這個設定值的使用範圍設定為:User
    [DefaultSettingValueAttribute("vito")]  //設定預設值
    public string myName {
        get { return (String)this["myName"]; }
        set { this["myName"] = value; }
    }

    [UserScopedSetting()]
    [DefaultSettingValueAttribute("1911/01/01")]
    public System.DateTime myBirthday {
        get { return (DateTime)this["myBirthday"]; }
        set { this["myBirthday"] = value; }
    }

    [UserScopedSetting()]
    [DefaultSettingValueAttribute("")]
    public string myEmail {
        get { return (string)this["myEmail"]; }
        set { this["myEmail"] = value; }
    }

    [ApplicationScopedSetting()]        //將這個設定值的使用範圍設定為:Application
    [DefaultSettingValueAttribute("255, 255, 255")]
    public Color sysColor
    {
        get { return (Color)this["sysColor"]; }
        set { this["sysColor"] = value; }
    }

    [ApplicationScopedSetting()]
    [DefaultSettingValueAttribute("aaa bbb")]
    public string sysProjectName
    {
        get { return (string)this["sysProjectName"]; }
        set { this["sysProjectName"] = value; }
    }
}

如何以程式碼修改設定值

不管增加了幾個應用程式設定檔,所有應用程式設定檔的資訊內容,都會被複製存一份放在 app.config 底下。 如果將設定值的使用範圍設為 User ,就會放在 <userSettings> 區段內;如果將設定值的使用範圍設為 Application ,就會放在 <applicationSettings> 區段內。

下列程式碼示範如何讀取與變更設定值:

private void button8_Click(object sender, EventArgs e)
{
    //讀取設定值
    SampleApp setting = new SampleApp();
    txtName.Text = setting.myName;
    dtBirthday.Value = setting.myBirthday;
    labColor.BackColor = setting.sysColor;
}

private void button6_Click(object sender, EventArgs e)
{
    //寫入設定值
    SampleApp setting = new SampleApp();
    setting.myName = txtName.Text;
    setting.myBirthday = dtBirthday.Value;
    setting.sysColor = labColor.BackColor;
    setting.Save();
}

PS1.

存檔之後,檢查 app.config 或 XXX.exe.config,為什麼資料都沒有改變呢?可是再執行一次程式,會發覺載入的資訊值卻是新的。為什麼?

這是因為,在 <userSettings> 這個區段底下的資訊,若被使用者變更後,會複製一份在 C:\Users\[username]\AppData\Local\Microsoft\.. 底下,檔名為 user.config 。 這時候,若再去變更 app.config 並不會發生什麼作用,因為關於 userSettings 的資訊,會以這個檔案優先讀取,除非它被刪除了,才會去讀取 app.config 裡面原始的設定值。 這也是為什麼<applicationSettings>這個區段是唯讀的原因,因為每個 User 只會讀取到屬於自已的 <userSettings> 部分。 若要在程式中變更全域的設定值,可以在公開的目錄底下建立custom config file。

下圖顯示, <userSettings> 這個區段真正的存放位置及內容.。

PS2.

所讀取的這個 user.config 檔案,是依據組件版號而異的,也就是,不同的版號,會自動建立一個目錄存放 user.config 檔。 所以一旦變更組件版號,就會讀取新的 user.config 檔。

利用 ApplicationSettings 儲存使用者習慣

在 WinForm 程式中,有時候我們會想記錄使用者上一次使用時的最後操作,方便下次開啟應用程式時自動載入前一次的設定。 例如下圖中,使用者必須透過 OpenFileDialog 設定操作的 Excel 檔案來源,這時我們可以利用 ApplicationSettings 快速的記錄下這個資訊,方便下次執行時自動載入。

要完成這個設定,你只要針對該控制項,新增一個 Text 屬性繫結(PropertyBinding)即可。步驟如下:

利用下拉選單中的功能,新增一個 ApplicationSettings 項目。

設定完成後,就會有一個 Text 的屬性繫結。

最後你必須找一個事件(例如:FormClosing),將上面設定儲存成預設值,等到程式下次執行時,就會自動載入這個預設值。

private void frmGPS_FormClosing(object sender, FormClosingEventArgs e)
    {
        Properties.Settings.Default.Save();
    }

沒有留言:

張貼留言