Applying MVVM Principles to SharePoint 2010 Development
Overview
Developing for SharePoint 2010 has become a whole lot easier with the included SharePoint
templates in Visual Studio 2010 although, the templates do not lend themselves well
to a clear separation of concerns. This leads to tightly coupled, untestable code,
especially in UI development. In my experience, this leads to a lot of manual testing
overhead and causes nightmares in regression testing. Such coupling is not limited
to SharePoint, it can be found in Windows and Web Forms development as well.
If you want to learn how to design highly responsive SharePoint applications utilizing Web 2.0 and the latest development
techniques, then read on...
MSTest
Out of the box unit testing is painful with SharePoint 2010 projects and MSTest.
This is because the SharePoint object classes such as SPSite and SPWeb are sealed
internal types which do not lend themselves well to mocking. Consider the following
code:
public string ReturnSiteName(string url)
{using (SPSite site = new SPSite(url))
{using (SPWeb web = site.OpenWeb()){return web.Title;}
}
}

Try and right-click to generate unit tests and you will get:
/// <summary> ///A test for ReturnSiteName ///</summary> [TestMethod()] public void ReturnSiteNameTest() { // TODO: Initialize to an appropriate value LearningWebPartService target = new LearningWebPartService(); string url = string.Empty; // TODO: Initialize to an appropriate value string expected = string.Empty; // TODO: Initialize to an appropriate value string actual; actual = target.ReturnSiteName(url); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); }
If you run the test, you will get a screen like below:

Test method UnitTests.LearningWebPartTest.TestMethod1 threw exception: System.IO.FileNotFoundException:
The Web application at http://server:8081/SitePages/Debug.aspx could not
be found. Verify that you have typed the URL correctly. If the URL should be serving
existing content, the system administrator may need to add a new request URL mapping
to the intended application. To explore OOB testing limitations, see this article.
In addition to that, the target framework (4.0) on the unit test project in Visual
Studio 2010 cannot be changed which makes testing against SharePoint 2010 (.Net
3.5) difficult.
Refer to this link for details:
http://connect.microsoft.com/VisualStudio/feedback/details/483939/unable-to-change-target-framework-version-on-unit-test-projects#
Typemock
There are some tools like TypeMock Isolator and Pex & Moles that provide a better
testing experience. Typemock can mock the SharePoint object model (even internal
ones) and is used by the Patterns and Practices team but its Developer price tag
of $799 puts it out of reach of a lot of developers.
Pex and Moles
Pex and Moles is a product from Microsoft Reasearch that does allow you to replace
any method with your own delegate (using Moles) and automate the test using Pex.
A great tutorial on this from Peli de Halleux can be accessed at http://research.microsoft.com/en-us/projects/pex/pexsharepoint.pdf.
It should be noted that this is still a research project and involves a learning
curve.
Layered Design
Why is it bad to have lots of logic in the UI layer?
The code in the UI layer of an application is very difficult to test without either
running the application manually or maintaining ugly UI runner scripts that automate
the execution of UI components. While this is a big problem in itself, an even bigger
problem is the reams of code that are duplicated between common views in an application.
It can often be hard to see good candidates for refactoring when the logic to perform
a specific business function is copied among different pieces in the UI layer. The
MVP design pattern makes it much easier to factor logic and code out of the UI layer
for more streamlined, reusable code that's easier to test. This article discusses
how to take the layered concepts from MVP/MVVM and apply them to SharePoint development.
Figure 1 shows the main layers that make up the sample application. Notice
that there are separate packages for UI and presentation.

Sourced from MSDN
Application Architecture
Model View Presenter
Overview

