【问题标题】:Autofac WCF Integration - Resolve dependencies based on request dataAutofac WCF 集成 - 根据请求数据解决依赖关系
【发布时间】:2014-09-25 19:02:54
【问题描述】:

如何配置 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 包是一个优点。
  • 还需要保持服务构造函数的签名不变。(见下面我的回答)

【问题讨论】:

    标签: c# wcf autofac


    【解决方案1】:

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

    // 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];
        }
    }
    

    另一种方法是使用元数据功能。更多关于wiki page的信息。

    【讨论】:

    • 谢谢@Alexandr。你的答案看起来很有效,我更喜欢它而不是编写我自己的工厂。但是,我想保持构造函数签名不变,因为更改它会破坏我的测试。我将这个约束添加到问题中。而且我也不喜欢在同一个类中混合应用程序逻辑和依赖关系解析。您想到的其他选择是什么?
    • 糟糕,我没有检查元数据链接。给我几秒钟。
    • 好的,阅读它,类似的概念。到目前为止最好的解决方案,但我不喜欢它。
    • @jdarsie 那么编写自己的工厂是唯一的解决方案。
    • @jdarsie 根据您的要求,您的构造函数参数是错误的。您的要求是 MyWcfService 在调用 Operation 之前不会知道它需要哪个 IService 实现。您当前的构造函数签名意味着MyWcfService 知道它在实例化时需要哪个单一实现。你可以通过大量的框架位变得聪明,但实际上你的意图是使用 Alexandr 的解决方案清楚地传达的。例如,如果第一次调用Operation 需要TypeA,但第二次调用需要TypeB,,那么这个类就没有做正确的事情。
    【解决方案2】:

    选项 1 - 使用 Autofac:

    创建您的服务实例的 Autofac 实例提供程序不使用或传递操作的消息。这是 Autofac 中的latest implementation of the method。请注意message 参数未使用。

    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 代码获得所需的行为,您需要使用构造函数注入以外的方式将依赖项注入到您的类中,即@Alexandr Nikitin's solution。这是合理的,但我同意“不喜欢它”的评论。

    选项 2 - 自定义 IInstanceProvider:

    编写自定义的 WCF IInstanceProvider 是一个合理的选择,但它会包含很多代码。

    好消息是code in Autoface.Integration.WCF 是一个很好的示例,您可以将实现插入 Autofac。

    坏消息是 Autofac.Integration.WCF 代码本身并不使用依赖注入。比如AutofacDependencyInjectionServiceBehavior直接调用var instanceProvider = new AutofacInstanceProvider(_rootLifetimeScope, _serviceData)。因此,您必须实现AutofacInstanceProviderAutofacDependencyInjectionServiceBehaviorAutofacHostFactory 的替换,可能还有更多。然后,您需要为AutofacInstanceContext 创建一个扩展,以包含从消息中读取的信息。它的代码很多。

    如果您要自定义 IInstanceProvider,我建议您阅读 Carlos Figueira 的博客:

    1. WCF 可扩展性 - IInstanceProvider - 良好的背景
    2. WCF 可扩展性 - Message Inspectors - 搜索以 WCF 开头的部分 消息对象只能“使用一次”。检查消息时需要遵循这些规则。

    【讨论】:

    • 谢谢@ErnieL。我支持选项 1。选项 2 听起来很酷,但我不想每次发布新版本时都修补 Autofac。顺便说一句,我找到了解决问题的方法。几分钟后发布答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多