DBContext has been disposed, Actionfilter

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

I am developing a plugin for nopcommerce. I want an actionfilter to check, if a condition is met. In case it is not it redirects to another page. To check this it creates an instance of a service of mine.

if (_testService == null)
                _testService = EngineContext.Current.ContainerManager.Resolve<ITestService>();


Inside the service I obtain a setting via the settingService provided by nopcommerce. The first time it hits the "OnActionExecuting" everything works fine, but for the second time I get an exception, that the DBContext has been disposed, while getting the setting from the database.

All my others changes work perfectly fine. Maybe I'm missing something for the actionfilter?

Anyone know anything about this? Any help would be greatly appreciated.

Thanks in advance!
7 years ago
You'll need to remove the constructors from the top of the class and use testService in this way:

var _testService = EngineContext.Current.ContainerManager.Resolve<ITestService>();


And change your DependencyRegistrar.cs to have .InstancePerLifetimeScope()

Hope this helps!
7 years ago
Hi,

I so not have service in the constructor. As far as I know the actionfilter does not get it's classes by Autofac. So what class in the DependencyRegistrar do I have to register like that?

Thanks in advance!
7 years ago
andreasdanek wrote:
Hi,
So what class in the DependencyRegistrar do I have to register like that?


    
public class DependencyRegistrar : IDependencyRegistrar
{
   public int Order
   {
      get
      {
         return 1;
      }
    }
   public void Register(ContainerBuilder builder, ITypeFinder typeFinder)
   {
       builder.RegisterType<TestService>().As<ITestService>().InstancePerLifetimeScope();
   }        
}
7 years ago
Hi Divyang,

I appreciate your help so far. Unfortunatly it didn't help and the context is still disposed. Maybe it helps if I show you what I've got so far.

So first of all I implemented an ActionFilter and the service like this:

builder.RegisterType<LicenceCheck>().As<IFilterProvider>();

builder.RegisterType<TestService>().As<ITestService>()
                .InstancePerLifetimeScope();


The ActionFilter itself looks like this:

public partial class LicenceCheck : ActionFilterAttribute, IFilterProvider
    {
        private ITestService _testService;

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            return new List<Filter>() { new Filter(this, FilterScope.Action, 0) };
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null || filterContext.HttpContext == null)
                return;

            HttpRequestBase request = filterContext.HttpContext.Request;
            if (request == null)
                return;

            string actionName = filterContext.ActionDescriptor.ActionName;
            if (String.IsNullOrEmpty(actionName))
                return;

            string controllerName = filterContext.Controller.ToString();
            if (String.IsNullOrEmpty(controllerName))
                return;

            if (filterContext.IsChildAction)
                return;
            
            if (_testService == null)
                _testService = EngineContext.Current.ContainerManager.Resolve<ITestService>();
            
            if (_testService.GetLicenceLevel() == 3)
            {
                var noLogonUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("TestLogin");
                filterContext.Result = new RedirectResult(noLogonUrl);
            }

            return;
        }
    }


Inside the TestService I've got my SettingService, which is automatically created via constructor. The method then just gets an encrypted setting from the database, decrypts it and returns the value.

private readonly ISettingService _settingService;

public int GetLicenceLevel()
        {
            string licencelevel = string.Empty;
                var cipherText = _settingService.GetSetting("licence.file");


This works for every first run, but after that the GetSetting method encounters the exception of DBContext has been disposed.

Hope this will get you better insight!

Greetings Andreas!
7 years ago
I'm not able to suspect the issue in your code, but there is the thing which I had done so far.

DI register:

builder.RegisterType<LicenceCheck>().As<IActionFilter>();
builder.RegisterType<MyFilterProvider>().As<IFilterProvider>();

builder.RegisterType<TestService >().As<ITestService>().InstancePerLifetimeScope();


ActionFilter:


public partial class LicenceCheck : ActionFilterAttribute, IActionFilter
{
  private readonly ITestService _testService = EngineContext.Current.Resolve<ITestService>();

  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
     if (filterContext == null || filterContext.HttpContext == null)
         return;

     HttpRequestBase request = filterContext.HttpContext.Request;
     if (request == null)
         return;

     string actionName = filterContext.ActionDescriptor.ActionName;
      if (String.IsNullOrEmpty(actionName))
          return;

     string controllerName = filterContext.Controller.ToString();
      if (String.IsNullOrEmpty(controllerName))
          return;

      if (filterContext.IsChildAction)
           return;

      if (_testService != null && _testService.GetLicenceLevel() == 3)
      {
           var noLogonUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("TestLogin");
           filterContext.Result = new RedirectResult(noLogonUrl);
      }

       return;
   }
}


FilterProvider:


    public class MyFilterProvider : IFilterProvider
    {
        private readonly IActionFilter _actionFilter = new LicenceCheck();

        public MyFilterProvider(IActionFilter actionFilter)
        {
            _actionFilter = actionFilter;
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            if ((actionDescriptor.ControllerDescriptor.ControllerType == typeof(Nop.Admin.Controllers.HomeController)) &&
                 actionDescriptor.ControllerDescriptor.ControllerName == "Home" && (actionDescriptor.ActionName.Equals("Index")))
            {
                return new[]
                      {
                          new Filter(_actionFilter, FilterScope.Action, null)
                        };
            }

            return new Filter[] { };
        }

    }    


If still you facing the issue then create a sample plugin, and gives us, I think it could be more better!
7 years ago
Try removing
  if (_testService == null)

i.e. always Resolve the service.
7 years ago
Hi New York,

I can't believe this already did the trick. I spent like a day figuring out what causes the error. Although I don't get why some parts of the objects should be disposed, while still in use. But I guess getting a new instance means no harm. Thank you for this and also a big thanks to Divyang for his great effort!

Keep it up.

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