再次关于 log4net 和 Unity IOC 配置

发布于 2024-08-02 21:41:21 字数 1695 浏览 6 评论 0原文

我在不同的网站上遇到了一些这样的问题,答案似乎是由 l4n 官方人士针对 log4net “是”的轻量级包装器的价值(你不明白吗?)以及类似的想法而编造的。 -令人难以置信的事实。

然而,似乎用户所要求的(这是我的问题)是如何将 log4net 对象模型适合流畅的配置界面中的 registertype/registerinstance 序列。

这里的目标不是重新包装 l4n,而只是获取一个像样的参考,不需要劫持流畅的流程。

可怜的 ejemplow,我想从 LogManger.GetLogger 方法获取对已配置的 ILog 实例的引用,并尽早将其放入流畅的流中,以便将其注入下游对象的属性中。

因此,为了回应一个不耐烦的建议,我尝试以规范的方式创建 ILog 的正常实例:

log4net.Config.XmlConfigurator.Configure();
static readonly log4Net.Ilog Log = LogManager.GetLogger(thatlongassemblyreflectionstuff);

因此,现在将该引用添加到 Unity 容器并继续我的美好生活似乎是微不足道的(真正意义上的毫不费力) 。

但是,RegisterInstance 方法的签名需要“类型”而不是接口。

对于那些没有搜索过 log4net 对象模型的人来说,爱好者是正确的:l4n 是一个“包装器”,您无法了解 Log 事物的实际“类型”。

所以现在我必须测试。你知道这意味着什么,它可能需要一分钟,但更有可能需要一小时或四个小时(“小时”和“四”的拼写类似,在现实生活中绝不会巧合)。

然而,以下内容,减去有关规范设置的省略部分,确实有效:

container
  .RegisterInstance("Logger", Log, new ContainerControlledLifetimeManager())
.RegisterType<IControllerContext, ControllerContext>
(
   "CtlrCtx", 
   new ContainerControlledLifetimeManager(), 
   new InjectionConstructor(new ResolvedParameter<IMessageBuilder>("MsgBldr")),
   new InjectionProperty("Log",new ResolvedParameter<ILog>("Logger"))
);

因此,原始 Log 对象和注入到我的 marvy Little Context 对象的属性中的 Log 对象的哈希码是相同的。

但是...

注入过程要求我通过 Context 对象的接口公开其 Log 属性,这意味着它不能再是静态对象。 log4net ILog 对象是否是静态的似乎是决定它是否可序列化以及是否可以在程序集之间进行混合的决定因素,而不会出现戏剧性的“运行时将变得不稳定”警告(这仅对 Matrix 粉丝才真正有意义)。

尽管没有被阻止,但我感到沮丧,我使用了 Resharper 的漂亮的“带有支持字段的属性”,并将支持字段设置为静态,而 Interface 属性保持非静态。一切顺利,测试顺利进行。

所以我什至进行了重建并且成功了。因此,也许当这个问题进入集成测试时,我会偷偷地绕过 log4net 不可序列化的崩溃。

所以也许这会有所帮助,

谢谢

Stato

I've bumped through a few of these questions laying around various sites and the answers seem to be spun by l4n officianados toward the value of the lightweight wrapper that log4net 'is' (don't you get it?) and similar points of mind-boggling fact.

However it seems that what users are asking for (and this is my question) is how to fit the log4net objet model into the registertype/registerinstance sequence in the fluent config interface.

The goal here wouldn't be to re-wrap l4n, but simply to grab a decent reference that doesnt' require hijacking the fluent flow, as it were.

poor ejemplow, I want to get a reference to a configured instance of ILog from a LogManger.GetLogger method and put it into the fluent flow early enough to inject it into properties of my downstream objects.

So in response to one impatient suggestion, I tried created a normal instance of ILog in the canonical manner:

log4net.Config.XmlConfigurator.Configure();
static readonly log4Net.Ilog Log = LogManager.GetLogger(thatlongassemblyreflectionstuff);

