Deploying MVC5 based provider hosted apps for On-premise SharePoint 2013

Why provider hosted apps:

IMHO – Microsoft is in the vision of making SharePoint as a port of entry to other web based appliances such as ASP.Net sites. And SharePoint Apps hold the key for authentication between SharePoint and apps either through OAuth tokens or S2S trusts.

SharePoint hosted apps works great for browser driven utilities  which works via Javascripts and CSOM. In the case of building three tier applications with Database entities, provider hosted apps is a better option and running these apps in different environment brings other distinct advantages such as App code isolation, easier upgrades independent of SharePoint versions etc.

How this model works:

Provider hosted Sharepoint apps supports authentication via S2S (Server to Server) trust. S2S is established between web server which hosts the remote web app and web server which hosts the SharePoint via X.509 server certificate. Remote webapp authenticates the user independent of SharePoint authentication and creates an access token with user identity and app token. This access token is then signed by the server certificate and validated in host SharePoint environment when executing CSOM or REST calls. SharePoint host trusts all the calls received by trusted security token providers.

For more details refer this excellent book by Scot Hillier and Ted Pattison

Why MVC:

At the heart of MVC is Separated Presentation layer. The idea behind Separated Presentation is to make a clear division between domain objects that model our perception of the real world, and presentation objects that are the GUI elements we see on the screen. Domain objects should be completely self contained and work without reference to the presentation, they should also be able to support multiple presentations, possibly simultaneously. More detailed explanation here

Most of modern day ASP.Net apps ar developed using MVC patterns to support rapid UI changes and better unit testing scenarios. Here is a simple tutorial to understand MVC basics.


This article does not cover how to set up App management Service infrastructure on your SharePoint App stores. Follow this informative article by Mirjam to set up App domain.

Deployment of provider hosted apps involves the listed steps.

1)Preparing remote App server

2)Preparing SharePoint server

3)Setting STS trust

4)Create VS 2013 MVC app


1)Preparing remote App server

1.1 Create new host entry:

Add a new Host (A) entry on DNS with the IP  of Server hosting remote web app. (sp2013apps.gsi.local)

Ping SP2013apps.gsi.local should resolve to the IP. Else do ipconfig /flushdns to reset the DNS cache


1.2: Install Management service delegate:

Remote web app deployment is done through WebDeploy. To support web deploy IIS should have “Management Service Delegate” features. Follow this blog from ScottGu to read  more on this. In the essence download webdeploy 3.5 from this link and select all the features while installing.

Webdeploy 3.5

service delegate

You should see this icon. Now double-click the Management Service Delegation  -> Edit Feature Settings -> Allow administrators to bypass rules option within this dialog box.  This will allow those with Administrator accounts on the server to bypass the delegation capabilities of the Web Management Service and perform actions using their administrator capabilities:

Bypass rules

Now click  Management Service, stop the service and check “Enable Remote Connections” checkbox to enable remote deployments.  You can optionally choose which IP address and port the management service runs on – as well as what client IP addresses are allowed to connect with it.  You can tweak these settings to lock down who can access the deployment service.

remote connections

1.3: Apply SSL to default website:

Since this is a Dev environment , SelfSSL 1.0 is used to generate the SSL certificates.

Thanks to Thomas Balkestahl for writing this blogpost using SelfSSL.

Download and install IIS 6.0 Resource Kit

Now add a new 443 port  binding to Default Website443 IIS

Open the SelfSSL utility installed in the last step


And run the following script to apply SelfSSL to the Default website.

selfssl.exe /N:CN=SP2013apps.gsi.local /K:1024 /V:365 /S:1 /P:443

Where /S:1 key represents App Site ID of default website (Site -> Advance Settings -> General ->ID)

/V switch for Validity



Once the certificate is installed on your IIS, add new  SSL binding on 443 port with the host name registered before


Now navigating to https://sp2013apps.gsi.local should bring IIS 8 logo page as shown below.


2)Preparing SharePoint server

Now repeat the steps 1.1 & 1.3 to SSL SharePoint WebApp.

selfssl.exe /N:CN=SP2013.gsi.local /K:1024 /V:365 /S:682683733 /P:443


where SP2013.gsi.local is the host name for SharePoint web app and /S:682683733 is the ID of SharePoint Webapp

Now add a new 443 HTTPS binding with sp2013.gsi.local as the host name.

2.2: Add new AAM:

Now navigate Central Admin -> Alternate Access Mapping -> Change AAM collection to SharePoint web app -> Click Edit public URL and add https://sp2013.gsi.local -> Save


Click Add Internal URL -> http://sp2013.gsi.local -> save


Now perform IISRESET and wait few seconds until AAM timer job updates the SharePoint routing tables.

