次の方法で共有


Consume SharePoint Web Services with WCF using the Repository, Gateway, Mapper, Domain Model and Factory Design Patterns

The SharePoint developer community has produced a wealth of knowledge and code samples that demonstrate how to consume SharePoint web services and leverage them in domain-specific applications.  This information is often task-centric, such as  "How to add an Item to a List using SharePoint Web Services."   In this article, we will take a framework-centric approach and apply sound, fundamental object-oriented (OO) design principles to implement a reusable library for working with the SharePoint web services.

Motivation and Goals

My motivation for this article is to help you create a foundation for a framework that can be used in one, or reused across many SharePoint-integrated applications.  I also want to demonstrate how good software design principles can (and should) be applied to SharePoint development, and confess my own sins for not always following them.  For some reason, I often find myself thinking procedurally when developing a SharePoint customization.  Perhaps it's because the product is a 70% solution and requires a different mindset and approach than a large greenfield software project does.  Maybe customers expect results faster when you build it on SharePoint, and I've taken shortcuts to meet them.  Or maybe I've just been lazy, but in any case, here are some of the issues I've seen or been responsible for:

  • Re-writing the same SharePoint code on each new project
  • Not refactoring within and across applications
  • Tightly coupling application code to the XML input and output from SharePoint services
  • Lack of a domain model; designing procedurally instead of applying domain-driven design (DDD)
  • Not having well-defined layers and strategies
  • Failure to design for testability and not writing unit tests

Here are some of the goals I would like to achieve with this framework:

  • Implement a domain model that is independent and decoupled from the SharePoint services
  • Define a set of patterns and strategies for communicating with the SharePoint services
  • Create a reusable library that can be used in many different domain-specific applications
  • Use DDD and Test-Driven-Design (TDD)
  • Apply good OO principals and patterns
  • Use Windows Communication Foundation (WCF)

Design

In the next section, I'll walk through the implementation and the process I went through to arrive at the design below.  Generally speaking, I used DDD and TDD (where it made sense) and followed the Single Responsibility principle.  If you are not familiar with this, it is often described as "a class should only have one reason to change."  I call it the "and test."  I describe the purpose of the class and if I have to use the word and, I consider refactoring some of the functionality to another class.

In the diagram below, the client application uses the repository and domain classes.  The repository is responsible for retrieving domain objects based on criteria.  The repository uses one or more service gateways to get the information it needs.  The service gateway communicates with the SharePoint web services using a WCF client.  The service calls typically return XML responses, and it is the job of the service response mapper to translate the XML to a domain object.  Finally, the WCF client factory creates clients configured to call the SharePoint services.

Get the code

SPServicePattern

 

Implementation

In this example, the goal is to get all the lists in a given site.  Following DDD, we will start the design in the domain layer and create a list class that has a title property:

image

Create the list repository class to define the method clients will call the get the lists in a given site:

image

Following TDD, we'll create a unit test that will fail until we implement the repository:

image

Return to the repository class and add the implementation to call the lists service gateway which we haven't created yet.  How did I know to create a lists service gateway?  I decided to have a gateway that corresponds to each SharePoint web service and did some research to find the exact service and method that would return the lists for a given site.  The implementation below is very simple, but you can imagine a more complex repository that uses several service gateways and does some additional processing to construct a domain object graph.

image

Create the lists service gateway so the project will compile:

image 

Create a failing unit test for the lists service gateway:

 image

Next we'll add a reference to the SharePoint Lists service.   Note: Visual Studio will add an app.config and a Properties > DataSources folder and you can delete both of them.  We are going to configure WCF programmatically.

image 

 

Return to the lists service gateway and fill in the implementation.  Now I'm pulling a "Julia Childs" on you.  I already went through several iterations of TDD and refactoring to arrive at the implementation below.  Initially this method had all the code to call the web service, and there was no WCF client factory nor a mapper.  After implementing this logic in several gateways, I refactored the commonality to classes.  It made sense to have a factory to construct WCF clients in a consistent way and allow me to make a change in one place if I discovered something new.  The Single Responsibility "and test" led me to refactor the mapping code to a separate class and the end result is a much cleaner implementation:

image

 

Next, we'll implement the WCF client factory.  As you can see, it has been through a few iterations of TDD and refactoring starting with the service url class.  This class contains constants and methods for working with SharePoint service urls.  The other thing you'll notice is the the WCF configuration that is typically done in a configuration file is being done programmatically in the service binding factory class.

image

Here is the implementation of the service binding factory:

image

The gateway uses a mapper to map the XML response from the SharePoint web service to a domain object.  The XML response is in the form of <element attribute1...n /> which, in this case, translates nicely to domain objects and properties.  The code below uses Linq to find all List elements and for each one it calls MapInternal which creates a list object from the element:

image

Now if we return to the repository GetLists unit test, it passes and output each list title in the site:

image

 

Summary

In this article and walkthrough, I demonstrated how DDD, TDD, patterns and good OO principles can be applied to implement a framework that consumes SharePoint web services.  Even though I focused on the web services, the SharePoint API can also be regarded as a service and the same fundamentals can be applied to developing applications that run on the server.  I hope this inspires and helps you to implement your own framework and improve the quality and reuse of your SharePoint code.

Get the code

 

References and Additional Reading

Comments

  • Anonymous
    January 03, 2009
    PingBack from http://www.codedstyle.com/consume-sharepoint-web-services-with-wcf-using-the-repository-gateway-mapper-domain-model-and-factory-design-patterns/

  • Anonymous
    January 05, 2009
    The comment has been removed

  • Anonymous
    January 16, 2009
    The comment has been removed

  • Anonymous
    April 06, 2009
    The download link appears broken.

  • Anonymous
    April 09, 2009
    Thanks for the great article.  Is there anyway to get the download link fixed, I would hate to start from scratch instead of leveraging your excellent start.

  • Anonymous
    April 13, 2009
    @Sonny John wrote me an email and told me to take a look at spud on Codeplex. It's a project he's been working on : it integrates what's been discussed here. http://www.codeplex.com/spud

  • Anonymous
    March 20, 2011
    I struggling until now to implement design pattern in SharePoint, at last...this article is trully an enlightment, thanks a ton ! :D

  • Anonymous
    January 09, 2012
    The download link is fixed

  • Anonymous
    June 21, 2012
    Lovely work John! Your tool is great.  I need an additional feature: how to return the SQL which generates the values of a lookup field with multiple values. Anyone know the secret?