1

I have found an issue with WebApi integration.

Sample project: https://github.com/VKrol/WebApplication19

Try to create a request to the "~/api/values", class Foo has been instantiated twice despite the fact that class Foo has been registered as InstancePerLifetimeScope. Please note that I resolve first instance in the Application_AcquireRequestState and the second has been injected in the ValuesController constructor. I think that this is a bug.

Thanks.

2 Answers2

3

The short version is: You're in a Web API project but you're trying to use the MVC dependency resolver. You haven't set up the MVC dependency resolver anywhere in the demo project.

When your event handler calls DependencyResolver.Current.GetService<Foo>(); it's going to use the default MVC dependency resolver, not Autofac.

public class WebApiApplication : HttpApplication {
  protected void Application_Start() {
    GlobalConfiguration.Configure(WebApiConfig.Register);

    var builder = new ContainerBuilder();
    var config = GlobalConfiguration.Configuration;
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    builder.RegisterType<Foo>().AsSelf().InstancePerLifetimeScope();

    var container = builder.Build();
    // Here's where the Web API resolver is set up...
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
  }

  protected virtual void Application_AcquireRequestState(object sender, EventArgs e) {
    // ...but this call is using the MVC dependency resolver!
    var foo = DependencyResolver.Current.GetService<Foo>();
  }
}

If you look at what the System.Web.Mvc.DependencyResolver.DefaultDependencyResolver does, it calls Activator.CreateInstance(type) on the type requested. In this case, your Foo type.

So - you will get two different instances because your dependency resolvers aren't set up correctly.

If you want to use the MVC dependency resolver, you're free to do that by setting it up per the documentation. Note that this will share the container, but not the request lifetime scope mechanism. If a Web API request comes in, it does not necessarily create a request lifetime scope in the same way as MVC so per-request dependencies will not work the way you think. There is a different mechanism to handle request lifetimes in Web API and that's also in the docs.

If you are using the non-OWIN Web API stuff, you can call GlobalConfiguration.Configuration.DependencyResolver to get the Web API dependency resolver, which you have set up with Autofac. You can't get the per-request scope from this, though, nor can you resolve per-request dependencies. But if you have to manually resolve a service, that's how you'd do it.

If you choose to switch to OWIN Web API, there is no global configuration or global dependency resolver. You'll then be forced to make use of the DependencyScope attached to a request message or make use of a mechanism like CommonServiceLocator.

Travis Illig
  • 23,195
  • 2
  • 62
  • 85
  • sir, i know it should be one another question but cant ask questions, if you dont mind, could you please tell me, why i should use "InstancePerLifetimeScope" as scope for domain event handlers? I have a working code with that scope, but without using a life time scope resolver(directly resolve over conteiner not over scope) cant find the concrete component of my abstract. I'm really confused and wondered why? When i check out services, there is still that concrete component there in services but as i said cant retrive it from there. – Ismail Yilmaz Sep 29 '16 at 16:33
0

I don't think this is a bug in Autofac.

LifeTimeScopes are dependant on the scope in which they were resolved. In your case, I think you are resolving Foo in two different scopes. In the application root scope (Application_AcquireRequestState) and in it's child scope (ValuesController). Autofac doesn't allow resolution from child scopes so both your request for services are resolved independently.

After commenting out the resolution in AcquireRequestState, I have added another class NClass to your project which requests for Foo and I see that Foo gets resolved only once as expected.

public class ValuesController : ApiController {
    private readonly Foo _foo;
    private NClass _nclass;

    public ValuesController(Foo foo,NClass nClass) {
        _foo = foo;
        _nclass = nClass;
    }

    public IEnumerable<string> Get() {
        return new[] { _foo.Id.ToString(),  _nclass.Id.ToString()};
    }
}
public class NClass
{
    private Foo _foo;
    public NClass(Foo foo) { _foo = foo; }
    public int Id { get  {  return _foo.Id; } set { } }
}
Community
  • 1
  • 1
su8898
  • 1,703
  • 19
  • 23