我认为此问题不会重复Autofac: Resolving dependencies with parameters。请阅读以下目的部分。
我声明了一个IContentProvider
和一个名为WebContentProvider
的实现,其中url
为构造函数参数。
interface IContentProvider
{
string Content { get; }
}
class WebContentProvider {
public WebContentProvider(string url) { ... }
public string Content => GetHtmlFrom(this.url);
}
现在,有两个消费者类需要WebContentProvder来提供来自不同网址的内容。它们都实现了接口IContentUser
。
class FirstContentUser : IContentUser
{
IContentProvider provider;
public FirstContentUser(IContentProvider provider)
{
this.provider = provider;
}
public void Use()
{
Console.WriteLine("[First Content User]");
Console.WriteLine(provider.Content);
}
}
类SecondContentUser
类似。
这是我的注册码:
public AttempAutofac()
{
var builder = new ContainerBuilder();
builder.RegisterType<WebContentProvider>()
.As<IContentProvider>();
// HERE!!! how can I use `url` metadata given below,
// or some other way to get the url while resolving
builder.RegisterType<FirstContentUser>()
.As<IContentUser>()
.WithMetadata("url", "http://the.1st.url");
builder.RegisterType<SecondContentUser>()
.As<IContentUser>()
.WithMetadata("url", "http://the.2nd.url");
container = builder.Build();
}
稍后,我想使用scope.Resolve<IEnumerable<IContentUser>>()
来获取所有消费者实例。
我希望在不久的将来,只需更改一个注册行,就可以轻松地将新课程FasterWebContentProvider
配置为代替WebContentProvider
。
这是我的目的:
Autofac用于根据接口组成实现。我希望一切都在注册时决定,而不是在解决阶段。这意味着消费者提供资源位置,然后Autofac选择IContentProvider
实施来从该位置加载内容(资源),并将内容提供给特定消费者。
所有接口和实现都是预先定义的,因此我无法修改它们(不能使用&#34;`Func隐式关系&#34;方式)。
解析IContentProvider
的参数是动态的,来自不同的消耗,而不仅仅是配置值。所以我不能使用&#34; lambda表达式注册&#34;答案中提到的方式。
也许Autofac模块可以解决问题,但我不知道如何做到这一点。
我不清楚我是否设计得当。我将非常感谢能够指出如何改进设计的人。
答案 0 :(得分:0)
我思考这个问题然后找出一件事:
IContentProvider
的实例应该在没有消费者的情况下创建,因此他们无法从消费者那里获得任何信息。因此,我必须注册不同的IContentProvider
个实例或创建者,然后消费者可以按键或名称找到一个。
关注'How do I pick a service implementation by context?',我得到了一个解决方案:
private void Register()
{
var builder = new ContainerBuilder();
builder.Register(c => new WebContentProvider("http://the.1st.url"))
.Keyed<IContentProvider>(typeof(FirstContentUser));
builder.Register(c => new WebContentProvider("http://the.2nd.url"))
.Keyed<IContentProvider>(typeof(SecondContentUser));
builder.RegisterType<FirstContentUser>()
.As<IContentUser>()
.WithParameter(
CreateResolvedParameter<IContentProvider, FirstContentUser>());
builder.RegisterType<SecondContentUser>()
.As<IContentUser>()
.WithParameter(
CreateResolvedParameter<IContentProvider, SecondContentUser>());
container = builder.Build();
}
private static ResolvedParameter CreateResolvedParameter<ParamType, KeyType>()
{
return new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(ParamType),
(pi, ctx) => ctx.ResolveKeyed<ParamType>(typeof(KeyType)));
}