Apps
The Core SDK Admin library provides SharePoint Apps related APIs for configuring app prerequisites for managing apps.
Creating Context
In this article, you'll see a lot of context use: in this case this is a PnPContext which was obtained via the PnPContextFactory as explained in the overview article and shown below:
using (var context = await pnpContextFactory.CreateAsync("SiteToWorkWith"))
{
// See next chapter on how to use the PnPContext for doing SharePoint admin operations
}
PnP.Core.Admin dependency
The functionality shown in this article depends on the PnP.Core.Admin nuget package. Once the PnP.Core.Admin nuget package has been installed you can get to the SharePoint admin features via using the GetSharePointAdmin, GetSiteCollectionAppManager, GetTenantAppManager and GetSiteCollectionManager extension methods:
using (var context = await pnpContextFactory.CreateAsync("SiteToWorkWith"))
{
// Use the GetSharePointAdmin extension method on any PnPContext
// to tap into the SharePoint admin features
var url = context.GetSharePointAdmin().GetTenantAdminCenterUri();
}
Two types of app catalogs
There are two types of app catalogs available in SharePoint Online. One is global at the tenant level called tenant app catalog. It hosts all the apps that are available for all sites in your tenant. The other app catalog type is a site collection app catalog. It's aimed to host apps for the specific site collection only.
PnP.Core.Admin package provides an explicit way of managing either tenant or site collection scoped apps. To do so, you should create an instance of the corresponding app manager using one of the extension methods GetTenantAppManager or GetSiteCollectionAppManager:
// instantiate a class to work with various tenant app catalog related operations
var tenantAppManager = context.GetTenantAppManager();
// instantiate a class to work with various site collection app catalog related operations
var siteCollectionAppManager = context.GetSiteCollectionAppManager();
Important
If you're willing to work with the site collection app catalog, you should call the GetSiteCollectionAppManager extension method using the site collection's app catalog context.
Depending on your requirements you will create any of the above objects to work with apps in your app catalog sites.
Common app operations
Tenant and site collection app managers provide some common app operations like GetAvailable, Add, Deploy, Install, etc. These operations are available for both tenant and site collection app managers and are listed below.
In the samples below you will see a lot of appManager usages. appManager can be either tenant or site collection app catalog manager (depending on which extension method you use). As mentioned above, all the below methods apply to any of the app catalog managers.
Get available app(s)
You can use the method GetAvailable to get either all or specific apps by their id or title. The app's id corresponds to the UniqueId field value inside the out-of-the-box AppCatalog list where all the apps are located.
// gets all available apps for the app catalog
var allApps = await appManager.GetAvailableAsync();
// gets the app instance by it's unique id
var app = await appManager.GetAvailableAsync(new Guid("34427a18-486d-45d2-b4e5-9fd5324ede53"));
// get the app instance by it's title
var app = await appManager.GetAvailableAsync("title of my app");
Add an app
To add an app to the app catalog you should use the Add method. It accepts a file path or a binary file as a bytes array:
// adds app package to the app catalog and overwrites if there is an existing one
var app = await appManager.AddAsync("path/to/file.sppkg", true);
// adds app package using bytes array and app name
var bytes = System.IO.File.ReadAllBytes("path/to/file.sppkg");
var app = await appManager.AddAsync(bytes, "My App", true);
Add method returns an instance of the App object, which you can use to perform further operations.
Deploy an app
When your app is added to the app catalog, it's not yet available to the sites. To make it available you should first deploy it using the corresponding method:
var app = await appManager.AddAsync(packagePath, true);
// deploy the app using the app's unique id
var result = await appManager.DeployAsync(app.Id, false);
Upon deployment, you can specify whether to perform global deployment (when your app immediately becomes available for all the sites). In SharePoint Framework this feature is called "Skip feature deployment". When you provide skipFeatureDeployment=true for the Deploy method, the app will be deployed globally.
To deploy the app you can also use the app instance itself:
var app = await appManager.AddAsync(packagePath, true);
// deploys app globally using app instance
await app.DeployAsync(true);
Under the hood, the app instance calls the Deploy method from the appManager.
Install an app
To install the app into the specific site you need to call the Install method:
// install the app to the site
await appManager.InstallAsync(app.Id);
// or use app instance
await app.InstallAsync();
Important
Install operation is context-specific. It means that you should use the PnPContext instance from the corresponding site to install the app to that site.
Approve Permissions
Some apps can request permissions to call additional APIs by adding a webApiPermissionRequests element in their package-solution.json file. Below snippet shows a part of such a file:
{
"solution": {
"name": "apicalltest-client-side-solution",
"id": "da4e941c-a64e-401a-b63d-664e5bf62bdc",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
},
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
}
]
}
Permissions requested this way can be approved by using the ApprovePermissionRequests method.
var app = await appManager.AddAsync(packagePath, true);
var result = await appManager.DeployAsync(app.Id, false);
// approve permissions requested from the app
IPermissionGrant2[] approvedPermissionGrants = app.ApprovePermissionRequests();
The result is an array of IPermissionGrant2 containing the effective permissions including those previously granted for other apps on this resource.
Upgrade an app
To upgrade the app on the specific site you need to call the Upgrade method:
// upgrades the app on the site
await appManager.UpgradeAsync(app.Id);
// or use app instance
await app.UpgradeAsync();
Important
Upgrade operation is context-specific. It means that you should use the PnPContext instance from the corresponding site to upgrade the app on that site.
Uninstall an app
To uninstall the app from the specific site you need to call the Uninstall method:
// uninstalls the app from the site
await appManager.UninstallAsync(app.Id);
// or use app instance
await app.UninstallAsync();
Important
Uninstall operation is context-specific. It means that you should use the PnPContext instance from the corresponding site to uninstall the app from that site.
Retract an app
Retract operation is the opposite to Deploy. If you don't want your app to be available for sites, you should call Retract. Retract command does not delete the app from the app catalog.
// retracts app
await appManager.RetractAsync(app.Id);
// or use app instance
await app.RetractAsync();
Remove an app
To completely remove the app from the app catalog you should call the Remove method:
// removes the app from the corresponding app catalog
await appManager.RemoveAsync(app.Id);
// or use app instance
await app.RemoveAsync();
List, add, revoke or delete the permission grants
Some apps can request permissions to call additional APIs by adding a webApiPermissionRequests element in their package-solution.json file. Below snippet shows a part of such a file:
{
"solution": {
"name": "apicalltest-client-side-solution",
"id": "da4e941c-a64e-401a-b63d-664e5bf62bdc",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
},
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
}
]
}
After adding and deploying an app to the app catalog these API permissions need to be approved by an admin (e.g. via https://contoso-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement) or via code. The code approach can be implemented using the IApp class and the ApprovePermissionRequests method (see Approve Permissions).
Additional API permissions are granted on the ServicePrincipal object. These permission grants can be listed, added, revoked, and deleted using these methods:
// instantiate the TenantAppManager
var appManager = context.GetTenantAppManager();
// list permissions granted to ServicePrincipal
IPermissionGrant2[] grants = appManager.ServisePrincipal.ListGrants2();
// add a grant, e.g. scope "Calendars.ReadWrite.Shared" for "Microsoft Graph"
IPermissionGrant2 addedGrant
= appManager.ServisePrincipal.AddGrant2("Microsoft Graph", "Calendars.ReadWrite.Shared");
// revoke the scope "Calendars.ReadWrite.Shared" for "Microsoft Graph" from 'addedGrant'
IPermissionGrant2 revokedGrant
= appManager.ServisePrincipal.RevokeGrant2(addedGrant.Id, "Calendars.ReadWrite.Shared");
// delete all permissions for 'addedGrant', all of "Microsoft Graph" in this example
appManager.ServisePrincipal.DeleteGrant2(addedGrant.Id);
Important
Please not that the previous implemenations of the GetPermissionRequests, ApprovePermissionRequest, DenyPermissionRequest, RevokeGrant, and ListGrants operations were based on the SharePoint Client Side Object Model (CSOM). These operations are considered for internal use only. Therefore these operations are now marked obsolete and will be removed in the next major release.
Enable or disable the SharePoint app service principal
The SharePoint app service principal can be enabled or disabled using the Azure Active Directory portal or via code. The Enable2 and Disable2 operations can be found on the ServicePrincipal object:
// Enable the ServicePrincipal
var appManager = context.GetTenantAppManager();
IServicePrincipalProperties result = await appManager.ServicePrincipal.Enable2();
// Disable the ServicePrincipal
var appManager = context.GetTenantAppManager();
IServicePrincipalProperties result = await appManager.ServicePrincipal.Disable2();
Important
Please not that the previous implemenations of the Enable and Disable operations were based on the SharePoint Client Side Object Model (CSOM). These oprations are considered for internal use only. Therefore these operations are now marked obsolete and will be removed in the next major release.
Tenant app catalog specific operations
Some methods are available only for the tenant app catalog. They are listed below.
Getting the url for the tenant app catalog site
When you're running setup tasks you need to ensure there's an app catalog site setup, using the GetTenantAppCatalogUri methods you can get the current tenant app catalog site url:
// Get the tenant app catalog url, returns null if there's none setup
var url = await context.GetTenantAppManager().GetTenantAppCatalogUriAsync();
Ensuring there's a tenant app catalog
If you want to ensure there's a tenant app catalog because you need to deploy an app to it, you can use the EnsureTenantAppCatalog methods. If the tenant app catalog site exists the methods return false, if there was no app catalog it will be setup using the default path of sites/appcatalog and the method returns true.
// Get the tenant app catalog url, returns null if there's none setup
if (await context.GetTenantAppManager().EnsureTenantAppCatalogAsync())
{
// App catalog site was missing, but now added as /sites/appcatalog
}
else
{
// The app catalog site was already available
}
Note that you have to use the GetTenantAppCatalogUri to get the actual app catalog site url, even when there was no app catalog site and it was created by calling EnsureTenantAppCatalog it's still recommended to get the actual url.
List all site collection app catalogs
Using the GetSiteCollectionAppCatalogs you can get all site collection app catalogs from the whole tenant:
var tenantAppManager = context.GetTenantAppManager();
var siteAppCatalogList = await tenantAppManager.GetSiteCollectionAppCatalogsAsync();
The result includes site collection app catalog metadata like absolute url and unique id.
Ensuring there's a site collection app catalog
To ensure a site collection app catalog does exist you can use the EnsureSiteCollectionAppCatalog methods, they check if there's an app catalog and if not one is created by calling the AddSiteCollectionAppCatalog methods.
var tenantAppManager = context.GetTenantAppManager();
await tenantAppManager.EnsureSiteCollectionAppCatalogAsync("https://contoso.sharepoint.com/sites/sitethatneedsacatalog");
Removing a site collection app catalog
If the app catalog of a site is not needed anymore then it can be removed using the RemoveSiteCollectionAppCatalog methods:
var tenantAppManager = context.GetTenantAppManager();
await tenantAppManager.RemoveSiteCollectionAppCatalogAsync("https://contoso.sharepoint.com/sites/sitethatneedsacatalog");
Check whether the solution contains MS Teams component
SharePoint Framework solutions might extend MS Teams as well. You can check, whether a particular SPFx app extends MS Teams or not:
// get tenant app manager
var tenantAppManager = context.GetTenantAppManager();
// get app
var app = await tenantAppManager.GetAvailableAsync("My App Title");
// check it
var containsTeams = await tenantAppManager.SolutionContainsTeamsComponentAsync(app.Id);
For example, If your SPFx solution lists any webpart with TeamsPersonalApp or TeamsTab as supported hosts, the method above will return true.
Get all apps, acquired from SharePoint Store
Your tenant app catalog hosts not only custom apps, but also apps installed from the SharePoint store. To easily get all third-party apps from the SharePoint Store, use the method below:
var tenantAppManager = context.GetTenantAppManager();
var storeApps = await tenantAppManager.GetStoreAppsAsync();
storeApps is a collection of App instances, where you can do all common operations like Install, UnInstall, etc.
Automate SharePoint Store apps deployment and installation
With tenant app manager you can also automate the process of installing apps from the SharePoint Store. To deploy an app from SharePoint Store you should know the unique store asset id. You can easily find it in the query string on the app home page. Usually the url has a format https://appsource.microsoft.com/en-us/product/office/WA200001111 or <your tenant>sites/appcatalog/_layouts/15/appStore.aspx/appDetail/WA200001111. The last part of the url is your asset id, i.e. WA200001111. Then you can use the below code to add the app:
var tenantAppManager = context.GetTenantAppManager();
var app = tenantAppManager.AddAndDeployStoreApp("WA200001111", CultureInfo.GetCultureInfo(1033).Name, false, true);
The method returns an App instance so that you can further install it to any SharePoint site using apps API.
Check if an upgrade for an app is available
Use below API to check whether the upgrade is available for the specific app on a site:
var tenantAppManager = context.GetTenantAppManager();
var app = await tenantAppManager.GetAvailableAsync("My App Title");
var result = await tenantAppManager.IsAppUpgradeAvailableAsync(app.Id);
The method returns true if the app can be upgraded from the app catalog using the most recent version.
Download MS Teams solution from SharePoint Framework app
SharePoint Framework solutions might extend MS Teams as well. If you want to download Teams specific component from SharePoint Framework solution, you should use DownloadTeamsSolution method:
var tenantAppManager = context.GetTenantAppManager();
var app = await tenantAppManager.GetAvailableAsync("My App Title");
// download MS Teams's solution stream
using (var stream = await tenantAppManager.DownloadTeamsSolutionAsync(app.Id))
using (var outputFileStream = new FileStream("teams app.zip", FileMode.Create))
{
// save stream to a file
stream.CopyTo(outputFileStream);
}