Sourced from MSDN
Model-view-presenter is a software pattern, considered a derivative of the model-view-controller
pattern.
Pattern Description
Model-view-presenter (MVP) is a user interface design pattern engineered to facilitate
automated unit testing and improve the separation of concerns in presentation logic.
The model is an interface defining the data to be displayed or otherwise acted upon
in the user interface. The view is an interface that displays data (the model) and
routes user commands (events) to the presenter to act upon that data. The presenter
acts upon the model and the view. It retrieves data from repositories (the model),
persists it, and formats it for display in the view.
Model View ViewModel
Overview
Sourced from WikipediaThe Model View ViewModel (MVVM) is an architectural pattern used in software engineering
that originated from Microsoft as a specialization of the Presentation Model design
pattern introduced by Martin Fowler. Largely based on the Model-view-controller
pattern (MVC), MVVM is targeted at modern UI development platforms (Windows Presentation
Foundation and Silverlight) in which there is a User Experience (UX) developer who
has different requirements than a more “traditional” developer (i.e. oriented toward
business logic and back end development). The View-Model of MVVM is “basically a
value converter on steroids” meaning that the View-Model is responsible for exposing
the data objects from the Model in such a way that those objects are easily managed
and consumed. In this respect, the View-Model is more Model than View, and handles
most if not all of the View’s display logic (though the demarcation between what
functions are handled by which layer is a subject of ongoing discussion and exploration).
MVVM was designed to make use of specific functions in WPF to better facilitate
the separation of View layer development from the rest of the pattern by removing
virtually all “code behind” from the View layer. Instead of requiring Interactive
Designers to write View code, they can use the native WPF markup language XAML and
create bindings to the ViewModel, which is written and maintained by application
developers. This separation of roles allows Interactive Designers to focus on UX
needs rather than programming or business logic, allowing for the layers of an application
to be developed in multiple work streams.

MVVM Diagram
Sourced from: Zamjad
Pattern Description
Broadly speaking, the Model-View-ViewModel pattern attempts to gain both the advantages
of separation of functional development provided by MVC as well as leveraging the
advantages of XAML and the Windows Presentation Foundation by binding data as far
back (meaning as close to the Model) as possible while using the XAML, ViewModel,
and any Business Layer’s inherent data checking features to validate any incoming
data. The result is that the Model and Foundation drive as much of the operations
as possible, minimizing the need for “code behind,” especially in the View.

Picture credit:
Suresh Kumar Veluswamy
Elements of the MVVM pattern include:
- Model: as in the classic MVC pattern, the model refers to either (a) an object
model that represents the real state content (an object-oriented approach), or (b)
the data access layer that represents that content (a data-centric approach).
- View: as in the classic MVC pattern, the view refers to all elements displayed
by the GUI such as buttons, windows, graphics, and other controls. - ViewModel: the ViewModel is a “Model of the View” meaning it is an abstraction
of the View that also serves in data binding between the View and the Model. It
could be seen as a specialized aspect of what would be a Controller (in the MVC
pattern) that acts as a data binder/converter that changes Model information into
View information and passes commands from the View into the Model. The ViewModel
exposes public properties, commands, and abstractions. The ViewModel has been likened
to a conceptual state of the data as opposed to the real state of the data in the
Model. - Controller: some references for MVVM also include a Controller layer or illustrate
that the ViewModel is a specialized functional set in parallel with a Controller,
while others do not. This difference is an ongoing area of discussion regarding
the standardization of the MVVM pattern.
MVVM/MVP in SharePoint 2010
Although MVVM was primarily designed for WPF/Silverlight, the basic principles of
modularity and separation of concerns can be applied to SharePoint development,
barring some technical challenges.
In this article, I will show you how to structure a SharePoint project to derive
a lot of the same benefits out of MVVM. Lets take a look at how the sample webpart
project can be retrofitted into the MVVM paradigm.

You will notice that the unit tests are more targeted at the model. By moving the
application logic out of the webpart and into the WCF service, not only have we
cleanly separated out the concerns but also made it easier to test this (as I will
demonstrate later). Admittedly, it is still hard to test the ViewModel (although
there are tools that can unit test Javascript, such as JSUnit), but even with just
the Model unit tests, we now have a large percentage of coverage, at little cost
just by utilizing the MSTest project.
Walkthrough
Lets now walkthrough the code structure.

