3 Strange Techniques that helped me when working on a project

Method hiding, stack trace manipulation and programmatic debuggery

Tonight I found myself using a few techniques that I’d never come across before. So I figured I’d document them before I forget what the heck was going on.

Some background first. I am working on a development tool not unlike NUnit. That is, there are two key components. The first is a library that contains some kind of API that you are supposed to call. In my case this is a fluent interface (or two). The second component is a command line utility that loads user code (in assemblies) and executes that code to achieve some effect.

Method Hiding

UPDATE: This first trick is one that is being used by a number of open source projects and originated with Daniel Cazzulino's excellent blog post How to hide System.Object members from your interfaces: the IFluentInterface.

This technique is very useful when you are writing Fluent APIs. It allows you to hide methods (or other members) from appearing in intellisense. Its easy enough, you apply the System.ComponentModel.EditorBrowsableAttribute to the method that you want to hide and initialize it with a System.ComponentModel.EditorBrowsableState of Never. Here’s a sample:

public class ClassWithSomeMethods
{
	public void AVisibleMethod()
	{
	}	

	[EditorBrowsable(EditorBrowsableState.Never)]
	public void AnInvisibleMethod()
	{
	}
}

Here is a snapshot of what the intellisense looks like:

Hidden Method

The method AnInvisibleMethod is not present. You can still call it any time that you want it just will not show up in intellisense. This is particularly important for Fluent APIs because they tend to rely on intellisense to guide consumers towards the options that are available at any point during the Fluent chain.

There is still the 4 methods there that are inherited from object (Equals, GetHashCode, GetType, ToString). The bad news is that everything has those (well everything which inherits from object which is everything). The good news is that they are virtual so we can override them and then apply the EditorBrowsable attribute and they go away. If you need to do that a lot then you might consider putting all of that into an interface and then implementing that (you’d need to keep a track of your fluent object via an interface implementing that one otherwise the IDE gets clever on you). This is often done with a static accessor of some kind). Enough talk, more code. Here’s what it looks like:

[EditorBrowsable(EditorBrowsableState.Never)]
public interface IFluentApi
{
	[EditorBrowsable(EditorBrowsableState.Never)]
	string ToString();

	[EditorBrowsable(EditorBrowsableState.Never)]
	bool Equals(object other);

	[EditorBrowsable(EditorBrowsableState.Never)]
	int GetHashCode();

	[EditorBrowsable(EditorBrowsableState.Never)]
	Type GetType();
}

public interface IMyFluentApi : IFluentApi
{
	IMyFluentApi ContextPreservingOperation();
	TheNextFluentClass ContextChangingOperation();
}

public static class Fluently
{
	public static IMyFluentApi Do
	{
		get
		{
			return new AFluentClass();
		}
	}
}

public class AFluentClass : IMyFluentApi
{
	public IMyFluentApi ContextPreservingOperation()
	{
		// Do operation
		return this;
	}

	public TheNextFluentClass ContextChangingOperation()
	{
		// Do operation
		return new TheNextFluentClass(this);
	}
}

public class TheNextFluentClass
{
	private readonly AFluentClass source;

	public TheNextFluentClass(AFluentClass source)
	{
		this.source = source;
	}
}

FluentApi

One final word because this one drove me nuts. This technique does not work if you make a Project Reference instead of a normal Assembly reference. That means that if you start a new project in your current solution to test this out it won’t work. This apparently has to do with the way that the method meta-data is loaded.

Stack Trace Manipulation

I’m calling methods via reflection like this:

Method.Invoke(Target, parameters);

If you are interested, Method is a System.Reflection.MethodInfo. The problem is that if the method being called throws an exception then what happens is that Method.Invoke throws a TargetInvocationException with the original exception as it’s InnerException. Here is a quick sample:

class Program
{
	static void Main(string[] args)
	{
		try
		{
			Execute();
		}
		catch (Exception ex)
		{
			Console.WriteLine(ex);
		}
	}

	public static void Execute()
	{
		var target = new Foo();
		var parameters = new object[0];

		var type = target.GetType(); ;
		var method = type.GetMethod("Bar");

		method.Invoke(new Foo(), new object[] { });
	}
}

public class Foo
{
	public void Bar()
	{
		throw new Exception("Actual Issue");
	}
}

