C# · 12月 31, 2021

c# – 使用EF4(edmx模型)时偶尔“底层提供程序无法打开”错误

我希望有人可以帮助我解决以下错误.发生错误的应用程序正在生产中运行,我从来没有经历过错误.不过每天大约20次我收到一封错误邮件告诉我:

The underlying provider Failed on Open. —>
system.invalidOperationException: The connection was not closed. The
connection’s current state is connecting.

这是堆栈跟踪

System.Data.EntityException: The underlying provider Failed on Open.
—> system.invalidOperationException: The connection was not closed. The connection’s current state is connecting. at
System.Data.ProviderBase.DbConnectionBusy.OpenConnection(DbConnection
outerConnection,DbConnectionFactory connectionFactory) at
System.Data.sqlClient.sqlConnection.open() at
HibernatingRhinos.Profiler.Appender.ProfiledDataAccess.ProfiledConnection.open()
at
System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean
openCondition,DbConnection storeConnectionToOpen,DbConnection
originalConnection,String exceptionCode,String attemptedOperation,
Boolean& closeStoreConnectionOnFailure) — End of inner exception
stack trace — at
System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean
openCondition,
Boolean& closeStoreConnectionOnFailure) at
System.Data.EntityClient.EntityConnection.open() at
System.Data.Objects.ObjectContext.EnsureConnection() at
System.Data.Objects.ObjectQuery1.GetResults(Nullable1
forMergeOption) at
System.Data.Objects.ObjectQuery1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1
source) at
System.Data.Objects.ELinq.ObjectQueryProvider.b__1[TResult](IEnumerable1
sequence) at
System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable1
query,Expression queryRoot) at
System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression
expression) at
System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at
GuideSites.DomainModel.Repositories.ClinicTermRepository.GetClinicTermByGuideSiteId(Int32
guideSiteId) in
C:\Projects\GuideSites\GuideSites.DomainModel\Repositories\ClinicTermRepository.cs:line
20 at
GuideSites.Web.Frontend.Helpers.VerifyUrlHelper.RedirectOldUrls() in
C:\Projects\GuideSites\GuideSites.Web.Frontend\Helpers\VerifyUrlHelper.cs:line
91 at
GuideSites.Web.Frontend.MvcApplication.Application_BeginRequest(Object
sender,EventArgs e) in
C:\Projects\GuideSites\GuideSites.Web.Frontend\Global.asax.cs:line 412
at
System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step,
Boolean& completedSynchronously)

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

在我的存储库中,我使用数据库环境,如下所示:

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

锁(Lock)的东西是我看过的,应该帮助这个问题,但在我的情况下,它没有.一般来说,很难找到描述我的问题的线索,更不用说解决问题了.

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

我希望有人可以帮忙,请让我知道,如果有一些我忘了提到.

解决方法 根据我的评论,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(); } }}

然后将模块插入到这样的请求管道中(您将其放入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>