Search code examples
c#dynamicrhino-mocks

can I use dynamic to redirect HttpContext.Current.Request?


I'm using RhinoMocks for testing. It's not good at redirecting statics; I've considered using another library like the successor to Moles (edit: I guess the Fakes tool is only available in VS2012? that stinks) or TypeMock, but would prefer not to.

I have a 3rd party library that takes in an HttpRequest object. My first stab at it was to use:

public void GetSamlResponseFromHttpPost(out XmlElement samlResponse, 
  out string relayState, HttpContextBase httpContext = null)
 {
  var wrapper = httpContext ?? new HttpContextWrapper(HttpContext.Current); 
  // signature of the next line cannot be changed
  ServiceProvider.ReceiveSAMLResponseByHTTPPost(
      wrapper.ApplicationInstance.Context.Request, out samlResponse, out relayState);

All looked fine, until I went to test it. The real issue here is that I need to stub out wrapper.ApplicationInstance.Context.Request. Which leads into a whole host of old school 'ASP.NET don't like testing' pain.

I have heard that you can use dynamic magic in C# to redirect static methods. Can't find any examples of doing this with something like HttpContext though. Is this possible?


Solution

  • Not an ideal solution, but my solution to test this was to use reflection and modify the object under the hood:

    httpRequest = new HttpRequest("default.aspx", "http://test.com", null);
    var collection = httpRequest.Form;
    
    // inject a value into the Form directly
    var propInfo = collection.GetType().GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
    propInfo.SetValue(collection, false, new object[] { });
    collection["theFormField"] = val;
    propInfo.SetValue(collection, true, new object[] { });
    
    var appInstance = new HttpApplication();
    var w = new StringWriter();
    httpResponse = new HttpResponse(w);
    httpContext = new HttpContext(httpRequest, httpResponse);
    
    // set the http context on the app instance to a new value
    var contextField = appInstance.GetType().GetField("_context", BindingFlags.Instance | BindingFlags.NonPublic);
    contextField.SetValue(appInstance, httpContext);
    
    Context.Stub(ctx => ctx.ApplicationInstance).Return(appInstance);
    

    My goal here was to have wrapper.ApplicationInstance.Context.Request return a form field value when asked. It may have been roundabout, but it works. This code only exists in test code so I'm happy with it.