Kolumne: SharePoint ganz praktisch

SharePoint-Automatisierung mit Objektmodellen
Kommentare

Das serverseitige Objektmodell: Um eigene programmatische Erweiterung in SharePoint einbringen zu können, muss das SharePoint-API bekannt sein. Seit SharePoint 2010 gibt es zwei API-Ausprägungen: eines auf der Client- und eines auf der Serverseite. Diese Ausgabe der Kolumne widmet sich zunächst der Servervariante.

Lernt man eine neue Programmiersprache, ist zunächst das Erlernen der speziellen Syntax der Sprache elementar. Danach schließt sich in der Regel der weitaus aufwändigere Prozess der Erkundung der eingebauten Bibliotheken oder Klassen an. Wird dieser Schritt vernachlässigt, kann es vorkommen, dass bereits vorhandene Funktionalität durch eigene Methoden oder Funktionen nachprogrammiert wird. Neben der dabei entstehenden redundanten Programmierung steigt die Zahl möglicher Fehlerquelle an. Gleiches gilt auch für die SharePoint-Programmierung. In der Regel entfällt hier allerdings der erste Schritt, da die meisten (neuen) SharePoint-Entwickler aus der .NET-Welt stammen. Wir starten daher direkt mit dem serverseitigen Objektmodell des SharePoint-Servers. Die Basisklassen sind seit der ersten SharePoint-Version relativ gleich und in der Regel mit den verschiedenen SharePoint-Versionen kompatibel.

Objektmodell = Server- und Seitenstruktur

Das SharePoint-Objektmodell entspricht der logischen Struktur und Aufteilung einer SharePoint-Installation. Jedem SharePoint-Element kann eine Klasse zugeordnet werden. Im Allgemeinen kommen die rechten Klassen für die Umsetzung eigener Lösungen häufig zum Einsatz. Die linken Klassen, wie SPServer, SPFarm, SPServiceInstance usw., werden hingegen für eigene Lösungen weniger beansprucht. Neben den gezeigten Klassen sind für den Anwendungsentwickler die Klassen aus Abbildung 1 zusätzlich von wesentlicher Bedeutung. Diese Klassen sind für die Verwaltung der Seiteninhalte verantwortlich. Den Einstiegspunkt bildet hierbei die Klasse SPSite. Obwohl die Klasse SPSite im Singular benannt ist, handelt es sich in Wirklichkeit um eine Auflistung in Beziehung stehender SPWeb-Objekte. Die Namensgebung der beiden Klassen SPSite und SPWeb führt leider des Öfteren zu Irritationen, daher wird an dieser Stelle detaillierter auf diese beiden Klassen eingegangen. Laut der MSDN-Beschreibung stellt ein SPSite-Objekt folgenden Kontext dar: „Represents a collection of sites in a Web application, including a top-level Web site and all its subsites. Each SPSite object, or site collection, is represented within an SPSiteCollection object that consists of the collection of all site collections in the Web application.“

Bei der SPSite-Klasse handelt es sich aber nicht selbst um eine Auflistungsklasse, da die Klasse lediglich von der allgemeinen Object-Klasse erbt. Auch besitzt die Klasse kein visuelles Gegenstück im SharePoint-Portal, sondern stellt lediglich eine Liste mit zugehörigen SPWeb-Instanzen bereit. Zusätzlich stellt die Klasse über die Eigenschaft RootWeb die oberste Webseite zur Verfügung.

Bei der Beschreibung der SPWeb-Klasse ist die MSDN-Dokumentation dagegen kurz und knapp: „Represents a SharePoint Foundation Web site.“

Diese Beschreibung ist klar und verständlich. Jede Instanz einer SPWeb-Klasse stellt eine Webseite dar und besitzt somit auch ein visuelles Gegenstück im SharePoint-Portal. Die Klasse erbt – genau wie die SPSite-Klasse – von der allgemeinen Object-Klasse. Somit haben die beiden Klassen SPSite und SPWeb objekttechnisch nichts miteinander gemeinsam. Die einzelnen Klassen sind mittlerweile sehr gut innerhalb der MSDN-Hilfeseiten dokumentiert [2]. Im Folgenden werden nun einige typische programmatische Zugriffe auf einen SharePoint-Server demonstriert.

