首页 文章

Autofac Wcf - 根据SOAP请求中的数据注入服务

提问于
浏览
1

我有一个WCF服务,其中包含以下操作 Contract :

[OperationContract]
Response SearchEntities(Query query);

此操作采用包含指定实体的请求,如下所示:

[DataContract]
public class Query
{
    [DataMember]
    public string SearchTerm { get; set; }

    [DataMember]
    public string Entity { get; set; }

    [DataMember]
    public bool ExactMatch { get; set; }
}

根据 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; }
}

可怕的设计,我知道!然而 . 我使用Autofac.Wcf作为我的服务工厂来注入依赖项 . 通常我会使用一个通用的接口和泛型来确定一个基于 Entity 值的服务,如下所示:

public interface IEntitySearch<T>
{
    Response Search(Query query);
}

上面的接口将为响应中的每个列表提供多个实现 . 使用诸如服务位置之类的设计模式,我可以确定使用哪个服务(所有服务都继承自 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();
    }
}

虽然这有效,但更优雅的解决方案(我相信)将根据请求中包含的数据,针对此特定操作的每个请求自定义Autofac容器 .

IE:在WCF管道将请求发送到服务实现之前,是否可以检查请求数据并自定义容器如何解析依赖项 . 这样我就可以避免在服务层中暴露依赖项解析 .

这可能吗?

如果除了Autofac之外的另一个DI库有解决方案,我将很乐意改变我们的DI框架 .

谢谢 .

2 回答

  • 0

    我没有亲自试过这个,但我认为你可以采取的方向是:

    您可以通过查看DefaultServiceImplementationProvider看到 IServiceImplementationDataProvider 的两个示例 - 默认情况下在Autofac WCF托管中工作的那个 . 和MultitenantServiceImplementationDataProvider,这更多关于生成代理以启用多租户WCF托管 .

    虽然这些都不使用 OperationContext.Current 来确定实际的支持服务,但您可以 Build 在以下思路上:

    • 查看Autofac.Multitenant.Wcf实现 . 您可以按原样使用它 . 实例数据提供者的要点是WCF grab 了托管服务的具体类型,如果您尝试从其下面交换类型,则会出现错误 . 多租户支持通过创建代理类型来欺骗WCF,您的实现类型可以在代理下交换出来 . 请注意 MultitenantServiceImplementationDataProvider 仅仅是关于该代理的't actually tie anything to a tenant or tenant ID; it' .

    • .svc 文件中指定服务接口而不是任何单独的具体实现,因为您将交换实现 .

    • 使用lambda注册来确定您的实现 .

    • 确保您的服务是 InstanceContextMode.PerCall ,以确保根据请求换出内容 .

    注册可能如下所示:

    builder.Register(ctx => {
      var context = OperationContext.Current;
      var type = DetermineTypeFromContext(context);
      return ctx.Resolve(type);
    }).As<IMyServiceInterface>();
    

    WCF上的Autofac WCFAutofac Multitenant部分也可能有所帮助 .

  • 0

    在我看来,你正试图将你的问题转移到另一个地方 . 为什么根据低级别WCF的请求做出决策比切换 SearchEntities 方法更好?这更糟糕;-)

    我会考虑使用 IEntitySearch 工厂/提供商e.q. 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();
        }
    }
    

    要么

    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();
            }
        }
    }
    

    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);
        }
    }
    

相关问题