Sunday, January 13, 2013

How to use SharePoint's OOB error page to show a friendly error message

In many cases, such as a feature activation, it is best to not overwrite the out-of-the-box error page with a custom one, but have the page show a custom message such that users know where the custom code you wrote, failed.

Envision the following scenario: you have an OOB site collection and on custom feature activation, you try to:

  • bind custom fields deployed by the feature to a metadata term store
  • add these custom fields to content types
  • create subsites programmatically
  • set permissions programmatically, etc.
Wrap each action in it's own try-catch statement and inside the catch call your custom Error Handler  method that writes to the ULS logs.

In addition to writing to the ULS logs, have your method also do a forced Response.Redirect to the OOB error page, with "ErrorText" in the QueryString object:

  //write to log first, then:

   string idcurr = CorrelationId.GetCurrentCorrelationToken().ToString();
   errorMessage = HttpUtility.UrlEncode(errorMessage);
   HttpContext.Current.Response.Redirect("/_layouts/error.aspx?ErrorText="+ errorMessage + "&ErrorCorrelationId=" + idcurr);


The ErrorCorrelationId QueryString parameter will ensure that the ID you see on the error page matches what you see in the ULS logs.
But the actual Error Handling, if custom, will generate it's own ID when writing to the logs.
It is necessary for these two to match, basically for the code to associate the custom Error message generated with the ID shown on the page.
The only way to grab the latest CorrelationID generated is to grab it via this class, and I am referencing this blog where I found the solution to the issue:


public class CorrelationId
    {
        [DllImport("advapi32.dll")]
        public static extern uint EventActivityIdControl(uint controlCode, ref  Guid activityId);
        public const uint EVENT_ACTIVITY_CTRL_GET_ID = 1;
        public static Guid GetCurrentCorrelationToken()
        {
            Guid g = Guid.Empty;
            EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, ref  g);
            return g;
        }
    }