Sharprepository Autofac InstancePerApiRequest in Webapi environment not working

1.5k Views Asked by At

Does anyone have a working example of sharprepository intergration with autofac using InstancePerApiRequest for DbContext?

I am registering my dbcontext thusly:

builder.RegisterType<AuditTestEntities>().As<DbContext>().InstancePerApiRequest();

If I remove the InstancePerApiRequest, sharprepository is able to get a dbcontext. But with the InstancePerApiRequest, I get the error message pasted below. Basically the crux of the error is, I suspect, the way sharprepository makes the call:

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.

The full error stack:

iisexpress.exe Error: 0 : Operation=DefaultHttpControllerActivator.Create, Exception=System.InvalidOperationException: An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor. ---> Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor()' on type 'AccountRepository'. ---> Could not resolve type 'System.Data.Entity.DbContext' using the 'AutofacDependencyResolver'. Make sure you have configured your Ioc container for this type. View the InnerException for more details. (See inner exception for details.) ---> SharpRepository.Repository.Ioc.RepositoryDependencyResolverException: Could not resolve type 'System.Data.Entity.DbContext' using the 'AutofacDependencyResolver'. Make sure you have configured your Ioc container for this type. View the InnerException for more details. ---> Autofac.Core.DependencyResolutionException: 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.

2

There are 2 best solutions below

9
Jeff Treuting On

Okay found the issue. There is a problem with using the SharpRepository AutofacDependencyResolver when using the MVC or Web API integration and trying to use the scope InstancePerApiRequest or InstancePerHttpRequest. Autofac expects those items to be resolved from the System.Web.DependencyResolver.Current instead of from the Autofac IContainer directly as the AutofacDependencyResolver is currently doing.

Here is how you can fix the issue right now until we make an overload for AutofacDependencyResolver that fixes the issue.

You will need to create your own dependency resolver within your project like this one:

public class CustomAutofacDependencyResolver : BaseRepositoryDependencyResolver
{
    private readonly IDependencyResolver _resolver;

    public CustomAutofacDependencyResolver(IDependencyResolver resolver)
    {
        _resolver = resolver;
    }

    protected override T ResolveInstance<T>()
    {
        return _resolver.GetService<T>();
    }

    protected override object ResolveInstance(Type type)
    {
        return _resolver.GetService(type);
    }
}

And then register it with SharpRepository so it will use it to resolve the DbContext and then it will work as expected.

RepositoryDependencyResolver.SetDependencyResolver(new CustomAutofacDependencyResolver(DependencyResolver.Current));

** Update** I was testing with MVC and able to replicate the error and fix it but that doesn't work with Web API. I am used to using StructureMap where it works fine using the GlobalConfiguration.Configuration.DependencyResolver.

It seems the issue is that Autofac needs a IDependencyScope that you can access from the HttpRequestMessage but I'm not seeing a way to get to that outside of the ApiController. This describes the issue and the reason: https://groups.google.com/forum/#!msg/autofac/b3HCmNE_S2M/oMmwFE5uD80J

Unfortunately right now I'm at a bit of a loss on the best way to handle this. But I'll keep thinking about it.

1
kirkpabk On

So, I was able to get mine working by changing the lifetime scope to InstancePerLifetimeScope. I don't know whether this has any unforeseen consequences or not. Everything appears to be working fine for me so far.