Best way of injecting application configuration

后端 未结 1 842
无人共我
无人共我 2021-01-11 19:38

Well, I\'m making my foray into this fantastic site with a question about the correct way to inject configuration settings into application components. So, the overview is

相关标签:
1条回答
  • 2021-01-11 20:28

    So, after a lot of searching and trial and error, I was presented with @default.kramer's link, which I duely followed! With a little bit of trial and error, again (best way in my opinion), I managed to get the solution I was looking for. Now, whilst you can follow the link (and I would highly suggest doing so), I am going to post the solution to my question as I implemented it. Hopefully this might help someone with a similar problem.

    So, I now have my configuration setup class like so :

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

    Now, before I was using a settings file to retrieve the configuration out of the app.config file. This was obviously good for ensuring I had flexibility in changing my config settings, but it left me with the problem of not being able to easily test those settings. Say 9/10 tests required the service to be active, but 1 test wanted to test "ServiceIsActive = false;", now I'm in trouble.

    Now, however, I am able to inject the configuration from the test :

    [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);
    }
    

    And then in the real world I am able to get the settings from 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;
    }
    

    And then the actual config class looks like :

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

    For the sake of completeness the interface looks like so :

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

    And finally, the config file looks like this :

    <?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>
    

    Now, anyone with a keen eye will spot "MyNamespace.XmlConfigurator". I found this on one of my Google journeys, and the code allows you to deserialize an Xml config into a class of your desire (as shown in this example). So, to ensure you have the complete code to make this technique work, below is the code for the XmlConfigurator. I cannot remember where I came across it, but a big thanks to the person who wrote it!!

    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;
            }
        }
    }
    

    And there you have it! I hope this allows anyone with a similiar issue to resolve it and is clear enough to follow!

    0 讨论(0)
提交回复
热议问题