So it would seem trivial (in the real sense of effortless) to now add that reference to the Unity container and get on with my wonderful life.

However, the signature for the RegisterInstance method wants a 'Type' not an interface.

For those who haven't searched through the log4net object model, the afficiananderos are correct: l4n is a 'wrapper' and you can't get a holt of the actual 'type' for the Log thingie.

So now I have to test. And you know what that means, it could take a minute, but will more likely take an hour or four (similarilties like the spellings of 'hour' and 'four' are never coincidental in real life).

However, the following, minus the elided part about the canonical setup, did work:

container
  .RegisterInstance("Logger", Log, new ContainerControlledLifetimeManager())
.RegisterType<IControllerContext, ControllerContext>
(
   "CtlrCtx", 
   new ContainerControlledLifetimeManager(), 
   new InjectionConstructor(new ResolvedParameter<IMessageBuilder>("MsgBldr")),
   new InjectionProperty("Log",new ResolvedParameter<ILog>("Logger"))
);

So the hashcodes for the orginal Log object and the Log object injected into the property of my marvy little Context object are identical.

However...

The injection process required that I expose the Log property of the Context object through its interface, meaning it could no longer be a static object. And whether the log4net ILog object is static seems to be the deciding factor as to whether it is serializable and can be mashalled between assemblies without the dramatic 'the runtime will become unstable' warnings (which are truly meaningful only to Matrix fans).

Discouraged, though not deterred, I used Resharper's nifty 'to property with a backing field' and set the backing field to be static whilst the Interface property stayed non-static. Well it built and the test ran green.

So I even did a rebuild and it worked. So maybe when this bubbles up to the integration tests I'll sneak past the log4net isn't serializable debacle.

So maybe this will help

Thanks

Stato

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半﹌身腐败 2024-08-09 21:41:21

在 Unity 2 中使用 InjectionFactory 有帮助吗? (请参阅此问题)。然后您的配置代码将如下所示:

IUnityContainer container = new UnityContainer();
container.RegisterType<ILog>(new InjectionFactory(factory => LogManager.GetLogger()));

然后您通过通常调用 Resolve() 检索记录器:

ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

您也可以将记录器的生命周期配置为 ContainerControllerLifetimeManager,以使其成为单例实例,但是我还没有验证过。

Would using the InjectionFactory in Unity 2 help? (see this question). Then your configuration code would look something like this:

IUnityContainer container = new UnityContainer();
container.RegisterType<ILog>(new InjectionFactory(factory => LogManager.GetLogger()));

Then you retrieve the logger with the usual call to Resolve():

ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

You might also be able to configure the lifetime of the logger to be ContainerControllerLifetimeManager as well, to make it a singleton instance, but I haven't verified that yet.

半夏半凉 2024-08-09 21:41:21
ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

确实有效。

但是,如果您在类上有记录器的属性,并且想要将此记录器实例注入其中,那么这将不起作用 AFAICT。我想我可能偏离了目标,但我正在尝试在新的上下文中重用记录器实例。这可能是可撤消的,所以我可能不得不放弃注入它,而只是将这一行添加

ILog logger = container.Resolve<ILog>();

到每个类中,这给我带来的结果似乎与在每个类中实例化它略有不同......

我希望

private ILog Logger {get;set;} 

可以只是被注入,但这似乎根本不起作用,因为通过 log4net 一切都是通过接口完成的,而具体的记录器则隐藏在绿野仙踪的幕后。

ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

does indeed work.

However, if you have a property for a logger on a class, and want to inject this logger instance to it, that will not work AFAICT. I guess I may be off target, but I am trying to reuse the logger instance in a new context. This may just be undoable, so I may have to give up on injecting it and just add the line

ILog logger = container.Resolve<ILog>();

to every class, which gives me an outcome that only seems marginally different than instantiating it in every class....

I was hoping that

private ILog Logger {get;set;} 

could just be injected but that doesn't seem to work at all, since all through log4net everything is done via interfaces and the concrete logger is hiding behind the curtain with the Wizard of Oz.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文