Using ASP.NET MVC 2 with Sharepoint Publishing
page 4 of 5
by Martin Bailey
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 31087/ 91

Mapping the data model

We can now run an ASP.NET MVC 2 web application directly underneath a Sharepoint  Publishing Site. So how do we display the Sharepoint Published content?

 

I am going to use a real world example here, www.TheMedicineCabinet.co.uk. (Copyright SSL International plc)

 

The Medicine Cabinet web site is a standard Sharepoint Publishing Site but it uses an ASP.NET MVC 2 web application as its presentation layer.

 

Unlike our previous example, this site has been created with a Virtual Directory named ‘Pages’. This allows the urls to have the following format :

 

http://www.themedicinecabinet.co.uk/Pages/{pagename}

 

All the HTML within this site is rendered using standard ASP.NET MVC 2 Masterpages and Views, running conventional ASP.NET MVC code.

 

Each of the textual elements and images are content managed within the Sharepoint Publishing Site. Here is this associated Sharepoint Publishing content managed page.

As you can see there is nothing special about the Sharepoint Publishing Page, it is managed in the conventional way and uses standard Sharepoint Publishing controls to allow content authoring

 

So how do we present this data within ASP.NET MVC Views?

 

To lever the ASP.NET MVC framework we want to be able to express our data in a well defined View Model. This View Model may well contain hierarchical data as well as complex types.

Below is the View Model for this sites home page

    public class HomePageViewModel : BasePageViewModel
    {
        public ENT_Image MainImage { get; set; }
 
        public string MainTitle { get; set; }
 
        public string Paragraph_01 { get; set; }
 
        public string Paragraph_02 { get; set; }
 
        public List<ENT_Image> CrossSellImageList { get; set; }
    }

We need to bind this View Model to the site columns within Sharepoint. Here are some of the Sharepoint site columns created to support the required content

 

In our example of the Home page View Model, we have the following element

public List<ENT_Image> CrossSellImageList { get; set; }

 

This property is a list of Image objects. The ENT_Image class is defined within in the ASP.NET MVC site. This happens to be the MVC application domain representation of a Sharepoint Publishing Image field.

 

The View Model makes use of the rich collection objects available within the .NET framework (in this case Generic List). The concept of collections does not really exist within the Sharepoint column schema. For this reason we have had to statically define a fixed number of Image columns

 

In this instance it was know that only 4 images were required for each page, a 5th one was created as a contingency. This can be seen as a compromise, if more are required in the future then there is a requirement to change the Sharepoint content type.

Retrieving Sharepoint content

So we have our well defined View Model, and a bunch of Sharepoint columns, how do we bind the two data models together ?

 

Let’s start with the following page request to our ASP.NET MVC site

 

http://www.themedicinecabinet.co.uk/Pages/Home

 

As this is a standard ASP.NET MVC site, the page name is resolved using the following route mapping.

 

routes.MapRoute(
   "Page",
   "{pageName}",
    new { controller = "Page", action = "Index", pageName = "home" }  
 );

 

 

So this route will give us a pageName of ‘Home’

We can now lookup this physical page in our Sharepoint Publishing Site, in this case Home.aspx. Since Home.aspx is a Sharepoint Publishing page contained within the pages document library of our site, we can retrieve this using the Sharepoint object model.

 

Since we have exposed the SPContext object within our ASP.NET MVC site, we can now use this to access the authored content. The following piece of code within the Home Page Controller retrieves this Sharepoint page. (In this example our content is held in the en-gb variation web)

using (SPSite site = new SPSite(SPContext.Current.Site.Url, 
      superUserToken))
{
   using (SPWeb web = site.OpenWeb("en-gb"))
   {
      SPFile file = web.GetFile(web.ServerRelativeUrl + "/pages/" + 
      pageName + ".aspx");
 
      //retrieve field values from the file.Item object  
   }
}

The SPFile.Item property gives us the SPListItem object, this holds the values for the page content.

 

Binding the View Model

Now that we have the SPListItem object associated with the Sharepoint page we need to write some custom .NET code to bind our View Model to our Sharepoint data model.

 

The following code gets the SPField named ‘SSL_Image_01’ from the SPListItem

 

ImageFieldValue image = (ImageFieldValue)listItem["SSL_Image_01"];

 

 

It can be a bit tedious fetching each value by name. In this instance all the custom columns have been create with the prefix, “SSL_” to distinguish the custom columns from all other columns. This allows these values to be retrieved dynamical from the field schema xml of the SPListItem.

 

The following code snippet shows how a list of custom field names can be retrieved dynamically based on a query built around the prefix.

  private List<string> GetContentManagedFieldNames
      (SPListItem listItem)
  {
      List<string> ret = new List<string>();
 
      XmlDocument aDoc = new XmlDocument();
 
      aDoc.LoadXml(listItem.Fields.SchemaXml);
 
      IQueryable<XmlElement> fieldElements =
              
      Queryable.AsQueryable<XmlElement>(aDoc.GetElementsByTagName("Field")
            .Cast<XmlElement>()).Where(e =>  
            e.Attributes["Name"].Value.StartsWith("SSL_"));
 
 
      fieldElements.ToList().ForEach(x => 
      ret.Add(x.Attributes["Name"].Value));
 
     ret = ret.OrderBy(x => x).ToList();
 
     return ret;
  }

This allows the authoring content type to be extended in Sharepoint without the need to update the ASP.NET MVC application code.

 

It is no stretch of the imagination to extend this methodology by decoration of our View Model classes with the name of the associated Sharepoint SPField name. This would facilitate the automatic binding of View Model objects to Sharepoint fields.

 

We can now iterate through our list of Sharepoint field names and bind to our View Model.

Data conversion

Binding to our View Model objects is pretty straight forward for primitive types, the field values can be retrieved using the SPListItem.GetFormattedValue function, for example

 

For complex types, ie the ENT_Image type in our example, converters can be created. The following code snippet shows the conversion between a Sharepoint Image type and the View Model image type, ENT_Image

public static ENT_Image Convert(ImageFieldValue image)
{
  ENT_Image ret = new ENT_Image();
 
  if (image == null)
    return ret;
 
  ret.ImageUrl = image.ImageUrl;
 
  ret.Hypelink = image.Hyperlink;
 
  ret.OpenInNewWindow = image.OpenHyperlinkInNewWindow;
 
  ret.Title = image.AlternateText;
 
  return ret;
}

Depending on the size and complexity of the site, this can may not be trivial process. But once we have all the data bound to our View Model we can now exploit all benefits of using MVC.

 

Now that we have data bound our HomePageViewModel, we can now compose our View in the same way as any other ASP.NET MVC 2 site

Navigation

In our example navigation within the ASP.NET MVC site is driven directly from the structure of the Sharepoint Publishing Site. It also reflects the Sharepoint Publishing Site navigation settings.

 

To access this within our ASP.NET MVC site we need to reference the following namespace

 

using Microsoft.SharePoint.Publishing.Navigation;

 

Then we can get reference to the Sharepoint Publishing SiteMapNode.

 

PortalSiteMapProvider siteMapProvider = new PortalSiteMapProvider();
 
SiteMapNode siteMapNode = siteMapProvider.FindSiteMapNode("en-gb", 
      SPContext.Current.Site.RootWeb);

 

In this fashion it is easy to get the SiteMapNode object from the SPContext object. We can now iterate through each node to construct our navigation.


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-10-20 12:10:02 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search