在autofac中使用模块和配置文件

时间:2011-04-20 20:04:41

标签: autofac

虽然我通常发现Autofac文档(在wiki上)很有帮助,但有关XML配置和模块的部分对我来说有点不清楚。现在,我有一个样本工作(我在下面介绍),但我不确定它是否代表了一种在Autofac环境下配置的混合方法。特别是,我不确定我在配置文件和代码文件中是否有更多或更少的东西。

以下是代码:

using System;
using System.IO;
using Autofac;
using Autofac.Configuration;

namespace AutofacTest.Animals
{
    interface IAnimal
    {
        void Speak ( );
    }

    abstract class Animal : IAnimal
    {
        protected TextWriter Writer
        {
            get;
            private set;
        }

        protected Animal ( TextWriter writer )
        {
            this.Writer = writer;
        }

        public abstract void Speak ( );

    }

    class Dog : Animal
    {

        public Dog ( TextWriter writer )
            : base ( writer )
        {

        }

        public override void Speak ( )
        {
            this.Writer.WriteLine ( "Arf!" );
        }
    }

    class Cat : Animal
    {
        public Cat ( TextWriter writer )
            : base ( writer )
        {

        }

        public override void Speak ( )
        {
            this.Writer.WriteLine ( "Meow" );
        }
    }

    // In actual practice, this would be in a separate assembly, right?
    class AnimalModule : Module
    {
        protected override void Load ( ContainerBuilder builder )
        {
            builder.RegisterInstance ( Console.Out ).As<TextWriter> ( ).SingleInstance ( );
            builder.Register ( d => new Dog ( d.Resolve<TextWriter> ( ) ) ).As<IAnimal> ( );
        }
    }

    class Program
    {
        static void Main ( )
        {
            Console.ForegroundColor = ConsoleColor.Yellow;

            ContainerBuilder builder = new ContainerBuilder ( );
            ConfigurationSettingsReader reader = new ConfigurationSettingsReader(); 
            builder.RegisterModule ( reader );
            //builder.RegisterModule ( new AnimalModule ( ) );
            builder.Build ( ).Resolve<IAnimal> ( ).Speak ( );
            Console.ReadKey ( );
        }
    }
}

这是一个相关的配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
    </configSections>
    <autofac defaultAssembly="AutofacTest">
        <components>
            <component
                type="AutofacTest.Animals.Cat"
                service="AutofacTest.Animals.IAnimal" />
            <component type="System.IO.StreamWriter" service="System.IO.TextWriter">
                <parameters>
                    <parameter name="path" value="C:\AutofacTest.txt"/>
                    <parameter name="append" value="false" />
                </parameters>
                <properties>
                    <property name="AutoFlush" value="true" />
                </properties>
            </component>
        </components>
        <modules>
            <module type="AutofacTest.Animals.AnimalModule, AutofacTest"/>
        </modules>
    </autofac>
</configuration>

一切正常。应用程序将“Meow”输出到文本文件。如果我注释掉组件元素,应用程序输出“Arf!”到控制台。

那么,一切都在这里吗?或者有更好的方法来解决这个问题吗?

我对基于模块的配置背后的想法有点不确定:

我是否正确,在实际操作中,模块应与应用程序的其余部分位于不同的程序集中?

我是否正确理解模块的主要功能之一是为DI容器提供一组默认配置设置?

理想情况下,我的配置文件应该有多广泛?换句话说,当使用Autofac时,我需要注意哪些配置文件反模式?

先谢谢(我认为)您的回复。

musicologyman

2 个答案:

答案 0 :(得分:4)

我个人建议谨慎使用XML配置。我只会将它用于您需要在不重新编译的情况下重新配置的部分。如果你正在构建一个可重用的库,那么这可能比你正在构建一个单一的webapp更重要。我尝试做的另一件事是使用以下代码使我的大多数类型都可以自动注册:

public static void AutoRegister(ContainerBuilder builder, params Assembly[] assemblies)
{
    builder.RegisterAssemblyTypes(assemblies)
        .Where(t => t.GetCustomAttributes(typeof (RegisterServiceAttribute), false).Any())
        .AsSelf()
        .AsImplementedInterfaces();
}

其中RegisterServiceAttribute是我的根项目中的一个属性:

[AttributeUsage(AttributeTargets.Class)]
[MeansImplicitUse]
public class RegisterServiceAttribute : Attribute
{
}

注意:MeansImplicitUse来自Resharper。

然后我将[RegisterService]放在我想要自动注册的任何类上。我的注册中至少有95%是以这种方式处理的。其余的注册发生在致电AutoRegister()之后。

答案 1 :(得分:4)

我不能100%确定您的示例预期的行为是什么 - 似乎您多次注册相同的组件集,如果您的意图是请忽略这些建议。

  • 如果您使用XML注册模块,则无需在模块中注册组件。
  • 同样,如果您在XML中注册模块,则无需在代码中注册模块。

关于“最佳实践”,我会说Jim谨慎地使用XML是一个很好的建议。就个人而言,我倾向于在模块内部完成所有繁重工作,然后通过XML注册模块以利用可在其中应用的配置。

我提出的另一个建议是使用XML仅配置模块。在您的示例中,您要在组件上设置配置;如果将参数应用于模块,则配置不太脆弱,然后该模块的内部将根据需要将它们传递给组件。模块不会倾向于流失,而组件需要能够在不破坏配置的情况下进行更改。

HTH,

尼克