in Development

Workflow + Portable Class Library (PCL) == No Intellisense In Visual Studio 2012-2013 (with fix!)

A few months ago I decided I wanted to bring some Reactive Extensions (Rx) awesomeness into some of my custom workflow activities. So, as any good .NET dev would do, I fired up the Package Manager Console and typed Install-Package Rx-Main and it installed Rx 2.1 for me. Then I started leveraging Rx APIs in my custom activity implementation and all seemed well… at first. At some point I had closed out of the solution and when I re-opened the solution I suddenly had no Intellisense for any types except those belonging to the mscorlib assembly, yet I could build the project no problem. I thought to myself “Wait, what? This was just working? What happened?”. After several attempts at trying to figure out what had gone wrong, I realized that it was adding the Rx library to the project caused the problem. At first I thought maybe it was something specific about Rx itself, but I knew that couldn’t be it. Then I realized that Rx was a PCL lib (note: 2.1 was at the time, 2.2 now adds a .NET 4.5 specific assembly too). So I installed another PCL lib just to check and, sure enough, it caused the same problem.

Next, as a sanity check, I created a brand new WF Console Application to make sure it had nothing to do with my specific solution/projects. As soon as I added a PCL lib, close and reopened the solution I lost Intellisense. So, I did what any frustrated Visual Studio user should do and I opened a bug on Connect. Unfortunately, that bug was promptly closed as “By Design” with a comment that it would be addressed in a future version of Visual Studio.

Now, I’d like to think I’m pretty good at memorizing APIs, but with the plethora of libraries that one works with these days, not to mention all the overloads, extensions, optional parameters, generic signatures, etc. it’s a very tall order to code at max efficiency without Intellisense support. This bug effectively breaks one of the key features of Visual Studio and they aren’t going to commit to fixing it in the next update… if not sooner? Yeah, I wasn’t satisfied with that response. This basically meant I would have to choose between throwing out WF and finding some other tech to solve those problems or not being able to leverage PCL libs. The investment in WF was too large to just toss (not to mention I personally find WF to be an awesome technology) and with PCL’s becoming more and more prevalent, even from MS groups, this simply wasn’t a choice I could make. So, back against the wall, I spent about an hour yesterday debugging the root cause and coming up with a workaround.

First thing I did was fire up two instances of Visual Studio 2013. The first instance would be where I open the Workflow Console Application project that I had been repro’ing the issue with and the second instance would be attached as a debugger of the first instance. Next I turned off the “Just My Code” feature in the debugger instance and configured to break on all CLR first chance exceptions. Then I popped over to the other instance and opened up the Workflow Console Application project. After stepping through a plethora of benign exceptions from various sources, I started to see an exception saying that the System.Runtime assembly could not be located. Specifically, I saw this:

A first chance exception of type 'System.IO.FileLoadException' occurred in System.Xaml.dll

Additional information: Cannot resolve dependency to assembly 'System.Runtime, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.

Hmm, well, I know System.Runtime is type fwd’d to mscorlib in .NET4.5, but why the heck wouldn’t that “just work”? Oh, wait… what’s that bit about ReflectionOnly? So I turned my attention to the stack trace:

