0

We have a web application in MVC 4 with Entity Framework 6.1 and using unity as DI framework,When we send many request to a page we got these errors:"The connection's current state is open" or somtimes "The underline provider failed to open" I think it should cause by using one instance of UnitOfWork or DbContex by multiple thread,But we check this and didn't find any thing wrong,Here are our codes

///////////////////////////////////////////////////////////////DatabaseFactory///////////////////////////////////////////////////////////////

public class DatabaseFactory : Disposable, IDatabaseFactory
{
    private MyDbContext dataContext;

    public MyDbContext Get()
    {
    var context=     dataContext ?? (dataContext = new MyDbContext());
        return context;
    }

    protected override void DisposeCore()
    {
        var dataContextAdapter = dataContext as IObjectContextAdapter;
        if (dataContextAdapter != null && dataContextAdapter.ObjectContext.Connection.State == ConnectionState.Open)
            dataContextAdapter.ObjectContext.Connection.Close();
        if (dataContext != null)
            dataContext.Dispose();

        }
}

///////////////////////////////////////////////////////////////UnitOfWork///////////////////////////////////////////////////////////////

public class UnitOfWork :Disposable, IUnitOfWork
{
    private readonly IDatabaseFactory databaseFactory;
    private MyDbContext dataContext;
    private LogContext logContext;
    public UnitOfWork(IDatabaseFactory databaseFactory)
    {
        this.databaseFactory = databaseFactory;

    }

    protected override void DisposeCore()
    {
        var dataContextAdapter = dataContext as IObjectContextAdapter;
        if (dataContextAdapter != null && dataContextAdapter.ObjectContext.Connection.State==ConnectionState.Open)
            dataContextAdapter.ObjectContext.Connection.Close();
         if (dataContext != null)
            dataContext.Dispose();
        if (databaseFactory != null)
            databaseFactory.Dispose();

    }

    protected MyDbContext DataContext
    {
        get { return  (dataContext = databaseFactory.Get()); }
    }

    public bool Commit()
    {
        try
        {
            DataContext.SaveChanges();
            return true;
        }
        catch (Exception)
        {
            return false;
        }

    }

}

///////////////////////////////////////////////////////////////RepositoryBase///////////////////////////////////////////////////////////////

    public abstract class RepositoryBase<T> : Disposable where T : class
    {
        private MyDbContext dataContext;
        private readonly IDbSet<T> dbset;
        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.Set<T>();
        }
        protected override void DisposeCore()
        {
            var dataContextAdapter = dataContext as IObjectContextAdapter;
            if (dataContextAdapter != null && dataContextAdapter.ObjectContext.Connection.State == ConnectionState.Open)
                dataContextAdapter.ObjectContext.Connection.Close();

            if (dataContext != null)
                dataContext.Dispose();

        }
        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        protected MyDbContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }

        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).ToList();
        }
    }

///////////////////////////////////////////////////////////////UnityRegisterTypes///////////////////////////////////////////////////////////////

    public static void RegisterTypes(IUnityContainer container)
    {

        container.RegisterType<IDatabaseFactory, DatabaseFactory>(new HttpContextLifetimeManager<IDatabaseFactory>())
            .RegisterType<IUnitOfWork, UnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>())
            .RegisterType<IMyDbContext, MyDbContext>(new HttpContextLifetimeManager<IMyDbContext>())
           .RegisterType(typeof(IRepository<>), typeof(RepositoryBase<>))

            //Orders
            .RegisterType<IOrdersRepository, OrdersRespository>(new HttpContextLifetimeManager<IOrdersRepository>())
            .RegisterType<IOrdersService, OrdersService>(new HttpContextLifetimeManager<IOrdersService>())
            //Orders 
            ....
  }

Any advice and suggestions will be greatly appreciated

  • Would recommend to use same DataContext throughout the lifecycle. In your code, it seems you are trying to close and then open the connection again using context. When multiple users access the site, it will cause parallel connections and you will get the error you are facing. – Sanket Tarun Shah Sep 23 '14 at 09:02
  • You might want to change the DbContext Unity registration to use PerRequestLifeTimemanager. That way you context will be created and disposed per request. I don't think you need the DisposeCore code either, because DbContext implements IDisposable. Let Unity do the work for you. Here is more info: http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why – tranceporter Sep 23 '14 at 09:03
  • Sanket Shah if you mean this code " if (dataContextAdapter != null && dataContextAdapter.ObjectContext.Connection.State == ConnectionState.Open) dataContextAdapter.ObjectContext.Connection.Close(); if (dataContext != null)" we didn't open connection manually anywhere this code just added due to our testing around this problem – user3333426 Sep 23 '14 at 09:05

2 Answers2

0

In my opinion, it's this line of code which is causing issues for you:

.RegisterType<IMyDbContext, MyDbContext>(new HttpContextLifetimeManager<IMyDbContext>())

We have similar issues in our code, becuase DbContext is not thread-safe, but sharing it between different requests is generally not a good idea. Instead we did this, and we have not had any connection issues:

.RegisterType<IMyDbContext, MyDbContext>(new PerRequestLifetimeManager())

This way a new instance of your context would be created per request. Also, DbContext implements IDisposable, so if you wanted to manually control the instantiation and disposal of your DbContext then you could simply do:

using (var context = new MyDbContext())
{
}
tranceporter
  • 2,241
  • 1
  • 21
  • 23
  • I changed the DbContext Creationtype to .RegisterType(new PerRequestLifetimeManager()) and aslo remove disposeCore But nothing changed, I don't know from where a DbContext object in our application could be accessed by multiple threads – user3333426 Sep 23 '14 at 10:01
  • All you need to do is create a Context class which inherits from DbContext, and then wire up unity registration. You do not need any of the database factory code. Make the Context implement an empty interface and inject that into the repository. Like public class TaskContext : DbContext, ITaskContext, and then inject ITaskContext into your repository. Your Context class will contain all the DbSet for the tables you need. – tranceporter Sep 23 '14 at 10:12
  • While generating the Edmx you would have given a name to you connection string. that gets into the app config of the project with the Entity. Have you copied the same connection string to your main Config file. Also the Name should be same as which you have given while generating the EDMX file. – tranceporter Sep 24 '14 at 08:13
  • I have found the problem and post it on top of this page,Please check it – user3333426 Sep 24 '14 at 10:06
0

I found the problem,We have a CustomFilterAttribute as shown below:

public class CustomFilters : ActionFilterAttribute
{

    [Dependency]
    public ICustomersService CustomersService { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)

if I remove this filter and override OnActionExecuting in controlller then it will work with no problem

We are using this provider to inject types into filters

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
    private IUnityContainer _container;

    public UnityFilterAttributeFilterProvider(IUnityContainer container)
    {
        _container = container;
    }

    protected override IEnumerable<FilterAttribute> GetControllerAttributes(
        ControllerContext controllerContext,
        ActionDescriptor actionDescriptor)
    {

        var attributes = base.GetControllerAttributes(controllerContext,
            actionDescriptor);
        foreach (var attribute in attributes)
        {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable<FilterAttribute> GetActionAttributes(
        ControllerContext controllerContext,
        ActionDescriptor actionDescriptor)
    {

        var attributes = base.GetActionAttributes(controllerContext,
            actionDescriptor);
        foreach (var attribute in attributes)
        {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

And we use this as below

        var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
        FilterProviders.Providers.Remove(oldProvider);
        var container = new UnityContainer();
        var provider = new UnityFilterAttributeFilterProvider(container);
        FilterProviders.Providers.Add(provider);
        UnityConfig.RegisterTypes(container);
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

We also change all of our type registering with "PerrequestLifeTimeManager" and nothing changed,what's wrong with this ?

  • That ICustomerService dependency on the filter. Is that getting correctly injected? That might be stopping the filter from being instantiated. – tranceporter Sep 24 '14 at 10:17
  • Yes it will be injected and the filters works but the only thing may occurre is this that it won't be inject by new instance on every request and cause these errors: the underline provider failed to open , the connection current state is open... I don't know why this should happen while i set every type to be injected on "PerrequestLifeTimeManager" ! – user3333426 Sep 24 '14 at 10:39
  • Try creating a customer service property in the filter and use DependencyResolver.Resolve instead and see if it helps? Or instead of using DI, just create a normal instance (var customerService = new CustomerService()) and see if it that helps? We need to narrow it down. – tranceporter Sep 24 '14 at 11:10
  • customerService = new CustomerService()) will solve the problem but we don't instance it manually we want to do it by unity like anywhere in our application – user3333426 Sep 24 '14 at 11:28
  • In our case, the cod to remove and add filterProvider is in UnityWebActivator class under App_Start of our web project. That class is automatically added when you install Unity3.Mvc nuget package. It works in our case. However we are using DependencyResolver.Current.GetService(); – tranceporter Sep 24 '14 at 12:53