xZ6a33YaYEfmv
xZ6a33YaYEfmv

Reputation: 1816

New instance of IAuthorizationFilter for each request

After I started to use DI in filters I am getting the next EF exception:

A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.

I'm using Unity as my IoC container. My setup looks like this:

config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);

var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();

//adding IFilterProvider provided by Unity
GlobalConfiguration.Configuration.Services.Add(
    typeof(IFilterProvider),
    new UnityActionFilterProvider(UnityConfig.GetConfiguredContainer()));

var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);

//removing default IFilterProvider
GlobalConfiguration.Configuration.Services.Remove(
    typeof(IFilterProvider),
    defaultprovider);

Then I'm registering my filter for authorization like this:

var authFilter = config.DependencyResolver.GetService(typeof(MyFilterType));
config.Filters.Add((MyFilterType)authFilter);

My authorization filter looks like this:

public class MyFilterType : IAuthorizationFilter
{
    private readonly MyServiceInterfaceType _service;

    public MyFilterType(MyServiceInterfaceType service)
    {
        _service = service;
    }

    public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> continuation)
    {
        var res = await _service.SomeAction();

        //the rest doesn't matter
    }
}

MyServiceInterfaceType internally aggregates MyRepositoryInterfaceType. So it's just usual Service-Repository pattern. Inside MyRepositoryInterfaceType EF context is initialized.

So, about exception. I know what it means - there are concurrent async calls to the context. I think it's because of these two lines:

var authFilter = config.DependencyResolver.GetService(typeof(MyFilterType));
config.Filters.Add((MyFilterType)authFilter);

Filter instance is stored in, basically, singleton. So, every filter call is served by the same EF context instance which is why there are exceptions.

(Please correct me if I am somewhere wrong with this.)

My question is: Is it possible to create new instance of my MyFilterType filter for each call to avoid these exceptions?

Upvotes: 0

Views: 470

Answers (1)

Keith Rousseau
Keith Rousseau

Reputation: 4485

You will need to do service location inside of your method.

var requestScope = actionContext.Request.GetDependencyScope();
var myService = requestScope.GetService(MyServiceInterfaceType) as MyServiceInterfaceType;

Autofac has their own filters that you could use if you were using it instead of Unity, but I don't think Unity provides anything similar. The Autofac docs provide a pretty good explanation of the situation: http://docs.autofac.org/en/latest/integration/webapi.html#provide-filters-via-dependency-injection

Upvotes: 1

Related Questions