Abb. 1: Struktur der SharePoint-Hierarchie

Erster Zugriff auf SharePoint

Im ersten Beispiel (Listing 1) wird eine SharePoint-Seite (SPWeb) geöffnet und die dort vorhandenen Listen (SPList) werden abgerufen. Anschließend werden aus der ersten gefundenen Liste alle Listeneinträge (SPListItem) ausgelesen. Als Lösungstyp wird hierfür eine einfache Konsolenanwendung verwendet. Damit die SharePoint-Klassen gefunden werden, muss dem neuen Projekt eine Referenz zu der SharePoint-Bibliothek (Assembly/DLL) „Microsoft.SharePoint.dll“ hinzugefügt werden. Bei einer Standardinstallation findet man diese DLL auf dem SharePoint-Server im Verzeichnis: C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14ISAPI. Wie aus dem Beispiel hervorgeht, ist der Zugriff auf Inhalte nicht sonderlich kompliziert. Kommt es bei der ersten Ausführung der Methode zu einer „File Not Found“-Ausnahme (Abb. 2), muss der Plattformtyp in Visual Studio noch auf x64 gesetzt werden (Abb. 3). Wie das Beispiel aus Listing 2 demonstriert, können auch sehr einfach neue Inhalte programmatisch erstellt werden. Innerhalb des Beispiels wird der Liste Customer ein neuer Eintrag hinzugefügt.

public static void ListsAndContent()
{      
  using (SPSite site = new SPSite("[SITE URL]"))
  {
    Console.WriteLine("Root web site: {0}", site.RootWeb.Title);
    using (SPWeb web = site.OpenWeb())
    {
      foreach (SPList list in web.Lists)
        Console.WriteLine("Liste: {0}", list.Title);
      Console.WriteLine("Inhalt der Liste: {0}",web.Lists[0].Title);
      foreach (SPListItem item in web.Lists[0].Items)
        Console.WriteLine(item[SPBuiltInFieldId.Title]);
    }
  }
}
public static void AddListEntry()
{
  using (SPSite site = new SPSite("[SITE URL]"))
  {
    using (SPWeb web = site.OpenWeb())
    {
      SPList listCustomer = web.Lists["Customer"];
      SPListItem item = listCustomer.AddItem();
      item[SPBuiltInFieldId.Title] = "Neuer Eintrag";
      item.Update();
    }
  }
}

Abb. 2: „File Not Found“-Ausnahme während der Ausführung

Abb. 3: Plattformtyp in den Projekteigenschaften festlegen

Anlage umfangreicher Elemente

