Integration von SharePoint 2013 und Windows Phone 8

SharePoint wird mobil
Kommentare

Die Integration der SharePoint-Plattform auf einem Windows Phone und die dadurch mögliche Mobilisierung von SharePoint-Daten und -Prozessen bringt neue spannende Entwicklungsoptionen. War es bis vor Kurzem noch sehr umständlich und aufwändig, SharePoint-Daten in eine Mobile-Applikation zu integrieren, haben sich auf diesem Feld inzwischen einige neue Wege aufgetan.

Dieser Artikel stellt anhand einer Windows-Phone-8-App die technischen Integrationsmöglichkeiten der SharePoint-2013-Plattform vor. Die Anwendung soll alle Listen mitsamt Elementen aus einer SharePoint-Website mobilisieren und über die Applikation zugreifbar machen. Dabei werden die verschiedenen Zugriffsmöglichkeiten auf SharePoint-Daten aufgezeigt, miteinander verglichen und anschließend ihre jeweiligen Vor- und Nachteile diskutiert. Abbildung 1 gibt einen groben Überblick über das Integrationsszenario und das generelle Zusammenspiel von Windows Phone, SharePoint 2013 und die dort enthaltenen Strukturen.

Abb. 1: Überblick: App-Szenario

Abb. 1: Überblick: App-Szenario

App-Infrastruktur

Zu Beginn wird der Applikationsrahmen erzeugt. Dafür bietet das „Microsoft SharePoint SDK for Windows Phone 8“ bereits vorgefertigte Templates, die die Setup-Arbeit erleichtern. Das SDK erweitert Visual Studio um zwei Projekttemplates für Windows-Phone-Applikationen und installiert die benötigten Bibliotheken für den Clientzugriff (Abb. 2).

Abb. 2: SharePoint SDK für Windows Phone Templates

Abb. 2: SharePoint SDK für Windows Phone Templates

Das Template „Windows Phone SharePoint List Application“ kann genutzt werden, um auf eine einzelne SharePoint-Liste zuzugreifen. Nach der Auswahl dieses Templates führt ein Wizard durch die Konfiguration der App. Der Entwickler wählt eine Liste, eine dazugehörige List View und die gewünschten CRUD-Operationen sowie die letztlich in der App anzuzeigenden Felder aus. Visual Studio erzeugt nach Abschluss des Wizards eine nach dem MVVM-Entwurfsmuster konzipierte Solution-Struktur, die den Zugriff auf die ausgewählte Liste enthält. Da im geplanten Szenario dieses Artikels jedoch nicht eine einzelne Liste, sondern alle Listen und deren Elemente aus einer beliebigen SharePoint-Website abgefragt werden sollen, ist das Template „Windows Phone Empty SharePoint Application“ besser geeignet. Visual Studio erstellt in dem Fall nur ein Projekt mit einer Grundstruktur und referenziert die SharePoint Client Assemblies (Abb. 3).

Abb. 3: Empty Project Solution

Abb. 3: Empty Project Solution

Bevor nun mit der Entwicklung begonnen wird, sollen kurz die Grundlagen zur Entwicklung von Windows-Phone-Apps erläutert werden. Wer bereits die eine oder andere Anwendung auf WPF-Basis entwickelt hat, wird schon einmal auf das Entwurfsmuster „Model View ViewModel“ (MVVM) gestoßen sein. Dies ist das Standardentwurfsmuster, das in der WPF-basierten Entwicklung eingesetzt wird (Abb. 4).

Abb. 4: Model View ViewModel

Abb. 4: Model View ViewModel

Ziel dieses Entwurfmusters ist die Trennung zwischen User Interface (UI), UI-Logik und der Datenhaltung einer App. Die Anwendung des Musters schafft die Voraussetzung für den flexiblen Umgang mit Anpassungen und Erweiterungen. Jede View, in diesem Fall also jede „Windows Phone Application Page“, besitzt ein eigenes ViewModel, das die Daten für sie aufbereitet.

Abb. 5: Design-Konzept-Views

Abb. 5: Design-Konzept-Views

Wie in Abbildung 5 dargestellt, sollen für die App drei Views erzeugt werden. In der ersten View werden die Zugangsdaten des Nutzers zur Authentifizierung gegen SharePoint abgefragt. Die Applikation leitet den Anwender dann auf die nächste View, in der alle Listen der Website angezeigt werden, auf die der Benutzer Zugriff hat. Wählt er nun eine Liste aus, wird der Benutzer zur dritten View weitergeleitet, in der dann alle Listenelemente der vorher ausgewählten Liste dargestellt werden. Dem MVVM-Entwurfsmuster folgend wird für jede der drei Views ein Model angelegt, in dem die Daten persistiert werden, die die View anzeigt. Weiterhin erhält jede View ein ViewModel, das sie befüllt und auf Aktionen des Nutzers reagiert.

