Error occurred in deployment step ‘recycle IIS Application Pool’: provider load failure

Gerade bin ich beim Versuch ein Projekt in Visual Studio 2010 zu deployen über diesen Fehler gestolpert: Error occurred in deployment step ‚recycle IIS Application Pool‘: provider load failure. Neustart von Visual Studio und iisreset brachten keine Besserung.

Ursache: unbekannt.

Lösung: den Windows-Dienst SharePoint 2010 Administration neu starten.

Silverlight 3: Styles anwendungsübergreifend verwenden

In diesem Beitrag soll gezeigt werden, wie man Styles in Silverlight 3 anwendungsübergreifend verwenden kann. Ich arbeite derzeit an einem Projekt, das unter anderem aus mehreren Silverlight-Anwendungen besteht. Das Aussehen dieser Anwendungen soll zentral verwaltet werden. Da ohnehin bereits eine gemeinsame Silverlight-Klassenbibliothek benutzt wird, weil die Anwendungen gleiche Daten nutzen, lag es nahe, auch die verwendeten Styles dort abzulegen.

Eine Recherche im Web brachte ziemlich viele Anleitungen zutage, wie man so etwas erreichen kann. Beim Testen mußte ich aber feststellen, daß keine der Anleitungen funktioniert. Visual Studio 2010 stellt die Styles zwar dar und die Anwendung läßt sich problemlos kompilieren, aber beim Versuch sie im Browser darzustellen erhält man eine Fehlermeldung. Im Debugger zeigt sich, daß die Styles aus der gemeinsamen Bibliothek dafür verantwortlich sind.

Nach ausgiebigen weiteren Recherchen bin ich auf die Lösung gestoßen: beim Einbinden der Styles aus der Klassenbibliothek muß ein zusätzlicher Schrägstrich / angegeben werden. Offenbar unterschied sich die Beta von Silverlight 3 an dieser Stelle von der RTM-Version und alle Anleitungen, die ich fand, beruhten auf der Beta (mit der ich nie zu tun hatte).

Deshalb hier nochmal die Vorgehensweise für alle, die dasselbe Problem haben – und für mich selbst zum Nachschlagen 🙂 Getestet mit Visual Studio 2010 und Silverlight 3.

Schritt 1: Silverlight-Klassenbibliothek mit Styles anlegen

Wir brauchen zuerst ein Projekt vom Typ "Silverlight Class Library", in dem wir alle gemeinsam genutzten Komponenten ablegen:

Es gibt dabei nichts besonderes zu beachten. Wir fügen dem Projekt jetzt ein Element vom Typ "Silverlight Resource Dictionary" hinzu, in dem wir die gemeinsam genutzten Styles ablegen:

Ich habe die Datei Styles.xaml genannt. Für die Datei muß im Eigenschaftenfenster unter "Build Action" unbedingt Resource eingestellt werden! Alles andere wie z.B. Embedded Resource, das wahrscheinlich viele aus der Windows Forms Entwicklung kennen, funktioniert nicht.

Wie man Silverlight-Styles erstellt und benutzt, soll hier nicht weiter gezeigt werden. Hier soll nur beispielhaft gezeigt werden, wie die Datei aufgebaut ist:

<ResourceDictionary

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;

  <Style x:Key="InputFormCellLight" TargetType="Border">

    <Setter Property="BorderBrush" Value="Black"/>

    <Setter Property="BorderThickness" Value="1,1,0,0"/>

  </Style>

</ResourceDictionary>

 

Schritt 2: die Styles aus der Bibliothek verwenden

Im zweiten Schritt soll gezeigt werden, wie man die Styles aus der Bibliothek verwendet. Dazu legen wir ein Projekt für die eigentliche Silverlight-Anwendung an (Silverlight Application) und fügen einen Verweis auf die Silverlight-Klassenbibliothek hinzu. Sonst gibt es auch bei diesem Projekt nichts besonderes zu beachten.

Damit wird die Styles verwenden können, müssen sie zuerst verfügbar gemacht werden. Am sinnvollsten macht man das in der Datei App.xaml, damit die Styles in der gesamten Anwendung verfügbar sind. Die Datei sieht dann so aus:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;

  x:Class="SilverlightApplication.App">

  <Application.Resources>

    <ResourceDictionary>

      <ResourceDictionary.MergedDictionaries>

        <ResourceDictionary Source="/SilverlightLibrary;component/Styles.xaml"/>

      </ResourceDictionary.MergedDictionaries>

    </ResourceDictionary>

  </Application.Resources>

</Application>

 

Wichtig ist dabei diese Zeile und genau dort lag auch mein anfängliches Problem:

  <ResourceDictionary Source="/SilverlightLibrary;component/Styles.xaml"/>

Im Source-Attribut wird zuerst der Name der Klassenbibliothek angegeben, d.h. der Name der DLL ohne Dateierweiterung. Wichtig ist hier der führende Schrägstrich! Bei der Beta von Silverlight 3 war dieser offenbar nicht notwendig. Danach folgt durch ein Semikolon getrennt der Pfad zur Datei, die die Styles enthält. Das Präfix "component" muß dabei immer vorangestellt werden!