Now navigating to https://sp2013.gsi.local should bring your home page.

3)Setting STS trust

Server to Server trust is one of the crucial pieces of provider hosted apps. SSL certificate from remote web server added as “trusted service consumer” in SharePoint environment.

Export the certificate from the remote web server and copy to Sharepoint environment

Open IIS -> Server Certificates


Double click the SSL generated in last step -> details -> Copy to file -> Donot export -> DER encoded

-> C:\Certs\selfsignedApps.cer

Now Copy the certificate to SharePoint server (C:\Certs) and run the following powershell script to establish trust

$publicCertPath = "C:\certs\selfsignedApps.cer"
$issuerId = [System.Guid]::NewGuid().ToString()
$spurl ="https://sp2013.gsi.local"
$spweb = Get-SPWeb $spurl
$realm = Get-SPAuthenticationRealm -ServiceContext $spweb.Site
$certificate = Get-PfxCertificate $publicCertPath
New-SPTrustedRootAuthority -Name "<strong>Hightrust MVC Cert</strong>" -Certificate $certificate
$fullIssuerIdentifier = $issuerId + '@' + $realm
New-SPTrustedSecurityTokenIssuer -Name $issuerId -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier –IsTrustBroker

Now check for the certificate at Central Administration -> Security -> Manage Trust

New certificate “Hightrust MVC Cert” is added to the trusted stores as expected.


To avoid SSL errors and proper authentication between the apps, add both SharePoint SSL and Remote web server SSL to trusted root stores.

Double click .cert file -> Install Certificate -> Local Machine -> Browse -> Trusted Root Certification Authorities -> OK

This will import the certificates.


Now we have all the frameworks and infrastructure required for provided hosted apps

4)Create VS 2013 MVC app

Now generate the server certificate of remote web server in PFX format.

Open IIS -> Certificates

Right click the SP2013apps.gsi.local -> export -> save with .pfx extension and password

Note down issuer ID by running following powershell script

$issuerId = [System.Guid]::NewGuid().ToString()


Install Visual Studio 2013.

Click New Project -> App for SharePoint 2013


Select ASP.NET MVC web app


Now select the PFX certificate generated in the last step. Provide password and Issuer ID


This will create a new MVC project.

MVC_Solution structure

Now Visual studio created two projects with in the same solution. MVCApp1 is the SharePoint App and MVCApp1Web is the remote webapp. Only artifact of the MVCApp1 is the appmanifest.xml. This is similar to what feature.xml to WSP. We provide the version, permission and startpage details of the app.


Make sure Windows authentication is enabled for web project


Now you can directly debug the app by pressing f5. Now login to app using your windows credentials and trust the app. This will lead to sample app hosted from VS2013 if all the settings are right.


Database driven MVC app:

Creating an MVC App involves

Creating a database model entity using Entity Framework Data Model

This is the schema of customer table used in MVC app.


To create an entity model for this database

Right click model -> Add new item -> ADO.Net Entity datamodel -> Generate from Database and connect to required Database objects

MVC_DB MVC_SelectTabe

Now this will generate Model entities and classes to support CRUD operations with the database


Adding a controller and View for Model via scaffolding

Scaffolding is a code generation framework for ASP.NET Web applications. Visual Studio 2013 includes pre-installed code generators for MVC and Web API projects. You add scaffolding to your project when you want to quickly add code that interacts with data models. Using scaffolding can reduce the amount of time to develop standard data operations in your project.

Now right click controller -> Add -> New Scaffolding Item -> Select MVC5 Controller with views using entity frame work


This will generate all controller and View files. View files are in .cshtml format. This can be edited to suit our design. (More on this in next blog post)


Changing the MVC routing

With MVC there is no direct URL access. Its all view containers is what we need. And the URL re-direction logics are stored in the RootConfig.cs located under App_Start folder

Default controller is changed to Customer. to route all the default request to MVCApp1\Customer page



Deployment involves App deployment and Website deployment

App Deployment:

Before publishing the app, a new client ID for the App should be generated form the app site. SharePoint uses this client ID to validate the App file while installing. Navigate to appregnew.aspx

Navigate to https://sp2013.gsi.local/sites/apps/ and generate AppId

MVC_Appreg new.

Right click the solution and click publish and select Package the app. And enter the client ID and the remote site URL.



This will generate an file. This is analogous to .wsp file.

On opening the .app file with good old WINRAR all the resources can be extracted out. And verify appmanifest.xml .



Now Install the app in App site.

WebSite Deployment:

Now go back to Publish page and click “Deploy your Web Project”. Select a new profile and enter the details of remote web server and client ID settings.

This will deploy the webapp to remote server IIS.

MVC_Publish MVC_SPApp