Abb. 6: App-Architektur

Abb. 6: App-Architektur

Das in Abbildung 6 skizzierte UML-Klassendiagramm visualisiert schematisch die Softwarearchitektur der App. Diese besteht aus im Wesentlichen zwei Bereichen:

  1. Die Gestaltung der Views, ihre Funktionen und deren Daten werden auf der linken Seite abgebildet. Dort ist die mittels MVVM implementierte Clientlogik enthalten, die sich um Seitenaufbau, Navigation, Anzeige und Bearbeitung der Daten kümmert. Die Methodenköpfe und Member der Abbildung beziehen sich auf die View zur Anzeige von ListItems.
  2. Die rechte Seite stellt den Zugriff auf SharePoint-Inhalte dar. Es empfiehlt sich, den Zugriff auf SharePoint zu abstrahieren und von der App-Logik getrennt zu implementieren. Die Entkopplung über ein Interface erlaubt es, den Zugriff sowohl über REST als auch über das Client-SideObject-Model (CSOM) zu implementieren. Später kann ohne Änderungen an den Views zwischen den Zugriffstechnologien getauscht werden.

CSOM

Das „Client Side Object Model“, kurz CSOM, ermöglicht es Entwicklern, mittels eines lokalen API, das von der Benennung der Klassen her an das Server-Object-Model angelehnt ist, remote auf SharePoint-Elemente zuzugreifen. Es wurde mit SharePoint 2010 veröffentlicht und in der aktuellen SharePoint-2013-Version nochmals umfangreich erweitert. Mittlerweile ist auch der Zugriff auf folgende SharePoint-Features per CSOM möglich: • Search • Taxonomy • Publishing • Workflow • User Profiles • E-Discovery • Analytics • Business Data • IRM • Feeds Die Unterstützung des CSOMs auf dem Windows Phone wurde mit dessen Version 7.1 eingeführt. Das war ein bedeutender Fortschritt für die Entwicklung von SharePoint-Connected-Apps auf dem Windows Phone, konnten so doch einige Unzulänglichkeiten der REST- und SOAP-basierten Services aus SharePoint 2010 ausgemerzt werden. Um das SharePoint-Client-API in einer App nutzen zu können, sind die beiden Assemblies Microsoft.SharePoint.Client.dll und Microsoft.SharePoint.Client.Runtime.dll notwendig. Interessant, aber auch gewöhnungsbedürftig bei der Arbeit mit CSOM, ist die Batchverarbeitung: Operationen werden hierdurch nicht sofort ausgeführt, sondern in einem ClientContext gesammelt und erst beim Aufruf der Methode ExecuteQueryAsync zum Server geschickt, um dort gebündelt ausgeführt zu werden. Die Ergebnisse der Operationen werden dann auch auf einmal zurückgegeben. Diese Art der Verarbeitung wurde zur Optimierung der Performance gewählt, da viele kleine Aufrufe den Server zu stark belasten würden und auch der Client zu oft Verbindungen aufbauen müsste. Abbildung 7 zeigt das Schema der Batchverarbeitung im CSOM

Abb. 7: Batchverarbeitung im CSOM

Abb. 7: Batchverarbeitung im CSOM

REST

SharePoint bietet eine weitere Schnittstelle für den Abruf von Daten: das REST API, das wie CSOM mit SharePoint 2010 eingeführt wurde. REST ermöglicht es, mit dem Standard-HTTP-Protokoll auf SharePoint-Elemente zuzugreifen und diese in JSON- oder OData-Form zu erhalten. Da diese Schnittstelle auf dem HTTP-Protokoll und Standardformaten wie JSON basiert, ist sie prädestiniert für die Interoperabilität und gerade im Zeitalter von HTML-5-Clients und Plattformunabhängigkeit hoch aktuell. SharePoint bietet für folgende Features REST-Endpunkte an: • SiteCollection • Website • Search • Publishing • User Profile Mittels der HTTP-Methoden GET, PUT, POST, DELETE und MERGE können CRUD-Operationen auf SharePoint-Listen und anderen SharePoint-Inhalten ausgeführt werden. Beispielsweise ist über folgenden URL ein Listenaufruf möglich: _api/web/lists/List1. Kleinere Berechnungen, Abfragen und Filter können direkt in den URL eingebunden werden. Außerdem hat Microsoft angekündigt, in Zukunft weitere REST-Endpunkte bereitzustellen.

