Kentico 8.1 Technology – Using SharePoint API

   —   
Kentico 8.1 features a brand new implementation of SharePoint integration. The main purpose was to make the developers’ lives easier and to provide you with the ability to retrieve data from a SharePoint server without the hassle. In this article, we will focus on how to use the API for the purposes of customization, specifically when the supplied SharePoint data source web part is not enough.
Kentico 8.1 allows you to integrate SharePoint in versions 2010, 2013 or Online on your Kentico site. All you have to do is reference our SharePoint library in your Visual Studio project and continue reading.

SharePoint services

SharePoint integration is logically divided into services – each of them is responsible for a portion of functions and is described by its own interface. For each supported SharePoint version there is a family of classes implementing these services. Basically, SharePoint integration was inspired by the abstract factory design pattern – this may not be evident since it is neatly tied together in order to provide you straightforward access to any service.

We have ISharePointSiteService, ISharePointListService and ISharePointFileService. The latter two services, in particular, will come in handy. But for now, let’s take a look at a simple piece of code that demonstrates the desired service instance retrieval.

Let’s say that we would like to test whether the server instance is accessible. The ISharePointSiteService is well-suited for our purposes. The following code snippet demonstrates how to use it:

// connectionData is instance of SharePointConnectionData try { ISharePointSiteService siteService = SharePointServices.GetService<ISharePointSiteService>(connectionData); string site = siteService.GetSiteUrl(); } catch...


For the sake of briefly describing what it does, GetService locates the correct family of classes based on the version provided via connectionData and gets you requested service implementation.

The catch clause is important here since we have to take care of all possible error conditions met in the process of site URL retrieval (unavailable SharePoint server, invalid credentials or unsupported authentication mode, etc.).

SharePoint connection data

The lines of code seen above make use of the SharePointConnectionData class. This is an envelope for all data needed to successfully connect to the SharePoint server instance. It contains typical properties like SharePointConnectionSharePointVersion, SharePointConnectionAuthMode etc. But you can add and access your own configuration items via the [] operator.

Those of you familiar with Kentico info objects might be wondering if they fit in here. Of course they do! When your users define their connection in the SharePoint application within the UI, they actually work with SharePointConnectionInfo. And when you have this type of info object describing your server, you can supply it to the ISharePointServiceFactory by calling the ToSharePointConnectionData method.

To clarify, there is a need for a SharePointConnectionData class instead of direct usage of an info object – we wanted a lightweight encapsulation of all necessary configuration data. Since every service implementation holds its own instance of connection data (to make sure it is not unintentionally modified from any external code), the overhead has to be minimized. When making your own service implementation, you should follow this practice and keep a clone of the connection data unless you are 100 percent sure no one from outside will modify it. The Clone method of the connection data class performs a shallow copy of all items specifically for this purpose.

Interacting with SharePoint lists

One of the main reasons why you should integrate with SharePoint is the necessity to retrieve data stored in SharePoint lists. Just to be clear, when we use the word list we mean list or library, which are very similar on the implementation level.

When you need to retrieve all lists of a certain type available on a server, the GetLists method of the ISharePointListService is the best choice – it takes one method argument to specify the list type that has to be retrieved. SharePoint recognizes various types of lists – we have chosen the ones that we consider to be most important. You can find them in the SharePointListType class. They can all be used for any supported SharePoint server versions. If you are in need of any other list type just consult Microsoft’s documentation (look for list template type) so that you get the right type code.

DataSet lists = listService.GetLists(SharePointListType.PICTURE_LIBRARY);


The snippet above retrieves all picture libraries within the server. The listService has been obtained in the same manner as the siteService in the previous example. The return type has been chosen with respect to easy binding to repeater controls or grids.

SharePoint list items

It’s good to know that the retrieval of lists works; but in real-life scenarios you may be more interested in the actual data items that are present within a list. This is where the GetListItems method comes into play. It contains more arguments than the previous one – we will explain them in further detail after we take a look at the following snippet of code:

// connectionInfo is instance of SharePointConnectionInfo ISharePointListService listService = SharePointServices.GetService<ISharePointListService>(connectionInfo.ToSharePointConnectionData()); string listTitle = "Company parties"; string folderServerRelativeUrl = "/Company parties/Christmas/2013"; List<string> viewFields = new List<string> { "ID", "FileRef", "FileLeafRef", "Title", "ImageWidth", "ImageHeight", "Keywords" }; int imageId = imageIdFromQueryString; // passed as method parameter SharePointListItemsSelection selection = null; if (imageId > 0) { selection = new SharePointListItemsSelection { FieldName = "ID", FieldType = "Counter", FieldValue = imageId.ToString() }; } SharePointView view = new SharePointView { Scope = SharePointViewScope.FILES_ONLY, QueryInnerXml = "<OrderBy><FieldRef Name=\"ID\" Ascending=\"true\"/></OrderBy>", ViewFields = viewFields }; DataSet result = listService.GetListItems(listTitle, folderServerRelativeUrl, view, selection);


In the retrieval of the ISharePointListService instance, you can see the conversion of the info object to the connection data.  The listTitle is the readable, human form of the list’s title. The folderServerRelativeUrl we are using assumes that we have a SharePoint picture library called Company parties that has a folder structure containing some photos. We are restricting the retrieved fields (viewFields) from the SharePoint server only to those we are interested in. It’s good practice to ask only for the data you really need. Please note that the SharePoint server will always pass along some system fields that cannot be excluded from transmission. The field names are actually the internal names used by the server.

