EntityFramework4.1とNinjectを使用するMVC3アプリケーションがあります。これは、PerRequestベースで(Ninjectからの)IUnitOfWork/DbContextを受け入れる標準のリポジトリパターンを使用します。
このWebサイトは、シングルユーザーテストで正常に機能しています。最近、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)
この問題の原因は、データベースを呼び出すためにDbContextにアクセスする必要があるMVCRoleProviderクラスを実装するカスタムRoleProviderがあるかどうか疑問に思っています。
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);
}
}
当初、DbContextが注入されたIStoreSecurityServiceのインスタンス(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;
}
なぜ接続状態がそんなに変化しているのかわかりません。
どんなアイデアでもありがたいです:)