Here is my hunch about what's going on.
UPDATE: I think this is a recursion problem with the AssemblyResolve event. Based on the comments, the stack overflow did not occur, but the recursion problem can still be resolved, so the answer is still applicable.
There is an indication that this error depends on the order of access to resources. Most likely, this happens when the first one is access to one of the static classes that you mentioned.
The first time you access a resource, the AssemblyResolve event fires several times. Subsequent resource requests do not result in AssemblyResolve events. This can be demonstrated by the following code:
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => { Console.WriteLine("Resolve {0}", eventArgs.Name); return null; }; Console.WriteLine(Resource1.String1); Console.WriteLine(Resource1.String1);
Result:
Resolve ConsoleApplication1.resources, Version=1.0.0.0, Culture=ru-RU, PublicKeyToken=null Resolve ConsoleApplication1.resources, Version=1.0.0.0, Culture=ru-RU, PublicKeyToken=null Resolve ConsoleApplication1.resources, Version=1.0.0.0, Culture=ru, PublicKeyToken=null Resolve ConsoleApplication1.resources, Version=1.0.0.0, Culture=ru, PublicKeyToken=null Value from resource Value from resource
The registrar refers to the resources, and this is indicated by:
000000c898899ff0 00007ff885b92014 System.Resources.ResourceManager.GetString(System.String, System.Globalization.CultureInfo) 000000c89889a0a0 00007ff89914aa62 NewRelic.Agent.Core.Config.ConfigurationLoader.InitializeFromXml(System.String, System.String) 000000c89889a140 00007ff89914a838 NewRelic.Agent.Core.Config.ConfigurationLoader.Initialize(System.String) 000000c89889a1a0 00007ff899143be9 NewRelic.Agent.Core.Config.ConfigurationLoader.Initialize() 000000c89889a210 00007ff899123a27 NewRelic.Agent.Core.Agent+AgentSingleton.CreateInstance() 000000c89889a280 00007ff8991239c2 NewRelic.Agent.Core.Singleton`1[[System.__Canon, mscorlib]]..ctor(System.__Canon) 000000c89889a2c0 00007ff89912388b NewRelic.Agent.Core.Agent..cctor() 000000c89889a700 00007ff8e4b2a7f3 [GCFrame: 000000c89889a700] 000000c89889ce88 00007ff8e4b2a7f3 [PrestubMethodFrame: 000000c89889ce88] NewRelic.Agent.Core.Agent.get_Instance() 000000c89889cef0 00007ff89912358c NewRelic.Agent.Core.AgentShim.GetTracer(System.String, UInt32, System.String, System.String, System.Type, System.String, System.String, System.String, System.Object, System.Object[])
My conclusion is that a logger can be successfully launched without the AssemblyResolve of any associated event for the first time and will never raise an AssemblyResolve event if it is fired for the first time this way.
If this is your first time accessing a resource from AssemblyResolve, a recursive call occurs, which raises a StackOverflowException. It is easy to simulate:
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => { Console.WriteLine("Resolve {0}", eventArgs.Name); Console.WriteLine(Resource1.String1); return null; }; Console.WriteLine(Resource1.String1);
And there is a Logger call:
catch { context.RunnerLog.Error(string.Format(CultureInfo.InvariantCulture, "Failed to load assembly {0}.", args.Name)); result = null; }
There may be a difference if the log was initialized before the AssemblyResolve event was connected, or another condition occurred that did not cause the registrar to trigger a failed AssemblyResolve event.
When you start with a call to a static class and have an exception in AssemblyResolve, and you have to catch it and register, a call to the log calls access to the resource and the other calls another build solution, and this recursion leads to a stack overflow.
While the first request has a lock on the static class constructor, if this operation took a long time before a StackOverflowException, other requests are blocked, but it does not matter because they fail with a TypeInitializationException. The latter will never happen, because the domain will still start unloading after a StackOverflowException.
The fact that he shows some sort of dictionary search method from above does not matter either - this is probably the last straw that contributed to the stack overflow.
One thing I would recommend using a different kind of logger inside AssemblyResolve event handlers.
Another thing is that I will try to avoid blocking I / O requests in static constructors, such as access to resources or manual assembly. Just initialize the main material inside and use another concurrency mechanism for lazy initialization in the public methods themselves.
However, I do not think that the reason for the suspicious stackoverflow is related to static constructors.
Also, it cannot be suspicious if the recursion is too slow for a stackoverflow situation to occur. Thus, the domain can start offloading for other reasons - for example, using some IIS resource protection tool, such as the number of threads or the consumption of shared memory. This is likely to happen if the requests last a long time.