Class Library使用DataContext時的連線字串設定問題

在Visual Studio中使用LINQ to SQL或EF時,拖拉資料庫產生Entity類別,VS會幫忙打理儲存連線字串。在小型ASP.NET專案裡,*.dbml被直接加入網站專案,VS就順理成章地在web.config <connectionStrings />中加入連線字串,實際上線時,將web.config裡的設定改連正式資料庫即可。

但當專案規模變大,我們常會將資料存取相關的程式移到獨立的DAL專案(Class Library),因此*.dbml / *.edmx等也被歸在此專案中,此時要如何處理連線字串設定?

首先,設計階段採用的資料庫連線字串也被保存在DAL專案的app.config(另外還有個Properties/Settings.Settings物件,提供以物件屬性方式存取這些參數,例如: Properties.Settings.Default.PlaygroundConnectionString)。因此我們在DAL專案的app.config中可以看到如下設定:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
    </configSections>
    <connectionStrings>
        <add name="ClassLibrary1.Properties.Settings.PlaygroundConnectionString"
            connectionString="Data Source=(local);Initial Catalog=Playground;
                              Integrated Security=True;"
            providerName="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

有趣的問題來了,我們ASP.NET專案中參照了ClassLibrary1,然後就可以大方地用new DataClass1DataContext()建立DataContext,接著LINQ到不亦樂乎:

不過,仔細一看web.config,咦? 只看到<connectionStrings />? 代表未設任何連線字串,而ClassLibrary1.dll也沒有夾帶config檔到ASP.NET專案,程式居然知道如何要連上哪一台資料庫,會不會太神了? 為追根究底,追一下程式:

先在DataClasses1.designer.cs找到DataClass1DataContext()建構式

public DataClasses1DataContext() : 
        base(global::ClassLibrary1.Properties.Settings.Default.
PlaygroundConnectionString, mappingSource)
{
    OnCreated();
}

原來它用了前述的Settings.Settings物件屬性模型去取連線字串,再追到Settings.Designer.cs

[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.SpecialSettingAttribute(
             global::System.Configuration.SpecialSetting.ConnectionString)]
[global::System.Configuration.DefaultSettingValueAttribute(
"Data Source=(local);Initial Catalog=Playground;Integrated Security=True;")]
public string PlaygroundConnectionString {
    get {
        return ((string)(this["PlaygroundConnectionString"]));
    }
}

謎底揭曉! Settings.Settings裡的屬性會與.NET的設定檔運作機制配合,當web.config或程式名.exe.config中有相關設定時,會自動讀取設定檔的連線字串;若config檔案未指定該連線字串,則可透過DefaultSettingValueAttribute取得預設值。這就是為什麼web.config沒給connectionString,程式仍可運作的理由。換句話說,當我們在web.config中加入name="ClassLibrary1.Properties.Settings.PlaygroundConnectionString"的連線字串設定(可以參考ClassLibrary1專案的app.config)後,程式就會以web.config中的連線字串為準。

最後提醒一點,VS處理連線字串時預設會以明碼方式保存在config中,若連線字串包含帳號密碼,就不符合資安要求,關於這部分可自行寫函數做加解密處理,或者直接使用ASP.NET內建的connnectionStrings加密機制保護。避免機密資訊大喇喇地在攤在檔案裡,是維護系統安全的重要原則,請大家多加留意。

2010-09-23更新】System.Configuration.DefaultSettingValueAttribute的做法雖可提供未設定web.cofig時的預設值,但也可能導致未加密連線字串被Build進dll/exe而有外流風險,正式部署前宜將相關連線資訊移除再編譯,會更加安全。感謝ChrisTorng補充!

歡迎推文分享:
Published 22 September 2010 07:29 AM 由 Jeffrey
Filed under: ,
Views: 13,134



意見

# ChrisTorng said on 22 September, 2010 08:25 PM

為了避免編譯後的 exe/dll 中包含敏感資訊如連線字串,我有研究過方法,分享給大家。

只要在 web.config 中保留連線字串,Settings 設定畫面中將連線字串內容清掉,即可將 Settings.Designer.cs 中內含的連線字串清掉,避免編譯後的 exe/dll 中包含敏感資訊,但執行時又有 web.config 連線字串可以取得。

另外日後 web.config 中有修改時,開啟 Settings 設定畫面時,會問要不要以 web.config 的最新內容來更新 Settings 設定,此時答「否」就不會重新將 web.config 的內容複製到 Settings 設定畫面中了...

# Jeffrey said on 22 September, 2010 10:54 PM

to ChrisTorng,謝謝你的寶貴心得分享!

# Eric said on 04 December, 2015 06:54 AM

您好,我有另一個想法,會用這樣的方法不外乎是DAL專案可能會被多個WEB專案所引用,如此ConnectionString只要在DAL內設定好,其餘每個WEB專案都不用在web.config內重新設定一次,較易維護。

而拿掉DefaultSettingValueAttribute,又在每個WEB專案內重新設定web.config,就失去了使用此方法的意義,如此還不如不要那麼麻煩去設定DAL內的Settings,app.config連線字串的名稱還可以比較簡短不是嗎? ^_^

# Jeffrey said on 04 December, 2015 09:05 AM

to Eric,在我的工作環境,上線OP與RD是兩組不同人員,連線字串的設定是OP的工作(RD不知道正式資料庫的帳號密碼,也不可能直接寫在程式碼裡),當系統內有多個DAL,多個連線字串集中放在web.config有其好處,一次修改搞定。(通常還需加密 blog2.darkthread.net/post-2015-11-28-encrypt-ef-connstring.aspx

以上經驗分享。

# Eric said on 04 December, 2015 09:34 AM

了解了~很實用的方法!!感謝您的快速回覆!! ^_^

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication