2012-01-30 8 views
11

Espero que alguien me pueda ayudar con una solución al siguiente error. La aplicación en la que ocurre el error se está ejecutando en producción y nunca experimento el error. Sin embargo, alrededor de 20 veces al día recibo un mensaje de error que me dice:Ocasional "El proveedor subyacente falló en abrir" errores al usar EF4 (modelo de edmx)

El proveedor subyacente falló en Abrir. ---> System.InvalidOperationException: la conexión no se cerró. El estado actual de la conexión se está conectando.

Aquí está el seguimiento de la pila

System.Data.EntityException: El proveedor subyacente falló en Abrir. ---> System.InvalidOperationException: la conexión no se cerró. El estado actual de la conexión es la conexión. en System.Data.ProviderBase.DbConnectionBusy.OpenConnection (DbConnection outerConnection, DbConnectionFactory ConnectionFactory) en System.Data.SqlClient.SqlConnection.Open() en HibernatingRhinos.Profiler.Appender.ProfiledDataAccess.ProfiledConnection.Open() en System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf (Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, cadena ExceptionCode, cadena attemptedOperation, Boolean & closeStoreConnectionOnFailure) --- final de excepción seguimiento de la pila --- en System.Data .EntityClient.EntityConnection.OpenStoreConnectionIf (Booleano openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, Cadena ExceptionCode, Cadena attemptedOperation, Boolean & closeStoreConnectionOnFailure) en System.Data.EntityClient.EntityConnection.Open() en System.Data.Objects.ObjectContext.EnsureConnection() a System.Data.Objects.ObjectQuery forMergeOption) en System.Data.Objects.ObjectQuery fuente) a System.Data.Objects.ELinq.ObjectQueryProvider.b__1 [TResult] (IEnumerable consulta , Expresión queryRoot) en Sys tem.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute [S] (Expresión la expresión) a System.Linq.Queryable.FirstOrDefault [TSource] (fuente IQueryable`1)
en GuideSites.DomainModel .Repositories.ClinicTermRepository.GetClinicTermByGuideSiteId (Int32 guideSiteId) en C: \ Projects \ GuideSites \ GuideSites.DomainModel \ Repositories \ ClinicTermRepository.cs: línea de 20 en GuideSites.Web.Frontend.Helpers.VerifyUrlHelper.RedirectOldUrls() en C: \ Projects \ GuideSites \ GuideSites.Web.Frontend \ Helpers \ VerifyUrlHelper.cs: línea 91 en GuideSites.Web.Frontend.MvcApplication.Application_BeginRequest (Objeto remitente, EventArgs e) en C: \ Projects \ GuideSites \ GuideSites.Web.Frontend \ Global.asax.cs: línea 412 en System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute () en System.Web.HttpApplication.ExecuteStep (IExecutionStep paso, booleana & completedSynchronously)

utilizo EF4 a través de un modelo de EDMX y la forma en que conecto a la base de datos (MS SQL 2008) es a través de un contexto basado en HttpContext por solicitud objeto de modo que las conexiones a la base de datos no se abren y cierran por cada pieza de datos que necesito en una carga de página determinada.

Mi clase de contexto de base de datos tiene el siguiente aspecto:

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(); 
    } 

} 

En mis repositorios utilizo el contexto de la base de esta manera:

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); 
     } 
    } 
} 

El bloqueo (Lock) cosa era algo que leí acerca debería ayudar este problema, pero en mi caso no es así. Y en general ha sido difícil encontrar hilos que describan exactamente mi problema y mucho menos una solución al problema.

La aplicación es una aplicación ASP.NET MVC3 y está configurada como una aplicación que se ejecuta para 9 sitios web diferentes (el dominio determina el contenido para ser servido al cliente). Los 9 sitios web no tienen más de 2.000 páginas vistas diarias, por lo que la base de datos debe destacarse en esa cuenta.

Espero que alguien pueda ayudar y por favor avíseme si hay algo que olvidé mencionar.

+0

¿Qué llama a 'DatabaseContext.Dispose()'? Utilizo una configuración similar de 'HttpContext.Items' y tengo un' HttpModule' que se deshace del 'ObjectContext' al final de una solicitud ... –

+0

En realidad, pensé que' Dispose() 'se llamaba automáticamente desde que' DatabaseContext' implementa 'IDisposable'. Pero si no lo es, definitivamente podría explicar el error. ¿Podría echar un vistazo a su código en su 'HttpModule'? – hylle

Respuesta

1

Según mi comentario, Dispose() tiene que ser llamado por algo al final de la solicitud. Puede hacer esto con un HttpModule así:

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(); 
     } 
    } 
} 

A continuación, conectar el módulo en la canalización de solicitud como esta (que lo puso en system.web y system.webServer por lo que está incluido para IIS y la web dev VS servidor):

<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

Encontré algunos otros ejemplos y los implementé anoche. En esencia, es lo mismo que escribiste aquí y definitivamente me pusiste en el camino correcto. Así que muchas gracias! – hylle

+0

De nada, feliz de ayudar :) –

+0

He recibido solo unos pocos correos de error con respecto a este problema desde anoche. He aquí una de ellas: la transacción _New no está permitido porque hay otros subprocesos que se ejecutan en el session._ Y aquí está la otra: _El ObjectContext ejemplo ha sido dispuesto y ya no puede ser utilizado para operaciones que requieren un connection_ El Este último sugiere un problema de carga lenta pero dado que solo recibo uno, no creo que sea demasiado serio. – hylle

Cuestiones relacionadas