Category Archives: Development

Google Maps Display Template – SharePoint 2013 – Part 1

As the most of you will know by now is that SharePoint 2013 has a new web part called the “Content Search” web part. This web part display’s search result by using specific display templates.

For one of our clients we were asked to display location/office information on a Google Maps card based on information they save in a list.  We first had the idea of using the new Geo Location fields that are pretty awesome. But we had a hard requirement for using Google Maps because they already had a licence for using that.

If you want more information about the Geo Location field you can read about here:

The easiest way to display this information is retrieving the results by its content type with the Content Search web part and using a Google Maps Display Template to display those results.

There are two primary types of display templates:

  • Control templates determine the overall structure of how the results are presented. Includes lists, lists with paging, and slide shows.

  • Item templates determine how each result in the set is displayed. Includes images, text, video, and other items.

The control display template defines the HTML structure for the overall layout and the item template defines the HTML structure for the item.

Combined HTML output of a control display template and item display template

If you want to read more information about display templates here is a good article:

SharePoint 2013 Design Manager display templates

In this Part we will be creating the item template. The easiest way to create a new item display template is using SharePoint Designer and create a copy of another display template.

The display templates can be found here:

All Files – _catalogs – masterpage – Display Templates – Content Web Parts

To get a new item display template you will need to copy an existing item template, for this example we will create a copy of the “Item_TwoLines.html” and rename it to “Item_GoogleMarker.html”.

When you open the file in edit mode you will see that there is a Title attribute on the top of the page. Change this title to Google Maps Marker because the item we will retrieve will represent markers on the map.

The result we will be retrieving will have the following information:

  • Title
  • Longitude
  • Latitude
  • Description
  • Address
  • Site Url (Url to a SharePoint site)

In order to get this information from search you will have to create managed properties for the specific field. In this post I will not tell you how to create those for more information you can read this post or look on MSDN for more information:

If you look further in the display template you will see the property “ManagedPropertyMapping” this will map the properties to specific variables in the file. To which property they are mapped can be changed in the tool part of the web part

image

<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Line 1}:&#39;Title&#39;,&#39;Line 2&#39;{Line 2}:&#39;&#39;,&#39;FileExtension&#39;,&#39;SecondaryFileExtension&#39;</mso:ManagedPropertyMapping>

Each property mapping exists out of three variables separated by &#39;,&#39; and the complete properties are separated by ‘, ‘.

For example “&#39;Line 1&#39;{Line 1}:&#39;Title&#39;”:

  • The first “Line 1” will represents the value in the display template.
  • The second “{Line 1}” represents the description and is displayed in the tool part. You can change this to each value you want.
  • The third “Title” is the default managed property it is mapped to.

For our item template we will extend the property with our own values we need to be able to retrieve the right values from the search engine.

<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Title}:&#39;Title&#39;,&#39;Line 2&#39;{Latitude}:&#39;Title&#39;,&#39;Line 3&#39;{Longtitude}:&#39;Title&#39;,&#39;Line 4&#39;{Description}:&#39;Title&#39;,&#39;Line 5&#39;{Address}:&#39;Title&#39;,&#39;Line 6&#39;{Site Url}:&#39;Title&#39;</mso:ManagedPropertyMapping>

When this is done you can change the “MasterPageDescription” property to the value of your choice.

When you go further down into the display template the values are retrieved within the div called “TwoLines”.

<!--#_
var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");

var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncode);
var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);

var line1 = $getItemValue(ctx, "Line 1");
var line2 = $getItemValue(ctx, "Line 2");
line1.overrideValueRenderer($contentLineText);
line2.overrideValueRenderer($contentLineText);

var containerId = encodedId + "container";
var pictureLinkId = encodedId + "pictureLink";
var pictureId = encodedId + "picture";
var dataContainerId = encodedId + "dataContainer";
var line1LinkId = encodedId + "line1Link";
var line1Id = encodedId + "line1";
var line2Id = encodedId + "line2";
_#-->

Replace this by the following code in which we get all of the values from our properties and use basically the same code the was in the original template:

<!--#_
  var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");
  var linkURL = $getItemValue(ctx, "Link URL");
  linkURL.overrideValueRenderer($urlHtmlEncode);
  var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);
       
  var title = $getItemValue(ctx, "Line 1");
  var latitude = $getItemValue(ctx, "Line 2");
  var longtitude = $getItemValue(ctx, "Line 3");
  var description = $getItemValue(ctx, "Line 4");
  var address = $getItemValue(ctx, "Line 5");
  var siteUrl = $getItemValue(ctx, "Line 6");
  title.overrideValueRenderer($contentLineText);
  latitude.overrideValueRenderer($contentLineText);
  longtitude.overrideValueRenderer($contentLineText);
  siteUrl.overrideValueRenderer($contentLineText);
      
  var itemId = ctx.CurrentItemIdx;
_#-->

Now that we have all of the values for a item. It is time to write the HTML we want for the display template. The easiest way is to place all of the information about the marker in a hidden input field. In the control template we will then retrieve the information and display it on the map.

The complete display template will then look like this:

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> 
<head>
<title>Google Map Marker</title>

<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Title}:&#39;Title&#39;,&#39;Line 2&#39;{Latitude}:&#39;Title&#39;,&#39;Line 3&#39;{Longtitude}:&#39;Title&#39;,&#39;Line 4&#39;{Description}:&#39;Title&#39;,&#39;Line 5&#39;{Address}:&#39;Title&#39;,&#39;Line 6&#39;{Site Url}:&#39;Title&#39;</mso:ManagedPropertyMapping>
<mso:MasterPageDescription msdt:dt="string">This Item Display Template will show a marker when used with the the Google Maps control.</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
<mso:HtmlDesignStatusAndPreview msdt:dt="string"></mso:HtmlDesignStatusAndPreview>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>

<body>
    <script>
        $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
    </script>

    <div id="TwoLines">
        <!--#_
        var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");
        var linkURL = $getItemValue(ctx, "Link URL");
        linkURL.overrideValueRenderer($urlHtmlEncode);
        var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);
        
        var title = $getItemValue(ctx, "Line 1");
        var latitude = $getItemValue(ctx, "Line 2");
        var longtitude = $getItemValue(ctx, "Line 3");
        var description = $getItemValue(ctx, "Line 4");
        var address = $getItemValue(ctx, "Line 5");
        var siteUrl = $getItemValue(ctx, "Line 6");
        title.overrideValueRenderer($contentLineText);
        latitude.overrideValueRenderer($contentLineText);
        longtitude.overrideValueRenderer($contentLineText);
        siteUrl.overrideValueRenderer($contentLineText);
        
        var itemId = ctx.CurrentItemIdx;
        _#-->
        <input type="hidden" id="_#= itemId =#_-Location" value="_#= title =#_;_#= latitude =#_;_#= longtitude =#_;_#= description =#_;_#= address =#_;_#= siteUrl =#_">
    </div>
</body>
</html>

One thing to notice is that we give the hidden input the ID of the result “var itemId = ctx.CurrentItemIdx;” so that we are able to retrieve all of the items in the control template by a specific ID.

In part 2 of the series I will show you how you can finish the set by creating a control template that will result in to the following:

Google Maps Card

Retrieve the Friendly URL of a Publishing Page

One of my first projects with SharePoint 2013 is building a SharePoint website. For the website we had to build a functionality that display’s the URL of specific pages.

For the website we are using Managed Navigation. Displaying URLs meant we wanted to display the friendly URLS. After searching for a while with ILSpy and looking at some MSDN articles:

I found out that the friendly URL can be retrieved by first getting a list of NavigationTerm items from a SharePoint list item. When you have a NavigationTerm you can retrieve the display URL of that term using the method “GetResolvedDisplayUrl”.

In short the code to retrieve the friendly URLs will look something like this.

public List<string> GetPagesUrls() {
    
    //list for saving the urls
    List<string> retVal = new List<string>();

    //current web
    SPWeb web = SPContext.Current.Web;

    //check if the current web is a publishing weg
    if (PublishingWeb.IsPublishingWeb(web)) {

        //get the pages list id
        Guid listId = PublishingWeb.GetPagesListId(web);

        //retrieve the pages list
        SPList pagesList = web.Lists[listId];

        //itterate trough the pages
        foreach (SPListItem item in pagesList.Items) {
            //retrieve the terms used for the navigation (this can be multiple terms)
            IList<NavigationTerm> terms = TaxonomyNavigation.GetFriendlyUrlsForListItem(item, false);

            string url = string.Empty;

            //check if the pages has terms associated with it
            if (terms.Count > 0) {
                //use the GetResolvedDisplayUrl to retrieve the page friendly urls
                url = terms[0].GetResolvedDisplayUrl(string.Empty);
            } else {
                //if the page does not have any terms get the normal url
                url = item.File.Url;
            }

            retVal.Add(url);
        }
    }
    return retVal;
}

What’s New for SharePoint Development in Visual Studio 2012

Now that the Visual Studio 2012 Release Candidate is released (31 may) it is the question, what kind of new features there are in Visual Studio 2012 when you are looking at SharePoint Development.

Most of the time the release candidates that Microsoft releases contain all of the features that should be in the Final Release.

Some of the new features to facilitate SharePoint Development are:

  • Create Lists and Content Types by Using New Designers
  • Create Site Columns
  • Create Silverlight Web Parts
  • Publish SharePoint Solutions to Remote SharePoint Servers
  • Test SharePoint Performance by Using Profiling Tools
  • Create Sandboxed Visual Web Parts
  • Improved Support for Sandboxed Solutions.
  • Support for JavaScript Debugging and IntelliSense for JavaScript
  • Streamlined SharePoint Project Templates
  • Test Your Code by Using Microsoft Fakes Framework

You can read all about it on this MSDN page:

http://msdn.microsoft.com/en-us/library/ee290856(v=vs.110).aspx

Visual Studio cannot debug managed applications because a kernel debugger is enabled on the system.

I developed some awesome features for my SharePoint environment and to my Surprise they weren’t working that well.

So I thought lets attach it to the debugger and take a look what is going wrong. When I attached the debugger I got the following error message:

“Visual Studio cannot debug managed applications because a kernel debugger is enabled on the system.”

After a couple of hours investigating the problem I found a strange behavior on the start up of my development machine it was starting up in some kind of debug mode. To check if you machine is running in debug mode do the following:

  1. Start – Run – msconfig
  2. Select the boot tab and click on advanced options.
  3. If the debug check box is marked it is running in a debug mode.

image

Unmark the checkbox and you will be able to debug your code.

.NET Library for quick and easy Twitter integration

A few days ago I wanted to create a solution to automatically tweet new blog posts. Because I did not have enough time to write a custom component to communicate to twitter I started looking for a .NET Twitter library.

After some time I found a very simple and effective library named Twitterizer. With Twitterizer you can easily implement the OAuth security mechanism.

After adding the reference to the Twitterizer library I created a ItemEventReceiver that starts on the ItemAdded event. In that event I post the title and the url to twitter.

public override void ItemAdded(SPItemEventProperties properties)
{
    base.ItemAdded(properties);

    string message = string.Format(CultureInfo.InvariantCulture, "New post #msftplayground :{0} - {1}", ToTinyURLS(properties.Web.Site.Url, properties.ListItem), properties.ListItem.Title);

    //TODO Get OAuth from web
    OAuthTokens tokens = GetTwitterToken(properties);
    TwitterResponse<TwitterStatus> response = TwitterStatus.Update(tokens, message);
}

private OAuthTokens GetTwitterToken(SPItemEventProperties properties)
{
    OAuthTokens retVal = null;
    
    string consumerKeySecret = EncryptionUtility.DecryptedString(properties.Web.GetPropertyBagProperty(Constants.PropertyBagKeyConsumerKeySecret, string.Empty));
    string consumerKey = EncryptionUtility.DecryptedString(properties.Web.GetPropertyBagProperty(Constants.PropertyBagKeyConsumerKey, string.Empty));
    string accessToken = EncryptionUtility.DecryptedString(properties.Web.GetPropertyBagProperty(Constants.PropertyBagKeyAccessToken, string.Empty));
    string accessTokenSecret = EncryptionUtility.DecryptedString(properties.Web.GetPropertyBagProperty(Constants.PropertyBagKeyAccessTokenSecret, string.Empty));

    if (!string.IsNullOrEmpty(consumerKeySecret) | !string.IsNullOrEmpty(consumerKey) | !string.IsNullOrEmpty(accessToken) | !string.IsNullOrEmpty(accessTokenSecret))
    {
        retVal  = new OAuthTokens();
        retVal.AccessToken = accessToken;
        retVal.AccessTokenSecret = accessTokenSecret;
        retVal.ConsumerKey = consumerKey;
        retVal.ConsumerSecret = consumerKeySecret;
    }
    return retVal;

}

