Thursday, February 10, 2011

ASP MVC and SharePoint 2010

Ever since ASP MVC came out, I have been a huge fan. I love how MVC embraces the web instead of abstracting it like web forms do. Being a SharePoint guy however, I am currently stuck with web forms. Now I have to admit that web forms work great for an intranet data oriented solution, and this is also where SharePoint has a lot of strength. I however tend to focus on internet facing web sites where MVC is far superior in my opinion.

It should come as no surprise that I have been wondering how to use MVC in SharePoint, and have tried a few things. There are a number of people who have done the same:

http://sharepointmvc.codeplex.com/
http://vspug.com/mbailey/files/2010/04/Using-ASP.NET-MVC-2-with-Sharepoint-Publishing.pdf

and all are good efforts.

Still, the efforts above all seem like fitting a square peg in a round hole. Not exactly elegant at all times, at least that is my feeling.

So I took another approach at this and think it works quite well. The key, the SharePoint client object model. Yeah, it's that simple. Let me walk you through it.

First, let's fire up Visual Studio and create a new MVC 2 project and make sure to choose .NET 3.5 in the framework drop down.
NOT MVC 3! This is because SharePoint runs on .NET 3.5 so we are currently stuck MVC 2 and no Razor :(




Go though the wizard, create your app with or without a test project (as you wish) and get your MVC app running. Nothing new here.

Now open up the Index view of the home controller, and ensure that the MainContent placeholder content looks like the following:

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= Html.Encode(ViewData["Message"]) %></h2>
    <p>
        To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
    </p>
    <img src="<%=ViewData["image"] %>" alt="" />
</asp:Content>

All this does is add an image tag that we will populate from the ViewData. For the rest it is the same as was generated by default.

Now open up the Home controller and go to the Index action. Here we will add code to talk to SharePoint with the Client object model, and pull out some data.

The code (this code is purely for illustrating a point, it is NOT production quality):

public ActionResult Index()
        {
            // get the client context
            ClientContext clientContext = new ClientContext("http://yoursharepointsite.local");

            // get the web reference
            Web site = clientContext.Web;
            clientContext.Load(site);
       
            // get the pages list reference
            List pages = site.Lists.GetByTitle("Pages");
            clientContext.Load(pages);
 
            // get the item with ID 1
            ListItem page = pages.GetItemById(1);
            clientContext.Load(page);
            clientContext.ExecuteQuery();

            // fish out the property PublishingPageImage
            string image = (string)page["PublishingPageImage"];
            
            // do some string magic to get the URL out of the property value
            int start = image.IndexOf("src=\"")+5;
            string imageUrl = image.Substring(start);
            int end = imageUrl.IndexOf("\"");
            imageUrl = imageUrl.Substring(0, end);
            imageUrl = string.Format("{0}{1}", sourceSite, imageUrl);

            // set the viewdata properties from the page item values
            ViewData["Message"] = string.Format("Title: {0}", site.Title);
            ViewData["Image"] = imageUrl;

            return View();
        }

Let's walk through it:

First we create a client context from a sharepoint site. This particular code is going to a stie at http://yoursharepointsite.local, you need to change this. I should also point out that the SharePoint site at that URL is a standard SharePoint Publishing Portal.

Next we get a reference to the root web, and then to a list called 'Pages' which should be familiar to anyone using SharePoint.

Then we get the first item in that list, just using the ID.

Since this is a standard Publishing Portal, we know that the content type this page uses has a field named 'PublishingPageImage' so we get the string value in this field. This value is the entire img tag which we don't necessarily want so we use a but of string magic to get just the value of the src element.

Lastly we populate some ViewData properties with values we got from the list item.

The magic happens when we run the MVC application. And I mean just run with F5 form Visual Studio. If all is well, you will see the following:


Recognize that image? And the title of my SharePoint site is 'Demo'. That you will have to believe. :)

Now let me point out something. Note the URL in the browser. This site is not running as part of SharePoint, it is not even on the same server! It is running on the built in Visual Studio web server, so it could run pretty much anywhere. As long as the user who is running this code has access to the items on the SharePoint site, this MVC site can run wherever. So in case of an internet site, Just make sure you have your SharePoint site set up for anonymous access, and your MVC site will work just fine.

