использование модулей и конфигурационных файлов в autofac - PullRequest
2 голосов
/ 21 апреля 2011

Хотя я нахожу документацию по Autofac (в вики) полезной, разделы, посвященные конфигурации и модулям 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>

Это все отлично работает. Приложение выводит «мяу» в текстовый файл. Если я закомментирую элементы компонента, приложение выдаст «Arf!» на консоль.

Итак, все в порядке? Или есть лучший способ сделать это?

И я немного не уверен в том, что стоит за конфигурацией на основе модулей:

Правильно ли я считаю, что на практике модули должны быть в отдельных сборках от остальной части приложения?

Правильно ли я понимаю, что одной из основных функций модулей является предоставление наборов параметров конфигурации по умолчанию для контейнеров DI?

В идеале, насколько обширными должны быть мои конфигурационные файлы? Другими словами, при использовании Autofac, какие анти-паттерны в конфигурационном файле мне нужны для наблюдения?

Спасибо (я думаю) заранее за ваши ответы.

musicologyman

Ответы [ 2 ]

4 голосов
/ 25 апреля 2011

Я не на 100% уверен в вашем примере, каково ожидаемое поведение - кажется, что вы регистрируете один и тот же набор компонентов много раз, если вы намерены, пожалуйста, игнорируйте эти предложения.

  • Если вы регистрируете модуль в XML, вам также не нужно регистрировать компоненты внутри модуля.
  • Аналогично, если вы регистрируете модуль в XML, вам не нужно также регистрировать модуль в коде.

Что касается «лучших практик», я бы сказал, что рекомендация Джима об экономном использовании XML является хорошей. Лично я склонен выполнять все тяжелые работы внутри модулей, а затем регистрировать модули через XML, чтобы воспользоваться преимуществами конфигурации, которая может быть применена там.

Еще одна рекомендация, которую я хотел бы сделать, - использовать XML для настройки только модулей. В вашем примере вы устанавливаете конфигурацию для компонента; конфигурация менее хрупка, если вы применяете параметры к модулю, а затем внутренне к этому модулю передаете их компонентам по мере необходимости. Модули не склонны к сильному перемешиванию, в то время как компоненты должны быть в состоянии заменять, не нарушая конфигурацию.

НТН,

Ник

4 голосов
/ 21 апреля 2011

Моя личная рекомендация - экономно использовать конфигурацию XML. Я бы использовал его только для тех частей, которые, как вы знаете, необходимо перенастроить без перекомпиляции. Если вы создаете библиотеку многократного использования, это, вероятно, больше, чем, например, если вы создаете монолитное веб-приложение. Другая вещь, которую я пытаюсь сделать, - сделать большинство моих типов автоматически регистрируемыми, используя этот код:

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().

...