- Create a SharePoint 2010 WebPart project from the installed templates
Add a project folder called DTO. This will contain the data transfer objects that will be serialized
to JSON using the JSON.Net serializer. See the code below for the 2 key Data Transfer Objects:There are 2 generic objects that marshall the data back and forth from the HTML (UI) layer to the service
layer; the WebRequest and WebResponse objects. The generic nature of the contained fields (Args in WebRequest
and Payload in WebResponse)
makes it easy to push any complex object into the WebRequest and
WebResponse objects, provided of course, that it can be serialized to JSON.

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.Serialization;namespace Sukul.Learning.SharePoint2010.LearningWebPart.DTO{/// <summary>/// This lightweight data transfer object represents a generic object that will be passed from a client calling the WCF service./// Any number of arguments can be stored within this class./// <author>Shailen Sukul</author>/// <url>http://shailen.sukul.org</url>/// </summary>[DataContract]
public class WebServiceRequest
{/// <summary>/// The args object will contain arguments that will be passed to the service./// </summary>[DataMember]
public object Args;
}
}
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.Serialization;namespace Sukul.Learning.SharePoint2010.LearningWebPart.DTO{/// <summary>/// This is lightweight, generic object returned from a WCF call. It contains indicators on whether the call was successful and the returned value as well as any error messages./// <author>Shailen Sukul</author>/// <url>http://shailen.sukul.org</url>/// </summary>[DataContract]
public class WebServiceResponse
{/// <summary>/// Indicates if the web service call was successful/// </summary>[DataMember]
public bool IsSuccess = false;
/// <summary>/// Contains the response message from the service/// </summary>[DataMember]
public object Payload = "Object not assigned";
/// <summary>/// Contains a friendly error message if the service encountered an exception/// </summary>[DataMember]
public string FriendlyErrorMessage = string.Empty;
/// <summary>/// Contains the full text of the exception, if one occurred/// </summary>[DataMember]
public string ErrorMessage = string.Empty;
/// <summary>/// Contains the exception trace, if one occurred/// </summary>[DataMember]
public string ErrorStackTrace = string.Empty;
/// <summary>/// Contains the date and time of the service response in UTC format./// </summary>[DataMember]
public string UTC_DateOfResponse = DateTime.Now.ToUniversalTime().ToString("dd MMM yyyy hh:mm:ss tt");
}
}
Create 3 mapped folders:
- Images - will contain all images used in this project
- ISAPI - will contain the service markup and its config file
- Layouts - will contain css and javascript files
Download the JSON.Net project source code from http://json.codeplex.com and reference
it in your project. This library is needed for serializing .Net types to JSON.
Specify a strong named key for this project and reference from your WebPart project.
Create a project folder called Service. Add the service interface and class definition here.
/* Any change to the interface name needs to be updated in App.config *//// <summary>/// This is the interface definition for the WCF service/// <author>Shailen Sukul</author>/// <url>http://shailen.sukul.org</url>/// </summary>[ServiceContract(Namespace="Sukul_Learning_SharePoint2010_LearningWebPart")]public interface ILearningWebPartService
{/// <summary>/// This method will return a collection of items to display in a scrolling carousel in the webpart./// </summary>/// <param name="request">The requests object will capture any arguments to be supplied to the service.</param>/// <returns>Returns a DTO.WebServiceResponse class in JSON format, hence the string return type.</returns>[OperationContract]
[WebMethod]
string GetWebPartResponse(DTO.WebServiceRequest request);}
-
Create a folder under the mapped ISAPI folder and add the service markup file (.svc) file
and a web.config file.
<%@ ServiceHost Language="C#" Debug="true" Service="Sukul.Learning.SharePoint2010.LearningWebPart.Service.LearningWebPartService, $SharePoint.Project.AssemblyFullName$"%>
Note: Notice the $SharePoint.Project.AssemblyFullName$ token. The SharePoint
Condensed instructions below:
project will not understand how to process this token in the .svc file so you have
to do the following to enable it:
Source: http://msdn.microsoft.com/en-us/library/ff521581.aspx
- Unload your project
- Right-click on your .csproj file and select Edit

