Using IAuthorizationFilter with Ninject and EF gives DbContext has been disposed error

老子叫甜甜 提交于 2019-12-07 07:49:39

问题


I'm trying to use my UnitOfWork inside an implementation of IAuthorizationFilter, but after I navigate between a few pages I get this exception:

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

FilterConfig.cs

filters.Add(DependencyResolver.Current.GetService(typeof(PermissionFilter)));

NinjectMappings.cs

public class NinjectMappings : NinjectModule
{
    public override void Load()
    {
        Bind<MyContext>().ToSelf().InRequestScope();
        Bind<IUnitOfWork>().To<UnitOfWork>();
    }
}

PermissionFilter.cs

public class PermissionFilter : IAuthorizationFilter
{
    public PermissionFilter(IUnitOfWork unitOfWork)
    {
        // etc...
    }
}

I was able to get around this with:

// NinjectMappings
Bind<IUnitOfWork>()
    .ToMethod(m => GetUnitOfWork())
    .WhenInjectedExactlyInto(typeof(PermissionFilter));

private IUnitOfWork GetUnitOfWork()
{
    return new UnitOfWork(new MyContext());
}

The problem now is that GetUnitOfWork is only called once, at app start. I tried alternating between InTransientScope and InRequestScope to no avail. So updates to the database are not retrieved, instead my UnitOfWork always returns the same data.

I have read quite a few questions dealing with DbContext has been disposed but none of them were implementing an IAuthorizationFilter.

What is the best way to solve this? I'd like to avoid new or using() inside the filter or using the Service Locator pattern.


回答1:


Your problem comes from the fact that your MyContext is instantiated in the scope of a request and is disposed at the end of the request.

To solve this avoiding new(), using, or ServiceLocator pattern, you may rely on a dedicated IFilterProvider

public class PermissionFilterProvider : IFilterProvider
{
    private readonly Func<PermissionFilter> _permissionFilterFactory = null;

    public PermissionFilterProvider(Func<PermissionFilter> filterFactory)
    {
        _permissionFilterFactory = filterFactory;
    }

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = new List<Filter>(); 

        // instantiate PermissionFilter action filter  
        filters.Add(new Filter(_permissionFilterFactory(), FilterScope.Action, 0));
        return filters;
    }
}

Your bindings would then be :

public class NinjectMappings : NinjectModule
{
    public override void Load()
    {
        Bind<MyContext>().ToSelf().InRequestScope();
        Bind<IUnitOfWork>().To<UnitOfWork>();
        Bind<IFilterProvider>().To<PermissionFilterProvider>();
        Bind<PermissionFilter>().ToSelf();
    }
}

Note that you will need an Ninject Factory extension like Ninject.Extensions.Factory to achieve the Func<PermissionFilter> factory pattern in PermissionFilterProvider constructor.

Also, I am not sure of the scope of your IUnitOfWork. Shouldn't it be the same as your MyContext ?



来源:https://stackoverflow.com/questions/35122561/using-iauthorizationfilter-with-ninject-and-ef-gives-dbcontext-has-been-disposed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!