Das abschließende Beispiel in Listing 3 zeigt, wie mehrere Elemente automatisiert erstellt werden können. Als Erstes wird eine neue Teamsite programmatisch angelegt. Innerhalb der erstellten Teamsite wird nach der Erstellung eine benutzerdefinierte Liste (Custom List) Kunden angelegt. Für die Liste wird zusätzlich eine neue Sicht (View) erstellt. Ebenfalls wird der neuen Liste ein erster Datensatz hinzugefügt. Danach wird die neue Liste auf der Startseite der Teamsite innerhalb eines Web Parts positioniert. Anhand dieses komplexeren Beispiels wird deutlich, dass nahezu alle Abläufe über das zugängliche API automatisiert werden können. Die Einstiegsmethode CreateSubWeb ist für die Anlage der neuen Teamsite verantwortlich. Um die neue Site anlegen zu können, wird die Methode Add der Webauflistung aufgerufen. Der Add-Methode werden der gewünschte Seitenname, eine Beschreibung und die gewünschte Sprache übergeben. Über die vorletzte bool-Variablen kann gesteuert werden, ob die Seite eigene Berechtigungen besitzen soll. Der letzte Parameter bestimmt, ob ein vorhandener Ordner in eine Site umgewandelt werden soll. Sobald die Teamsite angelegt wurde, wird die neue SPWeb-Instanz an die Methode CreateClientList übergeben. Diese Methode erstellt eine benutzerdefinierte Liste. Um eine neue Liste anlegen zu können, muss lediglich die Add-Methode der Listenauflistung aufgerufen werden. Dieser Methode werden der Listenname, eine Beschreibung sowie der Listentyp übergeben. Bei dem Listentyp handelt es sich um einen Zahlenwert (int), die vorhandene SPListTemplate-Aufzählung vereinfacht daher die Festlegung eines Listentyps durch interpretierbare Konstanten. Insgesamt stehen derzeit 52 Listendefinitionen bzw. Listenvorlagen zur Auswahl bereit. Die Add-Methode gibt in diesem Fall nicht direkt ein SPList-Objekt zurück, sondern lediglich die GUID der erstellten Liste. Mithilfe der GUID kann im Anschluss auf die Liste zugegriffen und notwendige Listenfelder können hinzugefügt werden. Neue Felder werden der Liste über die Feldauflistung (SPFieldCollection) hinzugefügt. Dabei wird wiederum die Add-Methode verwendet. Übergeben werden müssen der Feldname und der Feldtyp. Ebenfalls kann festgelegt werden, ob es sich bei dem Feld um ein Pflichtfeld handelt. Um die Auswahl des Feldtypen zu vereinfachen, kann auf die SPFieldType-Auflistung zurückgegriffen werden. Da jede Liste ein Title-Feld besitzt, das nicht immer benötigt wird, wird es in diesem Fall einfach umbenannt in Firma. Am Ende der Methode werden die Änderungen per Update gesichert und eine Instanz der neuen Liste wird zurückgegeben. Die anschließende Methode InsertDefaultListEntry erstellt einen ersten Listeneintrag in der neuen Liste. Dazu wird zunächst ein neues SPListItem erstellt. Danach werden die gewünschten Daten in die einzelnen Felder eingetragen. Am Ende wird der neue Listeneintrag per Update-Aufruf gespeichert. Nun wird noch eine spezielle Ansicht (View) für die Liste erstellt. Dazu müssen die gewünschten Felder, die in der Sicht sichtbar sein sollen, festgelegt werden. Die Feldnamen werden daher zunächst in einem Array (StringCollection) zusammengefasst. Anschließend wird der SPViewCollection über Add ein neuer Eintrag hinzugefügt. Dabei wird das zuvor erstellte Array mit den Spaltennamen übergeben. Der Add-Methode muss auch eine CAML-Abfrage übergeben werden, die das notwendige Where-Statement für die Abfrage enthält. Da in diesem Fall keine Daten gefiltert, sondern alle Daten angezeigt werden, kann die CAML-Abfrage der Standardansicht verwendet werden. Über den letzten bool-Parameter wird die neue Ansicht noch als neue Standardansicht festgelegt. Soweit ist nun alles vorbereitet und die Liste kann der Teamsite hinzugefügt werden. Dies übernimmt die Methode AddWebPartToPage. Der Methode wird das neue SPWeb-Objekt sowie die erstellte Liste übergeben. Innerhalb der Methode wird ein neues ListViewWebPart angelegt. Die Klasse ListViewWebPart ermöglicht die Darstellung einer SharePoint-Liste innerhalb eines Web Parts. Damit dies funktioniert, muss der zuvor erstellten Web-Part-Instanz noch mitgeteilt werden, welche Liste angezeigt werden soll. Dies wird durch die Festlegung der Eigenschaften ListName und ViewGuid erreicht. Über die Eigenschaft ListName wird der Name der anzuzeigenden SharePoint-Liste festgelegt. Die Eigenschaft ViewGuid legt die Ansicht fest, die für die Ausgabe verwendet werden soll. In diesem Fall wird die Standardansicht gesetzt. Das so fertig konfigurierte Web Part kann dann der Startseite mithilfe des aktuellen SPLimitedWebPartManager hinzugefügt werden. Abbildung 2 zeigt die programmatisch erzeugte Teamsite. Wie zu erkennen ist, wurden alle Elemente angelegt. Die Seite selbst ist vorhanden, die Liste mit einem Datensatz wurde angelegt und das Web Part wurde der Seite hinzugefügt.