This is an extremely simple demo example, just to get you started. Having thought about this for a bit, I think I would NOT enable anonymous access on my SharePoint site, and use a nice model in MVC to access SP as a specific user that is meant just for this purpose. This would involve some type of image handler so that images could be accessed by anonymous users, but that is not too hard to create. This approach combined with good caching could allow me to have an MVC site with content coming from SharePoint, but without the end user ever coming in contact with SharePoint. Another blog post perhaps....

Hope this gets your imagination going on how we can get lean and clean HTML and still use SharePoint as a place to store and manage all the content which it is great for.

20 comments:

yuriburger said...

Never thought about combining SharePoint and MVC so thanks for sharing! Cheers, Yuri

deanhavelock1 said...

Wow!! a really great tutorial and a great idea!. I have just started looking into using MVC3.0 with Sharepoint but realised that Sharepoint uses .Net3.5 instead of .Net4.0 so i will wait until the next release of sharepoint before learning this technology.. I would really like to see an example similar to the one you have posted using the latest compatable release of MVC at the point of the next release of Sharepoint.. Hopefully Sharepoint 2012 and MVC3 - 4. It would be good to see an example using "users" as you described on the MVC side!. Very nice work! I've added you to my bookmarks and will keep a lookout for a tutorial like this in the future. :)

Pierre said...

You can actually use MVC3, even though the client OM is .NET 3.5, while MVC3 is .NET 4. The new runtime can still load assemblies built to run on the old one.

shinyy83 said...

There are many Intranets solutions on the market, however if you are looking for a solid SharePoint based Intranet solution, check out SharePoint Implementeds' product. I think it's the best solution out for the price.They seem to have put a lot of thought into usability and filling in gaps that you would not know exsist in sharepoint until you start your implementation.

They offer a turnkey solution which provides a custom Home Site, Department Sites and Project Sites, installation, configuration and training all under $10,000 and even have a source code option.

One thing that I would love to see that they don't have now is a hosted solution

You can get more details at http://sharepointimplemented.com/AwesomeIntranetGorilla.html

Theo Medeiros said...

This is fantastic. I like the idea. I have never thought of it this way. Good stuff.

Rob J said...

You can use MVC3 - don't see why you couldn't. I've done it by creating a domain model layer which grabs the data, then referencing that in the MVC project. Then the MVC project doesn't need to know about Sharepoint. Pretty simple.

Joe said...

Thanks Rob J, I will have to give that a shot. I quickly tried something like that once and couldn't get it to work, guess it needed a bit more focus on my part.

Rob J said...

Joe - do you want me to zip the project (it's only a "bare bones" starting point) and drop it somewhere / email it?

Joe said...

Rob J, sure, that would be great. You can send it to "info - at - xcomplica.com" Thanks!

Rob J said...

Have sent you that now.. :)

Chirag Patel said...
This comment has been removed by the author.
Chirag Patel said...

Rob, would you be able to send me the sample project as well to patelcp at gmail dot com? Thanks, I've been looking into running MVC3 with SharePoint.

the hope said...

Rob, would you be able to send me the sample project to amjadlr at gmail dot com? Thanks, I've been looking into running MVC3 with SharePoint.

John Flotildes said...

Rob J, I would love to try. Would be able to send the code to tagacapiz at gmail com.

Thanks in advance - John F

yaronpr said...

Hi Rob,
Can you send your MVC3 sample to yaronpr at gmail dot com

Thanks,

Joe said...

I have written a post on how to get this working with MVC3, thanks to Rob J's example. http://jcapka.blogspot.com/2012/03/asp-mvc-and-sharepoint-revisited.html

Jetson Webart said...

The one thing I don't like about this idea is you have to host your mvc web app on a separate web app. Sharepoint in this case because your datasource only.

I'm looking for a true SP MVC hybrid implementation.

Jetson Webart said...

becomes

Alina Anastasia said...

wow, it's really great post, i never though about combining MVC and sharepoint, can i do this in Latest MVC and sharepoint version ?

Karthika Shree said...

That was a great message in my carrier, and It's wonderful commands like mind relaxes with understand words of knowledge by information's.
Sharepoint Training in Chennai