Click here to Skip to main content
Click here to Skip to main content

A Dose Of Code

By , 17 Apr 2009
 

While developing Ivonna, I often have to figure out how various stuff in System.Web works. Sometimes Reflectoring it is enough; however, there are some particularly gigantic methods, full of loops and branches, that are hard to figure out. In any case, Reflector gives a static picture, while I need to see it live. Sure now you can download the source and debug through it (although I've never managed), but the real hackers don't use debuggers, preferring asserts and console output.

Anyway, I needed to inject some code (or stop the debugger) at some particular method call in some assembly I don't have the code of. I've been using the TypeMock's MockMethodCalled event for it. After a while, it became tedious, so I decided to put some repetitive code into a class. Soon I found that it could have a couple of more useful features, but I wanted it to be really simple, and I didn't need much, so I'm keeping it to one class, three methods, three relaxed evenings of development.

How Does it Work

  1. Create an instance of Njector using the target type (this is something like creating a mocked instance).
  2. Add one or more injected pieces of code (something similar to adding expectations).
  3. Call the main code, in which an instance of the target type is created, and the target methods are called.
  4. The injected pieces are invoked before, after, or instead of the target methods. You also gain access to the target instance, target method parameters, and return value (in case you use the After injection).

Example

This is something that I actually used to figure out how the System.Web.HttpMultipartContentTemplateParser class parses the input using the ParseIntoElementList method. This method has several loops and branches, so it's not easy to find out what's happening given a particular piece of data. What you see here is just the preparation; after that I prepare the input data and call the framework code using Ivonna, but that's outside the scope of this post. GetPrivateField() is a utility extension method doing guess what.

var web = Assembly.GetAssembly(typeof(System.Web.HttpRequest));
var parserType = web.GetType("System.Web.HttpMultipartContentTemplateParser", true,
    true);
var inject = new Njector(parserType);
inject.After("GetNextLine", null, delegate(object target, MethodBase method, 
    object[] parameters, object retValue) {
    Console.WriteLine("GetNextLine: {0}", retValue);
    Console.WriteLine("Pos={0}", target.GetPrivateField("_pos"));
    Console.WriteLine("line={0}", target.GetPrivateField("_lineStart"));
    Console.WriteLine("partDataStart={0}", target.GetPrivateField("_partDataStart"));
});

inject.After("AtBoundaryLine", null, delegate(object target, MethodBase method,
    object[] parameters, object retValue) {
    Console.WriteLine("AtBoundaryLine: {0}", retValue);
});
inject.After("AtEndOfData", null, delegate(object target, MethodBase method,
    object[] parameters, object retValue) {
    Console.WriteLine("AtEndOfData: {0}", retValue);
});
inject.After("ParsePartHeaders", null, delegate( object target, MethodBase method,
    object[] parameters, object retValue) {
    Console.WriteLine("ParsePartHeaders");
});

inject.Before("ParsePartData", null, delegate(object target, MethodBase method,
    object[] parameters, object retValue) {
    Console.WriteLine("ParsePartData Before");
    Console.WriteLine("Pos={0}", target.GetPrivateField("_pos"));
    Console.WriteLine("line={0}", target.GetPrivateField("_lineStart"));
    //System.Diagnostics.Debugger.Break();
});
inject.After("ParsePartData", null, delegate(object target, MethodBase method,
    object[] parameters, object retValue) {
    Console.WriteLine("ParsePartData After");
    Console.WriteLine("Pos={0}", target.GetPrivateField("_pos"));
    Console.WriteLine("line={0}", target.GetPrivateField("_lineStart"));
    Console.WriteLine("partDataLength={0}", target.GetPrivateField("_partDataLength"));
});

//Prepare the data
//Do the POST
//The framework creates an instance of
//System.Web.HttpMultipartContentTemplateParser and calls its 
//ParseIntoElementList method, 
//which in turn calls the methods like GetNextLine, AtBoundaryLine, etc.
//After the GetNextLine method is called, our code is executed, and we're able to
//see the result.

Download the source here.

Update: There's a much better project now, called CThru, developed by TypeMock.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Artem Smirnov
Software Developer Freelancer
Russian Federation Russian Federation
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 17 Apr 2009
Article Copyright 2009 by Artem Smirnov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid