Wednesday, June 15, 2011

Speaking on Finland Sharepoint User Group

On the previous week I had a speech on the Finland Sharepoint User Group in Helsinki. It was nice to met new people and participate in Finland community’s professional life. Hope that my presentation about data retrieving methods in Sharepoint (LINQ 2 Sharepoint, CAML, Camlex.Net, ContentIterator, etc.) which was mostly developers-oriented was not so boring for non-developers who presented on the meeting :) Also I hope that it was only beginning and we will have more meetings and interesting discussions in the future.

Sunday, June 12, 2011

Show exception details on the client side for WCF RESTful endpoints

In one of my previous posts I described how to create custom error handler for the RESTful endpoints in WCF service. It uses simple idea: store exception message into Status Description field, so e.g. if with standard handler you got something like this:

HTTP/1.1 500 Internal Server Error

Then in with custom error handler you will get the following:

HTTP/1.1 500 InternalServerError: Customer Id can’t be empty

So when such exception will be handled on the client side you will have its actual reason. It was done using the following code in custom error handler:

   1: var rmp = new HttpResponseMessageProperty();
   2: rmp.StatusCode = statusCode;
   3: rmp.StatusDescription = string.Format("{0} {1}", statusCode, error.Message);
   4: fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);

And it works. But recently I found one problem with this approach (quite predictable I would say): with using HTTPS you may get the following exceptions from the server:

The server committed a protocol violation

Because of some reason for simple HTTP protocol it was not thrown (however for HTTPS it also was not regular). Anyway this is a problem which we should address and found more correct way to handle exceptions on the client side.

First of all I turned off my custom handler and ensure that problem is not reproducible without it. Of course I got only generic “Internal Server Error” again. After it I checked from where this exception is thrown on the client (remember that we are talking about RESTful endpoints – which use WebHttpBehavior. JSON and SOAP endpoints are out of scope in this post. I will describe them in the future posts). It is thrown in the WebFaultClientMessageInspector internal class which implements IClientMessageInspector interface:

   1: public virtual void AfterReceiveReply(ref Message reply, object correlationState)
   2: {
   3:     if (reply != null)
   4:     {
   5:         HttpResponseMessageProperty property = (HttpResponseMessageProperty) reply.Properties[HttpResponseMessageProperty.Name];
   6:         if ((property != null) && (property.StatusCode == HttpStatusCode.InternalServerError))
   7:         {
   8:             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(property.StatusDescription));
   9:         }
  10:     }
  11: }

(Another method of the interface BeforeSendRequest(…) just returns null).

Now it became clear why we always got generic “Internal Server Error” exception for the RESTful endpoints. Also it became clear why we can’t use FaultExceptions<FaultContract> for the RESTful service – it is ignored on client side and CommunicationException is thrown instead.

How to solve this problem? The answer is obvious: create custom implementation IClientMessageInspector and use it on client. Remember that it is called on the client side (on server side there is equivalent IDispatchMessageInspector). But how to send error message to the client? I used custom HTTP header with base64 encoded string. Algorithm is the following:

  1. On the server side register and use custom error handler as shown in the previous article.
  2. Instead of modifying of StatusDescription field we store error message in custom HTTP header (preliminary converted to base64 string)
  3. On the client side we use custom message inspector – check the custom HTTP header and if it is not empty, decode it and rethrow exception with initial error message
  4. As result we will have the exception with the same error message as initially thrown from the server

Now lets check the code. First of all we need to modify our custom error handler on the server:

   1: void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
   2: {
   3:     var statusCode = HttpStatusCode.InternalServerError;
   4:     if (error is WebException)
   5:     {
   6:         statusCode = ((WebException) error).Status;
   7:     }
   8:  
   9:     string errorMsg = error != null ? error.Message : "";
  10:  
  11:     fault = Message.CreateMessage(version, null, 
  12:         new ErrorBodyWriter {Code = statusCode, Message = errorMsg});
  13:     
  14:     var rmp = new HttpResponseMessageProperty();
  15:     
  16:     rmp.StatusCode = statusCode;
  17:     
  18:     // the following code causes "protocol violation" exception
  19:     //rmp.StatusDescription = string.Format("{0}: {1}", statusCode, error.Message);
  20:  
  21:     // convert error msg to base64 and store it in custom header. Client will read it via custom message inspector
  22:     if (!string.IsNullOrEmpty(errorMsg))
  23:     {
  24:         rmp.Headers["CustomError"] = Convert.ToBase64String(Encoding.UTF8.GetBytes(errorMsg));
  25:     }
  26:     fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
  27: }