Damit stehen die zentral verwalteten Styles zur Verfügung und können so benutzt werden:

Style="{StaticResource InputFormCellLight}"

WCF und Silverlight in SharePoint. Teil 2: eine Silverlight-Anwendung entwickeln, die den Dienst nutzt

Das ist der zweite Teil einer Serie über eigene WCF-Dienste in SharePoint und deren Nutzung in Silverlight. Im ersten Teil wurde gezeigt, wie der WCF-Dienst entwickelt wurde. Hier wird jetzt die zugehörige Silverlight-Anwendung entwickelt, die diesen Dienst nutzt.

Teil 2: eine Silverlight-Anwendung entwickeln, die den Dienst nutzt

Die grundsätzliche Entwicklung mit Silverlight soll hier nicht gezeigt werden. Auch dafür sollten sich im Web ausreichend Anleitungen finden lassen. Hier geht es nur um eine einfache Silverlight-Anwendung, die unseren im letzten Teil entwickelten WCF-Dienst nutzt.

Bei meinem "echten" Projekt ist noch eine Silverlight-Bibliothek dazwischengeschaltet, weil die gesamte Lösung aus mehreren Silverlight-Anwendungen besteht, die alle denselben Dienst und dieselben Businessdaten nutzen.

Schritt 1: Erstellen des Projekts in Visual Studio

Wir fügen unserer Projektmappe ein neues Projekt vom Typ Silverlight Application hinzu:

Ich habe es SilverlightDemo genannt. Im sich öffnenden Dialog wird die Option zum Erstellen eines Webprojektes (das normalerweise zum Testen der Silverlight-Anwendung dient) abgewählt:

Unsere Silverlight-Anwendung würde wegen Authentifizierungsproblemen im Testprojekt sowieso nicht (ohne Anpassungen) funktionieren und wir wollen sie ja in SharePoint haben. Als Silverlight-Version habe ich 3 gewählt. Version 4 sollte aber ebenso funktionieren.

Dem Silverlight-Projekt fügen wir jetzt noch Verweise auf System.Runtime.Serialization und System.ServiceModel (s. Teil 1) hinzu, damit wir WCF nutzen können. Zusätzlich brauchen wir Verweise auf die beiden Silverlight-Client-Assemblies von SharePoint, damit wir den Kontext bekommen. Die Assemblies heißen Microsoft.SharePoint.Client.Silverlight und Microsoft.SharePoint.Client.Silverlight.Runtime und befinden sich im ClientBin-Ordner:

Außerdem brauchen wir einen Verweis auf unseren Dienst (Rechtsklick auf References -> Add Service Reference):

In diesem Dialog gibt man oben die URL des Dienstes an (mit dem Suffix MEX, wie im Browser am Ende von Teil 1) und klickt dann auf Go. Wenn alles klappt, dann wird der Dienst mit seinen Methoden gefunden und angezeigt. Visual Studio erstellt dann Proxy-Klassen für den Dienst selbst und alle Entitäten, die die Methoden des Dienstes eventuell liefern. Der Namensraum, in dem diese Klassen erstellt werden, kann unten angegeben werden.

Schritt 2: die Silverlight-Oberfläche

Die Oberfläche der Silverlight-Anwendung, d.h. das was die Benutzer später sehen, befindet sich in MainPage.xaml. Ich habe dort einen Button zum Aufruf des Dienstes und einen TextBlock zur Anzeige des Ergebnisses eingefügt. Die Datei sieht dann so aus:

<UserControl x:Class="SilverlightDemo.MainPage"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;

  xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;

  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;

  mc:Ignorable="d">

 

  <Grid x:Name="LayoutRoot" Background="White">

    <StackPanel Name="stackPanel1" Orientation="Horizontal">

      <Button Height="30" Width="150" Content="Klick mich" Name="Button1" Click="Button1_Click" />

      <TextBlock Height="30" Text="klick den Button" Name="TextBlock1" Padding="6" />

    </StackPanel>

  </Grid>

</UserControl>

 

Optisch sieht das so aus:

Schritt 3: der Code zum Aufruf des Dienstes

Zuerst müssen wir den Kontext zu SharePoint herstellen. Das geschieht durch Hinzufügen einer Zeile zum Application_Startup-Ereignis, das sich in der Datei App.xaml.cs findet. Der gesamte Ereignishandler sieht dann so aus:

private void Application_Startup(object sender, StartupEventArgs e) {

  ApplicationContext.Init(e.InitParams, SynchronizationContext.Current);

  this.RootVisual = new MainPage();

}

Damit das funktioniert, muß man noch eine using-Direktive oben einfügen:

using Microsoft.SharePoint.Client;

Über die Klasse ApplicationContext, die zum SharePoint-Silverlight-Client gehört, erhält man später Zugriff auf den SharePoint-Kontext.

Jetzt können wir uns dem CodeBehind der eigentlichen Anwendung in MainPage.xaml.cs zuwenden. Im Ereignishandler für den Buttonklick definieren wir zunächst die Umgebung für den Dienst:

BasicHttpBinding binding = new BasicHttpBinding();

binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;

EndpointAddress endpoint = new EndpointAddress(ApplicationContext.Current.Url + "/_vti_bin/WcfDemo/DemoService.svc");

 