public static void CreateSubWeb()
{
  using (SPSite site = new SPSite("[SITE URL]"))
  {
    using (SPWeb web = site.OpenWeb())
    {
      SPWeb newWeb = web.Webs.Add("sps2010API",
       "Das SharePoint 2010 Objektmodell",
       "Diese Seite wurde programmatisch angelegt.",
       web.Language, SPWebTemplate.WebTemplateSTS, false, false);
      SPList defaultList = CreateClientList(newWeb);
      InsertDefaultListEntry(defaultList);
      SetupViewForList(defaultList);
      AddWebPartToPage(newWeb, defaultList);
    }
  }
}
private static SPList CreateClientList(SPWeb web)
{
  Guid guidList = web.Lists.Add("Kunden",
                  "Eine Liste zum Verwalten von Kundeninformationen",
                  SPListTemplateType.GenericList);
  SPList list = web.Lists[guidList];
  StringCollection choices = new StringCollection();
  choices.Add("Frau");
  choices.Add("Herr");
  list.Fields.Add("Anrede", SPFieldType.Choice, true, false, choices);
  list.Fields.Add("Vorname", SPFieldType.Text, true);
  list.Fields.Add("Nachname", SPFieldType.Text, true);
  list.Fields.Add("Firmen URL", SPFieldType.URL, true);
  list.Fields.Add("Interner Kontakt", SPFieldType.User, false);
  list.Fields.Add("Kontakt seit", SPFieldType.DateTime, true);
  list.Fields.Add("Bemerkung", SPFieldType.Note, false);
  list.Fields["Title"].Title = "Firma";
  list.Fields["Title"].Update();
  list.Update();
  return list;
}
private static void InsertDefaultListEntry(SPList list)
{
  SPListItem newItem = list.AddItem();
  newItem["Anrede"] = "Herr";
  newItem["Vorname"] = "Marc André";
  newItem["Nachname"] = "Zhou";
  newItem["Firma"] = "dev-sky.net";
  newItem["Firmen URL"] = "http://wwww.dev-sky.net";
  newItem["Kontakt seit"] = "2010-12-21";
  newItem.Update();
}
private static void SetupViewForList(SPList list)
{
  StringCollection displayFields = new StringCollection();
  displayFields.Add("Firma");
  displayFields.Add("Anrede");
  displayFields.Add("Vorname");
  displayFields.Add("Nachname");
  displayFields.Add("Kontakt seit");
  list.Views.Add("Kundenliste", displayFields,
                  list.Views[0].Query, 50, true, true);
}
public static void AddWebPartToPage(SPWeb web, SPList list)
{
  ListViewWebPart wp = new ListViewWebPart();
  wp.ZoneID = "Left";
  wp.ListName = list.ID.ToString("B").ToUpper();
  wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
  web.GetLimitedWebPartManager
  ("SitePages/Home.aspx", PersonalizationScope.Shared).
  AddWebPart(wp, "Left", 0);
}

Abb. 4: Programmatisch erstellte Teamsite

Zusammenfassung

Wie anhand der Objektmodellübersicht und des vorhandenen API deutlich wird, können alle Vorgänge innerhalb einer SharePoint-Umgebung automatisiert werden. Auch wenn das Objektmodell sehr komplex ist und zahlreiche Namensräume besitzt, können benötigte Klassen aufgrund der klaren Namensgebung leicht aufgefunden werden. Die nächste Ausgabe der SharePoint-Kolumne verbleibt beim serverseitigen Objektmodell und widmet sich dem Themenfeld Listenzugriffe.

SharePoint 2010 und SharePoint 2013: Die hier verwendeten Beispiele basieren auf einer SharePoint-2010-Umgebung. Die Beispiele und die Implementierungen sind aber auch unveränderlich innerhalb einer SharePoint-2013-/2007-Umgebung ausführbar. Zu beachten ist lediglich die verwendete .NET-Runtime-(CLR-)Version. Bis zur SharePoint-Version 2010 muss die .NET Runtime 2.0 verwendet werden. Erst ab SharePoint 2013 kann die höhere Version 4.0 zum Einsatz kommen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -