Thursday, 13 February 2014

SharePoint 2013 - Warning! Access of SPContext.Current before PostRequestHandlerExecute in an IHttpModule will Cause Improper Initialization and Partial Failure of SharePoint Components

Ran into a particularly insidious issue yesterday with a HttpModule (implementing the IHttpModule interface) running on a SharePoint 2013 web application. The symptoms of the problem were:
  1. A user Clicks Settings > Add A Page
  2. The "Create Default Wiki Pages" Dialog Appears

  3. The User Gets an "Access Required - Sorry, this site hasn't been shared with you." Error Dialog
This originally looked like a permissions issue - but that was a red herring. With great difficulty (and a smidgen of persistence), I found out that this problem occurs if you access the SPContext in an Event Handler that is before the PreRequestHandlerExecute Event. See my table below for when you can use SPContext.Current.

Event # HttpApplication Event Name OK to use SPContext.Current
1 BeginRequest NO
2 AuthenticateRequest NO
3 PostAuthenticateRequest NO
4 AuthorizeRequest NO
5 PostAuthorizeRequest NO
6 ResolveRequestCache NO
7 PostResolveRequestCache NO
8 PostMapRequestHandler NO
9 AcquireRequestState NO
10 PostAcquireRequestState NO
11 PreRequestHandlerExecute YES
12 PostRequestHandlerExecute YES
13 ReleaseRequestState YES
14 PostReleaseRequestState YES
15 UpdateRequestCache  YES
16 PostUpdateRequestCache  YES
17 LogRequest YES
18 PostLogRequest YES
19 EndRequest YES
In my case, we (not to place blame on any particular developer!) created calls to the SPContext in the PostAcquireRequestState event handler. As soon as any access to the SPContext takes place this early in the processing pipeline, forces an incorrect initialization of variables such as "SitePages" and "SiteAssetsLibrary". The SPContext.Current is not null - just half-baked.
The following code in an HttpModule will cause your "Add Pages" functionality in SharePoint 2013 to fail as well:
   public class SecurityModule : IHttpModule, IRequiresSessionState
        private void context_PostAcquireRequestState(object sender, EventArgs e)
            if (SPContext.Current == null)
                //Do nothing - this call to SPContext.Current too early in the Http Processing Pipeline will cause "Add Pages" in SP2013 to fail.
                //This is because the SiteAssets and SitePages Collections in SPWeb are not initialized properly for later calls in the pipeline.

Using Reflector, you can see that internally, the "Add Page" Dialog uses the SPWeb.SitePagesLibrary internal property.

If I step through Microsoft's SharePoint code with Reflector VS PRO, I see that some properties are not initialized when I use SPContext in my custom code before the PreRequestHandlerExecute event.

Lesson Learned (and something to watch out for as the problem is hard to detect) - even if you CAN access the SPContext.Current before PreRequestHandlerExecute, DON'T DO IT. Otherwise, it causes instability in objects initialized by your SPContext later in the request pipeline.

This includes SharePoint itself. You have been warned!