C# Autofac WCF集成-基于请求数据解决依赖关系

C# Autofac WCF集成-基于请求数据解决依赖关系,c#,wcf,autofac,C#,Wcf,Autofac,如何配置Autofac容器,使其根据操作参数(请求对象)的属性值解析WCF服务的依赖关系 例如,给定此数据契约 [DataContract] public class MyRequest { [DataMember] public bool MyBool { get; set; } } 此WCF服务 public class MyWcfService : IWcfService { private IService m_service; public MyWc

如何配置Autofac容器,使其根据操作参数(请求对象)的属性值解析WCF服务的依赖关系

例如,给定此数据契约

[DataContract]
public class MyRequest
{
    [DataMember]
    public bool MyBool { get; set; }
}
此WCF服务

public class MyWcfService : IWcfService
{
    private IService m_service;

    public MyWcfService(IService service)
    {
        m_service = service;
    }

    public virtual MyResponse Operation(MyRequest request) { }
}
而这些依赖性

public interface IService { }
public class TypeA : IService { }
public class TypeB : IService { }
如果MyBool等于true,我希望容器解析TypeA,否则解析TypeB。这个功能可用吗?我应该以不同的方式处理这个问题吗

限制条件:

  • 避免Autofac.Extras.Multitenant包是一个优势
  • 还需要保持服务构造函数的签名不变。(见下面我的答案)

    • 有几种方法可以实现这一点。其中一种方法是使用
      IIndex
      。它是一种内置的“查找”功能,可以根据密钥在服务实现之间进行选择。您可以在Autofac上找到更多信息。示例代码可能如下所示:

      // Register your dependency with a key, for example a bool flag
      builder.RegisterType<TypeA>().Keyed<IService>(true);
      builder.RegisterType<TypeB>().Keyed<IService>(false);
      
      // Your service could look like:
      public class MyWcfService
      {
          private readonly IIndex<bool, IService> _services;
      
          // Inject IIndex<Key,Value> into the constructor, Autofac will handle it automatically
          public MyWcfService(IIndex<bool, IService> services)
          {
              _services = services;
          }
      
          public virtual void Operation(MyRequest request)
          {
              // Get the service that you need by the key
              var service = _services[request.MyBool];
          }
      }
      
      //使用一个键(例如bool标志)注册依赖项
      builder.RegisterType().Keyed(true);
      builder.RegisterType().Keyed(false);
      //您的服务可能看起来像:
      公共类MyWcfService
      {
      私人只读索引服务;
      //将IIndex注入构造函数,Autofac将自动处理它
      公共MyWcfService(IIndex服务)
      {
      _服务=服务;
      }
      公共虚拟无效操作(MyRequest)
      {
      //通过钥匙获得您需要的服务
      var服务=_服务[request.MyBool];
      }
      }
      

      另一种方法是使用元数据特性。有关选项1-使用Autofac的详细信息:

      创建服务实例的Autofac实例提供程序不使用或传递操作的消息。这是Autofac中的示例。请注意,
      消息
      参数未使用

      public class AutofacInstanceProvider : IInstanceProvider
      {
          // lots of code removed...
      
          public object GetInstance(InstanceContext instanceContext, Message message)
          {
              if (instanceContext == null)
              {
                  throw new ArgumentNullException("instanceContext");
              }
              var extension = new AutofacInstanceContext(_rootLifetimeScope);
              instanceContext.Extensions.Add(extension);
              return extension.Resolve(_serviceData);
          }
      }
      
      因此,要使用现有的Autofac代码获得所需的行为,您需要使用构造函数注入以外的其他方法将依赖项注入到类中。这是合理的,但我同意“不喜欢它”的评论

      选项2-自定义安装提供程序:

      编写自定义WCF IInstanceProvider是一个合理的选择,但需要编写大量代码

      好消息是,这是一个很好的示例,您可以将实现插入Autofac

      坏消息是Autofac.Integration.WCF代码本身不使用依赖项注入。例如,
      AutofacDependencyInjectionServiceBehavior
      直接调用
      var instanceProvider=new AutoFacinInstanceProvider(\u rootLifetimeScope,\u serviceData)
      。因此,您必须实现对
      AutofacInstanceProvider
      AutofacDependencyInjectionServiceBehavior
      AutofacHostFactory
      ,以及更多功能的替换。然后,您需要为
      AutofacInstanceContext
      创建一个扩展,以包含从消息中读取的信息。它有很多代码

      如果你要做定制安装提供商,我建议你阅读卡洛斯·菲盖拉的博客:

    • WCF扩展性–用于良好的背景
    • WCF扩展性–搜索以WCF消息对象开头的部分只能“使用一次”。检查消息时,您需要遵循这些规则

    • 谢谢@Alexandr。你的答案看起来很有效,我更喜欢它,而不是编写我自己的工厂。但是,我希望保持构造函数签名不变,因为更改它会破坏我的测试。我将此约束添加到问题中。我也不喜欢在同一个类中混合应用程序逻辑和依赖项解析。Wh您还有其他选择吗?哦,我没有检查元数据链接。给我一点时间。好的,读一下,类似的概念。到目前为止,这是最好的解决方案,但我并不喜欢。@jdarsie然后编写自己的工厂是唯一的解决方案。@jdarsie根据您的要求,您的构造函数参数是错误的。您的要求是
      MyWcfService
      在调用
      操作
      之前不会知道它需要
      iSeries设备
      的哪个实现。您当前的构造函数签名意味着
      MyWcfService
      知道它在实例化时需要哪个实现。您可以巧妙地使用大量的框架位,但实际上,您的意图是通过Ale清楚地表达出来的xandr的解决方案。例如,如果第一次调用
      操作
      需要
      TypeA
      ,但第二次调用需要
      TypeB,
      ,那么这个类做得不对。谢谢@ErnieL。我支持选项1。选项2听起来很酷,但我不想在每次发布新版本时修补Autofac。顺便说一句,我想为我的问题找出解决方案。几分钟后公布答案。