[英]Autofac Wcf - Inject service depending on data within SOAP Request
I have a WCF Service with the following operation contract: 我有一个带有以下操作合同的WCF服务:
[OperationContract]
Response SearchEntities(Query query);
This operation takes a request that contains a specified Entity like so: 该操作接受一个包含指定实体的请求,如下所示:
[DataContract]
public class Query
{
[DataMember]
public string SearchTerm { get; set; }
[DataMember]
public string Entity { get; set; }
[DataMember]
public bool ExactMatch { get; set; }
}
Based on the value contained within the Entity
property, one the following properties is populated within this response: 根据
Entity
属性中包含的值,在此响应中填充以下属性之一:
[DataContract]
public class Response
{
[DataMember]
public List<Asset> Assets { get; set; }
[DataMember]
public List<Stage> Stages { get; set; }
[DataMember]
public List<Sector> Sectors { get; set; }
}
Terrible design, I know! 糟糕的设计,我知道! However.
然而。 I am using Autofac.Wcf as my service factory to inject dependencies.
我使用Autofac.Wcf作为服务工厂来注入依赖项。 Normally I would use a common Interface and Generics to determine a service to use based on the
Entity
value like so: 通常,我将使用通用的接口和泛型来基于
Entity
值确定要使用的服务,如下所示:
public interface IEntitySearch<T>
{
Response Search(Query query);
}
The above interface would have several implementations for each of the Lists within the response. 对于响应中的每个列表,上述接口都有几种实现。 Using a design pattern such as a service location I could determine which service to use (all of which inherit from
IEntitySearch<T>
, something like: 使用服务位置等设计模式,我可以确定要使用的服务(所有服务都继承自
IEntitySearch<T>
,类似:
public IEntitySearch ResolveSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
While this works, a more elegant solution (I believe) would be to customize the Autofac container per request for this particular operation, depending on the data contained within the request. 在这种情况下,一个更优雅的解决方案(我相信)是针对此特定操作的每个请求自定义Autofac容器,具体取决于请求中包含的数据。
IE: Before the WCF pipe line sends the request to the service implementation, is it possible to examine the request data and customize how the container resolves dependencies. IE:在WCF管道将请求发送到服务实现之前,可以检查请求数据并自定义容器如何解析依赖项。 That way I can avoid exposing dependency resolution within my service layer.
这样,我可以避免在服务层中公开依赖项解析。
Is this possible? 这可能吗?
If another DI library other than Autofac has a solution for this, I will happily change our DI framework. 如果Autofac以外的其他DI库对此有解决方案,我将很高兴更改我们的DI框架。
Thanks. 谢谢。
I haven't personally tried this but I think a direction you can go down is to combine: 我还没有亲自尝试过,但是我认为您可以选择的方向是结合起来:
OperationContext.Current
to get the current request message data. OperationContext.Current
获取当前请求消息数据。 IServiceImplementationDataProvider
for Autofac that tells Autofac which WCF interface to host for that request. IServiceImplementationDataProvider
,该参数告诉Autofac为该请求托管哪个WCF接口。 OperationContext.Current
. OperationContext.Current
切换支持服务。 You can see two examples of the IServiceImplementationDataProvider
by looking at the DefaultServiceImplementationProvider
- the one that works in Autofac WCF hosting by default; 通过查看
DefaultServiceImplementationProvider
可以看到IServiceImplementationDataProvider
的两个示例-默认情况下,该示例可在Autofac WCF托管中使用。 and MultitenantServiceImplementationDataProvider
, which is more about generating a proxy to enable multitenant WCF hosting. 和
MultitenantServiceImplementationDataProvider
,更多有关生成代理以启用多租户WCF托管。
While neither of these use OperationContext.Current
to determine the actual backing service, you can build on the ideas: 虽然这两个都不使用
OperationContext.Current
来确定实际的支持服务,但是您可以基于以下思想:
MultitenantServiceImplementationDataProvider
doesn't actually tie anything to a tenant or tenant ID; MultitenantServiceImplementationDataProvider
实际上并未将任何内容绑定到租户或租户ID。 it's only about that proxy. .svc
file specify a service interface rather than any individual concrete implementation since you'll be swapping out the implementation. .svc
文件中,指定服务接口而不是任何具体的实现,因为您将换出实现。 InstanceContextMode.PerCall
to ensure things get swapped out on a per request basis. InstanceContextMode.PerCall
以确保在每个请求的基础上交换出东西。 The registration might look something like this: 注册可能看起来像这样:
builder.Register(ctx => {
var context = OperationContext.Current;
var type = DetermineTypeFromContext(context);
return ctx.Resolve(type);
}).As<IMyServiceInterface>();
The Autofac WCF and Autofac Multitenant section on WCF may also help. WCF上的Autofac WCF和Autofac Multitenant部分也可能会有所帮助。
In my opinion you're trying to move your problem just to another place. 我认为您正在尝试将问题转移到另一个地方。 Why would making decision based on request at low-level WCF is better than switch in
SearchEntities
method? 为什么在低级WCF上基于请求进行决策比在
SearchEntities
方法中进行切换更好? It's much worse ;-) 更糟糕的是;-)
I would consider to use IEntitySearch
factory/provider eq IEntitySearchProvider
(it's not so much better but always). 我会考虑使用
IEntitySearch
工厂/提供程序eq IEntitySearchProvider
(虽然没有那么好,但总是如此)。
public interface IEntitySearch
{
bool IsMatchQuery(Query query);
Response Search(Query query);
}
// without service locator
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IEnumerable<IEntitySearch> _searchers;
public EntitySearchProvider(IEnumerable<IEntitySearch> searchers)
{
_searchers = searchers;
}
public IEntitySearch GetSearcher(Query query)
{
// last registered
return _searchers.LastOrDefault(i=>i.IsMatchQuery(query))
?? throw new NotSupportedException();
}
}
or 要么
public interface IEntitySearchProvider
{
IEntitySearch GetSearcher(Query query);
}
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IComponentContext _container;
public EntitySearchProvider(IComponentContext container)
{
_container = container;
}
public IEntitySearch GetSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
}
with 与
public class WcfService
{
private readonly IEntitySearchProvider _provider;
public WcfService(IEntitySearchProvider provider)
{
_provider = provider;
}
public Response SearchEntities(Query query)
{
var searcher = _provider.GetSearcher(query);
return searcher.Search(query);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.