Adr*_*ark 1 log4net inversion-of-control autofac
正如在Autofac Wiki上所讨论的,为类自动注入log4net.ILog实现的最佳方法是使用LogInjectionModule.该模块的实现在wiki文章中给出:
public class LogInjectionModule : Module
{
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
if (registration == null) throw new ArgumentNullException("registration");
registration.Preparing += OnComponentPreparing;
}
static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(new[]
{
new ResolvedParameter((p, i) => p.ParameterType == typeof(ILog), (p, i) => LogManager.GetLogger(t))
});
}
}
Run Code Online (Sandbox Code Playgroud)
我将此模块与我自己的模块一起包括在内以配置一些组件:
var builder = new ContainerBuilder();
builder.RegisterModule(new Common.Logging.LogInjectionModule());
builder.RegisterModule(new DataLayer.DataLayerModule("connectionstring"));
builder.RegisterType<SomeServiceType>();
AutofacHostFactory.Container = builder.Build();
Run Code Online (Sandbox Code Playgroud)
里面DataLayerModule我构造类型,如下所示:
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new DataAccess(this.ConnectionString, c.Resolve<ILog>()))
.As<IDataAccess>();
// Some other type registrations...
}
Run Code Online (Sandbox Code Playgroud)
当我的应用程序尝试构造一个IDataAccess对象时,我得到以下异常:
请求的服务'log4net.ILog'尚未注册.要避免此异常,请注册组件以提供服务,使用IsRegistered()检查服务注册,或使用ResolveOptional()方法解析可选依赖项.
我知道在维基页面上提到注入方法仅适用于构造函数注入.但是我认为这就是我在这里所做的.我错了吗?
编辑
在进一步调查中,我的原始答案并没有解决你的问题(我把它留在下面作为参考).问题是您的代码LogInjectionModule通过直接创建和解析new实例来绕过.这不是一个支持的使用模式,它旨在提供一个与Autofac激活的实例类型相匹配的实例(log4net的方法需要知道使用该记录器的类型).DataAccessILogLogInjectionModuleILogLogManager.GetLogger()
要解决此问题,您有两种选择.最简单的是直接提供记录器实例而不使用LogInjectionModule:
builder.Register(c =>
new DataAccess(
this.ConnectionString,
LogManager.GetLogger(typeof(DataAccess)))
.As<IDataAccess>();
Run Code Online (Sandbox Code Playgroud)
或者(更干净地),您可以DataAccess使用正常的Autofac方式注册,然后IDataAccess使用命名参数进行注册,以指定Autofac传递给构造函数的连接字符串.使用此技术,您可以使Autofac LogInjectionModule在解析构造函数的ILog参数时使用.
builder.RegisterType<DataAccess>();
builder.Register(c =>
c.Resolve<DataAccess>(
new NamedParameter("connectionString", this.ConnectionString)))
.As<IDataAccess>();
Run Code Online (Sandbox Code Playgroud)
(请注意,此代码假定DataAccess构造函数中的连接字符串参数名为"connectionString").
第二种技术的优点是您的模块不LogManager直接引用log4net的类,因此唯一的耦合是ILog接口.
原始(不正确)答案
该代码示例适用于Autofac v2.0(我最初在该Wiki页面上提供了示例).我当前工作模块的代码(适用于Autofac v2.4.5)是:
public class LogInjectionModule : ComponentInjectionModule
{
/// <summary>
/// Called when Autofac is preparing a component for activation.
/// </summary>
/// <param name = "sender">
/// The sender.
/// </param>
/// <param name = "e">
/// The <see cref = "ActivatingEventArgs{T}" /> instance containing the event data.
/// </param>
protected override void OnComponentPreparing(object sender, PreparingEventArgs e)
{
Enforce.ArgumentNotNull(e, "e");
Type t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof(ILog), (p, i) => LogManager.GetLogger(t))
});
}
}
Run Code Online (Sandbox Code Playgroud)
该代码依赖于我在下面定义的ComponentInjectionModule类.这个模块挂钩到注册/激活过程的方式有一些细微的差别.
/// <summary>
/// Base module for injecting into registrations when they are prepared/activated.
/// </summary>
public class ComponentInjectionModule : IModule
{
/// <summary>
/// Apply the module to the component registry.
/// </summary>
/// <param name = "componentRegistry">
/// Component registry to apply configuration to.
/// </param>
public void Configure(IComponentRegistry componentRegistry)
{
Enforce.ArgumentNotNull(componentRegistry, "componentRegistry");
foreach (var registration in componentRegistry.Registrations)
{
this.AttachToComponentRegistration(registration);
}
componentRegistry.Registered +=
(sender, e) => this.AttachToComponentRegistration(e.ComponentRegistration);
}
/// <summary>
/// Attaches to the <see cref = "IComponentRegistration.Preparing" /> event of a component registration.
/// </summary>
/// <param name = "registration">
/// The registration whose Preparing event will be attached.
/// </param>
protected virtual void AttachToComponentRegistration(IComponentRegistration registration)
{
Enforce.ArgumentNotNull(registration, "registration");
registration.Preparing += this.OnComponentPreparing;
registration.Activating += this.OnComponentActivating;
registration.Activated += this.OnComponentActivated;
}
/// <summary>
/// Called when Autofac has activated a component.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ActivatedEventArgs{T}"/> instance containing the event data.</param>
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", Justification = "Not an event handler")]
protected virtual void OnComponentActivated(object sender, ActivatedEventArgs<object> e)
{
}
/// <summary>
/// Called when Autofac is activating a component.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ActivatingEventArgs{T}"/> instance containing the event data.</param>
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", Justification = "Not an event handler")]
protected virtual void OnComponentActivating(object sender, ActivatingEventArgs<object> e)
{
}
/// <summary>
/// Called when Autofac is preparing a component for activation.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ActivatingEventArgs{T}"/> instance containing the event data.</param>
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", Justification = "Not an event handler")]
protected virtual void OnComponentPreparing(object sender, PreparingEventArgs e)
{
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2103 次 |
| 最近记录: |