One of the recent challenges we were dealing with on the project I'm currently on involved added unit tests to code that was written several years ago and has been modified consistently since then. The biggest problem we found was that the MiddleTier had references to System.Web because several methods took an HttpContext or HttpApplication instance. Some methods simply referenced the static HttpContext.Current property.
Due to the current implementation of the ASP.NET object model, it's not a simple task to instantiate a new HttpApplication or HttpContext and set the properties you require. One of the other guys had spent a day or two on the problem, and was expressing his frustration to me. I recommended using reflection to see if that would get him anywhere, and since he wasn't real familiar with it, we took a few hours and wrote the following code at my desk:
Assembly assembly = Assembly.GetAssembly(typeof(HttpApplication));
Type type = assembly.GetType("System.Web.HttpApplicationFactory", true);
PropertyInfo propertyInfo = type.GetProperty("ApplicationState", BindingFlags.NonPublic | BindingFlags.Static);
object applicationState = propertyInfo.GetValue(null, new object[0]);
type.TypeInitializer.Invoke(null, new object[0]);
ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, Type.EmptyTypes, new ParameterModifier[0]);
object applicationFactory = constructorInfo.Invoke(new object[0]);
FieldInfo fieldInfo = type.GetField("_theApplicationType", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(applicationFactory, typeof(HttpApplication));
fieldInfo = type.GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(applicationFactory, applicationState);
fieldInfo = type.GetField("_theApplicationFactory", BindingFlags.NonPublic | BindingFlags.Static);
fieldInfo.SetValue(null, applicationFactory);
using (StringWriter stringWriter = new StringWriter())
{
AppDomain.CurrentDomain.SetData(".appPath", Environment.GetEnvironmentVariable("TEMP"));
AppDomain.CurrentDomain.SetData(".appVPath", "/");
SimpleWorkerRequest request = new SimpleWorkerRequest(String.Empty, String.Empty, stringWriter);
HttpContext context = new HttpContext(request);
Type[] types = new Type[] { typeof(HttpContext) };
MethodInfo methodInfo = type.GetMethod("GetNormalApplicationInstance", BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, types, new ParameterModifier[0]);
object[] parameters = new object[] { context };
context.ApplicationInstance = (HttpApplication) methodInfo.Invoke(applicationFactory, parameters);
HttpContext.Current = context;
}
HttpContext.Current.Application.Add("FirstName", "Adrian");
Console.WriteLine("FirstName: {0}", HttpContext.Current.Application["FirstName"]);
The above code creates an HttpApplicationFactory, sets 2 required environment variables, and calls the application factory's GetNormalApplicationInstance method to create an HttpApplication. Once the application has been created, it is assigned to a new HttpContext's ApplicationInstance property. The last 2 lines are there to verify that the data put into the current HttpContext can be read back.
Most of this code wouldn't be possible without Reflector, which helped us quite a bit.
I'd also like to point out that running the above code probably requires the FullTrust permission, and I wouldn't recommend running it in a production environment with rigorous testing and performance tweaking. For us, we just needed this functionality for unit testing, nothing more.