Durch Setzen der EndpointAddress auf die aktuelle URL der Website plus den Pfad zu unserem Dienst wird erreicht, daß der Dienst immer im richtigen Kontext aufgerufen wird. Innerhalb des Dienstes kann man so z.B. über SPContext.Current.Site bzw. SPContext.Current.Web auf die aktuelle Websitesammlung bzw. auf die aktuelle Website von SharePoint zugreifen.

Jetzt können wir uns damit eine Instanz des Dienstproxy erzeugen:

DemoServiceClient srv = new DemoServiceClient(binding, endpoint);

In Silverlight können externe Dienstaufrufe immer nur asynchron erfolgen. Visual Studio hat das beim Erzeugen der Proxyklassen berücksichtigt und entsprechende EventHandler und Methodenaufrufe erzeugt. Wir rufen also die Methode GetMessage unseres Dienstes asynchron auf. Sobald der Dienst antwortet, ruft dieser dann den vorher gesetzten EventHandler auf und dort verarbeiten wir dann das Ergebnis:

srv.GetMessageCompleted += GetMessageCompleted;

srv.GetMessageAsync();

Und hier noch der entsprechende EventHandler:

private void GetMessageCompleted(object sender, GetMessageCompletedEventArgs e) {

  TextBlock1.Text = e.Result;

}

Wie man sieht, bekommt man den Rückgabewert der Dienstmethode hier über die Result-Eigenschaft der entsprechenden EventArgs. Man kann sie direkt verwenden und z.B. in einem TextBlock ausgeben. Um die Synchronisierung der verschiedenen Threads kümmert sich der erzeugte Proxy automatisch.

Hier nochmal der gesamte Code von MainPage.xaml.cs:

using System;

using System.Windows;

using System.Windows.Controls;

using System.ServiceModel;

using SilverlightDemo.ServiceProxy;

using Microsoft.SharePoint.Client;

 

namespace SilverlightDemo {

  public partial class MainPage : UserControl {

    public MainPage() {

      InitializeComponent();

    }

 

    private void Button1_Click(object sender, RoutedEventArgs e) {

      BasicHttpBinding binding = new BasicHttpBinding();

      binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;

      EndpointAddress endpoint = new EndpointAddress(ApplicationContext.Current.Url + "/_vti_bin/WcfDemo/DemoService.svc");

      DemoServiceClient srv = new DemoServiceClient(binding, endpoint);

      srv.GetMessageCompleted += GetMessageCompleted;

      srv.GetMessageAsync();

    }

 

    private void GetMessageCompleted(object sender, GetMessageCompletedEventArgs e) {

      TextBlock1.Text = e.Result;

    }

  }

}

 

Schritt 4: Abschluß und Test

Unser gesamtes Projekt sieht jetzt so aus:

Sobald man das Projekt kompiliert hat, kann es getestet werden. Dazu lädt man die erzeugte SilverlightDemo.xap-Datei (zu finden im Bin\Debug– bzw. Bin\Release-Ordner) in eine beliebige Dokumentbibliothek in SharePoint hoch und merkt sich den Pfad zur Datei (z.B. /site/library/SilverlightDemo.xap). Jetzt fügt man auf einer beliebigen Webpartseite das Silverlight-Webpart, das zu SharePoint 2010 gehört, hinzu:

Im darauf erscheinenden Dialog gibt man jetzt die URL zur vorher hochgeladenen Datei an (absolut oder relativ):

Das Webpart erscheint dann auf der Seite so:

Und nachdem auf den Button geklickt wurde:

Wie man sieht wird der Text aus der web.config des Dienstes ausgegeben. Dieser kann jetzt geändert werden und die Änderung wird dann sofort in Silverlight angezeigt – natürlich nur, wenn man erneut auf den Button klickt 😉

WCF und Silverlight in SharePoint. Teil 1: einen eigenen WCF-Dienst entwickeln und in SharePoint bereitstellen

Ich habe gerade ein größeres Projekt, bei dem zwar SharePoint als Frontend genutzt werden soll, aber ein Großteil der für die Benutzer sichtbaren Oberfläche in Silverlight gebaut werden muß. Die Anwendung soll außerdem intensiv auf SAP zugreifen – lesend und schreibend. Viele dieser SAP-Zugriffe müssen aus Silverlight erfolgen und da Silverlight im Browser, also auf dem Client, läuft und von dort der direkte Zugriff auf SAP nicht möglich ist, mußte eine Zwischenschicht her. Was bietet sich mehr an, als eigene WCF-Dienste?

Die Verwendung von Externen Inhaltstypen für die Integration von SAP wurde verworfen, weil sehr spezielle Operationen mit den Daten notwendig sind. Das könnte man zwar alles auch dort einbauen, aber die Entwicklung wäre mindestens genauso kompliziert. Außerdem werden diese Daten nur in Silverlight und nicht in SharePoint selbst benötigt. WCF-Dienste bieten die Möglichkeit genau die notwendige Funktionalität zu implementieren – nicht mehr und nicht weniger.

Zum Zugriff auf SAP benutzen wir übrigens ERPConnect von Theobald Software.

