Question

I have the following piece of code to build the dependencies:

private static void InitializeContainer(HttpConfiguration config)
{
    var builder = new ContainerBuilder();
    var controllers = AssemblyUtils.GetAssemblies(true);

    controllers.Add(Assembly.GetExecutingAssembly());

    builder.RegisterApiControllers(controllers.ToArray()).PropertiesAutowired();

    builder
        .RegisterAssemblyTypes(
            new List<Assembly>(AssemblyUtils.GetAssemblies(false))
            {
                Assembly.GetExecutingAssembly()
            }.ToArray())
        .Where(t =>
            t.GetCustomAttributes(typeof(IocContainerMarkerAttribute), false).Any() ||
            t.IsSubclassOf(typeof(HandlerAspectAttribute)) ||
            typeof(ICoreContract).IsAssignableFrom(t))
        .AsImplementedInterfaces().InstancePerDependency()
        .PropertiesAutowired().OwnedByLifetimeScope();

    var container = builder.Build();

    GlobalConfiguration.Configuration.DependencyResolver =
       new AutofacWebApiDependencyResolver(container);

    config.DependencyResolver =
        GlobalConfiguration.Configuration.DependencyResolver;
}

Handler:

public class ArchieveDocumentCommandHandler 
    : IHandler<ArchieveDocumentCommand>, IDisposable
{
    public IServiceMessageDispatcher Dispatcher { get; set; }
    public IDocumentRepository DocumentRepository { get; set; }
    public IFileSystemProvider FileSystemProvider { get; set; }
    public ICoreSettingRepository CoreSettingRepository { get; set; }

    public void Handles(ArchieveDocumentCommand message) { }

    public void Dispose() { }
}

But somehow Autofac is not calling the Dispose method in the object after the request has finished. I read about the lifetime scope, but since that in this case it is Autofac managing the scope, I can't understand what is going on.

Am I doing something wrong here?

UPDATE

public class CommandsController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Deliver()
    {
    ...

        var handler = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(ICommandValidator<>).MakeGenericType(message.GetType()));

        if (handler == null)
        {
            return new Dictionary<string, string>();
        }

        return (Dictionary<string, string>)handler.GetType()
            .InvokeMember("ValidateCommand", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, handler, new object[] { message });
    }
}

Also the autofac web api version I am using is: 3.1.1 Which also broke some exiting functionality:

A controller as such:

public class AProtectedReadModelController : ApiController
{ }

public class AssessmentController : AProtectedReadModelController
{
    [Route("queries/risk/assessment")]
    [HttpGet]
    public ProcessInitialScreenModel GetProcessInitialScreen()
    {
        return ...;
    }
}

is not loaded.

Was it helpful?

Solution

The challenge you're having is because you're trying to resolve objects right out of the DependencyResolver rather than using the request lifetime scope.

When you use Web API, the "request lifetime scope" is managed by the inbound request message. When you resolve something right from the root DependencyResolver it is getting resolved at the application/top level, not as part of the request. That's why you aren't seeing anything disposed - because the owning lifetime scope isn't getting disposed, because that owning lifetime scope is at the root level.

I have a long discussion about request lifetime scope as an answer to this question: Transitioning to AutofacWebApiDependencyResolver from MVC's DependencyResolver - Where is .Current?

While that other question talks about test scenarios, the answer to it still holds - if you need to manually resolve something (which I'd recommend against if possible - service location isn't that great), then you need to do so out of the request scope associated with the request message.

// In the controller...
var validatorType = typeof(ICommandValidator<>)
                      .MakeGenericType(message.GetType());
var handler = this.Request
                  .GetDependencyScope()
                  .GetService(validatorType);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top