Authentifizierung

Um auf SharePoint-Inhalte zugreifen zu können, ist zunächst die erfolgreiche Anmeldung im Portalsystem notwendig. Die zuvor konzipierte Login-Seite definiert den Einstiegspunkt in die App. Hier wird der Nutzer gebeten, Name, Kennwort und den URL des SharePoint-Portals einzugeben. Mit diesen Daten authentifiziert sich die App dann gegen SharePoint. SharePoint-seitig muss hier zwischen zwei Authentifizierungsmethoden unterschieden werden: der Windows- und der Form-based Authentication. Die Windows-Authentication authentifiziert den User gegen ein AD, die Form-based Authentication gegen ein beliebiges Drittsystem. Die Authentifizierungsmöglichkeiten werden auf Webapplikationslevel in SharePoint gesteuert, aber was bedeutet das nun für den Zugriff mittels CSOM oder REST?

Authentifizierung mit CSOM: Mittels des CSOMs gestaltet sich die Authentifizierungsmethode sehr einfach. In der Eigenschaft AuthenticationMode wird zuerst der gewünschte Authentifizierungsmodus eingestellt. Der Standardwert ist Default, hier muss lediglich eine konfigurierte Instanz der NetworkCredential-Klasse auf den ClientContext gesetzt werden:

NetworkCredential credentials = new NetworkCredential("username", "pwd", "domain"); 
ClientContext context = new ClientContext("http://sitecollection"); 
context.Credentials = credentials;

Wird die Form-based Authentication genutzt, muss eine konfigurierte Instanz der FormAuthenticationLoginInfo auf dem ClientContext gesetzt werden:

ClientContext context = new ClientContext("http://sitecollection"); 
context.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
context.FormsAuthenticationLoginInfo = new FormsAuthenticationLoginInfo("username", "pwd");

Authentifizierung mit REST: Über REST ergeben sich ebenfalls die beiden Möglichkeiten mittels Windows-Authentication oder die Anmeldung über FBA. Bei der Windows-Authentication werden wieder die NetworkCredentials benutzt:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://sitecollection");
NetworkCredential credentials = new NetworkCredential("username", "pwd", "domain");
request.Credentials = credentials; 

Ist FBA als Authentifizierungsmethode konfiguriert, besteht die Möglichkeit, sich über den standardmäßigen SOAP-SharePoint-Authentifizierungs-Web-Service /_vti_bin/authentication.asmx zu authentifizieren:

FBAAuthorization fbaAuth = new FBAAuthorization(Login.UserName, Login.Password, CreateAuthenticationServiceUrl("http://sitecollection/_vti_bin/authentication.asmx"));

Zugriff auf Listen

Nach erfolgreicher Anmeldung bei SharePoint sollen dem Benutzer nun alle Listen innerhalb der von ihm angegebenen Website angezeigt werden. Die Weiterleitung erfolgt in diesem Fall innerhalb des Login-ViewModels über den NavigationService, der Bestandteil des Windows-Phone-Frameworks ist:

NavigationService.Navigate(new Uri("/View/ListView.xaml", UriKind.Relative));

In dieser View sollen nun alle Listen innerhalb der Website angezeigt werden. Der Titel einer Liste und die Anzahl der in ihr enthaltenen Elemente sollen angezeigt und im Model der View persistiert werden. Abbildung 8 zeigt ein ListBox-Control, das die einzelnen Listen in der View „Lists“ visualisiert. Der Datenzugriff erfolgt über Data Binding auf das Model der View.

Abb. 7: Batchverarbeitung im CSOM

Abb. 7: Batchverarbeitung im CSOM

Zugriff auf Listen mit CSOM: Das Codebeispiel aus Listing 1 stellt den Zugriff auf alle Listen und alle Views jeder dieser Listen innerhalb einer SharePoint-Website mittels CSOM dar. Die ClientContext.Load-Methode lässt sich um einen Parameter include erweitern, der mithilfe von Lambda-Ausdrücken zusätzliche Daten des abgefragten SharePoint-Objekts bereitstellt. Über die Methode LoadQuery kann eine CSOM-Abfrage neben includes zusätzlich nach Kriterien gefiltert werden. In diesem Fall sollen nur Listen angezeigt werden, die sichtbar sind. Versteckte Listen enthalten SharePoint-interne Daten und sind für den Endanwender der App daher nicht relevant.

