Model-View-Presenter Pattern with SharePoint Web Parts
So what’s this MVP thing? Bil’s an MVP so now he’s a pattern? I don’t get it.
Well, not quite.
Model-View-Presenter (MVP) is a fairly new(er) term for an old(er) pattern in Software Design. Its similar (but not necessarily the same) as the Model-View-Controller pattern (MVC) that you may have heard of or seen around. MVP is a pattern that will abstract away the display of data from a user interface. This is done for a few benefits, like being able to test a UI without a UI (yeah, let that one cook in your noodle for a minute or two). It also reinforces your domain model so you’re not doing screwy things like writing logic decisions (should I display a row of information if the user has permisions or not) in the user interface. Bad, bad place to do this.
Quoting Martin Fowler, the MVP pattern “Separates the behavior of a presentation from the view while allowing the view to receive user events.”
So MVP is a great pattern for doing UI elements, and keeping your domain logic where it belongs (read: in the domain silly), while maintaining a good, clear separation from the UI. In essence, the view subscribes to events and the presenter, well, “presents” them to the UI. The UI then figures out how to update itself and doing crazy user interface stuff like change lists of data or display rows of information.
Still with me? Imagine that Bert is the View, Ernie is the Presenter, and Mr. Hooper is the Model. Mr. Hooper has some jellybeans for sale at his store. Ernie can go to Mr. Hoopers store and find out how many jellybeans he has for sale today. Ernie will tell Bert this so Bert can update the Sesame Street website. Ernie doesn’t know anything about HTML but does have the information Bert needs to do his thing. Bert isn’t allowed to talk to Mr. Hooper or go anywhere near his store (after that last incident with Mr. Snuffleupagus and the latex) so Ernie heads out to Mr. Hoopers store and counts the number of jellybeans he has for sale. He comes home and tells this to Bert. This is how Bert gets the information he needs to update the website. Got it?
The thing about MVP is that UI doesn’t really care how (or for that matter where) the data came from. The presenter just gives it to the UI in pieces. The UI is a dumb animal (and should be) and should only know simple things like adding items to a drop down list, or displaying a grid of information. User interfaces are stupid and should never get any smarter than knowing about the UI. Much like any project manager.
Okay, let’s get into this and walk through an example of creating the MVP pattern with SharePoint Web Parts. There’s an excellent article on The Code Project that describes the MVP pattern in-depth here. I’ve adapted it to use a SharePoint Web Part instead of an ASP.NET page for this article.
Side note: This is the first of two articles I’m going to do on the MVP pattern. The first is going to be for .NET 1.1 (Visual Studio 2003) and SharePoint v2 (or 2003 if you prefer). The second article will come later and be written in .NET 2.0 (Visual Studio 2005) and SharePoint v3 (or 2007). The two articles show the same pattern, but are implemented differently as I can make use of Generics and other features of the Web Part framework. I just thought I would kick it off with a 2003 demo so anyone writing Web Parts for SharePoint today could make use of it.
The View
No, not that crappy TV show with Starr Jones quitting over the number of M&Ms she needs, but rather the “V” in “MVP”. The View is responsible for exposing the data we want to the user interface. You might say that’s what say a class inherited from WebPart does. Well, yes, but since we want to tell the view (indirectly) what to update and we don’t want to know about UI type control things (listboxes, drop down lists, data grids, etc.) we need something called a View. The View gets implemented as an interface and as you know in .NET, you can implement as many interfaces as you want on a class.
Here’s a simple view that has one property of type DateTime called CurrentTime that any class implementing this interface must create the setter for.
1 using System;
2
3 namespace WebPartMVP
4 {
5 public interface ICurrentTimeView
6 {
7 DateTime CurrentTime {set;}
8 }
9 }
The Presenter
The Presenter is the guy behind the curtain that makes the magic happen. The Presenter marries the view and the model together in a harmonious fashion, wiring itself up to events that are triggered from the view. When the view requests a change, it does so through the Presenter and the Presenter (talking to the Model) will respond accordingly. Finally the View updates itself via the UI (whatever that UI may be, a User Control, WinForm, WebForm, or in our case a SharePoint Web Part).
Our presenter is simple and will do two things. First, it gets created using an object passed into the constructor that conforms to the ICurrentTimeView interface. Next, it provides a public method called InitView that will initialize the view when called. Here’s the code for our Presenter:
2
3 namespace WebPartMVP
4 {
5 public class CurrentTimePresenter
6 {
7 private ICurrentTimeView _view;
8
9 public CurrentTimePresenter(ICurrentTimeView view)
10 {
11 _view = view;
12 }
13
14 public void InitView()
15 {
16 _view.CurrentTime = DateTime.Now;
17 }
18 }
19 }
The Model
This is the class that represents the data we want to present. As you may not need to expose your entire domain object graph to the UI, this might be a subset or slice through that data. Whatever is relevant to the UI and the properties you need to expose. Our Model is going to be simple and we don’t have a class for it. It’s just what gets set during the initialization of the view but you could create your own Model class or have the Presenter talk to a Facade or Service object to get data. In this example, the Service object is the current DateTime instance.
Bringing it all Together
Let’s bring this puppy home. So we have a view interface, and we have a presenter that will take an interface of that type during construction. First we need to add the ICurrentTimeView interface to our Web Part and implement the member(s) that it describes. Here’s what that looks like in our Web Part:
2 using System.ComponentModel;
3 using System.Web.UI;
4 using System.Web.UI.WebControls;
5 using System.Xml.Serialization;
6 using Microsoft.SharePoint;
7 using Microsoft.SharePoint.Utilities;
8 using Microsoft.SharePoint.WebPartPages;
9
10 namespace WebPartMVP
11 {
12 [DefaultProperty("Text"),
13 ToolboxData("<{0}:WebPart1 runat=server></{0}:WebPart1>"),
14 XmlRoot(Namespace="WebPartMVP")]
15 public class WebPart1 : Microsoft.SharePoint.WebPartPages.WebPart, ICurrentTimeView
16 {
17 private const string defaultText = "";
18 private string text = defaultText;
19
20 [Browsable(true),
21 Category("Miscellaneous"),
22 DefaultValue(defaultText),
23 WebPartStorage(Storage.Personal),
24 FriendlyName("Text"),
25 Description("Text Property")]
26 public string Text
27 {
28 get
29 {
30 return text;
31 }
32
33 set
34 {
35 text = value;
36 }
37 }
38
45 protected override void RenderWebPart(HtmlTextWriter output)
46 {
47 output.Write(SPEncode.HtmlEncode(Text));
48 }
49
52 public DateTime CurrentTime
53 {
54 set
55 {
56 Text = value.ToLongDateString();
57 }
58 }
59 }
60 }
This is just the generated Web Part you get from the template in Visual Studio 2003, except we’ve got two new things. First the CurrentTime property, which is an implemention of the ICurrentTimeView interface and the interface has been added to our Web Part declaration.
The CurrentTime implementation is up to us and in our case, we’re going to set our Text property to it. When the Web Part renders, it will render out the Text property that will get set.
So how does the Presenter talk to the View? We need to add one more thing to our Web Part. In the override to the OnLoad method, we’re going to create the presenter object and initialize it like so:
40 {
41 CurrentTimePresenter presenter = new CurrentTimePresenter(this);
42 presenter.InitView();
43 }
Remember we said that the CurrentTimePresenter class takes in “this” (meaning the Web Part object) to its constructor. CurrentTimePresenter actually wants an object that implements the ICurrentTimeView interface. It doesn’t matter what object it is, or what it’s derived from, it only pays attention to the interface. Then it calls the “InitView” method of the view. That’s not part of the Web Part, but it will talk to the Web Part through it’s CurrentTime property.
It’s all about misdirection. Like magic.
This is a simple example. A more concise example is to have a backend data source (either a SharePoint list or a SQL database) feed the data through the Model (using a Data Access Layer or something). Or you can have the Presenter fetch the data through a Facade for the business layer (again calling some external data source via a DAL). Also you can have multiple properties and methods on your view interface (that your Web Part will have to implement). Use your imagination. Remember to keep your UI thin and simple. You’ll probably need one View and one Presenter to keep things clean but they’re simple to make and easy to use.
The killer gain here? First, I can unit test my presenter and model (and view) without SharePoint. No, I can’t get SharePoint data without SharePoint but remember when we created the Presenter in the Web Parts OnLoad event? Notice it passes “this” as a parameter, but the CurrentTimePresenter class doesn’t know anything about Web Parts. That’s the magic of interfaces and designing by contract. The CurrentTimePresenter class expects an object that implements ICurrentTimeView. The Web Part is derived from this so it can be passed into the Presenters constructor. The Presenter couldn’t care less about the other “SharePoint” stuff, it’s just going to call the implementation(s) of the views interface(s).
Also notice that the ICurrentTimeView implementation (the CurrentTime property) isn’t a SharePoint property, but it does set one internally. This is hidden from the Presenter so the Web Part could have just as easily set a text box, filled a data grid, or updated some AJAXy-type control (again, use your imagination). When the Presenter updates the Model, it does so through public properties that are defined in ICurrentTimeView. Again, it doesn’t know that this is updating a property on a SharePoint Web Part and couldn’t care less, it just knows that somewhere (somehow) the UI is going to make it work.
Neat huh?
Okay, go forth and code.