Wird das JavaScript Object Model (JSOM) verwendet, um auf SharePoint-Ressourcen zuzugreifen, wird ein ClientContext-Objekt benötigt.
Ob der Zugriff auf das App-Web, das Host-Web oder beliebige andere Site Collections erfolgt spielt eine wichtige Rolle. JSOM-Aufrufe über Domain-Grenzen und Site Collection-Grenzen hinweg erfordern einen jeweils dafür vorbereiteten ClientContext.
Dieser Beitrag zeigt anhand von Beispielen, wie der ClientContext in verschiedenen Fällen erzeugt werden muss.
Überschreitung von Domain-Grenzen
Eine Herausforderung des App-Modells in SharePoint 2013 ist die Verwendung verschiedener Domains für SharePoint und die Apps.
SharePoint generiert für SharePoint-hosted Apps bei deren Installation eine eigene URL. Wie diese genau aussieht, wird bei der Konfiguration der App-Umgebung festgelegt.
Beispiel:
- URL des Host-Webs: https://sharepoint2013.demo.local/site1
- URL der App: https://app-1cedbffe5a42ac.apps.local/site1/MeineApp/Pages/Default.aspx
Verschiedene Domains bedeuten Sicherheit, da der Browser Domain-übergreifende Zugriffe kontrolliert und u.U. blockiert (Same Origin Policy). Sollen Apps per JSOM mit SharePoint-Ressourcen arbeiten, dann ist aber eine Kommunikation über Domain-Grenzen notwendig.
SharePoint bietet uns JavaScript-Bibliotheken an, um Domain-übergreifende Zugriffe zu ermöglichen. Je nach "Richtung" der Zugriffe muss der für die Aufrufe verwendete ClientContext verschieden initialisiert werden. Die folgenden Abschnitte zeigen, wie das im Detail funktioniert.
JSOM-Aufrufe innerhalb derselben Domain
Wird Skript innerhalb des App-Webs ausgeführt und möchte auf Inhalte des App-Webs zugreifen, so findet kein Domain-Wechsel statt. In diesem Fall lässt sich der ClientContext recht einfach erstellen:
this.context = new SP.ClientContext(RELATIVEURLOFWEB);
this.web = this.context.get_web();
this.context.load(this.web);
Das funktioniert übrigens auch, wenn Sie Skripte im Host-Web platzieren und diese auf Host-Web-Ressourcen zugreifen.
In beiden genannten Fällen ist die Domain des Aufrufenden und das Aufrufziel dieselbe. Daher müssen keine Cross-Domain-Szenarien berücksichtigt werden.
JSOM-Aufrufe über Domain-Grenzen hinweg
Werden über Domain-Grenzen hinweg JSOM-Aufrufe ausgeführt muss ein wenig mehr Arbeit in die Konfiguration des ClientContext investiert werden.
Für SharePoint-hosted Apps interessant sind die Fälle, in denen die Grenze zwischen App-Web und Host-Web überschritten wird.
Zugriff vom Host-Web auf das App-Web
Unser Skript läuft im Host-Web und möchte auf das App-Web zugreifen. Der ClientContext wird in diesem Fall für die URL des App-Webs erzeugt. Die Cross-Domain-Klasse SP.ProxyWebRequestExecutorFactory erlaubt das Überschreiten der Domain-Grenzen:
var context = new SP.ClientContext(APPWEBURL);
var factory = new SP.ProxyWebRequestExecutorFactory(APPWEBURL);
context.set_webRequestExecutorFactory(factory);
var web = context.get_web();
Zugriff vom App-Web auf das Host-Web
Unser Skript läuft im App-Web und möchte auf das Host-Web zugreifen. Der ClientContext wird genauso wie im obigen (umgekehrten) Fall erzeugt. Zusätzlich ist die Verwendung von SP.AppContextSite notwendig:
var context = new SP.ClientContext(APPWEBURL);
var factory = new SP.ProxyWebRequestExecutorFactory(APPWEBURL);
context.set_webRequestExecutorFactory(factory);
var appContextSite = new SP.AppContextSite(context, HOSTWEBURL);
var web = appContextSite.get_web();
context.load(web);
Mein Verständnis nach dem Lesen der Dokumentation ist, dass hier zwei Dinge passieren:
- die Verwendung von SP.AppContextSite ermöglicht es, über Site Collection-Grenzen hinweg zu kommunizieren
- die Verwendung der Cross-Domain-Bibliothek SP.ProxyWebRequestExecutorFactory ermöglicht es, Domain-Grenzen zu überschreiten
Warum beim Zugriff vom App-Web auf das Host-Web das Setzen der SP.AppContextSite notwendig ist, im umgekehrten Fall aber nicht, erschließt sich mir nicht.
Zugriff von einer Site Collection auf eine andere Site Collection
Der Zugriff von einer Site Collection auf eine andere ist kein Cross-Domain-Szenario, sei aber trotzdem erwähnt. Bei der Verwendung von SharePoint-hosted Apps als Vorlage können Skripte im Host-Web platziert werden, die aus diesem Kontext heraus auf andere Site Collections zugreifen.
Mittels SP.AppContextSite soll es möglich sein, aus dem Kontext einer Site Collection heraus Informationen einer anderen Site Collection abzufragen. In diesem Fall wird SP.ProxyWebRequestExecutorFactory nicht verwendet (da keine Domain-Grenzen überschritten werden), sondern allein SP.AppContextSite. Ein Beispiel hat dieser Blog Post.
Wenn Sie Erfahrungen mit JSOM-Aufrufen zwischen beliebigen Site Collections gesammelt haben, dann geben Sie doch bitte kurz Feedback in den Kommentaren. In der Cloud soll es damit Probleme geben.
Notwendige App-Berechtigungen
Um mittels SP.AppContextSite Aufrufe über Site Collection-Grenzen hinweg auszuführen werden laut MSDN Tenant-Scope Berechtigungen benötigt:
"Apps can also access other site collections and websites as long as the app has tenant-scoped permissions and it has been deployed as a batch installation using the app catalog."
Nach meiner Erfahrung ist für den Zugriff aus dem App-Web auf das Host-Web kein Tenant-Scope notwendig. Mir reichte bisher bspw. Web-Scope um auf Host-Web-Ressourcen zuzugreifen. Das trifft auch zu, wenn die App im App Catalog installiert ist.
App-Installation im Web vs. Installation im App Catalog
Bezogen auf den ClientContext ließ sich ein interessanter Unterschied beobachten, je nachdem, wie eine App bereitgestellt wird.
Wird die App direkt in einem Web bereitgestellt (per Install-SPApp oder über die Oberfläche per "Add an app"), dann lässt sich aus dem App-Web direkt auf das Host-Web zugreifen, ohne die Verwendung zusätzlicher Bibliotheken. Es reicht, die relative URL des Host-Webs zu verwenden:
this.context = new SP.ClientContext(RELATIVEURLOFWEB);
this.web = this.context.get_web();
this.context.load(this.web);
Nehmen wir folgende URLs an:
- Host-Web: https://sharepoint2013.demo.local/site1
- App-Web: https://app-1cedbffe5a42ac.apps.demo.local/site1/MeineApp
Erzeugt ein Script im App-Web einen ClientContext für die relative URL "site1", dann kann dieser ClientContext für den Zugriff auf das Host-Web verwendet werden. Das sollte eigentlich nicht möglich sein ohne die Cross-Domain-Bibliothek SP.ProxyWebRequestExecutorFactory - ist es aber.
Dieser Zugriff funktioniert nicht mehr, wenn die App zentral über den App Catalog bereitgestellt und dafür im App Catalog installiert wird.
Erklärungsversuch
Das Verhalten deutet darauf hin, dass das App-Web bei direktem Deployment in ein Web als Sub-Site angelegt wird und daher nicht wirklich ein Cross-Domain-Aufruf und auch kein Zugriff über Site Collection-Grenzen hinweg erfolgt. Bei zentraler Bereitstellung über den App Catalog sieht das anders aus, da die App hier in der App Catalog Site Collection installiert wird.
Falle bei der Entwicklung
Wird eine App während der Entwicklung mit Visual Studio über F5-Deployment in einer Developer Site installiert, dann fällt es nicht auf, wenn der falsche ClientContext verwendet wird. Das Testkonzept sollte also den Fall "zentrale Bereitstellung über den App Catalog" beinhalten.
Zusammenfassung
Bei der Verwendung von JSOM in SharePoint-hosted Apps werden unter Umständen Domain-Grenzen überschritten.
Der für JSOM-Aufrufe verwendete ClientContext muss je nach Aufrufquelle und -ziel (App-Web, Host-Web, …) passend initialisiert werden. SharePoint stellt hierfür Bibliotheken bereit.
SharePoint-hosted Apps verhalten sich u.U. abhängig von der Bereitstellungsart verschieden. Es sollte die direkte Bereitstellung im Web sowie die zentrale Bereitstellung im App Catalog getestet werden.