System.Xaml.dll!System.Xaml.XamlSchemaContext.UpdateXmlNsInfo()	Unknown
System.Xaml.dll!System.Xaml.XamlSchemaContext.TryGetCompatibleXamlNamespace(string xamlNamespace, out string compatibleNamespace)	Unknown
System.Xaml.dll!System.Xaml.XamlXmlReader.IsXmlNamespaceSupported(string xmlNamespace, out string newXmlNamespace)	Unknown
System.Xaml.dll!System.Xaml.XmlCompatibilityReader.MapNewNamespace(string namespaceName)	Unknown
System.Xaml.dll!System.Xaml.XmlCompatibilityReader.GetMappedNamespace(string namespaceName)	Unknown
System.Xaml.dll!System.Xaml.XmlCompatibilityReader.NamespaceURI.get()	Unknown
System.Xaml.dll!System.Xaml.XmlCompatibilityReader.ReadStartElement(ref bool more)	Unknown
System.Xaml.dll!System.Xaml.XmlCompatibilityReader.Read()	Unknown
System.Xaml.dll!MS.Internal.Xaml.Parser.XamlScanner.DoXmlRead()	Unknown
System.Xaml.dll!MS.Internal.Xaml.Parser.XamlPullParser.Parse()	Unknown
System.Xaml.dll!MS.Internal.Xaml.NodeStreamSorter.StartNewNodeStreamWithSettingsPreamble()	Unknown
System.Xaml.dll!MS.Internal.Xaml.NodeStreamSorter.NodeStreamSorter(MS.Internal.Xaml.Context.XamlParserContext context, MS.Internal.Xaml.Parser.XamlPullParser parser, System.Xaml.XamlXmlReaderSettings settings, System.Collections.Generic.Dictionary<string,string> xmlnsDictionary)	Unknown
System.Xaml.dll!System.Xaml.XamlXmlReader.Initialize(System.Xml.XmlReader givenXmlReader, System.Xaml.XamlSchemaContext schemaContext, System.Xaml.XamlXmlReaderSettings settings)	Unknown
System.Xaml.dll!System.Xaml.XamlXmlReader.XamlXmlReader(System.Xml.XmlReader xmlReader, System.Xaml.XamlSchemaContext schemaContext, System.Xaml.XamlXmlReaderSettings settings)	Unknown
XamlBuildTask.dll!Microsoft.Build.Tasks.Xaml.PartialClassGenerationTaskInternal.ReadXamlNodes(string xamlFileName)	Unknown
XamlBuildTask.dll!Microsoft.Build.Tasks.Xaml.PartialClassGenerationTaskInternal.ProcessMarkupItem(Microsoft.Build.Framework.ITaskItem markupItem, System.CodeDom.Compiler.CodeDomProvider codeDomProvider)	Unknown
XamlBuildTask.dll!Microsoft.Build.Tasks.Xaml.PartialClassGenerationTaskInternal.Execute()	Unknown
[AppDomain (DefaultDomain, #1) -> AppDomain (PartialClassAppDomain_ba752eb5-e2fa-4aec-b2e9-5b9713fbf23d, #8)]

Now, as you probably know, Workflow is based on XAML and so what we see here is the XAML compiler trying to do its job. One of the things it does is create a “reflection only” AppDomain where it attempts to load/validate all the types in the XAML document. The other part of the error message mentions that the domain needs to be pre-initialized with all the assemblies that will be referenced OR someone has to resolve the assembly themselves by hooking the ReflectionOnlyAssemblyResolve event. First I peeked to see if something had hooked that event, but the delegate was null, so I knew that the XAML compiler must have been pre-loading the assemblies. So then I looked at the assemblies that were pre-loaded by calling AppDomain::ReflectionOnlyGetAssemblies and, guess what? No System.Runtime. How does the XAML compiler know what list of assemblies to pre-load? By the assembly references you have in your project.

As mentioned earlier, in .NET 4.5, there is no need to reference System.Runtime any more because the types are all in mscorlib now, so if you start a new 4.5 project (or upgrade an existing project to 4.5), there will be no reference to System.Runtime any more. However, PCL libraries target very specific subsets of .NET and if you look at a PCL lib, you will see it explicitly references the System.Runtime assembly. Since the XAML compiler is only pre-loading the references it reads from the project into the “reflection only” AppDomain that explains not being able to find that exactly assembly by name for reflection purposes.

Ok, great, problem identified. So how can we fix it? Turns out it’s pretty simple:

  1. Unload your project file
  2. Open it in the XML editor
  3. Add an explicit reference to System.Runtime by hand. (I usually just go stick it right under the System reference like so:
    <Reference Include="System" />
    <Reference Include="System.Runtime" />

Now we should just have to reload the project and we’re alllllll set. Err… nope. Didn’t work. WHAT!? “You lied to me!” Well, no, it turns out that after I fixed this it still didn’t work at first, so I debugged again and got another exception like above, but this time saying that it couldn’t find the assembly System.Resources.ResourceManager. This assembly is again rolled up into mscorlib in 4.5, so you need to play the same trick with a manual project reference. Therefore your final project file should look like so:

<Reference Include="System" />
<Reference Include="System.Runtime" />
<Reference Include="System.Resources.ResourceManager" />

Hopefully this work saves other people time and the cost of anger management therapy. I also hope it encourages Microsoft to address the issue with a simple update that has knowledge of PCLs and implicitly loads type forwarded assemblies into the “reflection only” AppDomain so they are properly discovered.

ScriptCs.ClrMD – Enabling rich, programmatic .NET Diagnostics

I’ve been tweeting about this for a little over a week now, but I figured it would make for a good subject for my first blog post since saying I was going to try for a comeback in 2013 which, otherwise, hasn’t been going so well thus far. 😉 Ok, so if you haven’t already heard […]

Microsoft Announces Shared CDN for Common AJAX Scripts

ScottGu broke the news last night that Microsoft is making a shared CDN available for the purposes of hosting the AJAX scripts. The full details of the scripts that are supported right now are available here, but basically it’s ASP.NET AJAX 4.0 Preview 5 (which just came out) and jQuery 1.3.2. If you’re using ASP.NET […]

ASP.NET AJAX 4.0 Preview 5 Released, Includes “Disposable Objects” Performance Fix!

Good news, ASP.NET AJAX 4.0 Preview 5 is here! Better yet, Microsoft has overhauled the implementation of tracking disposable objects to include the performance enhancement that was discussed in my “ASP.NET AJAX ‘Disposable Objects’ Performance Heads Up” posts (Part I & II). So how’d they do it? They tag each disposable object with an integer […]

Full Expression Tree Support Coming in .NET/C# 4.0

Yesssssssss! I’ve been waiting and hoping that this was coming in 4.0 and now it’s official: Full Expression Tree Support. This seems like a HUGE step forward to me. With the advent of this feature, one can finally implement support for converting an expression written in C# to something that runs on the GPU. For […]

ASP.NET AJAX “Disposable Objects” Performance Heads Up – Part II

Ok, I had to put together a Part II to this topic because I was totally wrong in Part I about objects being able to be used as keys because… well, I’m an idiot and didn’t do all my fact checking to make sure my implementation was 100% sound. 🙂 Thanks to Dave Reed who […]

ASP.NET AJAX “Disposable Objects” Performance Heads Up

Update: Make sure you read Part II as there was ultimately a fundamental flaw in this implementation which prevents it from working as I originally thought. One of the important features of the ASP.NET AJAX client side framework is the concept of disposing of components/controls so that they unregister event handlers and release DOM element […]

Getting a distinct list of changed files from TFS using PowerShell

If you’re like me and need to do code-reviews of other people’s stuff or maybe you just want to see everything that’s changed during a certain period of a project, then here’s a nice PowerShell tip for you. First, make sure you’ve downloaded the latest version of the Team Foundation Powertools. Starting with the October […]