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:
1 2 3 4 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">private static readonly string </span><span style="color: #000000;">_siteUrl;</span> <span style="color: #0000ff;">private static readonly string </span><span style="color: #000000;">_web;</span> <span style="color: #0000ff;">private static readonly string </span><span style="color: #000000;">_library;</span> <span style="color: #0000ff;">private static readonly string </span><span style="color: #000000;">_otherLibrary;</span></span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">static </span><span style="color: #000000;">MySharePointDAO() {</span> <span style="color: #000000;">_siteUrl = ...; </span><span style="color: #008000;">// Hard coded, from a Constants class, or from config.</span> <span style="color: #000000;">_web = ...;</span> <span style="color: #000000;">_library = ...;</span> <span style="color: #000000;"><span style="color: #003300;"> </span><span style="color: #000000;">_otherLibrary = ...;</span></span></span><span style="font-family: Lucida Console;"><span style="color: #000000;"> }</span></span> <span style="font-family: Lucida Console;"><span style="color: #0000ff;">public void </span><span style="color: #000000;">DoSomething() {</span> <span style="color: #0000ff;">using</span><span style="color: #000000;">(SPSite site = </span><span style="color: #0000ff;">new </span><span style="color: #000000;">SPSite(_siteUrl)) {</span> <span style="color: #0000ff;">using</span><span style="color: #000000;">(SPWeb web = site.OpenWeb(_web)) {</span> <span style="color: #000000;">SPList list = web.Lists[_library];</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">// Code goes here.</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
1 2 3 4 5 6 7 8 9 10 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">public void </span><span style="color: #000000;">DoSomethingElse() {</span> <span style="color: #0000ff;">using</span><span style="color: #000000;">(SPSite site = </span><span style="color: #0000ff;">new </span><span style="color: #000000;">SPSite(_siteUrl)) {</span> <span style="color: #0000ff;">using</span><span style="color: #000000;">(SPWeb web = site.OpenWeb(_web)) {</span> <span style="color: #000000;">SPList list = web.Lists[_otherLibrary];</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">// Code goes here.</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">;</span> <span style="color: #0000ff;">using </span><span style="color: #008080;">Microsoft</span><span style="color: #000000;">.SharePoint;</span></span> <span style="font-family: Lucida Console;"><span style="color: #0000ff;">namespace </span><span style="color: #000000;">SharePointExample</span> <span style="color: #000000;">{</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Abstraction for a SharePoint list.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public abstract class </span><span style="color: #000000;">Library : IDisposable</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private static readonly string </span><span style="color: #000000;">_siteUrl;</span></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">private readonly </span><span style="color: #000000;">SPSite _site;</span> <span style="color: #0000ff;">private readonly </span><span style="color: #000000;">SPWeb _web;</span> <span style="color: #0000ff;">private </span><span style="color: #000000;">SPList _list;</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Static initializer that sets the site URL.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">static </span><span style="color: #000000;">Library()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">_siteUrl = ...</span><span style="color: #000000;">; </span><span style="color: #008000;">// Hard coded, from config, or Constants</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Default constructor that creates the site and web.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">protected </span><span style="color: #000000;">Library()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">_site = </span><span style="color: #0000ff;">new </span><span style="color: #000000;">SPSite(_siteUrl);</span> <span style="color: #000000;">_web = _site.OpenWeb(WebName);</span> <span style="color: #000000;">_list = _web.GetList(ListName);</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Gets the name of the list. Inheriting classes</span> <span style="color: #008000;">/// implement this property for a specific list.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <value>The name of the list.</value></span> <span style="color: #0000ff;">protected abstract string </span><span style="color: #000000;">ListName { get; }</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Gets the name of the web.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <value>The name of the web.</value></span> <span style="color: #0000ff;">protected abstract string </span><span style="color: #000000;">WebName { get; }</span></span> <span style="font-family: Lucida Console;"> <span style="color: #ff0000;">#region </span><span style="color: #000000;">IDisposable Members</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Performs application-defined tasks associated with freeing, </span> <span style="color: #008000;">/// releasing, or resetting unmanaged resources.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public void </span><span style="color: #000000;">Dispose()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">Dispose(</span><span style="color: #0000ff;">true</span><span style="color: #000000;">);</span> <span style="color: #808000;">GC</span><span style="color: #000000;">.SuppressFinalize(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #ff0000;">#endregion</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Releases unmanaged and - optionally - managed resources</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <remarks></span> <span style="color: #008000;">/// See Cwalina, Abrams; Framework Design Guidelines, 1st Ed., p. 251</span> <span style="color: #008000;">/// </remarks></span> <span style="color: #008000;">/// <param name="disposing"><c>true</c> to release both managed and </span> <span style="color: #008000;">/// unmanaged resources; <c>false</c> to release only unmanaged resources.</param></span> <span style="color: #0000ff;">protected virtual void </span><span style="color: #000000;">Dispose(</span><span style="color: #0000ff;">bool </span><span style="color: #000000;">disposing)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if </span><span style="color: #000000;">(disposing)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if </span><span style="color: #000000;">(_web != </span><span style="color: #0000ff;">null</span><span style="color: #000000;">) _web.Dispose();</span> <span style="color: #0000ff;">if </span><span style="color: #000000;">(_site != </span><span style="color: #0000ff;">null</span><span style="color: #000000;">) _site.Dispose();</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
(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:
1 2 3 4 5 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">using</span><span style="color: #000000;">(ConcreteLibrary library = </span><span style="color: #0000ff;">new </span><span style="color: #000000;">ConcreteLibrary()) {</span> <span style="color: #008000;">// Do stuff here with the library.</span> <span style="color: #000000;">}</span></span> |
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
1 Response
[…] Design Patterns for SharePoint Part 1 […]