Now we need to catch it on the client. Create custom client message inspector:

   1: public class PoxClientMessageInspector : IClientMessageInspector
   2: {
   3:     public object BeforeSendRequest(ref Message request, IClientChannel channel)
   4:     {
   5:         return null;
   6:     }
   7:  
   8:     public void AfterReceiveReply(ref Message reply, object correlationState)
   9:     {
  10:         if (reply != null)
  11:         {
  12:             var property = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
  13:             if (property != null)
  14:             {
  15:                 string error = property.Headers["CustomError"];
  16:                 if (!string.IsNullOrEmpty(error))
  17:                 {
  18:                     error = Encoding.UTF8.GetString(Convert.FromBase64String(error));
  19:                     throw new CommunicationException(error);
  20:                 }
  21:             }
  22:         }
  23:     }
  24: }

The only remaining way is to register it on the client side. In order to do it we need to create custom inheritor of the WebHttpBehavior class and register our own message dispatcher instead of standard one:

   1: public class PoxClientBehavior : WebHttpBehavior
   2: {
   3:     protected override void AddClientErrorInspector(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   4:     {
   5:         clientRuntime.MessageInspectors.Add(new PoxClientMessageInspector());
   6:     }
   7: }

Now in order to register it via config file of our client application we need to create custom extension element:

   1: public class PoxClientBehaviorExtensionElement : BehaviorExtensionElement
   2: {
   3:     protected override object CreateBehavior()
   4:     {
   5:         return new PoxClientBehavior();
   6:     }
   7:  
   8:     public override Type BehaviorType
   9:     {
  10:         get { return typeof(PoxClientBehavior); }
  11:     }
  12: }

After these manipulations we can register and use our custom message dispatcher in client’s config file:

   1: <system.serviceModel>
   2:   <extensions>
   3:     <behaviorExtensions>
   4:       <add name="poxClientBehavior"
   5:            type="Client.PoxClientBehaviorExtensionElement, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=..."/>
   6:     </behaviorExtensions>
   7:   </extensions>
   8:  
   9:   ...
  10:  
  11:   <behaviors>
  12:     <endpointBehaviors>
  13:       <!-- plain old XML -->
  14:       <behavior name="poxBehavior">
  15:         <poxClientBehavior/>
  16:       </behavior>
  17:       ...
  18:     </endpointBehaviors>
  19:   </behaviors>
  20:  
  21:   <client>
  22:     <endpoint address="https://example.com/OurService.svc/pox"
  23:       behaviorConfiguration="poxBehavior" binding="webHttpBinding"
  24:       bindingConfiguration="webBinding" contract="IOurService" />
  25:   </client>
  26: </system.serviceModel>

Now on client we will get server’s error message without problems with protocol violation.

Tuesday, June 7, 2011

ContentIterator for Sharepoint server

In this post I would like to describe useful class which can be helpful in your every day Sharepoint development: ContentIterator. This class is defined in Microsoft.Office.Server.dll assembly and helps address common tasks like iteration through list items (SPListItem), files (SPFile), sites (SPWeb), etc. The cool thing is that it is implemented via SPQuery and so it has very good performance on the big lists. Also as documentation says:

SharePoint Server provides a new API, ContentIterator, to help with accessing more than 5,000 items in a large list without hitting a list throttling limit and receiving an SPQueryThrottleException

E.g. suppose that we have reference on SPFolder and want to iterate through all items in this folder. We can use ContentIterator.ProcessFilesInFolder method:

   1: SPFolder folder = web.GetFolder(...);
   2: SPList doclib = web.Lists[...];
   3: ContentIterator contentIterator = new ContentIterator();
   4:  
   5: bool isFound = false;
   6: contentIterator.ProcessFilesInFolder(doclib, folder, false,
   7:     f =>
   8:         {
   9:             // this is item iteration handler
  10:             ...
  11:         },
  12:     (f, e) =>
  13:         {
  14:             // error handler
  15:             ...
  16:         });

So we passed doclib and folder where we want to perform iteration, Third parameter specifies should iteration be recursive or not. Fourth parameter is the function which receives actual SPFile instance which was iterated. And last parameter is the error handler.

Lets see how it is implemented. In the underlying calls it uses another method ContentIterator.ProcessListItems. At first it constructs SPQuery object:

   1: public void ProcessListItems(SPList list, string strQuery, uint rowLimit,
   2:     bool fRecursive, SPFolder folder, ItemsProcessor itemsProcessor,
   3:     ItemsProcessorErrorCallout errorCallout)
   4: {
   5:     ...
   6:     SPQuery query = new SPQuery();
   7:     if (!string.IsNullOrEmpty(strQuery))
   8:     {
   9:         query.Query = strQuery;
  10:     }
  11:     query.RowLimit = rowLimit;
  12:     if (folder != null)
  13:     {
  14:         query.Folder = folder;
  15:     }
  16:     if (fRecursive)
  17:     {
  18:         query.ViewAttributes = "Scope=\"RecursiveAll\"";
  19:     }
  20:     this.ProcessListItems(list, query, itemsProcessor, errorCallout);
  21: }

String strQuery used here is calculated on the above call stacks:

   1: public static string ItemEnumerationOrderByPath
   2: {
   3:     get
   4:     {
   5:         return "<OrderBy Override='TRUE'><FieldRef Name='FileDirRef' /><FieldRef Name='FileLeafRef' /></OrderBy>";
   6:     }
   7: }

And the most interesting implementation of ProcessListItems method overload:

   1: public void ProcessListItems(SPList list, SPQuery query, ItemsProcessor itemsProcessor, ItemsProcessorErrorCallout errorCallout)
   2: {
   3:     string str2;
   4:     SPListItemCollection items;
   5:     ...
   6:     if (!list.get_HasExternalDataSource() && (list.ItemCount == 0))
   7:     {
   8:         return;
   9:     }
  10:     if (list.get_HasExternalDataSource() && (query.RowLimit == 0))
  11:     {
  12:         query.RowLimit = 0x7fffffff;
  13:     }
  14:     else if ((query.RowLimit == 0) || (query.RowLimit == 0x7fffffff))
  15:     {
  16:         query.RowLimit = string.IsNullOrEmpty(query.ViewFields) ? 200 : 0x7d0;
  17:     }
  18:     if (!list.get_HasExternalDataSource() && this.StrictQuerySemantics)
  19:     {
  20:         query.set_QueryThrottleMode(2);
  21:     }
  22:     string strListId = list.ID.ToString("B");
  23:     this.ResumeProcessListItemsBatch(strListId, out str2);
  24:     if (!string.IsNullOrEmpty(str2))
  25:     {
  26:         query.ListItemCollectionPosition = new SPListItemCollectionPosition(str2);
  27:     }
  28:     int batchNo = 0;
  29: Label_012B:
  30:     items = list.GetItems(query);
  31:     int count = items.Count;
  32:     batchNo++;
  33:     try
  34:     {
  35:         itemsProcessor(items);
  36:         this.OnProcessedListItemsBatch(strListId, items, batchNo, count);
  37:     }
  38:     catch (Exception exception)
  39:     {
  40:         if ((errorCallout == null) || errorCallout(items, exception))
  41:         {
  42:             throw;
  43:         }
  44:     }
  45:     if (!this.ShouldCancel(IterationGranularity.Item))
  46:     {
  47:         query.ListItemCollectionPosition = items.ListItemCollectionPosition;
  48:         if (query.ListItemCollectionPosition != null)
  49:         {
  50:             goto Label_012B;
  51:         }
  52:     }
  53: }

It sets row limit (to 200 or 2000 depending on the is ViewFields property specified or not). Then it sets SPQuery.QueryThrottleMode property to Strict. According to documentation it means:

Throttling for both the number of items and for number of Lookup, Person/Group, and Workflow Status fields will apply to the query regardless of user permissions.

Also it uses SPQuery.ListItemCollectionPosition property for retrieving items by batches using RowLimit as number of items per batch.

As you can see ContentIterator makes a lot of hidden infrastructure work for you. So it can economy your time and allow to concentrate on the business tasks.