C# Autofac WCF集成-基于请求数据解决依赖关系
如何配置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
[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
创建一个扩展,以包含从消息中读取的信息。它有很多代码
如果你要做定制安装提供商,我建议你阅读卡洛斯·菲盖拉的博客:
谢谢@Alexandr。你的答案看起来很有效,我更喜欢它,而不是编写我自己的工厂。但是,我希望保持构造函数签名不变,因为更改它会破坏我的测试。我将此约束添加到问题中。我也不喜欢在同一个类中混合应用程序逻辑和依赖项解析。Wh您还有其他选择吗?哦,我没有检查元数据链接。给我一点时间。好的,读一下,类似的概念。到目前为止,这是最好的解决方案,但我并不喜欢。@jdarsie然后编写自己的工厂是唯一的解决方案。@jdarsie根据您的要求,您的构造函数参数是错误的。您的要求是
MyWcfService
在调用操作
之前不会知道它需要iSeries设备
的哪个实现。您当前的构造函数签名意味着MyWcfService
知道它在实例化时需要哪个实现。您可以巧妙地使用大量的框架位,但实际上,您的意图是通过Ale清楚地表达出来的xandr的解决方案。例如,如果第一次调用操作
需要TypeA
,但第二次调用需要TypeB,
,那么这个类做得不对。谢谢@ErnieL。我支持选项1。选项2听起来很酷,但我不想在每次发布新版本时修补Autofac。顺便说一句,我想为我的问题找出解决方案。几分钟后公布答案。