Bei meinen ersten Tests mußte ich allerdings ziemlich schnell feststellen, daß das alles gar nicht so einfach ist, wie es (zumindest für mich) auf den ersten Blick aussah. Nach intensiver Webrecherche und sehr viel Ausprobieren habe ich jetzt aber eine funktionierende Testumgebung. Es gibt einen von außen d.h. ohne Codeänderung konfigurierbaren WCF-Dienst, der direkt in SharePoint bereitgestellt wird (und damit die Berechtigungen und die Grundkonfiguration von dort übernimmt) und es gibt eine Silverlight-Anwendung, die diesen Dienst nutzen kann. Die gesamte Lösung läßt sich in WSP-Dateien verpacken und so sauber beim Kunden bereitstellen.

Normalerweise versuche ich meine Beiträge in Deutsch zu verfassen und werde das auch hier tun. Allerdings ist meine gesamte Entwicklungsumgebung englisch und ich hatte auch noch nie eine deutsche Version von Visual Studio unter den Fingern. Screenshots und Erklärungen zu Visual Studio werden also in Englisch sein.

Da das Ganze naturgemäß etwas länger ist, werde ich es in zwei Teile aufteilen. Teil 1 (dieser Beitrag) behandelt die Entwicklung des WCF-Dienstes und dessen Bereitstellung in SharePoint. Teil 2 behandelt die Entwicklung einer SharePoint-fähigen Silverlight-Anwendung, die diesen Dienst nutzt.

Teil 1: einen eigenen WCF-Dienst entwickeln und in SharePoint bereitstellen

Die Bereitstellung eines WCF-Dienstes in WSS 3.0 bzw. MOSS 2007 war relativ kompliziert. Zum einen nutzt diese Version "nur" .NET 2.0, was Änderungen an der web.config notwendig macht und zum anderen ist die Konfiguration eines WCF-Dienstes auch ohne SharePoint relativ kompliziert. In SharePoint 2010 ist das jetzt deutlich einfacher. Zum einen weil SharePoint selbst mit .NET 3.5 und WCF-Diensten arbeitet, so daß das gesamte System bereits vorbereitet ist, und zum anderen weil man die Konfiguration des Dienstes SharePoint überlassen kann.

Eine grundlegende Anleitung zur Entwicklung und Bereitstellung eines WCF-Dienstes in SharePoint findet man hier auf MSDN. Ich habe noch ein paar Erweiterungen zur dort gezeigten Vorgehensweise gemacht. Z.B. weil ich meinem Dienst Konfigurationseinstellungen von außen mitgeben mußte.

Schritt 1: erstellen des Projekts in Visual Studio

Ich beginne immer damit, mir eine leere Projektmappe in Visual Studio anzulegen. Visual Studio legt dann alle Projekte dieser Projektmappe in Unterordnern an. Wenn man das nicht tut, dann liegt später entweder die SLN-Datei in einem Unterordner oder im Ordner eines Projektes. Eine neue, leere Projektmappe erstellt man, indem man File -> New -> Project klickt und dann diese Vorlage auswählt:

