InstancePerApiControllerType not working

2019-08-14 03:51发布

I am attempting to configure a web service with Autofac so that I can map a different connection context for each controller:

// database connections
container.Register(c => new DocumentControllerActivator()).As<IHttpControllerActivator>().InstancePerApiControllerType(typeof(DocumentController));
container.Register(c => new WorkflowControllerActivator()).As<IHttpControllerActivator>().InstancePerApiControllerType(typeof(WorkflowController));

and:

public class WorkflowControllerActivator : IHttpControllerActivator
{
    // snip...
    var connectionString = "workflow connection string";

    var container = new ContainerBuilder();

    container.Register(c =>
    {
        var newConnectionContext = new SqlServerConnectionContext(connectionString) {ProductID = productId};
        newConnectionContext.Open();

        return newConnectionContext;
    }).As<ISqlServerConnectionContext>().As<IConnectionContext>().InstancePerApiRequest();

    var dr = (AutofacWebApiDependencyResolver)GlobalConfiguration.Configuration.DependencyResolver;
    container.Update(dr.Container.ComponentRegistry);

    return (IHttpController)request.GetDependencyScope().GetService(typeof(WorkflowController));
}

The DocumentControllerActivator differs only in the connection string the the return object type.

[AutofacControllerConfiguration]
public class WorkflowController : ApiController

When I attempt to access the service, the DocumentController throws an error saying that "Unable to cast object of type 'SearchService.Controllers.WorkflowController' to type 'SearchService.Controllers.DocumentController'." It's as if the second InstancePerApiControllerType registration is overwriting the first (i.e. it is doing it for all controllers).

Any suggestions where I've gone wrong? Or, an alternate solution? (Other than a service locator pattern in each controller.)

1条回答
淡お忘
2楼-- · 2019-08-14 04:29

Not sure why the ControllerActivator approach isn't working, but a simpler and less web api stack specific alternative could be:

public interface ISqlServerConnectionContextFactory
{
  ISqlServerConnectionContext Create();
}

// Register this with your ContainerBuilder
public class SqlServerConnectionContextFactory : ISqlServerConnectionContextFactory
{
  private string _connectionString;

  public SqlServerConnectionContextFactory(string connectionString)
  {
    _connectionString = connectionString;  
  }

  public ISqlServerConnectionContext Create()
  {
    var connectionContext = new SqlServerConnectionContext(_connectionString);
    connectionContext.Open();
    return connectionContext;
  }
}

public class MyController : ApiController
{
  private ISqlServerConnectionContext _sqlServerConnectionContext;

  public MyController(Func<string, ISqlServerConnectionContextFactory> connectionFactory)
  {
    _sqlServerConnectionContext = connectionFactory("MyConnectionString");
  }
}

See http://nblumhardt.com/2010/01/the-relationship-zoo/ for more information about AutoFac relationships and auto generated factories

In this case, when the AutoFac Container sees the Func parameter, it passes in a delegate that acts as a factory method that returns a ISqlServerConnectionContextFactory and passes the string through to its constructor. AutoFac really is rather clever!

查看更多
登录 后发表回答