This question is more about C# than it is about log4net (I think).
这个问题更多的是关于c#而不是log4net(我认为)。
I created a custom appender and let it read a static field that was set previously by the program.
我创建了一个自定义appender,并让它读取程序之前设置的静态字段。
To my astonishment the static field was reinitialized and the set value dit not make it to the appender.
令我惊讶的是,静态字段被重新初始化,设置值dit没有将其设置到appender。
I fired up debugview and saw that the static constructor is called twice (!). This should not be possible in the same appdomain right? Only debugview brought this to light since VS didn't hit a second time on the breakpoint.
我启动了debugview,并看到静态构造函数被调用了两次(!)这在同一个appdomain中不应该是可能的,对吧?只有debugview将它打开,因为VS在断点上没有第二次命中。
Note that this is not a question about avoiding the use of static variable with log4net. I'm interested in what kind of magic log4net uses to accomplish this?
注意,这不是关于避免使用log4net静态变量的问题。我感兴趣的是什么神奇的log4net用来完成这个任务?
Edit #1
编辑# 1
Hello John, Big fan.
你好约翰,大风扇。
I isolated it further as requested. First I started blank and worked towards the target situation that exposes the error. Since I almost matched the target character by character and still didn't repro I went the other way round.
我按要求进一步隔离它。首先,我开始时是空白的,并致力于暴露错误的目标情况。因为我几乎和目标角色匹配了,而且还是不支持,所以我走了另一个方向。
Starting from the error situation I stripped out everything that I deemed not essential till it started ... working as expected.
从错误的情况开始,我剔除了我认为不重要的一切,直到它开始……按预期工作。
It seems there is some weird thing hoing on when the runtime tries to resolved the log4net assembly (as observed in debug mode)
当运行时试图解析log4net程序集(在调试模式中观察到)时,似乎会出现一些奇怪的事情。
This is what I see with debugview:
这就是我在debugview中看到的:
[7756] General: WARN - Failed to parse module's 'log4net' version . Exception: System.NullReferenceException: Object reference not set to an instance of an object. [7756] at DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor(String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version) [7756] General: WARN - Failed to parse module's 'FollowUp.Common' version . Exception: System.NullReferenceException: Object reference not set to an instance of an object. [7756] at DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor(String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version)
[7756] General: WARN -无法解析模块的“log4net”版本。例外:系统。NullReferenceException:对象引用未设置为对象的实例。[7756]在DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs . .ctor(String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version) [7756] General: WARN -解析模块的后续。常见的版本。例外:系统。NullReferenceException:对象引用未设置为对象的实例。[7756]在DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs . .ctor(String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version)
And VS shows no value for the path in the debug-module screen. Now how did I managed to come to that situation? Weird that it managed to load an assembly but can't tell anymore from where :)
而VS在调试模块屏幕上没有显示路径的值。我是怎么做到的呢?奇怪的是,它成功地加载了一个程序集,但再也无法从何处得知:)
Here is the isolated situation to the point that if I modify it further it starts working as expected.
这是一个孤立的情况,如果我进一步修改它,它将开始按预期工作。
https://www.sugarsync.com/pf/D6486369_1701716_00940
https://www.sugarsync.com/pf/D6486369_1701716_00940
I'm still interested in the technical details but after removing the reference to log4net and adding it again it all started to work again. I'm happy that it works but it nags me that I don't have a thorough explanation
我仍然对技术细节感兴趣,但是在删除了log4net的引用之后,再添加它,一切又开始工作了。我很高兴它能起作用,但它提醒我我没有一个完整的解释
Also, the static constructor *is*called twice now which makes sense since the type is initializes again when log4net gets its hands on it.
另外,静态构造函数*现在被调用了两次,这是有意义的,因为当log4net访问该类型时,类型将再次初始化。
I think it isn't worthwhile to spent more time on this cause I think the solution was in a weird state and to understand all this has marginal value. Still, if you can think of something to explain this I'd be glad to here.
我认为花更多的时间在这个问题上是不值得的因为我认为解决方案处于一种奇怪的状态并且理解所有这些都有边际价值。不过,如果你能想出什么解释的话,我很乐意在这里。
Edit #2
编辑# 2
It turned out that some assemblies were indeed loaded twice including the one with the static constructor. I'll investigate later how this is possible but I have a workaround by disabling and enabling Costura. Costura is a msbuild task that merges all the assemblies into one. I'm not saying that Costura is the root cause. It could easily be that the csproj/sln files were in strange state.
结果显示,一些程序集确实被加载了两次,包括带有静态构造函数的程序集。稍后我将研究这是如何实现的,但是我通过禁用和启用Costura来解决问题。Costura是一个msbuild任务,它将所有程序集合并为一个。我不是说科斯图拉是根本原因。很可能csproj/sln文件处于奇怪的状态。
Thinking on how to diagnose this problem faster in the future I fired up sysinternals ProcessExplorer. Now I expected to see the assemblies being loaded only once but I found saw that they were loaded twice. Seems this is a bug in the runtime thats fixed only in .NET 4
考虑到如何在未来更快地诊断这个问题,我启动了系统内部程序监控器(sysinternals ProcessExplorer)。现在我希望看到程序集只被加载一次,但是我发现它们被加载了两次。这似乎是运行时中的一个bug,只在。net 4中被修复。
http://forum.sysinternals.com/why-some-net-assemblies-are-duplicated-in-memory_topic15279.html https://connect.microsoft.com/VisualStudio/feedback/details/467560/clr-maps-assemblies-into-the-virtual-address-space-twice
http://forum.sysinternals.com/why-some-net-assemblies-are-duplicated-in-memory_topic15279.html https://connect.microsoft.com/VisualStudio/feedback/details/467560/clr-maps-assemblies-into-the-virtual-address-space-twice
Edit #3 Costura made the assemblies load twice. The issue was fixed on the same day by the project owner :) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304
编辑#3 Costura两次加载组件。项目所有者在同一天解决了这个问题:)http://code.google.com/p/costura/issues/detail?
We need a Costura tag but I don't have the necessary 1500 reputation points. Please create it if you have the rights. Thanks.
我们需要一个科斯图拉标签,但我没有必要的1500个积分。如果你有权利,请创建它。谢谢。
Kind Regards, Tom
亲切的问候,汤姆
2 个解决方案
#1
4
It looks like you managed to load two separate instances of log4net
into the same AppDomain
.
看起来,您成功地将log4net的两个独立实例加载到同一个AppDomain中。
One project references:
一个项目的引用:
<Reference Include="log4net">
<HintPath>..\packages\log4net.1.2.11\lib\net35-full\log4net.dll</HintPath>
</Reference>
The other:
另:
<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ExternalReferences\log4net.dll</HintPath>
</Reference>
One of them is strongly named, the other isn't, this resulted in .net giving them different identities. And the hint path differs too. Also one seems to be 1.2.10
, the other 1.2.11
.
其中一个是强命名的,另一个不是,这导致。net给了他们不同的身份。提示路径也不同。一个看起来是1。2.10,另一个是1。2.11。
try calling AppDomain.GetAssemblies()
and check if log4net
occurs twice.
尝试调用appdomain.getassembly()并检查log4net是否发生两次。
#2
1
Well it could be explcitly invoking the type initializer:
它可以解释调用类型初始化器:
var initializer = typeof(Foo).TypeInitializer;
initializer.Invoke(null);
However, I'd hope that it's not doing that. Can you come up with a short but complete program which demonstrates this happening?
然而,我希望它不会这么做。你能想出一个简短但完整的程序来证明这一点吗?
#1
4
It looks like you managed to load two separate instances of log4net
into the same AppDomain
.
看起来,您成功地将log4net的两个独立实例加载到同一个AppDomain中。
One project references:
一个项目的引用:
<Reference Include="log4net">
<HintPath>..\packages\log4net.1.2.11\lib\net35-full\log4net.dll</HintPath>
</Reference>
The other:
另:
<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ExternalReferences\log4net.dll</HintPath>
</Reference>
One of them is strongly named, the other isn't, this resulted in .net giving them different identities. And the hint path differs too. Also one seems to be 1.2.10
, the other 1.2.11
.
其中一个是强命名的,另一个不是,这导致。net给了他们不同的身份。提示路径也不同。一个看起来是1。2.10,另一个是1。2.11。
try calling AppDomain.GetAssemblies()
and check if log4net
occurs twice.
尝试调用appdomain.getassembly()并检查log4net是否发生两次。
#2
1
Well it could be explcitly invoking the type initializer:
它可以解释调用类型初始化器:
var initializer = typeof(Foo).TypeInitializer;
initializer.Invoke(null);
However, I'd hope that it's not doing that. Can you come up with a short but complete program which demonstrates this happening?
然而,我希望它不会这么做。你能想出一个简短但完整的程序来证明这一点吗?