2013-03-04 8 views
7

Mam stronę ASP5 ASP.NET MVC 3 (Razor), działającą pod IIS7. Teraz chcę móc zmienić ciąg połączenia z bazą danych MSSQL w zależności od poddomeny adresu URL, np. foo.mydomain.com powinien połączyć się z moją bazą danych "Foo", a bar.mydomain.com powinien połączyć się z bazą danych "Bar".Jak zmienić łańcuch połączenia EF na podstawie poddomeny witryny internetowej MVC?

Oczywiście rekordy DNS są tak skonfigurowane, że wszystkie wskazują na tę samą stronę internetową.

Jaki jest najskuteczniejszy sposób osiągnięcia tego?

+0

Dlaczego nie uruchamiasz ich jako dwóch oddzielnych witryn z różnymi konfiguracjami sieci? W ten sposób możesz ustawić ciągi połączeń w pliku konfiguracyjnym. Byłoby znacznie łatwiejsze i łatwiejsze w utrzymaniu niż zakłócanie ciągów połączeń za każdym razem, gdy deklarujesz kontekst. –

+1

@DoctorJones Ponieważ wtedy muszę wdrożyć do wielu stron internetowych za każdym razem, gdy naprawię błąd lub dodaję funkcję. –

+0

@shaul przekazanie połączenia w użyciu iniekcji zależności byłoby jednym z najlepszych rozwiązań problemu. Używanie fabryki DbContext sparametryzowanej na stronie nazwa byłoby inne. Jeśli twój kod nie pozwala ci to zrobić, potraktuj to jako okazję do poprawy i refaktoryzacji. – LeffeBrune

Odpowiedz

1

Wymyśliłem, co uważam za lepsze rozwiązanie niż wszystkie proponowane do tej pory. Używam domyślnego EntityModelCodeGenerator, więc być może istnieją inne, lepsze rozwiązania dla innych szablonów - ale to działa na mnie:

  1. Tworzenie drugą połowę częściowej klasy MyEntities.
  2. Zastąpienie OnContextCreated(), która jest wywoływana z poziomu konstruktora klasy.
  3. Zmień ciąg połączenia sklepu za pomocą wyrażenia regularnego.

To wychodzi następująco:

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

Więc w zasadzie zrobiłeś tak, jak powiedziałem, ale stworzyłeś własną odpowiedź? – jgauffin

+0

@jgauffin Nie, opublikowalem to przed opublikowaniem komentarza na temat twojej odpowiedzi. Oryginalna odpowiedź nie sugerowała tego ... –

+0

Poinformowałem cię, że możesz zmodyfikować ciąg połączenia, a mój przykład pokazuje, że możesz użyć żądania (które oczywiście istnieje w 'HttpContext.Current'). Pokazałem ci również alternatywny sposób zmiany DB (który można również zrobić w kontekście). Właśnie przeniosłeś go do wnętrza DbContext, ale wciąż jest to samo rozwiązanie. – jgauffin

0

Używaj różnych ciągów połączenia w pliku web.config. Może trochę badań, jeśli możesz mieć warunkowe transformacje XSL, w ten sposób, kiedy opublikujesz na określonej konfiguracji web.Release.config zmieni twój Web.Config tak, aby był tym, czego potrzebujesz.

Lub użyj |DataDirectory| ciąg podstawienia - http://msdn.microsoft.com/en-us/library/cc716756.aspx

więcej na DataDirectory substytucji ciąg tutaj: http://forums.asp.net/t/1835930.aspx/1?Problem+With+Database+Connection

Chyba, jeśli chcesz być przez książki, tworzyć konfiguracje zbudować dla każdej z oddzielnych wydaniach i umieść ciąg połączenia w odpowiednim web..config i kiedy publikujesz, transformacja XSL wstawi ciąg połączenia w wynikowym pliku web.config i voila.

0

Zrobiłem coś takiego ostatnio, dodając niestandardową konfigurację, która używa nagłówka hosta do określenia właściwości connectionStringName, której należy użyć.

EF5 ma konstruktora, który może obsłużyć tej nazwy

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

Nie skorzystałem z tego rozwiązania, ponieważ nie chcę przechodzić przez całą bazę danych, zastępując tym samym wszystkie domyślne konstruktory. Dzięki i tak! –

+0

Dlatego należy używać repozytorium ... – TGlatzer

+0

Co masz na myśli mówiąc "użyj repozytorium"? Czym różni się to od tego, co teraz robię? –

1

dlaczego nie zaczniesz przechodzi swój własny SqlConnection do YourDbContext?

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

Można również zmienić bazę danych w DBContext:

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

Nie poszedłem z tym rozwiązaniem, ponieważ nie chcę wracać do całego mojego kodu i zmieniać konstruktorów, aby wszędzie przekazywać ciąg połączenia. Dzięki i tak! –

+0

To dlatego kontenery IoC są tak świetne ... W każdym razie, możesz dodać zmianę bazy danych w swoim własnym konstruktorze DbContext (używając 'HttpContext.Current') ... – jgauffin

+0

Tak, właśnie to zrobiłem - zobacz moją odpowiedź na to pytanie . –

1

To nie jest bardzo proste ... należy zmienić konstruktora obiektu kontekście dynamicznie zmieniać parametry połączenia. Podaj nazwę subdomeny, używając System.Web.HttpContext.Current.Request.Url.Host. Następnie użyj go, aby obliczyć prawidłowy ciąg połączenia.

Powinieneś to zrobić w wygenerowanym przez projektanta kodzie. Oczywiście to nie jest dobre miejsce .. aby to działało, użyj szablonu T4. Otwórz model i kliknij prawym przyciskiem myszy na pustej powierzchni projektanta, a następnie wybierz "Dodaj element generowania kodu" -> Generowanie obiektu obiektu Ado.net. Spowoduje to utworzenie pliku .tt. Otwórz go i poszukaj składni konstruktora. Dodaj tam swoją logikę.

Powodzenia!

+0

+1 za wzmiankę o tym, jak usunąć hosta z HttpContext, mimo że poszedłem z własnym rozwiązaniem. Dzięki i tak! –

0

właśnie zrobił dla projektu

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) 
    { 

    } 
} 

A w web.config I dodać connectionString.

Powiązane problemy