Thursday, April 21, 2005

Make your own webhandler factory, why? Because you can!

In ASP.Net, the framework provide a default handler for ashx files. It is called
"System.Web.UI.SimpleHandlerFactory". You can find the mapping in machine.config.
The main job of this handler is to compile an ashx file, find the class that implements IHttpHandler, instanciate it and call its Process request so your handler can do its job.
This "System.Web.UI.SimpleHandlerFactory" does all this for you. I wanted to make my own, just for fun... Actually for my students who want to know a little more of what is going on behind the scene.

There are 3 parts to this:
- 1: A standard ashx file to make sure my new factory can create my handler and pass the request through.
- 2: A factory class that needs to be compiled as a library and placed in the bin directory. The name of the assembly needs to be webhandler.dll for this demo.
- 3: A web.config to remap the standard "System.Web.UI.SimpleHandlerFactory" to "DM.SimpleWebHandlerFactory"

Enjoy!

Part 1: Here is a standard ashx file


<%@ WebHandler Language="C#" class="SimplestHandlerEver" %>

using System;
using System.Web;

class SimplestHandlerEver : IHttpHandler
{
public SimplestHandlerEver()
{
}

public void ProcessRequest(HttpContext context)
{
context.Response.Write(this.GetType().FullName + " called");
}

public bool IsReusable
{
get
{
return false;
}
}
}
//--- End of File

Part 2: Here is the custom factory that you need to compile and place in the bin directory.

using System;
using System.Text;
using System.Web;
using Microsoft.CSharp;

namespace DM
{
///
/// Author: C. Fouquet
/// This is a very simple handler factory that can be used to replace the
/// standard System.Web.UI.SimpleHandlerFactory that is mapped to
/// the .ashx extension in the machine.config
/// Needless to say, this is a very crude implementation of an IHttpHandlerFactory.
/// This is just to illustrate the rough steps the actual System.Web.UI.SimpleHandlerFactory
/// goes through to create the handler.
/// It is very inefficient. The code is compiled every time, the generated assembly is
/// loaded every time.
/// Also, look at the web.config to see how we remap the default handler factory
///

public class SimpleWebHandlerFactory : IHttpHandlerFactory
{

public SimpleWebHandlerFactory()
{

}
#region IHttpHandlerFactory Members

public void ReleaseHandler(IHttpHandler handler)
{

}


public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
string HandlerRequested = pathTranslated;
string Language ;
string Class;

// Open the .ashx file being hit
using(System.IO.StreamReader fs = System.IO.File.OpenText(HandlerRequested))
{

// The first line is the webhandler directive. Or so we hope!
string Directive = fs.ReadLine();

// Extract the information we are looking for from the directive
if(ProcessDirective(Directive, out Language, out Class))
{
if(Language.ToUpper() != "C#" && Language.ToUpper()!="CSHARP")
{
throw new Exception(Language + " Language Not Supported");
}
}
else
{
throw new Exception("missing or badly formatted webhandler directive");
}

string TheCode = fs.ReadToEnd(); // This is the rest of the code

string Target = System.IO.Path.GetTempFileName(); // We need an output
// file name so let the OS pick it.

// For simplicity here, we just include what we need. Obviously
// we would have to process the import directives but .. not today
// This is just a demo remember?
string[] Imports = new string[] {
"System.Web.dll"
};

System.Collections.Specialized.ListDictionary options = new System.Collections.Specialized.ListDictionary();
options.Add("target","library"); // equivalent of doing csc /t:library ...

CompilerError[] Errors = Compiler.Compile(
new string[] { TheCode },
new string[] { "TheCode" },
Target,
Imports,
options);

// Now we can load it
System.Reflection.Assembly HandlerAssembly = System.Reflection.Assembly.LoadFile(Target);

// And find the type we listed in the directive
IHttpHandler TheActualHandler = (IHttpHandler) HandlerAssembly.CreateInstance(Class);

return TheActualHandler;
}
}


// This parses the Directive. It is a little heavy on regex.. but regex are so much fun!

private bool ProcessDirective(string Directive, out string Language, out string Class)
{
Language = Class = string.Empty;

string BackSlash ="\\";
string DoubleQuote ="\"";

StringBuilder sb = new StringBuilder();
sb.Append("<%@");
sb.Append(BackSlash);sb.Append("s+");
sb.Append("WebHandler");
sb.Append(BackSlash);sb.Append("s+");


// Language="C#"
sb.Append("Language=");sb.Append(DoubleQuote);
sb.Append("(?[A-Za-z0-9]");sb.Append(BackSlash);sb.Append("#?)");
sb.Append(DoubleQuote);

// Any space
sb.Append(BackSlash);sb.Append("s+");

// class="xyx"
sb.Append("class=");sb.Append(DoubleQuote);
sb.Append("(?");sb.Append(BackSlash);sb.Append("w+)");
sb.Append(DoubleQuote);

// Any space
sb.Append(BackSlash);sb.Append("s+");

sb.Append("%<");

string regex = sb.ToString();

System.Text.RegularExpressions.RegexOptions options = ((System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace | System.Text.RegularExpressions.RegexOptions.Singleline)
| System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(regex, options);

System.Text.RegularExpressions.Match m = reg.Match(Directive);
if(m.Success)
{
Language = m.Groups["Language"].Value;
Class = m.Groups["Class"].Value;
return true;
}

return false;

}


#endregion
}
}