// get login url from local app storage
ClientContext ctx = GetClientContext();
Web rootWeb = ctx.Site.RootWeb;
var myLists = web.Lists;
// batch load web and lists in one query
ctx.Load(rootWeb, web  => web.Include(w => w.Title, w => w.Url));
ctx.LoadQuery(myLists, lists => lists.Include(l => l.Id, l => l.Title, 
l => l.Views.Include(v => v.Title, v => v.ViewFields, v => v.ViewQuery)
.Where(v => v.DefaultView == true)).Where(l => l.hidden == false);

ctx.ExecuteQueryAsync ((object s, ClientRequestSucceededEventArgs args) =>
  {
    // map to view model
  },
  (object t, ClientRequestFailedEventArgs argz) => {
    // request failed
});

Um die Lesbarkeit des Codes zu erhöhen und die Schachtelung der Klammern durch die beiden Funktionsaufrufe ClientRequestSucceededEventArgs und ClientRequestFaildEventArgs, die pro SharePoint-Aufruf erforderlich sind, zu verringern, empfiehlt es sich, den Aufruf mittels einer ExtensionMethod zu erweitern:

public static class CSOMExtensions
{
  public static Task ExecuteQueryAsync(this ClientContext clientContext)
  {
    return Task.Factory.StartNew(() =>
      {
        clientContext.ExecuteQuery();
    });
  }
}

Generell sollten durch intelligente und gebündelte Abfragen so wenige SharePoint-Aufrufe wie möglich ausgeführt werden. Dies erhöht die Performance und spart Ressourcen. Im Kontext der Windows-Phone-App ist dies allerdings nicht immer möglich, da Benutzereingaben wie die Auswahl der anzuzeigenden Liste berücksichtigt werden müssen.

Zugriff auf Listen mittels REST: Im Codebeispiel aus Listing 2 wird der Zugriff auf alle sichtbaren Listen einer Website mittels REST veranschaulicht: Die Response kann als JSON oder OData (ATOM XML) zurückgegeben werden. In diesem Fall wird JSON zurückgegeben und mittels JSON.NET, einem populären JSON-Framework für .NET, direkt in typsichere Instanzen des Listobjekts konvertiert. Das zugehörige Model unterscheidet sich an dieser Stelle vom CSOMModel, da die Struktur des zurückgegebenen JSONs berücksichtigt werden muss.

HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists/?$filter=Hidden%20eq%20false");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";

HttpWebResponse httpResponse = response as HttpWebResponse;

using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
  string jsonString = reader.ReadToEnd();
  var return = JsonConvert.DeserializeObject(jsonString);
  // map to viewmodel
}

[ header = Seite 3: Zugriff auf Listenelemente ]

Zugriff auf Listenelemente

Der Benutzer wählt an dieser Stelle in der App eine der angezeigten Listen aus und wird anschließend auf die dritte und letzte View weitergeleitet. Dort werden ihm alle Elemente der Liste aufgelistet. Bei einem generischen Ansatz sind das Schema einer Liste und die Spalten im Voraus nicht bekannt. Jede SharePoint-Liste verfügt jedoch über eine DefaultView – diese beruht auf einer ViewQuery, die alle Felder inkludiert und so eine gute Möglichkeit darstellt, generisch auf Listeninhalte zuzugreifen.

Zugriff auf Listenelemente mit CSOM: Die Fortführung unseres Codebeispiels (Listing 3) zeigt die Abfrage von Listenelementen.

foreach(List list in myLists)
{
  CamlQuery query = new CamlQuery();
            query.ViewXml = myLists.Views.FirstOrDefault().ViewQuery;
            ListItemCollection items = currentList.GetItems(query);
            currentContext.Load(items, i => i.Include(
                it => it.DisplayName,
                it => it.Id, it.Item
            ));
  Task getView = currentContext.ExecuteQueryAsync();
  await getView.ContinueWith((t) => { });
  foreach (ListItem item in items)
  {
    currentContext.Load(item);
    Task getItems = currentContext.ExecuteQueryAsync();
    await getItems.ContinueWith((t) => { });
    foreach (string f in defaultView.ViewFields)
    {
      // map to viewmodel
    }
}}

Zugriff auf Listenelemente mit REST: Folgender REST-Endpunkt-Aufruf zeigt alle Elemente einer Liste an:

/_api/web/lists(guid’9e7934bd-65ec-482c-8d68-b8decc431177′)/items

Eine einzelne Liste kann entweder per GUID oder über die Methode GetByTitle()angesprochen werden. Um nur die Elemente anzuzeigen, die in der DefaultView der Liste enthalten sind, wird zunächst selbige aufgerufen und ihr viewfields-Parameter abgefragt:

/_api/web/lists/GetByTitle('yourTitle')/defaultView/viewfields

