Upgrade plugin from 3.30 to 3.40 - The operation cannot be completed because the DbContext has been disposed.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
9 years ago
Hi,

I have problem after I upgraded my plugin. I have some long running action that is running in separate thread and I periodically check her state from view.
In controller I call EngineContext.Current.Resolve my service. Inside my service I call this.categoryService.GetAllCategories and it throw exception

The operation cannot be completed because the DbContext has been disposed.

I expect that this is caused by LifeTimeScope but I do not how to fix it.

Best regards,
Rudolf
9 years ago
I am having the same issue.  Has anybody solved this?
9 years ago
Please share your plugin (with source code) and a complete list of steps to reproduce the issue
9 years ago
The same by me.
If you register in Autofac the IDbContext as SingleInstance() it'll never die but then you'll have an issues with not disposed Db data readers.
9 years ago
I have solved this problem.  I think that it is very specific to your individual plugin, but I will share what I did anyways.

Andrei, one question I did have is why are you using InstancePerLifetimeScope instead of InstancePerRequest?


3.30 State
In my plugin which I developed for 3.30 and was working correctly I registered all my domain entities as InstancePerHttpRequest (obviously this is obsolete in the version of Autofac that 3.40 uses).

In my plugin I use a FilterProvider and FilterActionAttribute which were in the same class and registered it like so:
         builder.RegisterType<FitmentsSearchActionFilter>().As<IFilterProvider>();

Then inside of that class I was searching for some conditions, basically specific methods, and then if I found what I was looking for I would do this:
         return new List<Filter> { new Filter(this, FilterScope.Action, 0) };

Where "this" is the ActionFilter itself.  Inside this same class I was injecting a plugin specific service.

3.40 State
After I upgrading I changed all the InstancePerHttpRequest to InstancePerLifetimeScope and then I was having issues in the FilterProvider/ActionFilter class.  Below is what I changed to make it work
1. Separated out the FilterProvider and ActionFilter into there own classes
2. Changed dependencyregister to the following for those 2 classes:

builder.RegisterType<FitmentFilterProvider>().As<IFilterProvider>()
                .InstancePerLifetimeScope();
builder.RegisterType<FitmentsSearchActionFilter>().As<FitmentsSearchActionFilter>();
builder.RegisterFilterProvider();
3. Then inside of the FilterProvider I would resolve the ActionFilter from the IoC container:

var fi = EngineContext.Current.ContainerManager.Container.Resolve<FitmentsSearchActionFilter>();

return new List<Filter> { new Filter(fi, FilterScope.Global, 0) };

After that everything started working correctly.  I hope this at least points someone in the right direction in their own code.
9 years ago
'var fi = EngineContext.Current.ContainerManager.Container.Resolve<FitmentsSearchActionFilter>();'
it works because each time your action gets called it resolves a *filter.

I develop wcf service as a plugin. In my case to make it work I use resolver for each client call. (in the method)
But I'd love to have it initialized once (of course via resolver) but once in parameterless constructor of the service which was working properly in 3.30.

For instance working version:
public ProductContext GetProduct(int id)
{
var repository = EngineContext.Current.ContainerManager.Resolve<IRepository<Core.Domain.Catalog.Product>>();
            var query = from p in repository.Table
                        where p.Id == id
                        select p;
var product = query.FirstOrDefault();
return product;
}

if to initialize 'repository' in constructor it's going to fail
9 years ago
Hi,
I have solved it similar way. I am resolving services inside my service using scope for sure.


using (var scope = EngineContext.Current.ContainerManager.Container.BeginLifetimeScope())
{
      this.ResolveDependency(scope);
}

protected override void ResolveDependency(ILifetimeScope scope)
{
      this.categoryService = this.Resolve<ICategoryService>(scope);
      this.urlRecordService = this.Resolve<IUrlRecordService>(scope);
}

protected T Resolve<T>(ILifetimeScope scope) where T : class
{
       return EngineContext.Current.ContainerManager.Resolve<T>(string.Empty, scope);
}



Rudolf
9 years ago
Hello,

Happened the same to us when using a plugin that worked in 3.30. We've tried rkotulan solution, and it has worked with some services, but we don't know exactly why it doesn't work with ProductService. Trying:

var productService = EngineContext.Current.ContainerManager.Resolve<IProductService>(string.Empty, scope);


Produces:

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested.
This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.)
Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.


Any idea about this?

Thanks!
9 years ago
Where are you trying to request IProductService?  Are you requesting it from an ActionFilterProvider or inside of a controller in your plugin?
9 years ago
We were resolving IProductService inside a class in our plugin, that performs a long task inside a thread. It is not the easiest context that I can imagine :).

We use a variety of services, and all of them should have the same instance of DbContext in order to mantain consistency. We tried rkotulan solution of opening a new Lifetime Scope, which works for all the services but ProductsService. I guess that some of the dependencies of the product service are not supported by this method.

This is the code:

(I removed EngineContext.Current.ContainerManager before .Resolve to make it easier to read)


var productTagService = Resolve<IProductTagService>(string.Empty, scope);
var productAttributesService = Resolve<IProductAttributeService>(string.Empty, scope);
var urlRecordService = Resolve<IUrlRecordService>(string.Empty, scope);
var pictureService = Resolve<IPictureService>(string.Empty, scope);
var categoryService = Resolve<ICategoryService>(string.Empty, scope);
var manufacturerService = Resolve<IManufacturerService>(string.Empty, scope);

var productService = Resolve<IProductService>(string.Empty, scope); //FAILS


Anyway, I've checked DependencyRegistrar in Nop.Web.Framework and ProductService is configured by InstancePerLifetimeScope, so I don't really get what is going on, as all my dependencies seems to be loaded in the same way.

Thanks!
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.