Faking SPContext

A common question is how to fake SPContext in a non-SharePoint context. An answer is found at the bottom of a great post on Structured and repeatable deployment of Content Query Web Part instances, but Google doesn’t seem to find it so hopefully this will help. The whole article is worth a read, but for those looking for a quick answer:

public static SPContext FakeSPContext(SPWeb contextWeb)
{
  // Ensure HttpContext.Current
  if (HttpContext.Current == null)
  {
    HttpRequest request = new HttpRequest("", web.Url, "");
    HttpContext.Current = new HttpContext(request,
      new HttpResponse(TextWriter.Null));
  }

  // SPContext is based on SPControl.GetContextWeb(), which looks here
  if(HttpContext.Current.Items["HttpHandlerSPWeb"] == null)
    HttpContext.Current.Items["HttpHandlerSPWeb"] = web;

  return SPContext.Current;
}

I’ve made two slight modifications to Waldek’s original code:

  1. Since we don’t care about the response, we can use TextWriter.Null instead of allocating a new StringWriter().
  2. By separating the HttpContext and SPContext logic, we can use this in non-SharePoint web contexts as well as non-web contexts like unit tests and timer jobs.

While this works well for a SPWeb-based SPContext, I have not figured out how to fake a list- or item-level SPContext. It should go without saying that trying to inject a different SPWeb into an existing SPContext is a really bad idea. And finally, it is your responsibility to ensure disposal of the SPSite and SPWeb you create for the fake context.

Faking SPContext might be a necessity to work with others’ code (like CQWP), but if you’re needing to use this to work with code you own, consider refactoring to use dependency injection instead.

Advertisements