ReBuildAll Blog
Thoughts (mostly) on .NET development

Extending ASP.NET MVC HtmlHelper and Gravatars   (MVC)   
I got excited about Gravatars the other day and decided to add support for them into my blog. You can read more about Gravatars and how they can be used in your project on the following page:

Gravatar

Having used ASP.NET MVC, the view that was displaying the comments had something like the following in them. This displayed the name of the commenter being a hyperlink, and that pointing to a mailto: link with the email address. The address was applied some transformations to prevent spammers from picking them from the page automatically:

<%= Html.Encode ( SomeBlogNamespace.SpamFreeEmail ( Model.Comment.CommentedEmail ) )%>

Now I did not want to change the model at all, but still wanted to add support for Gravatars. For this, I needed a method that could calculate the MD5 hash and display it in the format Gravatar wants it.

As I have my own base classes and model classes, I could have added the code there but decided to extend the MVC HtmlHelper instead. Using extension methods, that is really simple. I just added a new class to hold my extension method:

    public static class GravatarHelper
    {
        public static string GravatarHash ( this HtmlHelper html, string value )
        {
            var byteArray =
                   MD5CryptoServiceProvider.Create ().ComputeHash (
                        System.Text.ASCIIEncoding.ASCII.GetBytes ( value.ToLower () ) );

            string result = string.Empty;
            foreach ( var item in byteArray )
            {
                result += item.ToString ( "x2" );
            }

            return result;
        }
    }


I also needed to add a namespace import into the .ASCX file that contained my comments view:

<%@ Import Namespace="namespace" %>


After that I could change the view to display the picture from Gravatar by calculating the hash from within the view code:

        <%= Html.GravatarHash ( Model.Comment.CommentedEmail ) %>

If you make a comment into this blog now, you can take advantage of Gravatars by giving your Gravatar registered email address. If you have a registered avatar the blog will display the image beside your comment.

This same method can be used to extend HtmlHelper in many different ways, adding small (or big) utilities that you can code and take advantage from the View in ASP.NET MVC.

.NET routing and Web Part Zones == an impossible mix   (ASP.NET)   
Ever used Web Part Zones? How about ASP.NET Routing (introduced in .NET 3.5 SP1)? Both are interesting features. But try them together, and you are destined to fail. The reason for this is probably because different teams implemented them, and no one thought they would be using it together. Doh?! :-\

I bumped into this problem when I wanted to add Web Part Zone support for my rpgWiki application (a wiki we use for roleplaying). I was greeted with a nasty exception:

HttpException (0x80004005): The file '/WikiWeb/articles/Helsinki_by_Night.aspx' does not exist.

Here the /WikiWeb is the path to the application on my development server, and the rest of the path is a non existing virtual file. Without the Web Part Zone code, this works just fine, ASP.NET Routing will find the actual physical file and execute that.

Looking at what went wrong I found the following code fragment was being executed. The actual exception happened when invoking ToggleScope():

                if ( WebPartManager1.Personalization.Scope == PersonalizationScope.User )
                {
                    WebPartManager1.Personalization.ToggleScope ();
                }

In my rpgWiki project I did not want to provide per user customization. So whenever I saw the User scope, I wanted to change that to Shared scope. So why the hell do I get this exception all of a sudden?

Well, it turns out (after looking at the call stack and digging around with Reflector) that ToggleScope will change the setting, and after that execute a Server.Transfer() to the same page. In "classic" Web Forms without routing this is not a problem, but it turns out the ASP.NET team did not upgrade Server.Transfer() for routing. So it tries to execute the same address where the original request came to, and because it is a virtual path only understood by routing, it will not work.

I was able to speak with Scott Galloway from the ASP.NET team at a conference. He also confirmed this to be a bug, but couldn't say if it would be corrected.

Of course this means that not only Web Part Zones will not work, but rather Server.Transfer() will never work when you want to transfer to a page that does not exist and would need routing.



Overriding virtual methods at runtime   (Framework)   
I was faced with a problem where I had a big bunch of Web service proxy classes, generated from their WSDL descriptions. I needed to override one virtual method of the base class to provide some custom code in the proxy class. This however presented two problems:

- I have many proxy classes in which I want to include this new functionality. These are in many different projects.
- The proxy classes are generated, so when they would be regenerated the code change would need to be reapplied.

The second point could be solved by deriving yet another class from the proxy class (or by using partial classes). This way the changes would live through regeneration cycles, but would create me twice as much classes, and managing changes in these new classes would still be a problem. Not to mention this would require recompiling and redeploying and reconfiguring all the applications.

I ended up using a much different solution using reflection and code emit. This allows for ease of maintainability and allows me to apply the new features without code changes or recompilation in the existing projects.

The .NET Framework provides very good code emiting capabilities: you can create .NET code on the fly, dynamically, and then call it right away. While this was probably aimed at scripting engines, it does give me a solution to the problem. When I will need to call a method from a proxy class I will generate a new derived class dynamically and override the method in question. The proxy classes were being used through reflection to begin with, so not much change is required: I can just pass in the Type instance of the generated class instead of the original, and everything should work.

There are some minor problems with this solution. First, the method body has to be provided in IL - Intermediate Language. That is like writing code in assembly language for the x86 platform, not very friendly. I was able to partly navigate around this problem by creating a new static class that provides the functionality I want, and calling this class from the new overriden method. Another solution would have been to write the code myself in C#, compile, and then use either ILDASM or REFLECTOR to copy the IL generated into my project. Anyhow, I ended up studying a little bit of IL, which was actually quite fun :-)

So how do you create code on the fly? Lets suppose I have a class called MyOriginalClass. It is a generated proxy class, derived from SoapHttpClientProtocol. I want to provide an implementation for the GetWebRequest() method, that is a protected virtual method.

So I started by getting the type of the original class. Now I can create a new Assembly and Module. Think of the Assembly as containing the metadata and the Module as containing the actual code - you can find more about this in MSDN.

Type typeofOriginal = typeof ( MyOriginalClass );

AssemblyName asmName = new AssemblyName ( "Test" );
AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly (
    asmName,
    AssemblyBuilderAccess.RunAndSave );

ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule (
    asmName.Name,
    asmName.Name + ".dll" );


The code above creates a new assembly named Test. The module is just named using the same syntax, getting the .DLL extension. These is all done dynamically, so nothing is written to disc. Next step is creating the new class, that will derive from my original class.

TypeBuilder typeBuilder = modBuilder.DefineType (
    typeofOriginal.Name + "WithoutKeepAlive",
    TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
    typeofOriginal );


The new class has the name of the original one with WithoutKeepAlive added to the end. And it of course has the original class as its base class. So now it is time to generate our new overriden method. This will simply call MyNewClass.GetWebRequest() method, which is a public static method I define elsewhere. By calling this method I get away with writing as little IL as possible.

// create a new method
MethodBuilder methodBuilder = typeBuilder.DefineMethod (
    "GetWebRequest",
    MethodAttributes.Public | MethodAttributes.ReuseSlot |
      MethodAttributes.HideBySig | MethodAttributes.Virtual,
    typeof ( System.Net.WebRequest ),
    new Type[] { typeof ( Uri ) } );

// get IL generator instance
ILGenerator ilgen = methodBuilder.GetILGenerator ();

// declare local variable
LocalBuilder localBuilder =
ilgen.DeclareLocal ( typeof ( System.Net.WebRequest ) );

// create method body in IL
ilgen.Emit ( OpCodes.Ldarg_1 );
ilgen.Emit (
    OpCodes.Call,
    typeof ( MyNewClass ).GetMethod (
        "GetWebRequest",
        BindingFlags.Static | BindingFlags.Public ) );
   ilgen.Emit ( OpCodes.Stloc_0 );
   ilgen.Emit ( OpCodes.Ldloc_0 );
   ilgen.Emit ( OpCodes.Ret );


Well, that is about it. At this point I can either save the new assembly to disc, or start using it right away. The proxy class has a HelloWebService() method that that is making a Web service call. If I invoke this on the original class nothing new happens. However, if I invoke it on the new class, my static method will be called (through the new override method).

// finish code generation and create type
Type newType = typeBuilder.CreateType ();

// create new instance of the class
object client = Activator.CreateInstance ( newType );

// call web service
MethodInfo minf =
    newType.GetMethod (
        "HelloWebService",
        new Type[] { typeof ( string ) } );
        minf.Invoke ( client, new object[] { "World" } );


That is about it. By writing more IL you could create a solution that does not require the use of another class. But this solution works perfectly fine for me.

Of course it would be wise to cache the types created this way, so they can be reused when another call is to be made. Types created this way remain loaded in the application domain until the entire domain is unloaded, so creating them all the time is bad idea. Code is not garbage collected.

Debugger breakpoints from code   (Tips & Tricks)   
Did you ever have the need to stop the debugger from code? That is, without adding a breakpoint in the Visual Studio IDE?

Many times this seems to be a problem when a third party application loads my .DLL assembly and starts executing it. I want to place a breakpoint, but before the .DLL is loaded into this third party host, the breakpoint would not be active, and after the component is activated, it might be too late to place the breakpoint in the IDE.

Solution? Use the following code:

System.Diagnostics.Debugger.Break ();

And like magic, the debugger will stop here just as if there was a brakepont added.

If you are running this as a Windows application, the application error popup will also appear, allowing you to attach a debugger to the process. You can then just start stepping right from this code line forward.

ReBuildAll - What's all this?   (Bl0g)   
Hello and welcome to ReBuildAll blog. I have had a Hungarian language blog for some time now (over five years really). Then last year I felt like sharing my thoughts on .NET and related things, so I started an English language technology related blog on Blogger. But I was too lazy or something, and the effort died after two articles. This is my attempt to start again.

So first I imported the two entries into this blog, and stay tuned for possibly more. Please feel free to read and comment.

The aim of this blog is to share some of my thoughts regarding .NET development, write about experiences or just write something technology related.

At the same time this is the first time I get to test my own blog engine with English language support, so if something seems funky, its just a bug (and probably you are seeing something in Hungarian). :)