来自 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;
}
}
}
如果我有以下模块:
class MyModule : Module
{
public double SomeDouble { get; set; }
}
我的 app.config
<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;
}
}
}