How to programmatically install an provider hosted app?

There are lots of blog posts you would find in the internet to publish, register and install an app via user interface.  Like me, you would easily run into simple customer requirement to install an app programmatically then things get harder to find. MSDN documentation is very blank in this matter. My good friend Frank and I, spend lots of hours try to install an app programmatically, just before we gave up we found a solution. So let me describe.

We had a close look at the SharePoint, to see how he does it and here are the steps we found,

  1. Load the app package binary file and list item from “App for SharePoint” library in App catalog site collection.
  2. Read the App’s Client Id from the list item.
  3. Register an with App’s Client ID. (only if not already registered)
  4. Load and install the app on a target web.
  5. Trust an app programmatically.

Client Side: You can perform all the above steps except Step 5. Because of the security reason, SharePoint doesn’t provide API to trust an app programmatically. Without this step you may get the app installed successfully but you will not get access to app. When you click on the app it will throw “You are not authorized to perform this operation”  

Server Side: Yeah baby 🙂

Before you jump in to the code below, understand where to find App’s client ID.

Product ID / App ID:When you upload the app binary file to “App for SharePoint” library in app catalog you will see that, SharePoint automatically display the Product Id in the default view.

Client ID: Client ID is available in AppManifest.xml  inside the app binary file. To register an app you need client ID. The API to register an app tells you that “App Identifier” as input parameter, in the reality it expecting client ID. This means do we have to unpack the app binary file? the answer is No. The client ID is also available in in the hidden field in the “Apps for SharePoint” library. AppPermissionXML field of the list item contains XML string with client ID.

Here we go

//check if the app is not already installed in the target web
IList<SPAppInstance> existingInstances = targetWeb.GetAppInstancesByProductId(appProductId);

if (existingInstances.Count > 0) throw new Exception(“App is already installed in the target web”);

//Get the app list item from the “Apps for SharePoint” library in App catalog
SPListItem appCatalogItem = appCatalogItems.FirstOrDefault();
if(appCatalogItem==null) throw new Exception(“App is not found in the App catalog”);

//Get the permission XML
var appPermissionXml = appCatalogItem[“AppPermissionXML”].ToString();

//read the client Id from the Permission XML
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(string.Format(“<Approot>{0}</Approot>”,appPermissionXml));
var root = xmlDoc.DocumentElement;
var clientIdNode = root.SelectSingleNode(“//@ClientId”);

//load the client id, title and stream
var clientId = clientIdNode.InnerText;
var appItemTitle = appCatalogItem.Title;
var appPackageStream = appCatalogItem.File.OpenBinaryStream();

//load the principal manager
SPAppPrincipalManager manager = SPAppPrincipalManager.GetManager(targetWeb);
//Check if the app principal is registered in this farm using client ID
SPAppPrincipal appPrincipal = manager.LookupAppPrincipal(SPAppPrincipalIdentityProvider.External, SPAppPrincipalName.CreateFromAppPrincipalIdentifier(clientId));
//if the principal not found then add
if (appPrincipal == null)
{
	//end points  can be blank
	List<string> endpoints = new List<string>();

	//app  key
	SecureString secureString = new SecureString();
	DateTime now = DateTime.Now;
	SPAppPrincipalCredential credential = SPAppPrincipalCredential.CreateFromSymmetricKey(secureString, now, now);

	//create external parameters
	SPExternalAppPrincipalCreationParameters sPExternalAppPrincipalCreationParameters = new SPExternalAppPrincipalCreationParameters(clientId, appItemTitle, endpoints, credential);
	sPExternalAppPrincipalCreationParameters.SkipExternalDirectoryRegistration = false;

	//register the principal
	appPrincipal = manager.CreateAppPrincipal(sPExternalAppPrincipalCreationParameters);
}
//load it install in the target web
SPAppInstance appInstance = targetWeb.LoadAndInstallApp(appPackageStream);
//Trust the app
SPAppPrincipalPermissionsManager sPAppPrincipalPermissionsManager = new SPAppPrincipalPermissionsManager(targetWeb);
sPAppPrincipalPermissionsManager.AddAppPrincipalToWeb(appPrincipal, SPAppPrincipalPermissionKind.Read);
Advertisements
This entry was posted in SharePoint 2013 and tagged , , , . Bookmark the permalink.

2 Responses to How to programmatically install an provider hosted app?

  1. Pingback: Programmatically remove app registration | Anand Srinivasan's Blog

  2. Tiago says:

    Great article Anand.
    Not easy to find such a detailed code for such a common task! 😀

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s