In the code above you see the registration of the event. Within the event I retrieve the OAuthTokens for the security to Twitter. The tokens I need for the authentication are saved within the property bag of the current web.

As you can see in the code it is quite easy to post a status update to twitter with Twitterizer. On the site you can find more examples:

http://www.twitterizer.net/

Encoding SharePoint Field names.

The last couple of project I have been asked the same question several times. The question was how can you get the normal name from a SharePoint field name that is encoded like this: Test_x0020_ Name.

The field names get encoded because XML elements names can’t contain spaces or other different characters. In the example above the x0020 represents the space and the _ represents a delimiter.

You can decode these fields by using:

System.XML.XmlConvert.DecodeName("[Fieldname]") ;

You can encode fieldnames if you would like by using:

System.XML.XmlConvert.EncodeName("[FieldName]")

Problems with the SPSiteDataQuery and Content Type Name

Last week a colleague and I  were working on a solution to find items by its content type within a site collection using the SPSiteDataQuery.

When we moved the solution to the testing environment we discovered that the solution was only returning results that were in a single list.

the code we used was the following:

SPSiteDataQuery query = new SPSiteDataQuery();
query.Webs = "<Webs Scope=\"Recursive\">";
 
//Ask for all lists created from the contacts template.
query.Lists = "<Lists BaseType='1' MaxListsLimit='0'/>";
 
// Get the Title (Last Name) and FirstName fields.
query.ViewFields = "<FieldRef Name=\"Dossiername\" />";
query.ViewFields += @"<FieldRef Name='Dossiernumber'/>";
query.ViewFields += @"<FieldRef Name='ContentType'/>";
 
string where = "<Where><Eq>";
where += "<FieldRef ID='ContentType' />";
where += "<Value Type='Computed'>Dossier</Value>";
where += "</Eq></Where>";
 
query.Query = where; 
  
DataTable results = web.GetSiteData(query);
 
foreach (DataRow row in results.Rows){
    Console.WriteLine("{0} -- {1} -- {2}", row["ContentType"], row["Dossiername"], row["Dossiernumber"]);
}

So this code only returns the items from 1 list. You can solve this problem by searching on the content type id, instead of the content type name. Like the code below:

SPSiteDataQuery query = new SPSiteDataQuery();
query.Webs = "<Webs Scope=\"Recursive\">";
 
query.Lists = "<Lists BaseType='1' MaxListsLimit='0'/>";
 
query.ViewFields = "<FieldRef Name=\"Dossiername\" />";
query.ViewFields += @"<FieldRef Name='Dossiernumber'/>";
query.ViewFields += @"<FieldRef Name='ContentType'/>";
 
SPContentType cTypeCollection = web.ContentTypes["Dossier"];
string where = string.Format(
                  @"<Where>
                    <BeginsWith>
                        <FieldRef Name='ContentTypeId'/>
                             <Value Type='Text'>{0}</Value>
                     </BeginsWith>
                  </Where>", cTypeCollection.Id);

// Set the query string.
query.Query = where; 
 
 
DataTable results = web.GetSiteData(query);
 
foreach (DataRow row in results.Rows){
    Console.WriteLine("{0} -- {1} -- {2}", row["ContentType"], row["Dossiername"], row["Dossiernumber"]);
}

New version SPDisposeCheck

The SPDisposeCheck v14.0.4762.1000 was updated and released 12/13/2010. 

SPDisposeCheck is a tool that helps developers and administrators check custom SharePoint solutions that use the SharePoint Object Model helping measure against known Microsoft dispose best practices. This tool may not show all memory leaks in your code and may produce false positives which need further review by subject matter experts.

The SPDisposeCheck updated tool remains a standalone command line utility and we’ve added a Visual Studio 2008/2010 IDE Add-In which calls out to the SPDisposeCheck.  This Add-In was originally presented at the SPC 2009 and is now available publically.  In addition this version has been tested with both WSS 3.0 + MOSS 2007 and SharePoint 2010 (Foundation and Server) environments.