Part 3: The web.config

<configuration>
<system.web>
<httpHandlers>
<remove verb="*" path="*.ashx"/>
<add verb="*" path="*.ashx" type="DM.SimpleWebHandlerFactory, webhandler"/>
</httpHandlers>
</system.web>
</configuration>

I got burnt by ToString()

I have encountered a gotcha that I want to share. Strong typing is my thing. There is nothing that
bothers me more than seeing hardcoded strings in code.

In ADO.Net it is common to do something like this
Data ds = GetDataSetFromDB()
...
DataRow dr = ...

string Name = (string) dr["Name"];

If you mistype "Name" you are doomed. So I used to do this: define an enum called "Columns" that had all the
column names I am interested in.
enum Columns
{
Name,
Email,
Zip
// etc...
}

I can check the names once (visually and programmtically against the database) and in the code use this


string Name = (string) dr[Columns.Name.ToString()];

As long as you remember to use the enum, you can't mess up.

Now, before you go do this, it is very very slow. You would think that it is straightforward for the runtime
to convert an enum into its string representation. That's not the case.

if you compile this into an exe

using System;

public class HelloClient
{

public enum Columns
{
Name
}

public static void Main()
{
Console.WriteLine(Columns.Name.ToString());
}
}


and look at the ToString() with Reflector here is what you get. This is the ToString() from the
Enum type.

public override string ToString()
{
Type type1 = base.GetType();
FieldInfo info1 = Enum.GetValueField(type1);
object obj1 = ((RuntimeFieldInfo) info1).InternalGetValue(this, false);
return Enum.InternalFormat(type1, obj1);
}

and look at what GetValueField does...

private static FieldInfo GetValueField(Type type)
{
FieldInfo[] infoArray1;
if (type is RuntimeType)
{
infoArray1 = ((RuntimeType) type).InternalGetFields(BindingFlags.NonPublic | (BindingFlags.Public | BindingFlags.Instance), false);
}
else
{
infoArray1 = type.GetFields(BindingFlags.NonPublic | (BindingFlags.Public | BindingFlags.Instance));
}
if ((infoArray1 == null) || (infoArray1.Length != 1))
{
throw new ArgumentException(Environment.GetResourceString("Arg_EnumMustHaveUnderlyingValueField"));
}
return infoArray1[0];
}


Arg!!! Reflexion all over the place. No wonder it is slow....

Now, this is the generic Enum.ToString(). I would hope that it does not do that for Booleans... Let's check.

// Part of Boolean

public override string ToString()
{
if (!this.m_value)
{
return bool.FalseString;
}
return bool.TrueString;
}

public static readonly string FalseString;
public static readonly string TrueString;

// End of Boolean


Good!! Somebody is thinking.

Well, I guess we are stuck with the implementation of ToString() for our custom Enums. It would be nice though to let the
compiler know to inline the Enum's ToString() like a custom attribute. For instance:

[HeyCompilerBeSmartAboutTheToStringMethodPleaaaaseAttribute()]
enum Columns
{
Name,
Email
}

It would be nice indeed.

So I am stuck and went back to using strings like this

string Name = (string) dr["Name"];

Cool. If you use reflector again you will see that a hashtable look up is done every time
you access that column. I did some timing and it is still slow for my standards!

Let's push it further. What we want is brute speed like this.

string Name = (string) dr[3]; // 3 == "Name"

That is fast but brittle. If you move the column around in your table, you are out of synch and you will
most likelt get a beautiful exception.

This is why you need to use the "Ordinal" property on the "DataColumn".

If you want speed, you need to precompute the ordinals when the application starts and then use them.

You need to use a few tricks to do this on start up but it is worth it. Now my code is fast. I am a happy man.

Friday, April 15, 2005

Computer History is available for you to see

I found this. It is an archive of all the TV shows of the "Computer Chronicles".
You probably remember the guy always introducing himself the same way. It is fun to
see the old machines and the discussions of the time.

