使用EF4(edmx模型)时,偶尔"基础提供程序在打开时失败"错误

hyl*_*lle 13 c# edmx entity-framework-4 asp.net-mvc-3

我希望有人可以帮我解决以下错误.发生错误的应用程序正在生产中运行,我自己从未遇到错误.但是每天大约20次我收到一封错误邮件告诉我:

底层提供程序在Open上失败.---> System.InvalidOperationException:连接未关闭.连接的当前状态是连接.

这是堆栈跟踪

System.Data.EntityException:基础提供程序在Open上失败.---> System.InvalidOperationException:连接未关闭.连接的当前状态是连接.在System.Data.ProviderBase.DbConnectionBusy.OpenConnection(DbConnection outerConnection,DbConnectionFactory connectionFactory)的System.Data.SqlClient.SqlConnection.Open()处于System.Data.EntityClient的HibernatingRhinos.Profiler.Appender.ProfiledDataAccess.ProfiledConnection.Open()处. EntityConnection.OpenStoreConnectionIf(Boolean openCondition,DbConnection storeConnectionToOpen,DbConnection originalConnection,String exceptionCode,String attemptsOperation,Boolean&closeStoreConnectionOnFailure)---内部异常堆栈跟踪结束---在System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition,DbConnection storeConnectionToOpen ,DbConnection originalConnection,String exceptionCode,String attemptsOperation,Boolean&closeStoreConnectionOnFailure)System.Data.Object.EntityConnection.Open()at System.Data.Objects.ObjectContext.EnsureConnection()at System.Data.Objects.ObjectQuery 1.GetResults(Nullable1 forMergeOption)at System .Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 sour ce)System.Data.Objects.ELinq.ObjectQueryProvider.b__1 [TResult](IEnumerable 1 sequence) at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable1查询,Expression queryRoot)at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute [S](Expression expression)位于
C:\ Projects\GuideSites\GuideSites.DomainModel\Repositories\ClinicTermRepository.cs中的GuideSites.DomainModel.Repositories.ClinicTermRepository.GetClinicTermByGuideSiteId(Int32 guideSiteId)的System.Linq.Queryable.FirstOrDefault [TSource](IQueryable`1 source):line 20在GuideSites.Web.Frontend.Helpers.VerifyUrlHelper.RedirectOldUrls()在C:\项目\ GuideSites\GuideSites.Web.Frontend \助手\ VerifyUrlHelper.cs:线91在GuideSites.Web.Frontend.MvcApplication.Application_BeginRequest(对象发件人,EventArgs e)位于System.Web的System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()的C:\ Projects\GuideSites\GuideSites.Web.Frontend\Global.asax.cs:第412行.HttpApplication.ExecuteStep(IExecutionStep step,Boolean&completedS ynchronously)

我通过EDMX模型使用EF4,我连接数据库的方式(MS SQL 2008)是通过基于HttpContext的每请求对象上下文,因此不会为每一条数据打开和关闭数据库的连接我需要一个给定的页面加载.

我的数据库上下文类如下所示:

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

}
Run Code Online (Sandbox Code Playgroud)

在我的存储库中,我使用这样的数据库上下文:

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);
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

我读到的锁定(锁定)事情应该有助于解决这个问题,但在我的情况下却没有.通常很难找到描述我的问题的线程,更不用说解决问题了.

该应用程序是一个ASP.NET MVC3应用程序,它设置为一个运行9个不同网站的应用程序(该域确定要提供给客户端的内容).这9个网站每天的网页浏览量不超过2.000,因此应该在该帐户上强调数据库.

我希望有人可以提供帮助,如果有什么我忘记提及,请告诉我.

Ste*_*kes 1

根据我的评论,Dispose()必须在请求结束时通过某些内容进行调用。你可以这样做HttpModule

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,将模块插入到请求管道中,如下所示(将其放入 system.web 和 system.webserver 中,以便将其包含在 IIS 和 VS dev Web 服务器中):

<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>
Run Code Online (Sandbox Code Playgroud)