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

时间:2015-04-29 08:56:15

标签: c# .net autofac

如果我有以下模块:

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

我得到一个例外说:

  

输入字符串的格式不正确,值对于a无效   双

这是有道理的。

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

此刻可以在autofac中使用吗?

1 个答案:

答案 0 :(得分:1)

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

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

builder.Build();

CustomConfigurationRegistrar可以继承默认的ConfigurationRegistrar。 如果你查看source code,你可以看到RegisterConfiguredModules将在 foreach 循环中注册所有模块,没有注册单个模块的方法,所以你有从基类复制/过去它。

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

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