использование модулей и конфигурационных файлов в autofac

#autofac

#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, каковы некоторые антишаблоны конфигурационных файлов, на которые мне нужно обратить внимание?

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

музыковед

Комментарии:

1. просто напоминание, которое может сэкономить время и усилия других пользователей — в AutoFac 4.0 это БОЛЬШЕ недопустимо. Смотрите документацию для версии 4.0 о том, как использовать конфигурацию.

Ответ №1:

Моя личная рекомендация — экономно использовать конфигурацию 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() .

Комментарии:

1. Спасибо, Джим, за твой ответ. Мне нужно продумать, как ваша рекомендация согласуется с тем, что мы пытаемся сделать.

2. Возможно ли зарегистрировать некоторые srvices в xml, а другие — в коде для одного приложения?

Ответ №2:

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

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

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

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

HTH,

Ник