To select any given picture from the SharePoint picture library (based on the ID), you must define a selection. A selection is defined by a field name (internal name), a data type of the field and a value. The value is used in equality comparison. To get familiar with list data types you can have a look at the SharePoint server documentation. To perform a valid selection all three properties have to be specified. Otherwise, it will be ignored.

Last but not least, construct the SharePointView. The scope limits retrieved items to files only – any subfolders in our Christmas/2013 folder will not be included in the result. The QueryInnerXml is the raw content of the CAML Query element issued to the SharePoint server. If you are not familiar with the query syntax, see the Query documentation. Currently, SharePoint Online is hosted on the 2013 edition. Be aware that any custom queries that are using special features may not be independent from the SharePoint version.

Important: the properties forming the selection via SharePointListItemsSelection are safely encoded. However, the QueryInnerXml of the SharePointView inherently cannot be encoded, so be careful when processing a user defined input to prevent CAML query injection.

How the selection is made

Those of you with knowledge of SharePoint querying might be curious about the selection and how it was made. The selection uses equality comparison, and supplements the where condition provided via QueryInnerXml in the form of a logical conjunction – this was put in place to make it more comfortable to use.

Retrieving SharePoint files

In the last section devoted to SharePoint data retrieval, we will focus on binary data stored on the server. You may already sense that we are going to utilize the ISharePointFileService. First, we have to get a reference to the file as follows:

string fileRef = "/Company parties/Christmas/2013/IMG_0001.jpg"; ISharePointFileService fileService = SharePointServices.GetService<ISharePointFileService>(connectionData); ISharePointFile file = fileService.GetFile(fileRef);


The fileRef contains a value from the picture library field called FileRef. This is a default column for the SharePoint picture libraries’ binary content, but your custom-named columns can contain binary data as well. The lines above do not actually produce a request to the server. Rather, the provided ISharePointFileService uses lazy loading.

Accessing binary content

The ISharePointFile introduces two different approaches to binary content retrieval – all bytes at once or a stream. When you need to process a file on the application server (i.e. image resizing), the first available option is the correct one:

byte[] binaryFileContent = file.GetContentBytes();


The advantage here is simplicity – but when working with larger files their retrieval to an allocated array of bytes can take up a lot of memory. So when you do not actually need to process the data as a whole, you should obtain a reference to the byte stream and then forward the bytes via some buffer directly to the HTTP response stream (if sending to client is what you desire):

using (Stream fileStream = file.GetContentStream()) { // Read the stream to buffer // Do some on-the-fly processing (optional) // Flush the buffer to the HTTP response stream }


Accessing metadata

SharePoint stores some metadata along the binary file content. When you want to use any kind of metadata, you can use the following code:

string title = file.Title; string etag = file.ETag; long length = (file.IsLengthSupported) ? file.Length : -1; DateTime? ceated = file.TimeCreated;


Once read, the metadata properties will be retrieved all at once. Since SharePoint 2010 does not include support for the length property, you should access the property’s content conditionally when writing a version-independent code.

Registering custom SharePoint service factory

The day may come when you are in need of your very own service factory. The reasons for doing this may vary, but the way to do so is still the same. First, you have to prepare your implementation of ISharePointServiceFactory. By examining the interface’s methods, you will find out that the only one you need to implement is:

IService GetImplementationFor<IService>(SharePointConnectionData connectionData) where IService : ISharePointService;


The name of the method speaks for itself. Based on the requested service kind and connection data, you have to return a suitable service implementation instance. Or simply throw SharePointServiceNotSupportedException to indicate the inability to satisfy the request.

Now you have to let the system know about your service implementation. This can be achieved by simply annotating your assembly in the following manner:

[assembly: RegisterSharePointServiceFactory("sharePoint2140", typeof(SharePoint2140ServiceFactory)] public class SharePoint2140ServiceFactory : ISharePointServiceFactory { public IService GetImplementationFor<IService>(SharePointConnectionData connectionData) where IService : ISharePointService { ... } }


The RegisterSharePointServiceFactory attribute performs all the necessary work for you.

You may also want to introduce your custom services within the service family served by your factory. If this is the case, you ought to inherit the ISharePointService interface when declaring your own service’s interface.

Good programming habits

In the examples shown above we have omitted the try-catch clauses to make the code shorter and easier to read – but you should definitely avoid doing that in your own production code, unless you want your users to meet some uncaught exceptions.

Also note that the services offer a direct SharePoint server querying, which can be rather costly operation. Therefore, you should consider some caching mechanism that is suitable for you. The SharePoint data source web part has the ability to cache the retrieved data out of the box.

Conclusion

To sum it all up, when accessing SharePoint data the following steps are necessary:

  1. Pick the right ISharePointService to be instantiated by a service factory and retrieve it by calling SharePointServices.GetService.
  2. Use the service as described in the pieces of code shown in the article.
  3. Be aware of any possible exceptions.

Share this article on   LinkedIn

Marek Fesar

Hi, I am the Principal Technical Leader here at Kentico and I primarily focus on the design, architecture and core of our solution.

Comments