When you run this you get:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Actual Issue
   at ConsoleApplication1.Foo.Bar() in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 38
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at ConsoleApplication1.Program.Execute() in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 30
   at ConsoleApplication1.Program.Main(String[] args) in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 14

Scary huh. The first line tells you that the method you called threw an exception. We knew that. After that is the two lines we actually want. Then there is a marker and then 6 lines of crap (actually there is 4 lines of crap and then 2 lines we could possibly use but we’ll get to that).

We could catch the TargetInvocationException where it occurs and throw its InnerException like this:

try
{
	method.Invoke(new Foo(), new object[] { });
}
catch (TargetInvocationException tiex)
{
	throw tiex.InnerException;
}

The result is possibly not what we wanted

System.Exception: Actual Issue
   at ConsoleApplication1.Program.Execute() in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 37
   at ConsoleApplication1.Program.Main(String[] args) in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 15

We’ve kept those last two lines (the ones going in) but lost the most important ones (the ones at the site of the exception). This happens because the throw statement reorganizes the stack trace. That means that if we try to do anything to manipulate the stack trace then when we hit the throw statement it will all be lost.

If you’ve ever done any remoting work then you’ve probably come across the situation where a call to a remote component that throws an exception has it’s stack trace persisted across the remoting boundary. How the heck does it do that?

When an exception propagates to a remoting boundary it is “prepped” for crossing. This involves taking the current stack trace info and appending it to an internal field called _remoteStackTraceString. When the exception gets to the other side of the boundary it is essentially rethrown and then your code can treat it however it likes.

In the course of handling that exception you might access the StackTrace property. It never occurred to me that this property was calculated. It actually concatenates the remote stack trace string with the local stack trace string. That means that if we want to be sneaky we can manipulate where it appears an exception comes from and retain all of the stack information from the point of manipulation back to the site where the exception is handled. There doesn’t appear to be any way to set _remoteStackTraceString from outside of the Exception class so we’ll have to use some reflection-fu. Lets see how that works:

public static void Execute()
{
	var target = new Foo();
	var parameters = new object[0];

	var type = target.GetType(); ;
	var method = type.GetMethod("Bar");

	try
	{
		method.Invoke(new Foo(), new object[] { });
	}
	catch (TargetInvocationException tiex)
	{
		throw AdjustedRealException(tiex);
	}
}

private static Exception AdjustedRealException(TargetInvocationException tiex)
{
	var remoteStackTraceString = typeof(Exception)
									.GetField("_remoteStackTraceString", 
									BindingFlags.Instance | BindingFlags.NonPublic);

	remoteStackTraceString.SetValue(
		tiex.InnerException, 
		tiex.InnerException.StackTrace + Environment.NewLine);

	return tiex.InnerException;
}

Given the description of what happens during remoting above none of that should come as a surprise. All of the action takes place in the AdjustedRealException helper method. We are using reflection to get access to a private field of the Exception class (_remoteStackTraceString). We then take the value of stack trace from the inner exception (our real exception, remember, the one we want to keep), append a newline to it and push that value into the _remoteStackTraceString field of the inner exception. Lastly we return the inner exception and then rethrow it (in the caller).

When we run this version we get exactly what we wanted:

System.Exception: Actual Issue
   at ConsoleApplication1.Foo.Bar() in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 55
   at ConsoleApplication1.Program.Execute() in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 37
   at ConsoleApplication1.Program.Main(String[] args) in D:\Research\TheQuestion\ConsoleApplication1\Program.cs:line 15

Programmatic Debuggery

OK last one I promise and it’s a quick one. The tool I am working on requires some command line stuff to get it going. I can’t be bothered faking that up at the moment for when I want to debug a particular issue (especially as I already have a batch file that feeds in the data I need). That’s when I found System.Diagnostics.Debugger.Launch().

Calling this method in your code will essentially raise a breakpoint, load a debugger and put you in the surrounding method right after the call. Life saver if, for whatever reason, you need to hit a breakpoint but for some reason you can’t start the app under the debugger.

If you are still reading this then you deserve some kind of prize so here is a link to what I’ve been working on. More soon.

Posted by: Mike Minutillo
Last revised: 15 Jun, 2012 06:54 AM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.