Лучший способ внедрения конфигурации приложения - PullRequest
10 голосов
/ 04 октября 2011

Ну, я делаю набег на этот фантастический сайт с вопросом о том, как правильно внедрить параметры конфигурации в компоненты приложения.Итак, обзор таков: у меня есть приложение, написанное на C # .Net 3.5.Он состоит из 3 сборок - Ядро, Данные и Сервис.Для сборок данных и сервисов требуются настройки, извлеченные из файла app.config, который выполняется с помощью файла настроек, например

Код:

public static String RequestQueueConnectionString
{
    get { return ConnectionSettings.Default.RequestQueueConnectionString; }
}

Конфигурация:

<applicationSettings>
  <MyNamespace.Data.ConnectionSettings>
    <setting name="RequestQueueConnectionString" serializeAs="String">
    ...

Теперь все сборки настроены с использованием StructureMap для IoC - что, на мой взгляд, должно дать ответ на то, что я ищу, но я просто не могу это увидеть!

IoC:

public static void ConfigureStructureMap(IContainer container)
{
    container.Configure(x => ...
    ...

Что я хочу сделать, это внедрить класс конфигурации, уже заполненный в контейнере IoC, так, чтобы эти параметры использовались для этой сборки, а НЕ указанныев файле настроек / app.config.Так что, возможно:

public static void ConfigureStructureMap(IContainer container, MyConfigClass config)
{
    container.Configure(x => x.For<DataConfig>()
                              .Singleton()
                              .Use ???
    ...

Я надеюсь, что предоставил здесь достаточно подробностей - простите новичка, если я этого не сделал, и, пожалуйста, дайте мне знать, что еще поможет ответить на этот вопрос!

1 Ответ

4 голосов
/ 10 октября 2011

Итак, после долгих поисков, проб и ошибок мне представили ссылку @ default.kramer, по которой я должным образом перешел!С небольшим количеством проб и ошибок, снова (лучший способ на мой взгляд), мне удалось найти решение, которое я искал.Теперь, пока вы можете перейти по ссылке (и я настоятельно рекомендую это сделать), я собираюсь опубликовать решение моего вопроса по мере его реализации.Надеюсь, это может помочь кому-то с подобной проблемой.

Итак, теперь у меня есть свой класс настройки конфигурации следующим образом:

public static class DispatchConfiguration
{
    public static void ConfigureStructureMap(IContainer container, IDispatchConfiguration dispatchConfig)
    {
        DispatchProcessBatchSize = dispatchConfig.DispatchProcessBatchSize;
        ServiceIsActive = dispatchConfig.ServiceIsActive;
        ...
    }

Теперь, прежде чем я использовал файл настроек для получения конфигурациииз файла app.config.Очевидно, это было полезно для обеспечения гибкости в изменении настроек конфигурации, но у меня осталась проблема с невозможностью легко протестировать эти настройки.Скажем, тесты 9/10 требовали, чтобы служба была активной, но один тест хотел проверить «ServiceIsActive = false;», теперь у меня проблемы.

Однако теперь я могу ввести конфигурацию из теста:

[Given(@"Config\.IsServiceActive returns false")]
public void GivenConfig_IsServiceActiveReturnsFalse()
{
    var settings = new DispatchSettings
    {
        ServiceIsActive = false,
        DispatchProcessBatchSize = 100,
        UpdatedBy = "Unit Test"    
    };

    DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, settings);
}

И тогда в реальном мире я могу получить настройки из app.config:

public void Start(String[] args)
{
    var dispatchConfig = this.GetDispatchConfiguration();
    DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, dispatchConfig);
    ...
}

private IDispatchConfiguration GetDispatchConfiguration()
{
    var config = (DispatchSettings)ConfigurationManager.GetSection("DispatchSettings");
    return config;
}

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

[XmlRoot(ElementName = "DispatchSettings", Namespace = "")]
public sealed class DispatchSettings : IDispatchConfiguration
{
    public Int32 DispatchProcessBatchSize { get; set; }
    public Boolean ServiceIsActive { get; set; }
    ...
}

Ради полноты интерфейс выглядит так:

public interface IDispatchConfiguration
{
    Int32 DispatchProcessBatchSize { get; }
    Boolean ServiceIsActive { get; }
    ...
}

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

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="DispatchSettings" type="MyNamespace.XmlConfigurator, MyNamespace.Core" />
    </configSections>

    <DispatchSettings type="MyNamespace.DispatchSettings, MyNamespace.Core">
        <ServiceIsActive>True</ServiceIsActive>
        <DispatchProcessBatchSize>100</DispatchProcessBatchSize>
    </DispatchSettings>

Теперь любой, у кого острый глаз, заметит «MyNamespace.XmlConfigurator».Я нашел это в одной из моих поездок в Google, и этот код позволяет десериализовать конфигурацию Xml в класс по вашему желанию (как показано в этом примере).Итак, чтобы убедиться, что у вас есть полный код для работы этого метода, ниже приведен код для XmlConfigurator.Я не могу вспомнить, где я сталкивался с этим, но большое спасибо человеку, который написал это !!

public sealed class XmlConfigurator : IConfigurationSectionHandler
{
    public XmlConfigurator()
    {
    }

    public object Create(object parent, object configContext, XmlNode section)
    {
        XPathNavigator navigator = null;
        String typeName = null;
        Type sectionType = null;
        XmlSerializer xs = null;
        XmlNodeReader reader = null;

        try
        {
            Object settings = null;

            if (section == null)
            {
                return settings;
            }

            navigator = section.CreateNavigator();
            typeName = (string)navigator.Evaluate("string(@type)");
            sectionType = Type.GetType(typeName);
            xs = new XmlSerializer(sectionType);
            reader = new XmlNodeReader(section);

            settings = xs.Deserialize(reader);

            return settings;
        }
        finally
        {
            xs = null;
        }
    }
}

И вот оно у вас!Я надеюсь, что это позволяет любому, у кого похожая проблема, решить ее, и достаточно ясно, чтобы следовать за ней!

...