- In the project file, add a TokenReplacementFileExtensions tag as follows:
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{F455078E-8836-403A-9E63-5E5F21B5F694}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>RevertService</RootNamespace> <AssemblyName>RevertService</AssemblyName> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <ProjectTypeGuids>{BB1F664B-9266-4fd6-B973-E1E44974B511};{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <SandboxedSolution>False</SandboxedSolution> <TokenReplacementFileExtensions>svc</TokenReplacementFileExtensions> </PropertyGroup> . . . .
- Save and close the project and reload.
Copy the following service config code and paste into your web.config file:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<bindings>
<webHttpBinding>
<binding name="customWebHttpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="Sukul.Learning.SharePoint2010.LearningWebPart.Service.LearningWebPartServiceBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="DebugBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Sukul.Learning.SharePoint2010.LearningWebPart.Service.LearningWebPartService"
behaviorConfiguration="DebugBehavior">
<endpoint address=""
behaviorConfiguration="Sukul.Learning.SharePoint2010.LearningWebPart.Service.LearningWebPartServiceBehavior"
binding="webHttpBinding"
contract="Sukul.Learning.SharePoint2010.LearningWebPart.Service.ILearningWebPartService"
bindingConfiguration="customWebHttpBinding"/>
</service>
</services>
</system.serviceModel>
</configuration>
Now that the service is configured, let's focus on the UI.

Open the LearningVisualWebPart.cs file and inject a script reference to the prior service file:
ScriptManager scriptManager1 = ScriptManager.GetCurrent(this.Page);if (scriptManager1 == null)
{scriptManager1 = new ScriptManager() { ID = "ScriptManager1" };
this.Controls.Add(scriptManager1);}
scriptManager1.Services.Add(newServiceReference("/_vti_bin/Sukul.Learning.SharePoint2010.LearningVisualWebPart/LearningWebPartService.svc"));
Next, open the markup for the VisualWebPartUserControl.ascx file. The HTML code is your client side UI. Knowing that the
service reference has already been injected, we can simply invoke the WCF service from here using the fully qualified
name. You will recall that the namespace was set in the service interface file above.
/* Makes an asychronous call to the registered WCF service */function CallService(input) {ShowProgress();
var req = { Args: input };var proxy = new Sukul_Learning_SharePoint2010_LearningWebPart.ILearningWebPartService();proxy.GetWebPartResponse(req, onSuccess, onFail);
}
An important part of UI design is templating. Microsoft have released a templating
plugin, that will eventually be packaged with jQuery. The templating plugin allows
you to define your UI around a DTO object which will be supplied at runtime, which
the plugin uses to gracefully "fill in the blanks".
So, in order to get started you will need the templating plugin:
<script type="text/javascript" src="~/_layouts/Sukul.Learning.SharePoint2010.LearningVisualWebPart/jquery.tmplPlus.js"></script>
And then design the UI template and leave placeholders that will be filled in when the data object is supplied at runtime.
<script id="vw_Sites" type="text/x-jquery-tmpl">
<span><b>Site Collections that the user has access to:</b></span>
<table class="customTable">
<tr><th>Site Title</th><th>Site Url</th></tr>
{{each Payload}}<tr>
<td style="width:30%">${$value.SiteCollectionTitle}</td>
<td style="width:70%">${$value.SiteCollectionUrl}</td>
</tr>
{{/each}}</table>
</script>
And finally make a call to the templating plugin to supply the data object
$("#vw_Sites").tmpl(retVal).appendTo("#resultsDiv");
Coming Full Circle - Unit Testing Revisited
Now that the business logic is encapsulated in the WCF service, let's see how to create a unit test around this.
Create a Unit Test project and add a project reference to your SharePoint project and the Newtonsoft library.

Add a LearningWebPartTest.cs class and add the following code:
/// <summary>/// This test illustrates how you can run a test directly on an assembly/// that does not need the SharePoint context./// </summary>[TestMethod]
public void TestWebServiceResponse1()
{try{ Service.ILearningWebPartService service = new Service.LearningWebPartService();DTO.WebServiceRequest request = new DTO.WebServiceRequest();request.Args = ServiceArgs.Arg_GetBanners;
string s_response = service.GetWebPartResponse(request);Console.WriteLine(s_response);
DTO.WebServiceResponse response = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO.WebServiceResponse>(s_response);
if (response.Payload != null)
{foreach (var r in (System.Collections.ICollection)response.Payload)
{Console.WriteLine(r.ToString());
}
}
Assert.IsNotNull(response.Payload);
}
catch (Exception ex){Assert.Fail(ex.ToString());
}
}
/// <summary>/// This test illustrates how to invoke a WCF call where SharePoint /// context is required and how to disassemble the /// result into testable objects./// </summary>[TestMethod]
public void TestWebServiceResponse2()
{try{Service.ILearningWebPartService service = new Service.LearningWebPartService();DTO.WebServiceRequest request = new DTO.WebServiceRequest();request.Args = ServiceArgs.Arg_GetSites;
string data = "{\"request\": " + JsonConvert.SerializeObject(request) + "}";
string s_response = Helper.Instance.CleanJSONObject(Helper.Instance.GetResponse(SERVICE_URL, data));/* JSON response object to extract the payload */var responseJsonObj = JObject.Parse(s_response);
/* Strong typed response object minus the object Payload */var responseTypedObj = JsonConvert.DeserializeObject<DTO.WebServiceResponse>(s_response);
/* Ensure the call succeeded */Assert.IsTrue(responseTypedObj.IsSuccess);
Console.WriteLine("Server response values ...");Console.WriteLine("IsSuccess: {0}{2}DateTime of Response(UTC): {1}", responseTypedObj.IsSuccess, responseTypedObj.UTC_DateOfResponse, Environment.NewLine);
Console.WriteLine("");JObject SiteInfo = null;/* Extracting the Payload from a strongly typed object */Console.WriteLine("Extracting the Payload from a strongly typed object....");foreach (var r in (System.Collections.ICollection)responseTypedObj.Payload)
{SiteInfo = JObject.Parse(r.ToString());
SiteInfo = JObject.Parse(r.ToString());
Console.WriteLine(string.Format("Site Collection Title: {0}{1}Site Collection Url: {2}",
SiteInfo["SiteCollectionTitle"].ToString(), Environment.NewLine, SiteInfo["SiteCollectionUrl"].ToString()));
}
Console.WriteLine("");/* Extracting the Payload form a loosely typed object */Console.WriteLine("Extracting the Payload from a loosely typed object....");var payLoad = (JArray)responseJsonObj["Payload"];foreach (var r in payLoad)
{SiteInfo = JObject.Parse(r.ToString());
Console.WriteLine(string.Format("Site Collection Title: {0}{1}Site Collection Url: {2}",
SiteInfo["SiteCollectionTitle"].ToString(), Environment.NewLine, SiteInfo["SiteCollectionUrl"].ToString()));
}
}
catch (Exception ex){Assert.Fail(ex.ToString());
}
}
[TestMethod]
public void TestWebServiceResponse3()
{try{Service.ILearningWebPartService service = new Service.LearningWebPartService();DTO.WebServiceRequest request = new DTO.WebServiceRequest();request.Args = ServiceArgs.Arg_Error;
string data = "{\"request\": " + JsonConvert.SerializeObject(request) + "}";
string s_response = Helper.Instance.CleanJSONObject(Helper.Instance.GetResponse(SERVICE_URL, data));/* JSON response object to extract the payload */var responseJsonObj = JObject.Parse(s_response);
/* Strong typed response object minus the object Payload */var responseTypedObj = JsonConvert.DeserializeObject<DTO.WebServiceResponse>(s_response);
/* This test simulates an error condition */Assert.IsFalse(responseTypedObj.IsSuccess);
Console.WriteLine("Simulating server side error ....");Console.WriteLine("");if (responseTypedObj.Payload != null)
{Console.WriteLine(string.Format("FRIENDLY ERROR MESSAGE: {0}{3}ERROR MESSAGE: {1}{3}STACK TRACE: {2}{3}",
responseTypedObj.FriendlyErrorMessage, responseTypedObj.ErrorMessage,
responseTypedObj.ErrorStackTrace, Environment.NewLine));
}
}
catch (Exception ex){Assert.Fail(ex.ToString());
}
}
TestWebServiceResponse1
This test illustrates how to invoke a test on the WCF service class directly, since
there is no dependency on the SharePoint context.
A WebRequest object is created and the argument is set to "banners". Based on this,
the service class wil return a list of banner links.
The test will now succeed and the JSON object will be returned.

TestWebServiceResponse2
This unit test needs access to the SharePoint context so it will make a direct call to the hosted SharePoint
web service and pass it the credentials of the unit test user.
It employs the use of the Helper class to invoke the REST service and "clean up" the output.
/// <summary>/// This helper class makes a call to the supplied WCF REST /// service, injects the JSON input and returns the returned JSON/// result in string format./// </summary>/// <param name="url"></param>/// <param name="data"></param>/// <returns></returns>public string GetResponse(string url, string data)
{if (url.Equals(string.Empty))
{throw new ArgumentException("Please supply a url first.");
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";request.ContentType = "application/json";/* /* This is the user connecting to the SharePoint service */request.Credentials = ActiveUser;
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);request.ContentLength = byteData.Length;
using (Stream postStream = request.GetRequestStream()){postStream.Write(byteData, 0, byteData.Length);
}
string responseAsString = string.Empty;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream stream = response.GetResponseStream()){StreamReader sr = new StreamReader(stream);responseAsString = sr.ReadToEnd();
stream.Close();
}
return responseAsString;}
/// <summary>/// This cleans up JSON respones which are returned as /// d: { ... }/// </summary>/// <param name="response"></param>/// <returns></returns>public string CleanJSONObject(string response)
{/* Replace delimiters */response = response.Replace("\\", string.Empty);/* Get the internal data of the response, ie everything after the d: */
response = response.Substring(response.IndexOf("{", 2), response.LastIndexOf("}") - response.IndexOf("{", 2) - 1);return response;}
The web service requires an argument of type WebServiceRequest which contains an internal string field
called Args which will be set to the value "getsites".
So how do we compose the argument in JSON format?
DTO.WebServiceRequest request = new DTO.WebServiceRequest();request.Args = ServiceArgs.Arg_GetSites;
string data = "{\"request\": " + JsonConvert.SerializeObject(request) + "}";
The format of the argument will be: { WebServiceVariableName : { "Args": "getsites" } }
The helper class will add the argument to the request stream of the HttpWebRequest object and
set the content type to "application/json". You also have the option of setting the
security of the call by setting the ActiveUser property.
public ICredentials ActiveUser{get;
set;
}
Now that we have the ability to invoke the service without any dependency on SharePoint,
we should get back a formatted JSON resultset. Next we need to convert the JSON string back
into a .Net object. I have 2 examples below, one where the return object is typed into
the WebResponse object and the other, where it deals directly with the JSON object model.
/* JSON response object to extract the payload */var responseJsonObj = JObject.Parse(s_response);
/* Strong typed response object */var responseTypedObj = JsonConvert.DeserializeObject<DTO.WebServiceResponse>(s_response);
We can now loop through the returned object with ease:
/* Extracting the Payload from a strongly typed object */Console.WriteLine("Extracting the Payload from a strongly typed object....");foreach (var r in (System.Collections.ICollection)responseTypedObj.Payload)
{SiteInfo = JObject.Parse(r.ToString());
Console.WriteLine(string.Format("Site Collection Title: {0}{1}Site Collection Url: {2}",
SiteInfo["SiteCollectionTitle"].ToString(), Environment.NewLine, SiteInfo["SiteCollectionUrl"].ToString()));
}
Console.WriteLine("");/* Extracting the Payload form a loosely typed object */Console.WriteLine("Extracting the Payload from a loosely typed object....");var payLoad = (JArray)responseJsonObj["Payload"];foreach (var r in payLoad)
{SiteInfo = JObject.Parse(r.ToString());
Console.WriteLine(string.Format("Site Collection Title: {0}{1}Site Collection Url: {2}",
SiteInfo["SiteCollectionTitle"].ToString(), Environment.NewLine, SiteInfo["SiteCollectionUrl"].ToString()));
}
The output will display all sites that the user has access to:

