需要帮助,我想将参数传递给依赖组件

时间:2017-03-20 16:17:42

标签: c# autofac

  

我认为此问题不会重复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

这是我的目的:

  1. Autofac用于根据接口组成实现。我希望一切都在注册时决定,而不是在解决阶段。这意味着消费者提供资源位置,然后Autofac选择IContentProvider实施来从该位置加载内容(资源),并将内容提供给特定消费者。

  2. 所有接口和实现都是预先定义的,因此我无法修改它们(不能使用&#34;`Func隐式关系&#34;方式)。

  3. 解析IContentProvider的参数是动态的,来自不同的消耗,而不仅仅是配置值。所以我不能使用&#34; lambda表达式注册&#34;答案中提到的方式。

  4. 也许Autofac模块可以解决问题,但我不知道如何做到这一点。

  5. 我不清楚我是否设计得当。我将非常感谢能够指出如何改进设计的人。

1 个答案:

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