在autofac中注册组件

时间:2013-03-11 09:11:50

标签: autofac

我是autofac的新手(使用2.1.14.854),我仍然试图理解

我有一个接口,这个接口有一个或多个实现,并且应该按特定的顺序触发实现。

例如:

public IPipeline
{ 
void execute(); 
}


public MyPipeLine_1:IPipeline
{
public void execute(){}
}

public MyPipeLine_2:IPipeline
{
public void execute(){}
}

foreach(IPipeline pipeline in pipelines)
          pipeline.execute(); 

IPipeline的订单执行应该是MyPipleLine_2,MyPipleLine_1等

我有两个问题 1)如何注册在程序集中实现IPipeLine接口的所有组件并将它们放在List中 2)我可以在注册时定义这些组件的执行顺序

提前致谢。

2 个答案:

答案 0 :(得分:2)

[快速说明:你使用的是旧版Autofac。您可能需要更新才能获得我正在谈论的功能。]

第一部分很简单 - Autofac implicitly supports IEnumerable<T>。只需注册所有类型并解决:

var builder = new ContainerBuilder();
builder.RegisterType<MyPipeLine_1>().As<IPipeline>();
builder.RegisterType<MyPipeLine_2>().As<IPipeline>();
var container = builder.Build();
var containsAllPipelineComponents = container.Resolve<IEnumerable<IPipeline>>();

如果您可以将其作为IEnumerable<T>而不是列表,那会更好,但如果您必须有一个列表,则可以为其添加注册:

builder
  .Register(c => new List<IPipeline>(c.Resolve<IEnumerable<IPipeline>>()))
  .As<IList<IPipeline>>();

第二部分并不那么容易。 Autofac不一定保证列表中项目的顺序。如果您需要订购它们,您需要在它们上面添加某种排序元数据 - 属性,属性,以及您的内容事后可以用来订购管道。

或者,如果您的管道具有“阶段”或“事件”,其中不同的组件适用,请查看管道的设计并为每个事件设置不同的管道接口。在事件中,每个项目执行的顺序无关紧要。(这类似于.NET中的事件处理程序现在如何工作。您希望模仿该行为 - 整个生命周期中不同阶段的不同事件,但在每个特定阶段处理程序的执行顺序无关紧要。)

示例可能如下所示:

public interface IFirstStage
{
  void Execute();
}

public interface ISecondStage
{
  void Execute();
}

public interface IThirdStage
{
  void Execute();
}

public class PipelineExecutor
{
  public IEnumerable<IFirstStage> FirstHandlers { get; private set; }
  public IEnumerable<ISecondStage> SecondHandlers { get; private set; }
  public IEnumerable<IThirdStage> ThirdHandlers { get; private set; }

  public PipelineExecutor(
    IEnumerable<IFirstStage> first,
    IEnumerable<ISecondStage> second,
    IEnumerable<IThirdStage> third)
  {
    this.FirstHandlers = first;
    this.SecondHandlers = second;
    this.ThirdHandlers = third;
  }

  public void ExecutePipeline()
  {
    this.ExecuteFirst();
    this.ExecuteSecond();
    this.ExecuteThird();
  }

  public void ExecuteFirst()
  {
    foreach(var handler in this.FirstHandlers)
    {
       handler.Execute();
    }
  }

  // ExecuteSecond and ExecuteThird look just
  // like ExecuteFirst, but with the appropriate
  // set of handlers.
}

然后当您注册处理程序时,这很简单:

var builder = new ContainerBuilder();
builder.RegisterType<SomeHandler>().As<IFirstStage>();
builder.RegisterType<OtherHandler>().As<IFirstStage>();
builder.RegisterType<AnotherHandler>().As<ISecondStage>();
// You can have any number of handlers for any stage in the pipeline.
// When you're done, make sure you register the executor, too:
builder.RegisterType<PipelineExecutor>();

当您需要运行管道时,请解决并运行。

var executor = container.Resolve<PipelineExecutor>();
executor.ExecutePipeline();

这就像事件处理程序,但不使用委托。您有一个固定的管道“事件”或“阶段”顺序,但每个阶段内的处理程序都不能保证订单。

如果您需要修改管道以获得更多阶段,是的,您需要修改代码。就像你想要揭露一个新事件一样。但是,要添加,删除或更改处理程序,只需修改Autofac注册即可。

答案 1 :(得分:1)

我建议您使用Metadata功能。 它为您提供了在注册阶段定义订单的优势。

以下是一个例子:

internal class Program
{
    private static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        var s1 = "First";
        var s2 = "Second";
        var s3 = "Third";
        builder.RegisterInstance(s1).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 1));
        builder.RegisterInstance(s2).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 2));
        builder.RegisterInstance(s3).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 3));

        using (var container = builder.Build())
        {
            var strings = container.Resolve<IEnumerable<Meta<string, Order>>>();
            foreach (var s in strings.OrderBy(meta => meta.Metadata.OrderNumber))
            {
                Console.WriteLine(s.Value);
            }
        }
        Console.ReadKey();
    }

    public class Order
    {
        public int OrderNumber { get; set; }
    }
}