TestWebServiceResponse3
This test will simulate an error occuring in the web service and display the error message that comes back.
/// <summary>/// This test expects an error message coming back from the WCF service./// </summary>[TestMethod]
public void TestWebServiceResponse3()
{try{Service.ILearningWebPartService service = new Service.LearningWebPartService();DTO.WebServiceRequest request = new DTO.WebServiceRequest();request.Args = ServiceArgs.Arg_Error;
string data = "{\"request\": " + JsonConvert.SerializeObject(request) + "}";
string s_response = Helper.Instance.CleanJSONObject(Helper.Instance.GetResponse(SERVICE_URL, data));/* JSON response object to extract the payload */var responseJsonObj = JObject.Parse(s_response);
/* Strong typed response object minus the object Payload */var responseTypedObj = JsonConvert.DeserializeObject<DTO.WebServiceResponse>(s_response);
/* This test simulates an error condition */Assert.IsFalse(responseTypedObj.IsSuccess);
Console.WriteLine("Simulating server side error ....");Console.WriteLine("");if (responseTypedObj.Payload != null)
{Console.WriteLine(string.Format("FRIENDLY ERROR MESSAGE: {0}{3}ERROR MESSAGE: {1}{3}STACK TRACE: {2}{3}",
responseTypedObj.FriendlyErrorMessage, responseTypedObj.ErrorMessage,
responseTypedObj.ErrorStackTrace, Environment.NewLine));
}
}
catch (Exception ex){Assert.Fail(ex.ToString());
}
}
Demonstration

