c# - 消除工厂中的 IoC 容器耦合

标签 c# asp.net-mvc solr autofac solrnet

我在一个 Web 应用程序下运行多个多语言“网站”。每个“语言环境”都有自己的 Solr 核心(在所有语言环境中具有相同的字段)。我正在使用 SolrNet 执行搜索查询。

为了根据每个请求切换核心,我注册了 ISolrOperations<SearchResult>命名实例在每个语言环境的 Autofac 容器中(对于那些不熟悉 SolrNet 的人来说,这实际上是我出于查询目的进入库的入口点)。

然后我有一个ISearchService界面,具有具体SolrSearchService实现,其构造函数签名如下所示:

public SolrSearchService(ISolrOperations<SearchResult> solr)

为了根据每个请求动态切换核心,我的 Controller 采用(注入(inject))ISearchServiceFactory而不是简单地 ISearchService 。我的SolrSearchServiceFactory看起来像这样:

public class SolrSearchServiceFactory : ISearchServiceFactory
{
    private readonly IComponentContext _ctx;

    public SolrSearchServiceFactory(IComponentContext ctx)
    {
        _ctx = ctx;
    }

    public ISearchService Create(string id)
    {
        var result = _ctx.ResolveNamed<ISolrOperations<SearchResult>>(id);
        return new SolrSearchService(result);
    }
}

id只是区域设置标识符。为了将 Autofac 与我的服务/ Controller 解耦,但保持每个请求切换核心的能力(基于 Controller 中执行的逻辑),这是我所能做到的最好的结果。

但是,我对此仍然不太满意,因为工厂本身仍然与 Autofac 耦合。有没有办法解决这个问题(从 SolrNet 或 Autofac 的角度来看)?

我已经考虑过使用 Autofac 的工厂委托(delegate),但似乎没有办法在这种情况下应用它们。

最佳答案

您可以使用键控/命名服务和 IIndex 来完成此操作,autofac 页面 here 上有一个很好的条目.

这是一个简单的示例:

    public class Factory
    {
        private readonly IIndex<string, ISearchService> _index;

        public Factory(IIndex<string, ISearchService> index)
        {
            _index = index;
        }

        public ISearchService Resolve(string id)
        {
            return _index[id];
        }
    }

        // Registrations
        var builder = new ContainerBuilder();
        builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A");
        builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B");
        builder.Register<Factory>(c => new Factory(c.Resolve<IIndex<string, ISearchService>>()));
        // as per autofac's page linked above, autofac automatically implements IIndex types

        // Usage

        var aSearchService = fact.Resolve("A");

编辑:我认为我们可以做得更好,所以这里有一些扩展方法来避免创建显式工厂类:

    public delegate TReturn AutoFactoryDelegate<TParam, TReturn>(TParam param);

    public class AutoFactory<TParam, TReturn>
    {
        private readonly IIndex<TParam, TReturn> _index;

        public AutoFactory(IIndex<TParam, TReturn> index)
        {
            _index = index;
        }

        public TReturn Resolve(TParam param)
        {
            return _index[param];
        }
    }

    public delegate TReturn AutoFactoryDelegate<TParam, TReturn>(TParam param);

    public static class AutofacExtensions
    {
        public static void RegisterAutoFactoryDelegate<TParam, TReturn>(this ContainerBuilder builder)
        {
            builder.Register(c => new AutoFactory<TParam, TReturn>(c.Resolve<IIndex<TParam, TReturn>>()));

            builder.Register<AutoFactoryDelegate<TParam, TReturn>>(c =>
               {
                 var fact = c.Resolve<AutoFactory<TParam, TReturn>>();
                 return fact.Resolve;
               });
        }
    }

// Registration
var builder = new ContainerBuilder();
builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A");
builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B");
builder.RegisterAutoFactoryDelegate<string, ISearchService>();

// Usage
// fact is an AutoFactoryDelegate<string, ISearchService>
var aSearchService = fact("A");

编辑2:再次查看后,我们不需要工厂类,因为 IIndex 实际上已经是工厂了。这使得实现方面变得相当简单:

public static void RegisterAutoFactoryDelegate<TParam, TReturn>(this ContainerBuilder builder)
{
    builder.Register(c =>
                        {
                            var iindex = c.Resolve<IIndex<TParam, TReturn>>();
                            return (Func<TParam, TReturn>) (id => iindex[id]);
                        });
}

// Registration
var builder = new ContainerBuilder();
builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A");
builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B");
builder.RegisterAutoFactoryDelegate<string, ISearchService>();

// Usage
// fact is an Func<string, ISearchService>
var aSearchService = fact("A");

关于c# - 消除工厂中的 IoC 容器耦合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21588426/

相关文章:

c# - 将未知类型的对象传递给函数

c# - 我想添加一个 if 语句来检查学生 ID 是否有 PaymentID 目前是 mvc 中的新手

css - 在 Razor Grid 输出中使用 css

c# - 当 Controller 接收到数据时,模型是否保持其结构?

solr - 有没有一种方法可以使用 lucene 根据搜索查询发现单词的相关性

ruby-on-rails - Rspec 测试在错误的环境中运行?

javascript - 从客户端填充时,不会触发 Dropdown 的 SelectedIndexChanged 事件

c# - 使用 LinqToXSD,如何在不强制转换的情况下获取 xml 中的对象?

asp.net-mvc - Html.Dropdown 的 Html 属性

java - 解决方案。 numfound 是什么意思?