<CharlieDigital/> Programming, Politics, and uhh…pineapples

29Aug/09Off

Design Patterns For SharePoint : Entry 1

One thing that I've discovered is that it's easy to write sloppy, hard to read code when SharePoint is involved. A lot of it may be due to the quick-and-dirty code samples out on the 'Net and a general lack of thought put into the structural details of the examples on MSDN (I can understand why as it can make example code much longer to write it well). I have a whole series of blog post ideas on how to mitigate this (based on my own real world experiences) that I've been meaning to put together that kind of put together a big picture of how to make your team's SharePoint development experience less crappy.

While I have some general workflow related tips and tricks, I'll start off this series with a code based sample. Something small that I think will make a big impact in cleaning up code.

One of the most common things that developers need to do when working with SharePoint is to create an instance of SPSite, open an instance of SPWeb and then get a list (or do something else against the web).

Typically, this takes on the following pattern:

private static readonly string  _siteUrl;
private static readonly string  _web;
private static readonly string  _library;
private static readonly string  _otherLibrary;
static MySharePointDAO() {
    _siteUrl = ...; // Hard coded, from a Constants class, or from config.
    _web = ...;
    _library = ...;
    _otherLibrary = ...;
}
 

public void DoSomething() {
    using(SPSite site = new SPSite(_siteUrl)) {
        using(SPWeb web = site.OpenWeb(_web)) {
            SPList list = web.Lists[_library];

            // Code goes here.
        }
    }
}
public void DoSomethingElse() {
    using(SPSite site = new SPSite(_siteUrl)) {
        using(SPWeb web = site.OpenWeb(_web)) {
            SPList list = web.Lists[_otherLibrary];
 

            // Code goes here.
        }
    }
}

There are many different variations of this basic pattern (in the worst case, this code is written right into layout pages or webpart code which I imagine to be quite a common practice...). Sometimes, the strings are hard coded inline, sometimes the strings are from a Constants class, sometimes the strings are read from a configuration file. No matter how it's done, it tends to muck up the code and it ends up all over the place. One of my beefs with this is that it's not very aesthetically pleasing; deep nesting does that (plus, depending on how deep the rest of the code nests, it may start to scroll horizontally...yuck!). You can also stack the using statements (instead of nesting), but that still leaves it a mess (my other beef) since you need to specify the site URL, the web, and potentially a list - it creates a lot of useless, duplicated code all over your codebase.

Yet there is a very simple solution: abstract this logic into a class that implements IDisposable:

using System;
using Microsoft.SharePoint;
 

namespace SharePointExample
{
    /// <summary>
    /// Abstraction for a SharePoint list.
    /// </summary>
    public abstract class Library : IDisposable
    {
        private static readonly string _siteUrl;

        private readonly SPSite _site;
        private readonly SPWeb _web;
        private SPList _list;

        /// <summary>
        /// Static initializer that sets the site URL.
        /// </summary>
        static Library()
        {
            _siteUrl = ...; // Hard coded, from config, or Constants
        }

        /// <summary>
        /// Default constructor that creates the site and web.
        /// </summary>
        protected Library()
        {
            _site = new SPSite(_siteUrl);
            _web = _site.OpenWeb(WebName);
            _list = _web.GetList(ListName);
        }

        /// <summary>
        /// Gets the name of the list.  Inheriting classes
        /// implement this property for a specific list.
        /// </summary>
        /// <value>The name of the list.</value>
        protected abstract string ListName { get; }

        /// <summary>
        /// Gets the name of the web.
        /// </summary>
        /// <value>The name of the web.</value>
        protected abstract string WebName { get; }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <remarks>
        /// See Cwalina, Abrams; Framework Design Guidelines, 1st Ed., p. 251
        /// </remarks>
        /// <param name="disposing"><c>true</c> to release both managed and 
        /// unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_web != null) _web.Dispose();
                if (_site != null) _site.Dispose();
            }
        }
    }
}

(It's generally not advised to call abstract/virtual members in a constructor, but in this case, they should simply return strings -- should be safe.)

And that's it; so simple. What do our calls look like now? From our presenters/controllers/views, we have something like this instead:

using(ConcreteLibrary library = new ConcreteLibrary()) {

	// Do stuff here with the library.

}

If we only consider this as a win, then it's a very small win. But in the bigger picture, our downstream callers don't need to know about the SPSite, SPWeb, or the SPList if we take the abstraction far enough -- we'll examine this in future installments. Furthermore, we now have a convenient place to put common list based operations and if our business requirements dictate that there are specific lists for specific types of documents, this abstraction becomes even more useful.

I've intentionally left the "Do stuff here..." empty. In the simplest case, at this point, you can simply expose the list, web, and/or site as public properties to inheriting/calling classes and just access library.List or library.Web and use it as you normally would. If nothing else, you've cleaned up the nesting and the leakage of the site URL, web names, and list names. (To make this abstraction more useful, IMO, we would have you hide all of our operations in the ConcreteLibrary and expose the site, web, and list as protected properties to the inheriting classes only.)

This design assumes that you have specific, well known libraries in your SharePoint deployoment in which case it makes sense to create library specific methods and a concrete library sub-type for each library. For example, if a library holds proposals that your sales department has written, you may want to have a class called ProposalsLibrary with a method called FindPendingProposals()which is specific to that library. Of course, common functionality across all lists can be easily added to the base abstract Library class (and this usually involves a "find" operation of some sort).

In general, it's a very small, easy, and intuitive change that makes the code that implements your business logic (as it pertains to SharePoint) much easier to read and to maintain. As we'll explore in future entries in this series, if we take the abstraction far enough, we can completely eliminate the Microsoft.SharePoint namespace from our business/presentation logic.

See also: SharePoint Design Patterns: Entry 2

Posted by Charles Chen

Filed under: Dev, SharePoint Comments Off