Deployment
Now that we have the solution structured using mapped SharePoint folders, deployment should be easy enough.
The SharePoint tools provided with Visual Studio 2010 will be able to package the project artifacts into a single WSP file.
The only extra thing that has to be done is to download the Newtonsoft project, supply it the solutions' strong named key and include it
in the SharePoint project. If you have not done this before, the method for doing this is not quite so obvious.
To add the GAC dll, open your project and click on the Advanced bottom tab and select Add Assembly.

As an added bonus, all public classes, methods and properties have been commented and Sandcastle has been run over
the commented code to generate the documentation. The help file can be downloaded here:
Help File
Note: In order to open the CHM file, save it first, open its properties and select "unblock".
The WSP file can be downloaded from here: WSP File
Summary
As you can see, with a little refactoring, you can get test coverage for a large percentage of your SharePoint code with
little effort.
There are still gaps in testing the ViewModel (i.e. the javascript controller).
There are fameworks like JSUnit that allow testing javascript
and will be explored in a later article.
The code sample can be downloaded by clicking here.

Downloads
| Link | Description |
|---|---|
| Presentation Download | Presentation Deck |
| WSP File | WSP for deployment |
| Source code | WSP for deployment |
| Help File | Help File in CHM format |
References
Author | Description | Link |
|---|---|---|
Sahil Malik | Great podcast from Sahil dicussing layered design in SharePoint. | http://www.dotnetrocks.com/default.aspx?showNum=589 |
Jean-Paul Boodhoo | MSDN post about the MVP Pattern | http://msdn.microsoft.com/en-us/magazine/cc188690.aspx |
Andrew Connel | Andrew's summary of MVVM | http://www.andrewconnell.com/blog/archive/2010/10/03/mvvm-why-i-like-it-and-how-i-learned-it.aspx |
Suresh Kumar Veluswamy | Suresh's comparision of MVVM versus MVP | http://sureshkumarveluswamy.wordpress.com |
Jeremy Thake | Unit Testing with SharePoint 2010 | http://www.sharepointdevwiki.com/display/sp2010/Unit+Testing+with+SharePoint+2010+Development |
is involved in the delivery of enterprise-scale applications that utilize the SharePoint
platform, the .Net Framework and agile methods.
He also delivers training courses and presentations in SharePoint 2010, .Net development
and Architectural Patterns.
Shailen Sukul can be reached at shailensukul@gmail.com
Shailen's Details
| shailensukul@gmail.com | |
| Cell | +1 (916) 359-9557 |
| MSN/Galk | shailensukul |
| shailensukul | |
| Skype | shailen.sukul |
| Blog | http://www.shailen.sukul.org |
Great article Shay-len! ;) Thanks for your efforts... BTW, I would definitely recommend that you compare this with the Presentation Design Pattern for SharePoint and post your findings. Also an article on the Service Locator pattern in sharepoint would be great. I know you will post something cool. Best luck.
ReplyDeleteGreat find, I’m going to have to check this one out. Thanks for sharing.
ReplyDeleteVery informative….
This link "http://code.sukul.org/Public/SharePoint%202010/MVVM/SharePoint%20MVVM%20Project.rar" does not work. Please, could not you correct it.
ReplyDeleteI fixed the Http header content-type for the link above. please try and click on it now and it should prompt you to save.
ReplyDeleteGood work Sukul. This is the first article of its kind i have read so far. Enjoyed it alot. I wanted to test your code, so i downloaded it and deployed on my local sharepoint 2010 server. When i browse the webpart webpage, It displays "Authentication Required" box asking for my username and password. I plugin my domain account info, but it fails to log me in. when i click cancel, i can see the html part of the webpart, again when i click on "Invoke" button i see the "Authentication Required" box. Any clue what is causing Authentication at this level? Thank you.
ReplyDeleteAleem
@Aleem,
ReplyDeleteIt could be a loopback issue with your environment. See this article: http://www.shailen.sukul.org/2010/06/loopback-fix.html