我在一个网络应用程序下运行多个多语言“网站”。每个“语言环境”都有自己的Solr核心(所有语言环境中的字段相同)。我正在使用SolrNet来执行搜索查询。
为了在每个请求的基础上切换核心,我在我的Autofac容器中为每个区域设置注册{em>名为的ISolrOperations<SearchResult>
(对于那些不熟悉SolrNet的人来说,这是有效地进入库进入查询目的)。
然后我有一个ISearchService
接口,具有一个具体的SolrSearchService
实现,其构造函数签名如下所示:
public SolrSearchService(ISolrOperations<SearchResult> solr)
为了在每个请求上动态切换核心,我的控制器采用(注入)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与我的服务/控制器分离但保持每个请求切换核心的能力(基于控制器中执行的逻辑)而设法做的最好的。
我已经看过使用Autofac的工厂代表,但似乎没有办法在这个实例中应用它们。
答案 0 :(得分:1)
您可以使用键控/命名服务和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");
答案 1 :(得分:1)
我没有使用过Autofac,但根据温莎的做法以及我刚刚发现的你应该能够做到这样的事情
builder.Register(c =>
new SolrSearchServiceFactory(HttpContext.Current.GetIdFromUrlOrSomething)
)
.As<ISearchServiceFactory>()
.InstancePerHttpRequest();
如果您可以从http上下文获取Id,则autofac应为每个请求连接工厂。
/迈克尔