While diagnosing causes of low memory on an application converted from VB6 to VB.NET, we ran across a situation in which the application loaded the System.Web assembly (about 12MB) despite no user code referencing it.

The problem

After hooking the AppDomain.AssemblyLoad event, it was eventually determined that System.Web was being loaded by code calling My.Application.Info.DirectoryPath. But why?

The stack trace when the AssemblyLoad event for System.Web was raised looked something like this:

  • (event handler for assembly load event)
  • System.Type.GetType(...)
  • Microsoft.VisualBasic.MyServices.Internal.SkuSafeHttpContext.InitContext()
  • Microsoft.VisualBasic.MyServices.Internal.ContextValue<Utilities.My.MyApplication>.Value.get()
  • Utilities.MyUserCodeThatNeedsAssemblyPath

Apparently, calling My.Application was creating a SkuSafeHttpContext, whatever that was. Doing some quick Googling and even disassembling the module did not seem to reveal anything obvious.

Reproducing it

Creating a test application did not reproduce the problem; calling My.Application.* from the constructor of a WPF window did not bring System.Web along for the ride. Nor did calling it from the Application constructor of the project tht I was trying to fix.

Eventually, it was determined that it was only when you call My.Application from a separate assembly that this behaviour seems to manifest. In my test application, I set up something like this:

  • Demo.sln
    • Demo.vbproj [application project]
    • DemoUtilities.vbproj [.NET Framework class library]
      • Static method that calls My.Application.Info.CurrentPath

This test successfully forced System.Web to be loaded, with a callstack that looked very similar to our production application.

My hope is that this can help other developers in the future figure out why they may have phantom loads of the relatively large System.Web assembly in their VB.NET applications.

Open Questions

I am still not sure why this happens. My assumption is that since My.Application is intended to be a semi-global pseudo-namespace (it appears to have some magic for extending it), the developers of the VB.NET standard library determined that it should be a sort of singleton.

To avoid circular referencing, it is clear that they used some kind of decoupling mechanism so a “Helper” library does not need to know its owning application. I am not sure why they chose what appears from the signature to be an HTTP transport for this information. Could it be an analogue to .NET remoting?

ContextValue<T> is basically only documented by Microsoft as being used to support the My sugar, and also that we should never touch it.