2012-01-30 8 views
11

Mam nadzieję, że ktoś może mi pomóc w rozwiązaniu następującego problemu. Aplikacja, w której wystąpił błąd, jest uruchomiona podczas produkcji i sam nigdy nie doświadczyłem tego błędu. Jednak około 20 razy dziennie otrzymuję wiadomość o błędzie z informacją:Okazjonalne Błędy "Dostawca podstawowy nie powiodło się podczas otwierania" podczas korzystania z EF4 (model edmx)

Dostawca podstawowy nie spełnia warunków Open. ---> System.InvalidOperationException: połączenie nie zostało zamknięte. Bieżący stan połączenia łączy się.

Oto ślad stosu

System.Data.EntityException: Podstawowym dostawcą powiodło się na Open. ---> System.InvalidOperationException: połączenie nie zostało zamknięte. Aktualny stan połączenia to połączenie. w System.Data.ProviderBase.DbConnectionBusy.OpenConnection (DbConnection outerConnection, DbConnectionFactory ConnectionFactory) w System.Data.SqlClient.SqlConnection.Open() w HibernatingRhinos.Profiler.Appender.ProfiledDataAccess.ProfiledConnection.Open() w System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf (logiczna openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, logiczna & closeStoreConnectionOnFailure) --- Koniec wewnętrznej wyjątkiem stosu śladu --- w System.Data .EntityClient.EntityConnection.OpenStoreConnectionIf (Logiczna openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, logiczna & closeStoreConnectionOnFailure) w System.Data.EntityClient.EntityConnection.Open() w System.Data.Objects.ObjectContext.EnsureConnection(), w System.Data.Objects.ObjectQuery forMergeOption) w System.Data.Objects.ObjectQuery źródła) w System.Data.Objects.ELinq.ObjectQueryProvider.b__1 [TResult] (IEnumerable zapytania Wyrażenie queryRoot) pod adresem Sys tem.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute [S] (wyrażenie ekspresji) z System.Linq.Queryable.FirstOrDefault [TSource] (źródło IQueryable`1)
w GuideSites.DomainModel .Repositories.ClinicTermRepository.GetClinicTermByGuideSiteId (Int32 guideSiteId) w C: \ Projects \ GuideSites \ GuideSites.DomainModel \ Repositories \ ClinicTermRepository.cs: linia 20 przy GuideSites.Web.Frontend.Helpers.VerifyUrlHelper.RedirectOldUrls() w C: \ Projects \ GuideSites \ GuideSites.Web.Frontend \ Helpers \ VerifyUrlHelper.cs: line 91 at GuideSites.Web.Frontend.MvcApplication.Application_BeginRequest (Object nadawcy EventArgs e) C: \ Projects \ GuideSites \ GuideSites.Web.Frontend \ Global.asax.cs: Linia 412 w System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute () w System.Web.HttpApplication.ExecuteStep (IExecutionStep krok, Boolean & completedSynchronously)

używam EF4 pośrednictwem modelu EDMX i sposób połączyć się z bazą danych (MS SQL 2008) jest przez HttpContext opartej kontekście per żądanie obiektu tak, że połączenia z bazą danych nie są otwierane i zamykane dla każdego pojedynczego fragmentu danych potrzebnego na danym pageload.

Moja klasa kontekst bazy danych wygląda następująco:

public class DatabaseContext : IDisposable 
{ 
    private const string ContextName = "context"; 
    private static dbEntities _dbEntities; 

    public dbEntities GetDatabaseContext() 
    { 
     SqlConnection.ClearAllPools(); 

     if (HttpContext.Current == null) 
      return _dbEntities ?? (_dbEntities = new dbEntities()); 

     if (HttpContext.Current.Items[ContextName] == null) 
      HttpContext.Current.Items[ContextName] = new dbEntities(); 

     _dbEntities = (dbEntities)HttpContext.Current.Items[ContextName]; 
     if (_dbEntities.Connection.State == ConnectionState.Closed) 
     { 
      _dbEntities.Connection.Open(); 
      return _dbEntities; 
     } 

     return _dbEntities; 
    } 


    public void RemoveContext() 
    { 
     if (HttpContext.Current != null && HttpContext.Current.Items[ContextName] != null) 
     { 
      ((dbEntities)HttpContext.Current.Items[ContextName]).Dispose(); 
      HttpContext.Current.Items[ContextName] = null; 
     } 

     if (_dbEntities != null) 
     { 
      _dbEntities.Dispose(); 
      _dbEntities = null; 
     } 
    } 


    public void Dispose() 
    { 
     RemoveContext(); 
    } 

} 

W moim repozytorium używam kontekstu bazy danych tak:

public class SomeRepository 
{ 
    private static readonly object Lock = new object(); 
    private readonly dbEntities _dbEntities; 

    public SomeRepository() 
    { 
     var databaseContext = new DatabaseContext(); 
     _dbEntities = databaseContext.GetDatabaseContext(); 
    } 


    public IEnumerable<SomeRecord> GetSomeData(int id) 
    { 
     lock (Lock) 
     { 
      return 
       _dbEntities.SomeData.Where(c => c.Id == id); 
     } 
    } 
} 

Blokada (Lock) było to coś czytałem o powinno pomóc ten problem, ale w moim przypadku tak się nie stało. I generalnie trudno było znaleźć wątki, które opisują dokładnie mój problem, nie mówiąc już o rozwiązaniu problemu.

Aplikacja jest aplikacją ASP.NET MVC3 i jest skonfigurowana jako jedna aplikacja uruchomiona na 9 różnych stronach internetowych (domena określa treść, która ma być wyświetlana klientowi). 9 witryn nie ma więcej niż 2000 odsłon dziennie, więc baza danych powinna być akcentowana na tym koncie.

Mam nadzieję, że ktoś może pomóc i proszę dać mi znać, jeśli jest coś, o czym zapomniałem wspomnieć.

+0

Co wywołuje 'DatabaseContext.Dispose()'? Używam podobnego ustawienia 'HttpContext.Items' i mam' HttpModule', który zrzuca 'ObjectContext' na końcu żądania ... –

+0

Właściwie myślałem, że' Dispose() 'został wywołany automatycznie, ponieważ implementuje' DatabaseContext' 'IDisposable'. Ale jeśli nie, to z pewnością może wyjaśnić błąd. Czy mogę rzucić okiem na twój kod w 'HttpModule'? – hylle

Odpowiedz

1

Zgodnie z moim komentarzem, Dispose() musi zostać wywołany przez coś na końcu żądania. Można to zrobić za pomocą HttpModule tak:

public class ContextDisposer : IHttpModule 
{ 
    private readonly DatabaseContext _context = new DatabaseContext(); 

    public void Init(HttpApplication context) 
    { 
     context.EndRequest += (sender, e) => this.DisposeContext(sender, e); 
    } 

    private static bool DoesRequestCompletionRequireDisposing(
     string requestPath) 
    { 
     string fileExtension = Path.GetExtension(requestPath) 
      .ToUpperInvariant(); 

     switch (fileExtension) 
     { 
      case ".ASPX": 
      case string.Empty: 
      case null: 
       return true; 
     } 

     return false; 
    } 

    private void DisposeContext(object sender, EventArgs e) 
    { 
     // This gets fired for every request to the server, but there's no 
     // point trying to dispose anything if the request is for (e.g.) a 
     // gif, so only call Dispose() if necessary: 
     string requestedFilePath = ((HttpApplication)sender).Request.FilePath; 

     if (DoesRequestCompletionRequireDisposing(requestedFilePath)) 
     { 
      this._context.Dispose(); 
     } 
    } 
} 

Następnie podłączyć moduł do żądania rurociągu tak (można umieścić go w system.Web i system.webServer więc to jest wliczone dla IIS i dev internecie VS serwer):

<system.web> 
    <httpModules> 
     <add name="ContextDisposer" 
      type="MyNamespace.ContextDisposer" /> 
    </httpModules> 
</system.web> 

<system.webServer> 
    <modules runAllManagedModulesForAllRequests="true"> 
     <add name="ContextDisposer" 
      type="MyNamespace.ContextDisposer" /> 
    </modules> 
</system.webServer> 
+0

Znalazłem kilka innych przykładów i wprowadziłem go ostatniej nocy. W istocie jest to to samo, co napisałeś tutaj i zdecydowanie stawiasz mnie na właściwej drodze. Dziękuję bardzo! – hylle

+0

Nie ma za co, chętnie pomożemy :) –

+0

Otrzymałem tylko kilka komunikatów o błędach dotyczących tego problemu od zeszłej nocy. Oto jeden z nich: Nowa transakcja jest niedozwolona, ​​ponieważ w sesji są uruchomione inne wątki. A oto druga: _Obiekt ObjectContext został usunięty i nie można go już używać do operacji wymagających połączenia. ten ostatni sugeruje jakiś leniwy problem z ładowaniem, ale ponieważ mam tylko jeden, nie sądzę, że jest zbyt poważny. – hylle

Powiązane problemy