开发者

ExecuteReader requires open Connection. Current state: Broken

开发者 https://www.devze.com 2023-02-15 15:51 出处:网络
I\'m using StructureMap to inject a LINQ data context (DB class) into my repositories for read queries on a HTTP-context basis, which are queried via a service layer. Everything works fine for a few h

I'm using StructureMap to inject a LINQ data context (DB class) into my repositories for read queries on a HTTP-context basis, which are queried via a service layer. Everything works fine for a few hours until I get a "Broken" Connection ExecuteReader error (see below for full dump).

Write queries (not read queries) are wrapped in a using (var db = new DB()) {...} statement, which I don't think cause the problem.

I've added MultipleActiveResultSets=true; to my connection string, which seemed to solve the problem for a while, but the error returns until I recycle my application pool, which temporarily solves the problem. Presumably recycling the pool frees all the "broken" data contexes.

StructureMap is configured to inject a data context and repository for each HTTP context:

For<DB>().HttpContextScoped().Use(new DB());
For<IUserRepository>().HttpContextScoped().Use<SqlUserRepository>();

The data context is consumed by my user repository like so:

private DB _db;
public SqlUserRepository(DB db)
{
    _db = db;
}

which, in turn conveniently queries the data context like so:

public IQueryable<User> GetUsers()
{
    var users = from u in _db.Users
                select u; // omitted the rest
}

Which after a few hours ends up with this horrible error:

System.InvalidOperationException: ExecuteReader requires an open and available 
Connection. The connection's current state: Broken. at 
System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async) at 
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior 
runBehavior, Boolean returnStream, String method, DbAsyncResult result) at 
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior 
runBehavior, Boolean returnStream, String method) at 
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at 
System.D开发者_如何学Pythonata.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at 
System.Data.Common.DbCommand.ExecuteReader() at 
System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, 
IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] 
subQueries, Object lastResult) at 
System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, 
IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) at 
System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expressi
on query) at System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression 
expression) at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source) at 
MyApp.Data.SqlUserRepository.GetUser(String username) at 
MyApp.Services.BranchService.GetUser(String username) at 
MyApp.Controllers.BranchController.get_CurrentUser() at 
MyApp.Controllers.BranchController.OnActionExecuting(ActionExecutingContext filterContext) 
at 
System.Web.Mvc.Controller.System.Web.Mvc.IActionFilter.OnActionExecuting(ActionExecutingCon
text filterContext) at 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, 
ActionExecutingContext preContext, Func`1 continuation) at 
System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<>c__DisplayClassf.b__c() at 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext 
controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 
parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext 
controllerContext, String actionName)

How do I solve this? I really don't want to have to manually wrap every query in a using-statement.


It looks like you're unintentionally are creating a singleton of the Context:

For<DB>().HttpContextScoped().Use(new DB());

In order to create a new context per request, use this instead:

For<DB>().HttpContextScoped().Use(() => new DB());


I would just use a new DataContext for each repository unless you can't for some reason. See this question: Strange behaviour with StructureMap / ASP.MVC / Visual Studio / LinqToSql


Your GetUsers method is returning an IQueryable, meaning the data will not be retrieved from the database until something iterates over it. If you return the IQueryable, close your data reader, and then attempt to iterate over the data, you will get an error, because the connection is closed.


One reason for this would be that your connection could not be opening at all. What ever exception that is coming at the "SqlConnection.Open" statement is being suppressed. If the problem is not in your application it could be that server is unable to grant you a connection. Could be because of a connection leak in your app or in some other database hosted on the same server.

0

精彩评论

暂无评论...
验证码 换一张
取 消