Der neuen Projektmappe fügt man jetzt ein neues, leeres SharePoint-Projekt hinzu (durch Rechtsklick im Solution Explorer und dann Add -> New Project:

Ich habe es WcfDemo genannt. Wichtig ist, daß im sich öffnenden SharePoint Customization Wizard die Option "Deploy as a farm solution" ausgewählt wird. Der Dienst läßt sich nicht als sandboxed solution bereitstellen:

Dem Projekt müssen jetzt noch mehrere Verweise hinzugefügt werden (Rechtsklick auf References und dann Add Reference): System.Runtime.Serialization und System.ServiceModel werden für WCF gebraucht. System.Web wird für das Auslesen der Einstellungen gebraucht. Man findet sie direkt im .NET-Reiter:

Zur Benutzung der von SharePoint bereitgestellten Service Factories, die den Dienst automatisch konfigurieren, ist ein weiterer Verweis auf Microsoft.SharePoint.Client.ServerRuntime notwendig. Die Datei findet sich im GAC und kann über den Browse-Reiter des Dialogs ausgewählt werden:

 

Schritt 2: implementieren des Dienstes

Zum Auslesen und Bereitstellen der Einstellungen (dazu weiter unten mehr) gibt es eine statische Klasse AppSettings:

using System;

using System.Collections.Specialized;

using System.Web.Configuration;

 

namespace WcfDemo {

  internal static class AppSettings {

 

    public static string Message {

      get { return WebConfigurationManager.AppSettings["Message"]; }

    }

 

  }

}

Wie genau ein WCF-Dienst entwickelt wird, soll hier nicht weiter erläutert werden. Im Web sollten sich dazu ausreichend Quellen finden lassen. Der Dienst soll zu Testzwecken einfach einen String aus den Einstellungen zurückgeben. Wir brauchen dazu ein Interface IDemoService und eine Klasse DemoService, deren Inhalt ich hier kommentarlos bereitstelle:

using System;

using System.Collections.Generic;

using System.Runtime.Serialization;

using System.ServiceModel;

 

namespace WcfDemo {

  [ServiceContract]

  public interface IDemoService {

 

    [OperationContract]

    string GetMessage();

 

  }

}

 

 

using System;

using System.Collections.Generic;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Activation;

using Microsoft.SharePoint.Client.Services;

 

namespace WcfDemo {

  [ServiceBehavior]

  [BasicHttpBindingServiceMetadataExchangeEndpointAttribute]

  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

  public class DemoService : IDemoService {

 

    public string GetMessage() {

      return AppSettings.Message;

    }

 

  }

}

Schritt 3: den Dienst bereitstellen

Der Dienst soll im ISAPI-Ordner unterhalb des 14-Hive bereitgestellt werden, damit er später über das von SharePoint bereitgestellte virtuelle Verzeichnis _vti_bin erreicht werden kann. Im Web finden sich mehrere Anleitungen, wie man einen WCF-Dienst konfigurierbar machen kann. Meist wird dabei entweder die web.config-Datei im ISAPI-Ordner angepaßt (eine zu SharePoint gehörende Datei, die man nicht verändern sollte) oder es wird ein eigener Service Host entwickelt, der Einstellungen dann aus einer beliebigen Quelle (Datei, Datenbank, …) verarbeiten kann (was relativ kompliziert ist).

Ich habe hier einen anderen, einfacheren Weg gewählt: wir legen den Dienst in einen Unterordner, damit wir ihm seine eigene web.config-Datei bequem per WSP-Datei mitgeben können. Diese web.config wird nichts anderes enthalten, als die benötigten Einstellungen. Wie bei ASP.NET üblich, werden dadurch alle anderen Konfigurationseinstellungen von der übergeordneten web.config (im ISAPI-Ordner) geerbt.

Wir nehmen in unser Projekt also einen "SharePoint Mapped Folder" auf (Rechtsklick auf das Projekt -> Add -> SharePoint Mapped Folder):

Dem Ordner fügen wir jetzt einen Unterordner hinzu (Rechtsklick -> Add -> New Folder), z.B. WcfDemo. In diesen Ordner nehmen wir zwei neue Dateien auf (Rechtsklick -> Add -> New Item). Als Vorlage nimmt man Text File und benennt die Dateien web.config und DemoService.svc.

Die Datei web.config enthält nur die Einstellungen, die wir im Dienst brauchen und die später jederzeit geändert werden können, z.B. wenn sich in der Umgebung beim Kunden etwas ändert. Das können z.B. Servernamen von Fremdsystemen oder Verbindungsstrings zu Datenbanken sein. Die Datei sieht so aus:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<configuration>

  <appSettings>

    <add key="Message" value="Hallo Welt!"/>

  </appSettings>

</configuration>

Durch Hinzufügen von weiteren add-Elementen kann man beliebige weitere Einstellungen ablegen und später bequem über die AppSettings-Klasse (s.o.) wieder auslesen.

Die Datei DemoService.svc stellt den eigentlichen Dienst bereit. Sie sieht so aus:

<%@ServiceHost Language="C#" Debug="true"

Service="WcfDemo.DemoService, $SharePoint.Project.AssemblyFullName$"

Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Das Factory-Attribut legt fest, wie SharePoint den Dienst konfiguriert. Die Möglichkeiten sind hier auf MSDN beschrieben. Beim Service-Attribut gibt man die Klasse mit Namensraum des Dienstes und den "fully qualified assembly name" an. Mit Visual Studio 2010 und seinen SharePoint-Projektvorlagen kann man die korrekte Angabe Visual Studio überlassen. Das Token $SharePoint.Project.AssemblyFullName$ wird nach dem kompilieren automatisch ersetzt. Was damit alles machbar ist, findet man hier auf MSDN.

Allerdings ersetzt Visual Studio standardmäßig keine Tokens in svc-Dateien. Damit das funktioniert, muß man entweder die Projektdatei editieren (dann funktioniert es in diesem Projekt) oder man paßt gleich die verantwortliche MSBuild-Datei an, damit es für alle Projekte funktioniert. Eine kurze Anleitung wie das geht findet man z.B. hier bei Andrew Connell.

Schritt 4: Abschluß und Test

Das gesamte Projekt sieht im Solution Explorer jetzt so aus:

Durch einen Rechtsklick auf das Projekt und Deploy kann es jetzt einfach kompiliert und in SharePoint bereitgestellt werden. Man kann den Dienst dann mit dem Browser über die folgende URL aufrufen: http://<sharepoint>/_vti_bin/WcfDemo/DemoService.svc/MEX (das angehängte /MEX steht für Metadata Exchange).

BeforeProperties und AfterProperties bei verschiedenen Ereignissen

Dieser Beitrag soll nicht zeigen, wie man EventReceiver für SharePoint-Listen und –Bibliotheken entwickelt. Dafür gibt es meiner Meinung nach bereits ausreichend Anleitungen (z.B. hier von Microsoft). Hier soll gezeigt werden, wie sich die BeforeProperties und AfterProperties bei verschiedenen Ereignissen verhalten.

Es geht hier auch nur um die verschiedenen Ereignisse rund um Listenelemente. SharePoint bietet weit mehr Ereignisse, die von eigenem Programmcode behandelt werden können, z.B. für Listen und für Webs.

Um Ereignisse eines Listenelements behandeln zu können, schreibt man eine Klasse, die von SPItemEventReceiver abgeleitet ist und überschreibt dort die angebotenen Methoden der Basisklasse. All diese Methoden erhalten einen Parameter vom Typ SPItemEventProperties. Über diesen Parameter lassen sich sehr viele nützliche Dinge über die Umgebung herausfinden wie z.B. die GUID der Liste, in der das Ereignis auftrat und die ID des Elements, das das Ereignis ausgelöst hat. Mit Hilfe der BeforeProperties und AfterProperties läßt sich herausfinden, welches Feld oder welche Felder des Elements sich geändert haben. Außerdem gibt es eine Eigenschaft ListItem, die Zugriff auf das zugehörige Listenelement liefert.

Leider sind diese Eigenschaften der SPItemEventProperties in den verschiedenen Ereignissen unterschiedlich belegt und obendrein unterscheiden sie sich auch noch zwischen Listen und Bibliotheken. Um einen Überblick zu schaffen und etwas zum Nachschlagen zu haben, habe ich diese Liste zusammengestellt, die die unterschiedlichen Werte von ListItem, BeforeProperties und AfterProperties bei unterschiedlichen Ereignissen gegenüberstellt.

So verhält es sich bei Listen:

Ereignis

ListItem

BeforeProperties

AfterProperties

ItemAdding

 null leer  neue Werte 

ItemAdded

neue Werte   leer  neue Werte

ItemUpdating

 alte Werte  leer  neue Werte

ItemUpdated

 neue Werte  leer  neue Werte

ItemDeleting

 allte Werte  leer  leer

ItemDeleted

 null  leer  leer

 

So verhält es sich bei Bibliotheken:

Ereignis

ListItem

BeforeProperties

AfterProperties

ItemAdding

null  leer  leer 

ItemAdded

 neue Werte  leer  leer

ItemUpdating

 alte Werte  alte Werte  neue Werte

ItemUpdated

 neue Werte  alte Werte  neue Werte

ItemDeleting

 alte Werte  leer  leer

ItemDeleted

 null  leer  leer

Dienstanwendung für die Verwendungsdatenerfassung starten

Bei manchen Installationen steht man vor dem Problem, daß der Proxy der "Dienstanwendung für die Verwendungsdatenerfassung" immer mit dem Status "Angehalten" stehenbleibt und damit die Verwendungsanalyse nicht funktioniert. Auf Englisch heißt die entsprechende Service Application "Usage and Health Data Collection". (Ich sollte vielleicht doch besser auf Englisch bloggen. Bei manchen Übersetzungen bricht man sich regelrecht die Zunge. Allerdings war ich der Meinung, daß es bereits genügend englischsprachige Blogs zu SharePoint gibt.)

Diese Dienstanwendung kann nicht, wie die meisten anderen, über die "Neu"-Schaltfläche eingerichtet werden. Auch der Konfigurationsassistent erstellt sie nicht. Die Dienstanwendung wird eingerichtet, sobald man in der Zentraladministration unter "Überwachung" auf "Verwendungs- und Integritätsdatenerfassung konfigurieren" klickt. Es öffnet sich folgende Seite:

Wenn der Haken bei "Verwendungsdatenerfassung aktivieren" gesetzt wird, wird die Anwendung eingerichtet. Bei einigen Installationen bestand dann das Problem, daß in der Liste der Dienstanwendungen (Anwendungsverwaltung Dienstanwendungen verwalten), beim Proxy dieser Dienstanwendung immer der Status "Angehalten/Stopped" angezeigt wurde. Die Verwendungsanalyse funktioniert dann natürlich nicht. Löschen und neu Erstellen der Dienstanwendung bringt keine Abhilfe.

Es zeigte sich, daß die Dienstanwendung bereitgestellt werden muß. Das kann mit folgendem PowerShell-Skript erledigt werden:

$App = Get-SPServiceApplicationProxy | where {$_.ID -eq "12345678-abcd-1234-abcd-1234567890ab"}
$App.Provision()

Das Skript führt man in der "SharePoint 2010 Management Shell" aus. Die richtige GUID für den Proxy findet man, wenn man einfach Get-SPServiceApplicationProxy ohne weitere Parameter aufruft.

CKS:EBE 3.0 in SharePoint 2010 verwenden

Beim Einrichten dieses Blogs hatte ich verschiedene Optionen durchprobiert, da mir die Standard-Blogvorlage von SharePoint aus verschiedenen Gründen nicht ausreichend schien. Verwendet wurde schließlich die Enhanced Blog Edition aus dem Community Kit for SharePoint (CKS:EBE) in der Version 3.0. Diese Version ist nicht offiziell für SharePoint 2010 vorgesehen, aber es braucht nur ein paar kleine Änderungen in der web.config damit es trotzdem funktioniert.

Man kann bei der Installation nach dem Installation Guide vorgehen, muß aber einen weiteren Schritt zur Änderung der web.config berücksichtigen:

  • Hinzufügen der Lösung CKS.EBE.wsp
  • Bereitstellen der Lösung für die gewünschte Webanwendung
  • Aktivieren des Webanwendungsfeatures
  • Ändern der web.config
  • Aktivieren des Websitefeatures

Diese Schritte sind im Installation Guide gut dokumentiert, mit Ausnahme der für SharePoint 2010 notwendigen Änderungen in der web.config. Diese werden hier beschrieben.

CKS:EBE registriert in der web.config ein http-Module und mehrere http-Handler. Allerdings erwartet SharePoint 2010 diese an anderer Stelle. Sie müssen also verschoben werden. Dazu öffnet man die web.config der entsprechenden Webanwendung mit einem passenden Editor. Zur Not geht auch Notepad. Die Datei findet man standardmäßig unter C:\inetpub\wwwroot\wss\VirtualDirectories\<Anwendung>.

Man sucht nach <httpModules> und findet darunter diese Zeile:

<add name="CksEbeModule" type="CKS.EBE.BlogHttpModule, CKS.EBE, Version=0.1.0.0, Culture=neutral, PublicKeyToken=3e8b700c069fb747" preCondition="integratedMode" />

Die Zeile schneidet man aus, sucht nach <modules und fügt sie dort nach dem letzten <remove, aber als erstes <add-Element ein. Außerdem fügt ma folgendes Attribut ein: preCondition="integratedMode". Es sollte dann etwa so aussehen:

<modules runAllManagedModulesForAllRequests="true">
      <remove name="AnonymousIdentification" />
      <remove name="FileAuthorization" />
      <remove name="Profile" />
      <remove name="WebDAVModule" />
      <remove name="Session" />
      <add name="CksEbeModule" type="CKS.EBE.BlogHttpModule, CKS.EBE, Version=0.1.0.0, Culture=neutral, PublicKeyToken=3e8b700c069fb747" preCondition="integratedMode" />
      <add name="SPRequestModule" preCondition="integratedMode" type="Microsoft.SharePoint.ApplicationRuntime.SPRequestModule, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 

Jetzt mach man dasselbe mit den Handlern, die man unter <httpHandlers> findet, ausschneidet und unter <handlers> wieder einfügt. Sie bekommen ebenfalls das preCondition="integratedMode"-Attribut. Außerdem sollte man ihnen einen beliebigen, aber eindeutigen Namen geben: name="eindeutigerName".

Das war auch schon alles. CKS:EBE 3.0 kann jetzt unter SharePoint 2010 benutzt werden.

Anonymen Zugriff bei SharePoint 2010 einrichten

Grundsätzlich unterscheidet sich das Einrichten des anonymen Zugriffs in SharePoint 2010 nicht von der Vorgängerversion. Allerdings sind die entsprechenden Schalter an anderen Stellen.

Um anonymen Zugriff auf eine Website (z.B. ein Blog) einzurichten, sind folgende Schritte notwendig:

  • über die Zentraladministration anonymen Zugriff auf die Webanwendung erlauben
  • anonymen Zugriff auf die Websitesammlung erlauben
  • (optional) erlauben, was anonyme Benutzer sehen und ggf. ändern dürfen

1. Über die Zentraladministration anonymen Zugriff auf die Webanwendung erlauben

Zuerst muß über die Zentraladministration für die gewünschte Webanwendung der anonyme Zugriff erlaubt werden. Falls dies bereits bei der Anlage der Webanwendung geschehen ist, kann dieser Schritt übersprungen werden.

Man gelangt über "Anwendungsverwaltung" -> "Webanwendungen verwalten" zur Liste der Webanwendungen:

Hier klickt man auf "Authentifizierungsanbieter" und es öffnet sich folgender Dialog:

Das sieht erstmal nicht sehr interessant aus. Unser Ziel verbirgt sich hinter dem Zonennamen (Standard). Ein Klick und es öffnet sich ein weiterer Dialog:

Hier kann man jetzt den Haken bei "Anonymen Zugriff aktivieren" setzen und speichern.

Zurück in der Liste der Webanwendungen klickt man noch auf "Richtlinie für anonymen Zugriff":

Hier muß für alle Zonen "Keine – Keine Richtlinie" ausgewählt sein und damit ist man in der Zentraladministration fertig.

2. Anonymen Zugriff auf die Websitesammlung erlauben

Jetzt muß der anonyme Zugriff für die gewünschte Websitesammlung erlaubt werden. Dazu geht man über "Websiteaktionen" -> "Websiteberechtigungen" (oder "Websiteaktionen" -> "Websiteeinstellungen" -> "Websiteberechtigungen") auf die Seite, über die die Berechtigungen gesteuert werden. Über den Menüpunkt "Anonymer Zugriff" öffnet sich folgendes Dialogfenster:

 

Bei Auswahl von "Nichts" erhalten (wie die Bezeichnung vermuten läßt) anonyme Besucher keinerlei Zugang.

Bei Auswahl von "Gesamte Website" erhalten anonyme Besucher Lesezugriff auf alle Seiten, Listen und Bibliotheken, können aber nichts ändern oder gar löschen. Sollen sie bestimmte Bereiche nicht sehen, muß dort die Berechtigungsvererbung durchbrochen und anonymen Benutzern der Zugang entzogen werden. Siehe dazu weiter unten "Erlauben, was anonyme Besucher sehen und ggf. ändern dürfen". Für die meisten Anwendungsfälle dürfte diese Einstellung passen.

Bei Auswahl von "Listen und Bibliotheken" erhalten anonyme Besucher erstmal keinerlei Zugriffsrechte. Um ihnen Zugriff auf ein Element wie z.B. eine Liste zu gewähren, muß dort die Berechtigungsvererbung unterbrochen und ihnen Zugang gewährt werden. Siehe dazu weiter unten "Erlauben, was anonyme Besucher sehen und ggf. ändern dürfen". Man kann dabei sehr genau festlegen, was anonyme Besucher sehen dürfen und was nicht. Außerdem erhalten anonyme Besucher nicht versehentlich Zugriff auf Informationen, die nicht für sie bestimmt sind, weil immer zuerst ein Administrator explizit Zugang gewähren muß.

Ein Problem bei dieser Einstellung ist, daß man anonymen Besuchern keinen Zugang zur default.aspx gewähren kann. Ruft ein anonymer Besucher die URL der Website (z.B. http://sharepoint/site) ohne eine Seitenangabe auf, erhält er die Aufforderung sich anzumelden. Nur angemeldete Benutzer werden auf die Default-Homepage weitergeleitet. SharePoint unterscheidet sich dabei vom Standardverhalten eines Webservers wie z.B. IIS.

3. (Optional) erlauben, was anonyme Besucher sehen und ggf. ändern dürfen

Soll anonymen Besuchern explizit Zugang zu einem bestimmten Element gewährt oder entzogen werden, wechselt man auf die Berechtigungsseite des Elements. Bei Listen und Bibliotheken findet man die Seite in den Einstellungen. Bei Listenelementen und Dokumenten im Kontextmenü. Im Menüband (Ribbon) finden sich auch entsprechende Schaltflächen. Die Seite sieht anfänglich so aus:

Um die Berechtigungen an dieser Stelle ändern zu können, klickt man auf "Berechtigungsvererbung beenden". Jetzt erscheinen im Menüband neue Schaltflächen und eine Checkbox vor jedem Eintrag. Durch Markieren der Checkbox(en) können einzelne Berechtigungen geändert, entfernt oder hinzufügt werden. Durch Klicken auf "Anonymer Zugriff" man kann steuern, was anonyme Besucher dürfen. Sollen die Änderungen rückgängig gemacht werden, klickt man auf "Berechtigungen erben" und alle individuell gemachten Änderungen werden rückgängig gemacht.

Willkommen bei Andis Blog!

Es ist soweit: auch ich bin unter die Blogger gegangen 🙂

Über diesen Blog:

Hier werde ich versuchen in halbwegs regelmäßigen Abständen über meine Erfahrungen mit SharePoint zu berichten.

Wie schon bei der letzten Version WSS 3.0 bzw. MOSS 2007, so ist es auch jetzt mit der (immer noch) neuen Version SharePoint Foundation 2010 bzw. SharePoint Server 2010 sehr schwer Dokumentation zu finden. Wie beim letzten Mal ist damit zu rechnen, daß sich die Lücken im Laufe der Zeit, sowohl durch Microsoft selbst als auch durch die Blogosphäre, schließen. Dazu möchte ich auch einen Teil beitragen.

Bei der Beschäftigung mit SharePoint stoße ich immer wieder auf solche Dokumentationslücken, die ich dann meist durch intensives Suchen im Web und durch ebenso intensives Selbst-Ausprobieren schließen kann. Die Ergebnisse dieser Forschungen blieben bisher leider meist undokumentiert. Bestenfalls schlugen sie sich irgendwo im Sourcecode oder in irgendwelchen Notizen nieder, die ich dann meist vergaß oder nicht mehr fand. Deshalb soll in Zukunft dieser Blog auch der Dokumentation meiner eigenen Arbeit dienen. In der Vergangenheit habe ich zu oft nach etwas geforscht, mit dem ich mich ein Jahr vorher bereits beschäftigt hatte. Oft genug fiel mir das erst ein, wenn ich das Ergebnis schon wieder neu erarbeitet habe.

Verwendete Technik:

Natürlich läuft dieser Blog auf einer SharePoint 2010 Maschine (die mir dankenswerter Weise mein Arbeitgeber Evocom Informationssystem GmbH zur Verfügung stellt). Vielleicht kommen bald ja noch mehr Blogs von Kollegen dazu…

Außerdem benutze ich die Enhanced Blog Edition aus dem Community Kit for SharePoint. Die ist zwar offiziell nicht für SharePoint 2010 gedacht, aber nach ein paar Stunden Rumgefrickel geht es jetzt. Dazu und zum Thema "wie richte ich anonymen Zugriff auf eine Website in SharePoint 2010 ein" werde ich demnächst gleich die ersten Beiträge verfassen.

Als Design habe ich erstmal "Intensive" aus CKS:EBE verwendet. Sollte ich irgendwann Zeit und Lust dazu haben, werde ich mich mit einem eigenen Theme beschäftigen. Da ich aber Entwickler und kein Designer bin, kann das dauern…

Und noch ein Hinweis für eventuelle Leser: da ich mich um den Server selbst kümmern muß, ist es gut möglich, daß er ab und an kurz ausfällt. Ich kann und will hier keine Hochverfügbarkeit bieten.