我有一个使用 Entity Framework 4.1 和 Ninject 的 MVC3 应用程序。它使用标准存储库模式,该模式在 PerRequest 的基础上接受 IUnitOfWork/DbContext(来自 Ninject)。
该网站在单用户测试中运行良好。我们最近开始对 2 个以上的用户进行一些并发负载测试,并开始在某些请求中出现此错误:
连接未关闭。连接的当前状态是正在连接。
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 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, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
at System.Data.EntityClient.EntityConnection.Open()
at System.Data.Objects.ObjectContext.EnsureConnection()
at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Store.Security.StoreSecurityService.GetUserGroupRoles(String username) in C:\Dev\Store2\Trunk\Store.Security\StoreSecurityService.cs:line 57
at Store.Security.StoreSecurityService.GetRolesForUser(String username) in C:\Dev\Store2\Trunk\Store.Security\StoreSecurityService.cs:line 23
at Store.Security.StoreRoleProvider.GetRolesForUser(String username) in C:\Dev\Store2\Trunk\Store.Security\StoreRoleProvider.cs:line 37
at System.Web.Security.RolePrincipal.IsInRole(String role)
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext)
at System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext)
at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
我想知道这个问题是否是由实现 MVC RoleProvider 类的自定义 RoleProvider 引起的,该类需要访问 DbContext 才能调用数据库。
public class StoreRoleProvider : RoleProvider
{
public IStoreSecurityService StoreSecurityService { get; set; }
public StoreRoleProvider()
{
StoreSecurityService = DependencyResolver.Current.GetService(typeof(IStoreSecurityService));
}
public override string[] GetRolesForUser(string username)
{
return StoreSecurityService.GetRolesForUser(username);
}
}
最初,我们解析了一个 IStoreSecurityService 实例,该实例中注入了一个 DbContext (PerRequest),但我知道 RoleProvider 仅在应用程序启动时创建一次,因此 DbContext 将在请求结束时被处理掉。
我在构造函数中尝试了一个特定的实例,如下所示:
public StoreRoleProvider()
{
StoreSecurityService = new StoreSecurityService(new DbContext());
}
但这会产生类似的错误。
抛出错误的 linq 查询并不是特别困难......
public IEnumerable<string> GetRolesForUser(string username)
{
var roles = (from user in _dbContext.Set<User>()
join userRole in _dbContext.Set<UserRole>()
on user.Id equals userRole.IserId
join role in _dbContext.Set<Role>()
on userRole.RoleId equals role.Id
where user.UserName == username && !userRole.IsDeleted
select role.Name).ToList<string>();
return roles;
}
我不明白为什么连接状态变化如此之大。
任何想法将不胜感激:)