The Mysterious +<>c__DisplayClass1

by jmorris 9. July 2011 01:23

While unit testing a a VirtualPathProvider today, I came upon an interesting exception:

System.Runtime.Serialization.SerializationException : Type 'Foo.Web.Core.UnitTests.Plugins.Modules.PluginRegistrarTests+<>c__DisplayClass1' in assembly 'Foo.Web.Core.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

I was stumped by this…what, where and who  is +<>c__DisplayClass1'? Granted my scenario was somewhat complex in that I am testing in a by using a fake AppDomain that mimics the ASP.NET HostingEnvironment ala this post.

When I saw that error, I immediatly thought the problem was that I was missing the Serializable attribute, since the exception explicitly states: “[type] is not marked as serializable.” I added that attribute to class that I was loading into the faux AppDomain for the same result:

image

WTF? I was stumped! I googled around a bit and got side tracked by some discussions of MarshalByRefObject and finally stumbled upon something on Ode2Code. I wasn’t quite sure of what the problem was until I read some of comments. Most notable this one. A quick check of the IL with ILSpy confirmed my suspicions:

image

Fix was easy: simply move the declaration of the FakeHttpApplication class to within the scope of the delegate itself. Here is how I had it defined:

image

And after I moved into the scope of the delegate:

image

So, what was the problem? Basically it comes down to the scoping of Anonymous methods and how the compiler generates code to support them. Anonymous methods are simply compiler generated types. The generated type c__DisplayClass1 is not marked as serializable, so it fails when passed into the scope of the Anonymous delegate call…which is executing in another AppDomain (that does not contain the Anonymous type definition).

Tags: ,

Unit Testing

Dynamic Types Make Unit Testing JSON in ASP.NET MVC a Breeze!

by jmorris 18. October 2010 22:57

The new dynamic type in C# 4 was mainly added to offer simpler creation of objects using reflection and the ability to treat objects as they are no matter where they were created: COM interop, DLR, etc. It basically defers static typing until runtime. The object itself is statically typed, however the compiler bypasses compile-time static type checking until runtime.

One place where this kind of late bound typing is really useful is unit testing ASP.NET MVC action methods that return JSON via JsonResult. For example, given the following controller action method:

image 

And the following unit test you’ll quickly discover that while you can see the values as a watch in Visual Studio or while debugging, you cannot actual run an assert on any of the members (Assert.AreEqual(1, data.FeedId) will throw an exception:

image 

It should be relatively obvious as to why this will not work, notably anonymous types are internal to the assembly that they were created in and results.Data returns a System.Object. Using the dynamic keyword, one might assume that the we should be able to run asserts on the properties of the JSON result, but unfortunately, it’s not that simple:

image 

The exception gives some subtle hints as to what the problem is:

'MyFantasyFootBallGuruTests.Controllers.AlertsControllerTests.GetCurrentPick2' failed: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : 'object' does not contain a definition for 'FeedId' at CallSite.Target(Closure , CallSite , Object )  at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) Controllers\AlertsControllerTests.cs(47,0): at MyFantasyFootBallGuruTests.Controllers.AlertsControllerTests.GetCurrentPick2()

Well it’s somewhat of a hint…the object does not contain a definition for ‘FeedId’ is caused by the fact that while we can see the values with the debugger, the reality is that the ‘object’ is really an anonymous type, which exists in the assembly containing the controller. Since anonymous types by definition are always internal to the assembly they are defined in, the runtime throws an exception. Fortunately, the fix is for this is easy.

When you create a new project (assembly) in Visual Studio, a “Properties” folder with a class called “AssemblyInfo.cs” is automatically created. This class contains attributes that define the metadata of the assembly: the name, description, title, whether or not the assembly is visible to COM components, the version, and other information related to the assembly. There is also another very important attribute to those wishing to test anonymous types in assemblies other than the assembly that the anonymous type is defined in: InternalsVisibleToAttribute.

The InternalsVisibleToAttribute makes types that are normally only visible in the defined assembly to other assemblies specified in the attribute. For instance:

image

Adding this attribute to the assembly that contains the controller classes, makes any anonymous types visible to the unit test assembly, MyFantasyFootballGuruTests. After adding this attribute, the unit tests will not only compile, but allow the properties of the anonymous type to be tested:

image

References

Tags: , , , , , ,

Unit Testing

Use System.Web.HttpRuntime.Cache Instead of System.Web.Caching.Cache for Unit Testing

by jmorris 24. August 2009 21:41

I ran into an interesting problem today while unit testing some code that depended upon System.Web.Cache where the Cache object itself was instantiated, but the internal dictionary was not. What happens is you end up getting null reference exceptions when you try add, remove, etc. anything from the Cache while unit testing. For example:

 



Kinda dififcult to spot what the issue is since it looks like the error is caused by the "PageTemplateKey" not matching on a cached item, but that's not the behavior of System.Web.Caching.Cache. When an item does not exist, null is returned...so what else could be causing this? The "'ContentFactory.Cache.Count' threw and exception" is the dead give away. The internal cache object was not being created in a non server environment.

For my unit tests I am using the Moq framework and mocking the major players of the ASP.NET HTTP stack. Notice that when I perform the setup on the mockContext object below I am setting the return value to be a new Cache(), this is where I am running into the issues described above.



So what to do now? There are at the least to ways to work around this issue: 1) create a mock cache wrapper or 2) use System.Web.HttpRuntime.Cache as a replacement. Opting for simplicity, I switched out the code on my MakeMockContext method to use System.Web.HttpRuntime.Cache and viola, problem solved:


This worked like a charm:

 



The reason why this works is that System.Web.Cache uses CacheInternal, which you guessed it, is set by an internal setter, called SetInternalCache. HttpRuntime directly makes the call to create CacheInternal when you access the HttpRuntime.Cache property.

Tags: , , , ,

Jeff Morris

Tag cloud

Month List

Page List