Now add the installed app from any site and trust it. On clicking the app page will be redirected to index page https://sp2013apps.gsi.local/MVCApp1/customer/


Now we have a complete set of pages that perform simple CRUD operations for Customer entity.

SharePoint 2013: Basic Search box Customization


Customize the small search box to support both portal and google searching capabilities

This is the OOB small search control

2013-11-18 12_46_20-Advent_QA - - Remote Desktop Connection

This should be customized such that when the user is on “search Google” tab and click search button it should open google results in new tab and OOB search should work as usual.

2013-11-18 12_37_10-Advent_QA - - Remote Desktop Connection


Small search box is one of the delegate control in the master page.

<div id="searchInputBox">
 <SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox" />

Definition of this delegate control is available at  \15\TEMPLATE\FEATURES\OSearchBasicFeature\SearchArea.xml

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="">
 ControlClass=" Microsoft.Office.Server.Search.WebControls.SearchBoxScriptWebPart" ControlAssembly="Microsoft.Office.Server.Search, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
 <Property Name="UseSharedSettings">true</Property>
 <Property Name="RenderTemplateId">~sitecollection/_catalogs/masterpage/Display Templates/Search/Control_SearchBox_Compact.js</Property>
 <Property Name="EmitStyleReference">false</Property>
 <Property Name="ServerInitialRender">true</Property>
 <Property Name="TryInplaceQuery">false</Property>
 <Property Name="QueryGroupNamesJson">[&"MasterPage&"]</Property>
 <Property Name="ChromeType">None</Property>
 <Property Name="ID">SmallSearchInputBox1</Property>

<Property Name=”RenderTemplateId”> holds the display template value which is rendered for small search box. OOB searchbox can be override by creating a new delegate control with custom display template.


Step 1:

Make a copy of ~sitecollection/_catalogs/masterpage/Display Templates/Search/Control_SearchBox_Compact.html and rename to Custom_Control_SearchBox_Compact.html and upload to same location. This will create a new JS file Custom_Control_SearchBox_Compact.js.

Step 2:

Now create a new project in Visual studio with empty feature and add a element.xml file with new delegate definition

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="">
 ControlClass="Microsoft.Office.Server.Search.WebControls.SearchBoxScriptWebPart" ControlAssembly="Microsoft.Office.Server.Search, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
 <Property Name="UseSharedSettings">false</Property>
 <Property Name="RenderTemplateId">~sitecollection/_catalogs/masterpage/Display Templates/Search/Custom_Control_SearchBox_Compact.js</Property>
 <Property Name="EmitStyleReference">false</Property>
 <Property Name="TryInplaceQuery">false</Property>
 <Property Name="QueryGroupNamesJson">[&"MasterPage&"]</Property>
 <Property Name="ChromeType">None</Property>
 <Property Name="ID"><strong>SmallSearchInputBoxCustom</strong></Property>

Now deploy the solution and make the change in masterpage to refer the new delegate function

<div id="searchInputBox">
 <SharePoint:DelegateControl runat="server" ControlId="<strong>SmallSearchInputBoxCustom</strong>" />

Step 4:

Now make changes to the display template Custom_Control_SearchBox_Compact.html to achieve the required functionality.

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<title>Site Search Box</title>

<!--[if gte mso 9]><xml>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:MasterPageDescription msdt:dt="string">Displays the Search Box control in a compact form.</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106601</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#SearchBox;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
<mso:HtmlDesignStatusAndPreview msdt:dt="string">http://sp2012/_catalogs/masterpage/Display Templates/Search/Adv_Control_SearchBox_Compact.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
<mso:CrawlerXSLFile msdt:dt="string"></mso:CrawlerXSLFile>
<mso:HtmlDesignPreviewUrl msdt:dt="string"></mso:HtmlDesignPreviewUrl>
 <script >

$includeCSS(this.url,"~sitecollection/_catalogs/masterpage/Display Templates/Search/SearchBox.css");
 $includeLanguageScript(this.url,"~sitecollection/_catalogs/masterpage/Display Templates/Search/jquery-1.9.1.js");
 $includeLanguageScript(this.url,"~sitecollection/_catalogs/masterpage/Display Templates/Search/SearchBox.js");

<div id="Control_SearchBox_Compact">
 var showQuerySuggestions = ctx.ClientControl.get_showQuerySuggestions();
 var showNavigation = ctx.ClientControl.get_showNavigation();

var prompt = ctx.ClientControl.get_initialPrompt();
 if ($isNull(prompt))
 prompt = "E.g., TFS";