Die Response und somit die einzelnen Felder der View werden erneut mittels JSON.NET deserialisiert und anschließend im nächsten Aufruf für das Lesen der Listenelemente genutzt (Listing 4).

HttpWebResponse httpResponse = response as HttpWebResponse;

using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
  string jsonString = reader.ReadToEnd();
  toReturn = JsonConvert.DeserializeObject(jsonString);
}
string viewfields = string.Empty;
StringBuilder builder = new StringBuilder();

for (int i = 0; i < toReturn.d.Items.results.Count; i ++)
{
  builder.Append(string.Format("{0},",toReturn.d.Items.results[i]));
}

viewfields = builder.ToString();
viewfields = viewfields.Remove(viewfields.LastIndexOf(','));

string getListItemURL = string.Format("/_api/web/lists/GetByTitle('SprintLinkConfig')/items?$select={0}", viewfields);

// call listitems request

HttpWebResponse httpResponse1 = response as HttpWebResponse;

using (var reader = new StreamReader(httpResponse1.GetResponseStream()))
{
  string jsonString = reader.ReadToEnd();
  JObject res = JObject.Parse(jsonString);
  JArray listItems = (JArray)res["d"]["results"];
}

// map to viewmodel 

Um den generischen Ansatz an dieser Stelle zu wahren, wird mithilfe eines JObjects deserialisert. Dieses enthält einen Array aller Listenelemente, mit dem weitergearbeitet werden kann. Zu beachten ist, dass der InternalName der Felder für eine erfolgreiche Abfrage erforderlich ist. Eine Abfrage über den DisplayName eines Felds ist nicht fachgemäß. Auch ist auf die Groß- und Kleinschreibung innerhalb des URLs zu achten, da dieser Case-sensitive ist.

Abb. 9: Fertige App

Abb. 9: Fertige App

Abbildung 9 zeigt abschließend alle drei konzipierten Views im fertig implementierten Zustand. Die dritte View zeigt Listenelemente aus der zuvor ausgewählten Liste „Niederlassungen“.

Vergleich zwischen CSOM und REST

Abschließend sollen die beiden Technologien CSOM und REST miteinander verglichen werden (Tabelle 1). Dabei haben beide Technologien ihre Vor- und Nachteile. In reinen .NET-Kontexten, wie dem Beispiel dieses Artikels, hat das CSOM zurzeit die Nase vorn. Erfahrene SSOM-Entwickler kennen die komplexen Objekte des CSOM aus dem Serverkontext, ähneln sich die Objekte doch sehr. Auch gibt es hier in punkto Performance aufgrund der Batchverarbeitung auf dem Server mehr Spielraum für komplexe Abfragen. Gehen die Anforderungen über simple CRUD-Anfragen hinaus, beispielsweise in Richtung BCS, Taxonomy oder Workflows, ist CSOM der klare Sieger. Allerdings plant Microsoft in Zukunft den weiteren Ausbau der REST-Schnittstelle und damit die Bereitstellung weiterer SharePoint-Endpunkte.

HTML5-JavaScript-App-Entwickler hingegen werden REST bevorzugen. Plattformunabhängigkeit und gute Integration in aktuelle Frameworks wie AngularJS oder Knockout fallen hier deutlich ins Gewicht. Fachliche oder infrastrukturelle Voraussetzungen, persönliche Vorlieben oder Kenntnisse geben letztlich den Ausschlag für bzw. gegen eine der beiden Technologien. An dieser Stelle ist die Entwicklung unserer SharePoint-App abgeschlossen. Die nächsten Schritte wären eine Auswahlmöglichkeit für einzelne Websites, die Einbindung der SharePoint-Suche, eine gesonderte Behandlung für Dokumentenbibliotheken und das Editieren von Inhalten. Es gibt also genügend Anreize, sich tiefer mit der mobilen Integration von SharePoint auseinanderzusetzen.

CSOM REST
benötigt Speicherplatz für Assemblies keine zusätzlichen Assemblies notwendig
CAML Queries (Lambda-Abfragen) Standard RESTful URLs (cachebar)
Batch Calls ermöglichen weniger Kommunikation mit dem Server pro Ressource ist eine eigene Abfrage nötig
Rückgabe eines komplexen Objekts Rückgabe von JSON oder OData
hohe Abdeckung des Server-side Object Models (SSOM) geringere Abdenkung des SSOM
benötigt das .NET Framework programmiersprachen- und plattformunabhängig

Tabelle 1: Vergleich zwischen CSOM und REST

Aufmacherbild: Woman using her Mobile Phone in the street, night light Background von Shutterstock / Urheberrecht: LDprod

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -