2013-03-04 32 views
7

我有一個EF5 ASP.NET MVC 3(Razor)網站,在IIS7下運行。現在,我希望能夠根據URL的子域將連接字符串更改爲MSSQL數據庫,例如, foo.mydomain.com應該連接到我的「Foo」數據庫,並且bar.mydomain.com應該連接到「Bar」數據庫。如何根據MVC網站的子域更改EF連接字符串?

很明顯,DNS記錄的設置使得它們都指向同一個網站。

實現此目的的最有效方法是什麼?

+0

爲什麼不把它們作爲兩個獨立的網站使用不同的網頁配置?這樣你就可以在配置文件中設置連接字符串。這會比每次聲明上下文時連接字符串搞亂更容易和更易維護。 – 2013-03-04 11:39:42

+1

@DoctorJones因爲那時我每次修復一個bug或添加一個功能時都必須部署到那麼多網站。 – 2013-03-04 11:47:58

+0

@shaul傳遞使用依賴注入的連接將是解決此問題的最佳解決方案之一。使用站點名稱參數化的DbContext工廠將是另一個。如果你的代碼不允許你這樣做,那麼把它作爲一個改進和重構的機會。 – LeffeBrune 2013-03-04 13:06:58

回答

1

我想出了我認爲比迄今爲止所有提議的更好的解決方案。我使用的是默認EntityModelCodeGenerator,所以也許還有其他更好的,對其他模板解決方案 - 但是這對我的作品:

  1. 造成局部類MyEntities的另一半。
  2. 覆蓋OnContextCreated(),它是從類的構造函數中調用的。
  3. 使用正則表達式更改商店連接字符串。

這出來如下:

partial void OnContextCreated() 
{ 
    // change connection string, depending on subdomain 
    if (HttpContext.Current == null) return; 
    var host = HttpContext.Current.Request.Url.Host; 
    var subdomain = host.Split('.')[0]; 
    switch (subdomain) 
    { 
    case "foo": 
     ChangeDB("Foo"); 
     break; 
    case "bar": 
     ChangeDB("Bar"); 
     break; 
    } 
} 

private void ChangeDB(string dbName) 
{ 
    var ec = Connection as EntityConnection; 
    if (ec == null) return; 
    var match = Regex.Match(ec.StoreConnection.ConnectionString, @"Initial Catalog\s*=.*?;", RegexOptions.IgnoreCase); 
    if (!match.Success) return; 
    var newDbString = "initial catalog={0};".Fmt(dbName); 
    ec.StoreConnection.ConnectionString = ec.StoreConnection.ConnectionString.Replace(match.Value, newDbString); 
} 
+0

所以你基本上按我說的做了,但創建了自己的答案? – jgauffin 2013-03-04 13:24:17

+0

@jgauffin不,我在發表評論之前發佈了這個答案。你的原始答案沒有暗示這... – 2013-03-04 13:35:25

+0

我曾告訴你,你可以修改連接字符串,我的例子顯示你可以使用請求(當然存在於'HttpContext.Current'中)。我還向您展示了更改數據庫的另一種方法(這也可以在上下文中完成)。你只是把它移到了DbContext裏面,但它仍然是相同的解決方案。 – jgauffin 2013-03-04 14:13:25

0

在web.config中使用不同的連接字符串。如果可以進行條件XSL轉換,那麼也許需要研究一下,這樣,當您在特定配置上發佈web時,Release.config會將您的Web.Config更改爲您所需要的。

或者,使用|DataDirectory|字符串替換 - http://msdn.microsoft.com/en-us/library/cc716756.aspx

更多DataDirectory目錄字符串替換此處 http://forums.asp.net/t/1835930.aspx/1?Problem+With+Database+Connection

我想,如果你想通過這本書,爲每個獨立版本的創建構建配置並將連接字符串放在相應的web..config文件中,當您發佈時,XSL轉換會將連接字符串放入生成的web.config文件中。

0

我最近做了類似的事情,添加了一些自定義配置,它使用主機頭來確定必須使用的connectionStringName。

EF5有一個構造函數,它可以處理這個名字

var context = new MyDbContex("name=<DBConnectionStringName>"); 
+0

我沒有使用這個解決方案,因爲我不想通過我的整個數據庫來替換所有的默認構造函數。不管怎麼說,還是要謝謝你! – 2013-03-04 13:02:28

+0

這就是爲什麼一個人應該使用存儲庫... – TGlatzer 2013-03-04 13:05:56

+0

你是什麼意思,「使用存儲庫」?這與我現在所做的有什麼不同? – 2013-03-04 13:10:29

1

你爲什麼不開始傳遞自己SqlConnectionYourDbContext

var partialConString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString; 
var connection = new SqlConnection("Initial Catalog=" + Request.Url.Host + ";" + partialConString); 
var context = new MyDbContext(connection, true); 

您還可以更改數據庫中的DbContext:

context.Database.Connection.ChangeDatabase("newDbname"); 
+0

我沒有使用這個解決方案,因爲我不想回頭查看所有的代碼,並更改構造函數以在任何地方傳遞連接字符串。不管怎麼說,還是要謝謝你! – 2013-03-04 13:00:29

+0

這就是爲什麼IoC容器是如此之大......無論如何,你可以在你自己的DbContext構造函數中添加數據庫更改(使用'HttpContext.Current')... – jgauffin 2013-03-04 13:23:04

+0

是的,這正是我所做的 - 看到我對這個問題的回答。 – 2013-03-04 13:24:13

1

這不是很容易... 你應該改變對象上下文的構造函數來動態地更改連接字符串。 使用System.Web.HttpContext.Current.Request.Url.Host取得子域名。然後用它來計算正確的連接字符串。

您應該在設計器生成的代碼中執行此操作。當然,這不是一個好的地方..使它使用T4模板。打開你的模型並右鍵單擊空白的設計器表面,然後選擇「添加代碼生成項目」 - > Ado.net實體對象生成。這將創建一個.tt文件。打開它並查找構造函數語法。在那裏添加你的邏輯。

祝你好運!

+0

+1提到如何讓主機脫離HttpContext,儘管我使用自己的解決方案。不管怎麼說,還是要謝謝你! – 2013-03-04 13:01:30

0

我只是做了一個項目

public partial class admpDBcontext : DbContext 
{ 

    public static string name 
    { 
     get 
     { 
      if (System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority).ToString() == "http://fcoutl.vogmtl.com") 
      { 
       return "name=admpDBcontext"; 
      } 
      else { return "name=admpNyDBcontext"; } 
     } 

    } 


    public admpDBcontext() 
     : base(name) 
    { 

    } 
} 

而且在web.config我添加的connectionString。