C# 温莎城堡-将解析参数传递给下层

C# 温莎城堡-将解析参数传递给下层,c#,asp.net-web-api,inversion-of-control,castle-windsor,C#,Asp.net Web Api,Inversion Of Control,Castle Windsor,我有一个web api项目,其中控制器依赖于某个存储层。例如。 每个控制器都有类似的代码: public class ResourceController : ApiController { private readonly IResourceStorage _resourceStorage; private readonly IOtherStorage _otherStorage; public ResourceController(IResourceStorage

我有一个web api项目,其中控制器依赖于某个存储层。例如。 每个控制器都有类似的代码:

public class ResourceController : ApiController
{
    private readonly IResourceStorage _resourceStorage;
    private readonly IOtherStorage _otherStorage;


    public ResourceController(IResourceStorage resourceStorage, IOtherStorage otherStorage)
    {
       _resourceStorage = resourceStorage;
       _otherStorage = otherStorage;
    }

    // Web API Actions
}
存储的通用代码如下所示:

public class ResourceStorage : DBProvider, IResourceStorage
{
    public ResourceStorage(string connectionString) : base(connectionString)
    {
    }

    // storage methods  
}
基于Web Api请求的某些特定条件,我需要能够将不同的连接字符串注入控制器的存储器。伪代码可能如下所示:

public class WindsorControllerActivator : IHttpControllerActivator
{
   public IHttpController Create(
      HttpRequestMessage request,
      HttpControllerDescriptor controllerDescriptor,
      Type controllerType)
   {
      string connectionString = ChooseDbConnectionStringBasedOnRequestContext(request);

      var controller =
         (IHttpController)_container.Resolve(connectionString, controllerType, new {databaseType = connectionString});

      request.RegisterForDispose(
         new Release(
            () => _container.Release(controller)));

      return controller;
   }
}
我不知道如何以破坏性较小的方式将参数传递到存储器:)

我试过什么?备选方案:

  • 将参数作为Castle Windsor附加参数传递,并在下一层中使用DynamicParameters处理它。参数获取控制器层,但我找不到方法将其获取到存储-它有自己的CreationContext,我找不到方法将其从控制器传递到存储
  • 拥有N个(等于连接字符串的数量)容器,并在ControllerActivator内选择其中一个容器。这似乎是一个巨大而丑陋的解决方案,完全不灵活,但它是有效的
  • 创建N组控制器,每个控制器都有自己的名称,并在存储动态参数内部检查处理程序的组件名称并选择连接字符串。从控制器激活器将钥匙传递到正确的控制器组。也很难看——控制器注册太多,管道代码太多

  • 您可以使用工厂模式:

    然后简单地


    我找到的解决方案是引入连接字符串提供程序:

    public interface IConnectionStringProvider
    {
      string ConnectionString { get; }
    }
    
    使用工厂方法根据web请求注册此提供程序时:

     kernel.Register(
        Component.For(typeof (IConnectionStringProvider))
                 .ImplementedBy(typeof (ConnectionStringProvider))
                 .UsingFactoryMethod(
                    (k, context) =>
                       new ConnectionStringProvider(context.AdditionalArguments["connectionString"].ToString()))
                 .LifestylePerWebRequest());
    
    在控制器激活器中,首先使用正确的参数解析连接字符串提供程序,然后解析控制器:

     // The lifecycle of connection string provider if per web request.
     // We resolve it first time with the correct parameters,
     // so it is injected with the correct connection string throught the lifecycle of the request.
     _container.Resolve<IConnectionStringProvider>(new {connectionString});
    
     var controller =
        (IHttpController) _container.Resolve(controllerType);
    
    //连接字符串提供程序的生命周期(如果为每个web请求)。
    //我们用正确的参数第一次解决它,
    //因此,在请求的整个生命周期中,它都被注入了正确的连接字符串。
    _Resolve(新的{connectionString});
    无功控制器=
    (IHTTP控制器)\ u容器解析(控制器类型);
    

    它仍然不完美,看起来有点粗糙,但它允许保持对底层接口的依赖性,并且需要对我发现的解决方案中的代码库进行更少的更改

    可以肯定,它的侵入性要小得多。谢谢你的建议。我在这里仍然看到两个问题:1)必须为所有控制器提供额外的参数StorageFactory(它可以是通用的,但还有一个参数),2)必须在分配每个存储之前调用create,这也是一种侵入性的。我不会将你的答案标记为已被接受,并希望有人有一个更自然的解决方案,例如,工厂是否可以用于注射某种类型的电子注册注射?
     kernel.Register(
        Component.For(typeof (IConnectionStringProvider))
                 .ImplementedBy(typeof (ConnectionStringProvider))
                 .UsingFactoryMethod(
                    (k, context) =>
                       new ConnectionStringProvider(context.AdditionalArguments["connectionString"].ToString()))
                 .LifestylePerWebRequest());
    
     // The lifecycle of connection string provider if per web request.
     // We resolve it first time with the correct parameters,
     // so it is injected with the correct connection string throught the lifecycle of the request.
     _container.Resolve<IConnectionStringProvider>(new {connectionString});
    
     var controller =
        (IHttpController) _container.Resolve(controllerType);