http://www.archive.org/details/computerchronicles

Wednesday, February 09, 2005

An old friend, the ZX81

A friend of mine read my bio on the Developmentor web site and reminded me that I forgot to mention the ZX81 in my history of technologies I worked with. If you remember this machine, it was popular in the early 80s. It had 1K RAM , expandable to 16K (which I had bought). It seems so amazing that we could even do anything with it but we did. Saving the programs on an audio tape was really a pain but cheap. The internet was not even there but I managed to transfer a program through the air! A friend of mine was doing some radio show on a local FM station. We decided to tell our audience to start recording on tape the ZX81’s super cool program I had written. As he broadcasted 5 minutes of awful sounds, I recorded it and could reload my own program on my ZX81. Thinking of it, I was probably the only one listening to this anyway! The ultimate geeky evening but it was a lot of fun. Here is a link for the ZX81 http://www.zx81.nl/

Monday, December 20, 2004

FireFox is cool



I am using FireFox more and more. I have seen it crash but that’s expected from something that new.

The thing I really like is that is allows me to check my email through a web enabled Outlook access much better.

Using the web interface for Outlook through IE is just plain painful and almost useable.

Switching to FireFox makes it more than usable and it is very close to having the feel of a real mail client.

Try it!


Keith Brown .Net Security Book

I am currently ready it (http://www.amazon.com/exec/obidos/ASIN/0321228359/ccomput-20/103-4748007-2595816?creative=327641&camp=14573&link_code=as1)

Now, if you want to get scared about the safety of your data/machine then read it too. I always wanted to get into security since it is an obscure science (at least for me). This book is giving a taste of what's going on inside Windows. Some of it makes sense. Some of it is really mind boggling. If I am learning one lesson from this is that I am running all my stuff as Admin which is really, really a bad idea.

I made myself a "MeWithNoPrivileges" account under my machine that I now try to use as much as possible especially when surfing the web.

Saturday, October 09, 2004

Tic Tac Toe as a composite control

I just posted a composite control on the serverside.net. Click here to get to it.
Most developers prefer using UserControls to aggregate other controls easily. The Visual Studio IDE allows you to drag and drop elements on the design surface. It is certainly a very productive way to work. One of the disavantages of UserControls is that they cannot be put in the global assembly cache. This is most of the time not a problem when developing real applications. However, if you are a control developer and you sell your controls to the public, you usually want to be able to put your assembly in the cache.

This code sample is quite simple but illustrates what needs to be done to programmatically assemble the pieces. Fritz Onion has a client side Tic Tac Toe example in his book "Essential ASP.Net". I thought it would be a good addition to show how to do this server side.

Tuesday, September 21, 2004

ClientID is not reliable in CreateChildControls in ASP.Net

Here is a tip that will save you a few hours of digging. I made a composite control and instanciated my inner controls in

createChildControls. Something like this:

createChildControls()

{

t = new TextBox();

img = new Image();

Controls.Add(t);

Controls.Add(img);

// Make some javascript using ClientId like this…

….. t.ClientId …..

}

If you do it this way, your control may work fine in some pages and not in some others. This depends on how nested your

control is. Of course, you would think that the INamingContainer interface would take care of all this and give you a reliable way of getting

the client ID regardless how deep you are in the control hierarchy. After all, my textbox and Image are part of the hierarchy already since

I use ClientID after these inner controls have been added to the Control collection…

Well, this is not true to my uttermost surprise and disappointment. To cut the story short, here is the fix. The control hierarchy is

settled just before the rendering so you should always use ClientID in the prerender. So you do it like this

protected override void OnPreRender(EventArgs e)

{

// use ClientId here

}

This works fine. My googling did not reveal a real source of explanation on why this is but people have had the same problem.

I would be interested to find out a true M$ explanation for this.

Friday, September 10, 2004

Tuesday, August 31, 2004

CitiBank has your internet password.

I had to call CitiBank to get some info about my credit card. The representative asked me for my password!!
I answered I did not want to give it to her. She then told me it was ok to give it to her for checking my identity and that she was looking at it on her screen.

Needless to say I was stunned to find out that any CitiBank employee dealing with customers has
access to my internet password! So any employees can access my account from any machine in
the world! This is reassuring.

And then they ask you not to write your password anywhere and protect it. They also claim to take all the precaution to protect your information... This is all BS.

Obviously, they have not heard of one way encryption.... They probably have password in ClearText in their DataBase. Cool!

I am writing a letter to the CEO to make some fuss.

Also, I am cancelling my CitiBank credit cards and I encourage you to do the same!