来自 xml 的模块属性,提供默认值

Module properties from xml, providing default values

如果我有以下模块:

class MyModule : Module
{
    public double SomeDouble { get; set; }
}

我的 app.config

中有以下 autofac 部分
<autofac>
   <modules>
      <module type="MyNamespace.MyModule, MyNamespace">
         <properties>
            <property name="SomeDouble" value="" />
         </properties>
      </module>
   </modules>
</autofac>

调用时builer.Build()

我收到一条异常消息:

Input string was not int the correct format, value is not valid for a double

有道理。

我希望能够提供某种处理程序来处理异常,而不是让整个 Build() 失败,或者提供默认值。

目前可以在 autofac 中实现吗?

没有简单的方法可以做到这一点。我能看到的唯一解决方案是为 ConfigurationSettingsReader

提供自定义 IConfigurationRegistrar
var builder = new ContainerBuilder();
builder.RegisterModule(new ConfigurationSettingsReader()
{
    ConfigurationRegistrar = new CustomConfigurationRegistrar()
});

builder.Build();

CustomConfigurationRegistrar可以继承默认的ConfigurationRegistrar。 如果你查看 source code,你会发现 RegisterConfiguredModules 会在 foreach 循环中注册所有模块,没有注册单个模块的方法,所以你必须从基础 class 开始 copy/past 它。

因为错误来自用于注入 属性 的参数,我们可以创建一个 LazyParameter 来处理错误和 return 默认值。

public class CustomConfigurationRegistrar : ConfigurationRegistrar
{
    internal class LazyParameter : Parameter
    {
        public LazyParameter(Parameter originalParameter)
        {
            this._originalParameter = originalParameter;
        }

        private readonly Parameter _originalParameter;

        public override Boolean CanSupplyValue(ParameterInfo pi, IComponentContext context, out Func<Object> valueProvider)
        {
            Boolean canSupplyValue = this._originalParameter.CanSupplyValue(pi, context, out valueProvider);
            if (canSupplyValue)
            {
                Func<Object> originalValueProvider = valueProvider;
                valueProvider = () =>
                {
                    try
                    {
                        return originalValueProvider();
                    }
                    catch
                    {
                        Console.WriteLine(pi.Member.Name);
                        // log it and throw or return default value
                        return null;
                    }
                };
            }
            return canSupplyValue;
        }
    }


    protected override void RegisterConfiguredModules(ContainerBuilder builder, SectionHandler configurationSection)
    {
        if (builder == null)
        {
            throw new ArgumentNullException("builder");
        }
        if (configurationSection == null)
        {
            throw new ArgumentNullException("configurationSection");
        }
        foreach (ModuleElement moduleElement in configurationSection.Modules)
        {
            this.RegisterConfiguredModule(builder, configurationSection, moduleElement);
        }
    }

    private void RegisterConfiguredModule(ContainerBuilder builder, SectionHandler configurationSection, ModuleElement moduleElement)
    {
        try
        {
            var moduleType = this.LoadType(moduleElement.Type, configurationSection.DefaultAssembly);
            IModule module = null;

            IEnumerable<Parameter> parameters = moduleElement.Parameters.ToParameters().Select(p => new LazyParameter(p));
            IEnumerable<Parameter> properties = moduleElement.Properties.ToParameters().Select(p => new LazyParameter(p));

            using (var moduleActivator = new ReflectionActivator(
                moduleType,
                new DefaultConstructorFinder(),
                new MostParametersConstructorSelector(),
                parameters,
                properties))
            {
                module = (IModule)moduleActivator.ActivateInstance(new ContainerBuilder().Build(), Enumerable.Empty<Parameter>());
            }
            builder.RegisterModule(module);
        }
        catch (Exception)
        {
            // log it
            throw;
        }
    }
}