var searchBoxDivId = ctx.ClientControl.get_id() + "_sboxdiv";
 var searchBoxId = ctx.ClientControl.get_id() + "_sbox";
 var navButtonId = ctx.ClientControl.get_id() + "_NavButton";
 var suggestionsListId = ctx.ClientControl.get_id() + "_AutoCompList";
 var navListId = ctx.ClientControl.get_id() + "_NavDropdownList";
 var searchBoxLinkId = ctx.ClientControl.get_id() + "_SearchLink";
 var searchBoxProgressClass = "ms-srch-sbprogress";
 var searchBoxPromptClass = "ms-srch-sb-prompt ms-helperText";

ctx.OnPostRender = function(rCtx) {

 if (!$('#Googleli').hasClass('searchSelect'))
 var sb = $('#' + searchBoxId);
 sb.val("e.g., Wall Street Journal");

 if (!$('#portalli').hasClass('searchSelect'))
 var sb = $('#' + searchBoxId);
 sb.val("E.g., DFS DQM");




<div id="SearchBoxAdv" name="Control" >
 <div class="ms-srch-sbAdv">
 <ul id ="AdvSearchBox">
 <li id="portalli">Search portal</li>
 <li id="Openli"></li>
 <li id="Googleli">Search Google</li>

<input type="text" value="_#= $htmlEncode(ctx.ClientControl.get_currentTerm()) =#_" maxlength="2048" class="ms-textSmall"
 accessKey="_#= $htmlEncode(Srch.Res.sb_AccessKey) =#_"
 title="_#= $htmlEncode(prompt) =#_"
 id="_#= $htmlEncode(searchBoxId) =#_" autocomplete="off" autocorrect="off"

onkeypress="if (Srch.U.isEnterKey(String.fromCharCode(event.keyCode))) {

onkeydown="var ctl = $getClientControl(this);ctl.activateDefaultQuerySuggestionBehavior();"
 onfocus="var ctl = $getClientControl(this);ctl.hidePrompt();this.value=' ';"
 onblur="var ctl = $getClientControl(this);ctl.showPrompt();" />

var imagesUrl = "/PublishingImages/searchicon.png";
 if (showNavigation) {
 <a class="ms-srch-sb-navLink" title="_#= $htmlEncode(Srch.Res.sb_GoNav) =#_" id="_#= $htmlEncode(navButtonId) =#_"
 onclick="$getClientControl(this).activateDefaultNavigationBehavior();return Srch.U.cancelEvent(event);"
 href="javascript: {}" >
 <img src="_#= $urlHtmlEncode(imagesUrl) =#_" class="ms-srch-sb-navImg" id="navImg" alt="_#= $htmlEncode(Srch.Res.sb_GoNav) =#_" />
 <a title="_#= $htmlEncode(Srch.Res.sb_GoSearch) =#_" class="ms-srch-sb-searchLink" id="_#= $htmlEncode(searchBoxLinkId) =#_"
 onclick="getResults($getClientControl(this),$get('_#= $scriptEncode(searchBoxId) =#_').value);" href="javascript: {}">
 <img src="_#= $urlHtmlEncode(imagesUrl) =#_" id="searchImg" alt="_#= $htmlEncode(Srch.Res.sb_GoSearch) =#_" />
 if (showQuerySuggestions) {
 <div class="ms-qSuggest-container ms-shadow" id="AutoCompContainer">
 <div id="_#= $htmlEncode(suggestionsListId) =#_"></div>

if (showNavigation) {
 <div class="ms-qSuggest-container ms-shadow" id="NavDropdownListContainer">
 <div id="_#= $htmlEncode(navListId) =#_"></div>
 if (ctx.ClientControl.get_showAdvancedLink()) {
 var advancedUrl = ctx.ClientControl.get_advancedSearchPageAddress();
 <div class="ms-srch-sb-link"><a id="AdvancedLink" href="_#= $urlHtmlEncode(advancedUrl) =#_">_#= $htmlEncode(Srch.Res.sb_AdvancedLink) =#_</a></div>
 if (ctx.ClientControl.get_showPreferencesLink()) {
 var preferencesUrl = ctx.ScriptApplicationManager.get_preferencesUrl();
 <div class="ms-srch-sb-link"><a id="PreferencesLink" href="_#= $urlHtmlEncode(preferencesUrl) =#_">_#= $htmlEncode(Srch.Res.sb_PreferencesLink) =#_</a></div>

ctx.ClientControl.activate() renders the OOB small search control. Add custom html elements around this to customize the search control.

onkeypress” event passes Search control and search query to a custom javascript function SearchBox.js which opens google search results in a new tab if google tab is selected.

function getResults(cliSrchobj,query) {

 var totalUrl = &quot;;;
 totalUrl+= query;,'_blank');

 return Srch.U.cancelEvent(event);


2013-11-18 12_37_10-Advent_QA - - Remote Desktop Connection