Browsing all articles in Developer

In meinem letzten Post für den SharePoint Adventskalender 2011 möchte ich ein kleines Schmuckstück in der SharePoint Welt vorstellen. clip_image002Unser amerikanischer SharePoint MVP Kollege Marc D Anderson entwickelt seit August 2009 kontinuierlich an SPServices.

SPServices ist ein jQuery Plugin. Den größten Bestandteil von SPServices stellen die Wrapper für die SharePoint ASMX Webservices dar. Mit diesen Wrappern sind Aufrufe für die meisten in SharePoint 2007 und SharePoint 2010 vorhandenen. Hier ein Auszug der aktuell implementierten Methoden. Die gesamte Liste findet ihr in der Doku auf CodePlex.

clip_image003

Die SharePoint ASMX-WebServices werden auch in SharePoint 2010 noch sehr häufig verwendet. Unter anderem werden die Attachments von ListItems über die GetAttachmentCollection Methode geladen. Das neue Client Object Model (CSOM) stellt nämlich keinerlei Möglichkeit bereit Anhänge von ListItems zu laden.

Ohne SPServices müssten wir nun an dieser Stelle die SOAP Message erstellen, damit der WebService die Attachments des gewünschten ListItems zurückgeben kann. Doch Marc’s SPSerives nimmt genau diese Arbeit ab.

 

Um SPServices in SharePoint nutzen zu können muss zunächst jQuery in SharePoint geladen werden. Christian hat in seinem Eintrag ja bereits beschrieben wie dies gemacht wird. Darüber hinaus muss man nun noch SPServices selbst in SharePoint integrieren. Das Laden von SPService kann auf die gleiche Art erreicht werden wie bei jQuery.

In meinem Beispiel wird die Lösung auf einem OnPremise SharePoint ausgeführt, daher können beide JavaScript Files auch bequem mittels DelegateControl in SharePoint integriert werden.

 

Dazu muss man folgende Dinge durchführen

1. Ein neues SharePoint Projekt erstellt werden

2. Das Projekt muss als Farm Solution markiert werden

3. Die jQuery und SPSerivces Source Files müssen in einem Mapped Folder auf die SharePoint Farm bereitgestellt werden

clip_image004

4. Ein UserControl mit dem Namen ScriptInjector zum SharePoint Projekt hinzufügen

5. Beide JavaScript Files im UserControl laden

clip_image006

6. Ein neues Empty Element mit folgendem Inhalt hinzufügen

clip_image008

 

Mit diesem Setup werden sowohl jQuery als auch SPServices auf allen SharePoint Seiten geladen. Somit kann auf jeder SharePoint Seite nun frei los-gescriptet werden. Open-mouthed smile

 

Bevor ich zum eigentlichen Service Aufruf komme noch der Hinweis dass sämtliche WebService Methoden über die gleiche Syntax aufgerufen werden können. Somit kann man auch noch unbekannte Servicemethoden im Handumdrehen in die eigene Lösung einbauen und sicher verwenden.

SPServices_GetAttachments

Der Beispielaufruf zeigt wie alle Attachments des Elementes mit der ID 3 aus der Kundenliste abgerufen und als Hyperlink zum Result-Div hinzugefügt werden.

Wichtig ist, dass die Antwort des ServiceCalls (immer noch XML) natürlich interpretiert werden muss. Sicherlich gibt es jede Menge Libraries oder Plugins für jQuery um das Finden der e ntsprechenden Bausteine sehr vereinfachen bzw. sehr beschleunigen, dennoch macht es meiner Meinung nach mehr Sinn die Anzahl an externen JavaScript Bibliotheken aufgrund der Ausführungs- und Ladegeschwindigkeit gering zu halten.

Neben den eben gezeigten WebService Wrappern stellen die SPServices noch diverse Methoden bereit um die SharePoint Formulare etwas mehr aufzupeppen.

Aus den vorhandenen Methoden möchte ich die Methode SPAutocomplete vorstellen. Durch SPAutocomplete kann man an jedes InputField (TextBox auf einer New- oder EditForm) einen AutoComplete Mechanismus anhängen. Das Besondere daran ist, das SharePoint selbst als Datenquelle für das AutoComplete fungiert. Analog zu den ServiceWrappern ist auch dieser Aufruf spielend einfach.

 

clip_image010

 

Wie bereits bei den Services musste auch diesmal wieder die WebURL angegeben werden. Damit bei einer Vielzahl von Methodenaufrufen nicht jedesmal die WebURL angegeben werden muss, solltet ihr die SPServices Defaults verwenden. Hier könnt Ihr die WebURL vorbelegen, so dass diese von allen Calls wiederverwendet werden kann.

clip_image011

 

Ein Tipp aus der Praxis

SPServices ist echt ein geniales kleines Framework, welches die Arbeit mit den SharePoint ASMX WebServices viel angenehmer macht. Doch richtig viel Spaß macht meiner Meinung nach erst die Kombination aus SPServices und jTemplates. jTemplates ist ein jQuery Plugin, welches dazu verwendet wird UI Templates zu definieren und diese mit Daten zu füllen. Mit der Kombination wird die clientseitige SharePoint Entwicklung noch mächtiger und schneller. Daher ist auch jTemplates auf jeden Fall einen Blick wert.

 

Happy scripting,

Thorsten

JavaScript erfreut sich wieder immer größerer Beliebtheit, nicht zuletzt durch den neuen HTML5 Hype. In SharePoint Online bietet JavaScript, insbesondere in Kombination mit dem ECMA Client Object Model, uns gute Möglichkeit Limitationen von Sandboxed Solutions zu überwinden. Aber wie registriere ich JavaScripts richtig in SharePoint Online?

Probleme

In ASP.NET wird oft der ClientScriptManager benutzt um JavaScripts im Code Behind auf der Page zu registrieren. Das funktioniert aber leider nicht in einer Sandboxed Solutions. Obwohl uns zwar das Page Objekt im Code Behind eines WebParts zur Verfügung steht, haben jedoch Änderungen an diesem keine Auswirkungen auf das echte Page Objekt in ASP.NET. Der Grund hierfür ist, dass der Code von Sandboxed Solution nicht im IIS läuft, sondern im User Code Service und der simuliert lediglich den ASP.NET Page Life Cycle.

In SharePoint 2010 gibt es sogar extra die .NET Klasse ScriptLink um JavaScripts zu registrieren. Aber auch diese funktioniert nicht in Sandboxed Solutions.

Lösungen

Eine sehr einfache, aber nicht unbedingt elegante Möglichkeit JavaScripts global auszurollen besteht darin, die Master Page anzupassen und das Skript dort zu registrieren. Auch die in SharePoint 2007 sehr beliebten Delegate Controls stehen uns in Sandboxed Solutions leider nicht zur Verfügung.

Eine andere Möglichkeit ist das Skript innerhalb der Render Methode eines Webparts manuell zu registrieren. Hierbei sollte man aber darauf achten, dass das Skript nicht mehrfach zu laden wenn mehrere Instanzen eines WebParts auf einer Seite laufen. Genau hierfür bietet SharePoint eine sehr nützliche JavaScript Klasse namens SP.SOD (SharePoint Scripts on Demand, leider schlecht dokumentiert). Die Aufgabe von SP.SOD ist es Skripte bei Bedarf dynamisch zu laden. SharePoint selbst nutzt SP.SOD sehr intensiv und lädt viele JavaScript erst bei Bedarf dynamisch. Das hat den Vorteil, dass die Seite dem Benutzer schneller angezeigt wird und dann erst die Funktionalität (JavaScript) nachgeladen wird. Vielleicht ist auch dem ein oder anderen schon mal aufgefallen, dass die Ribbon Buttons erst kurz nach dem Laden der Seite aktiviert werden. Auch die oben erwähnte .NET Klasse ScriptLink macht im Hintergrund nichts anderes als serverseitig clientseitige SP.SOD Aufrufe zu generieren. Glücklicherweise steht uns SP.SOD auch in Sandboxed Solutions zur Verfügung. Jetzt genug Theorie, hier ein Beispiel.

Beispiel

myscript.js

image

Myscript.js registriert den Namespace “ilsp.scripts” und eine einfache “sayHello” Methode. Der letzte Aufruf teilt SP.SOD mit, dass das Skript mit dem Key “myscript.js” geladen wurde und dass eventuell vorhandene Callback Funktionen die auf myscript.js warten jetzt aufgerufen werden können.

Nun registrieren wir myscript.js mit Hilfe einer Custom Action.

image

In SharePoint 2010 kann man Scripts via Custom Action registrieren. Hierzu kann man entweder wie oben das ScriptBlock Attribut nutzen oder das ScriptSrc Attribut. Nachteil von ScriptSrc ist, dass man keine externen Scripts laden kann. Das Script muss entweder im Layouts Ordner liegen (nicht möglich in Sandboxed Solutions!) oder innerhalb der SharePoint Site (kann über ein Modul bereitgestellt werden). Des Weiteren kann man die Scripts nicht “On Demand” laden. In SharePoint Online lade ich Script Libaries gerne aus dem Azure Blob Storage. Hierdurch kann das Script nachträglich leicht, zentral gewartet werden. RegisterSod lädt das Script nicht direkt sondern registriert es lediglich zum späteren laden, sofern benötigt.

Als nächstes Erstellen wir ein Sandboxed Visual Webpart.

image

image

In sayHelloClick wird durch LoadSodByKey das bereits registrierte myscript.js dynamisch geladen. Dynamisch geladen bedeutet, dass der entsprechende Script Tag dynamisch erstellt und zum HTML Head Element hinzugefügt wird. Die Callback Funktion im zweiten Parameter wird nur aufgerufen wenn das Script initial geladen wurden. ExecuteOrDelayUntilScriptLoaded wartet bis ein Script fertig geladen wurde (SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs) und ruft dann die definierte Callback Methode auf.

Ablauf

Bei jedem Laden einer Seite wird myscript.js als SOD registriert aber noch nicht geladen (alert: Register SOD).

Erst wenn “Say Hello” zum ersten Mal geklickt wird, wird myscript.js geladen und dann ilsp.scripts.sayHello aufgerufen (alerts: Loading Scripts…; Notify Script Loaded; Hello Thorsten!).

Beim zweiten klick wird myscript.js nicht nocheinmal geladen, sondern nur noch ilsp.scripts.sayHello aufgerufen (alerts: Hello Martina!)

Hört sich verwirrend an? Ist es auch clip_image001

(…weitere Details zu SP.SOD findet Ihr auch auf meinem Blog.)

 

Mit SharePoint 2010 sind auch die Word Automation Services ab der SharePoint Standard Version verfügbar. Mit den Word Automation Services können Dokumente aus verschiedenen Word Formaten konvertiert werden. Die Word Automation Services sind in der Lage folgende Dateiformate zu öffnen:

  .docx,  .docm, .dotx, .dotm, .dot, .doc, .mht, .rtf, .xml, .mhtml

Als Ausgabeformat können die Word Automation Services die folgenden Dateiformate erzeugen:

  •   .pdf, .xps, .docx, .docm, .dotx, .dotm, .dot, .doc, .mht, .rtf, .xml, .mhtml

Am interessantesten sind wohl die Varianten PDF und XPS, daher möchte ich im Beispiel auch alle Word Dokumente aus einer SharePoint Bibliothek unter Verwendung der Word Automation Services in PDF’s konvertieren.

Beispiel

Zunächst müsst ihr ein neues SharePoint Projekt anlegen. Hierbei ist es wichtig dass Ihr das Projekt als Full-Trusted Solution markiert.

clip_image001

 

Im neu angelegten Projekt müsst Ihr eine Assembly-Referenz zur Microsoft.Office.Word.Server.dll hinzufügen. Die Assembly findet Ihr wie gewohnt im %SharePointRoot%\ISAPI\ Ordner.

clip_image002

 

In meinem Beispiel möchte ich eine ApplicationPage als Ausgangspunkt verwenden, daher wird an dieser Stelle zunächst die ASPX angelegt.

clip_image003

 

Um auf die Klassen der Word Automation Services zugreifen zu können müssen nun die entsprechenden Namespaces referenziert werden.

clip_image004

 

Zunächst wird – analog zur Programmierung mit anderen Service Applications – der aktuell verfügbare ServiceProxy ermittelt. Für die Word Automation Services verwenden zu können muss der Proxy vor der Verwendung in eine Instanz vom Typ ConversionJob gecasted werden.

clip_image005

 

Die daraus resultierende ConversionJob Instanz stellt einen Wrapper um eine neue TimerJob Instanz dar, daher muss der neuen Instanz noch gesagt werden in welchem UserContext der TimerJob ausgeführt werden soll und wie dessen Name lauten soll.

clip_image006

 

Somit sind alle Vorbereitungen getroffen und die Konfiguration der ConversionJob Instanz kann getätigt werden. In meinem Beispiel möchte ich – wie bereits erwähnt – die Dokumente in PDFs konvertieren, deshalb muss auf die Settings.OutputFormat Property auf den Wert SaveFormat.PDF gestellt werden.

Zum Abschluss werden noch die Quell- und Zielliste angegeben und der ConversionJob kann gestartet werden.

Zur besseren Übersicht hier nochmals der gesamte Code

clip_image008

 

Nach dem Aufruf der Start Methode wird ein neuer TimerJob geplant, welcher dann die Konvertierung der Dokumente vornimmt. Daher kann es unter Umständen einige Minuten dauern bis die ersten PDFs in die Zielliste einlaufen.

Nach dem Durchlauf des TimerJobs sollten eure Quell- und Ziellisten vom Content her identisch sein.

 

Quellliste

clip_image010

 

Zielliste

clip_image012+

 

 

Fazit

 

Die Word Automation Services sind ein echt cooles Feature von SharePoint, welches schnell anprogrammiert und in eigene Lösungen integriert werden kann. Gerade die Konversation von Dokumenten in Workflows wird von Kunden immer häufiger gefordert und kann mit den Word Automation Services recht einfach erreicht werden.

Wir bleiben noch etwas im Sandkasten (in den Thorsten mittlerweile schon ein paar Löcher gebohrt hat ;) und werfen einen Blick Sandboxed Workflow Actions. Seit SharePoint 2007 besteht die Möglichkeit SharePoint um eigene Workflow Actions zu erweitern. Allerdings musste man die Actions Farm-weit zur Verfügung stellen. In SharePoint 2010 können wir jetzt auch Workflow Actions via Site Collection Feature bereitstellen. Dies gilt sowohl für Farm Solutions als auch für Sandboxed Solutions. Mit Hilfe einer Sandboxed Solution können wir custom Workflow Actions auch einfach in Office 365 bereitstellen. Die Programmierung einer Sandboxed Workflow Action funktioniert etwas anders als die einer Farm Solution. Im folgenden Post werde ich anhand einer “Create Site Action” zeigen wie man Sandboxed Workflow Actions selbst schreiben kann.

1. Neues leeres SharePoint Projekt in Visual Studio erstellen

2. Sandboxed Solution auswählen

3. Site Collection Feature anlegen (Workflow Actions sollten immer in ein eigenes Feature und nicht mit anderen Feature-Elementen vermischt werden. Es kannst sonst zu Problemen kommen=>Feature-Element-Gulasch)

4. Empty Element hinzufügen und das XML wie folgt bearbeiten:

image_thumb[35]

SandboxedFunction=”true” teilt der Workflow Infrastructure mit, dass es sich um eine Sandboxed Action handelt. FunctioName verweist auf die entsprechende Methode in der Implementierung. Das Element RuleDesigner beschreibt die UI in SharePoint Designer und mapped UI Felder mit Hilfe des Field Attributes auf die Parameter. Die verfügbaren DesignerTypes findet man hier. Die Parameters Elemente binden die Parameter an die Parameter und den Rückgabewert der Methode der Implementierung.

5. Die Implementierung der Create Site Action

image_thumb[36]

Der Name der Methode muss dem FunctionName Attribut des Element Manifest entsprechen (grün). Die Parameter der Methode entsprechen den Direction=”In” Parametern des Manifest (orange). Einzige Ausnahme ist der interne Parameter “___Context” bei dem die Unterstriche fehlen. Die Keys der Hashtable entsprechen den Direction=”Out” Parametern des Manifests (rot).

6. Sandboxed Solution hochladen in der Solution Gallery hochladen und das Site Collection Feature aktivieren

7. Workflow bauen

SNAGHTML1d5d65a_thumb[6]

image_thumb[41]

ENDE

Download

Die SharePoint Sandbox wurde nun bereits mehrmals gut beschrieben, seit diese mit SharePoint 2010 das Licht der Welt erblickt hat.

Heute möchte ich aufzeigen, wie man mit SharePoint 2010 OnPremise Wege aus der Sandbox implementieren kann.

 

Warum möchte man Wege aus der Sandbox finden?

Die SharePoint Sandbox isoliert Custom Code, so dass die vorhandene SharePoint Farm von vermeidlich „kleinen“ oder „unscheinbaren“ Lösungen nicht in Mitleidenschaft gezogen werden kann. Sie ermöglicht es SiteCollection Administratoren direkt über die Solution Gallery WSPs – welche explizit als Sandboxfähig markiert sind – bereitzustellen und zu aktivieren. Ein perfekter Mechanismus für die OnDemand Variante Office365, doch in Konzernen möchte man häufig etwas mehr.

Dieses „etwas“ kann der Aufruf eines bestimmten WebServices, das Schreiben auf eine bestimmte FileShare oder das Laden und Interpretieren des Unternehmens-Feeds sein. In jeder Limitation die uns die Sandbox vorschreibt finden SharePoint Anwender ein kritisches Feature welches Sie aber innerhalb Ihrer Sandbox als verfügbar sehen möchten.

Durchaus üblich sind solche Anforderungen von zentralen IT Abteilungen, die womöglich weltweit verfügbare und verwendete SharePoint Farmen administrieren. Hier muss natürlich auf Sandboxing gesetzt werden, weil der Betrieb solcher SharePoint Farmen schon sehr intensiv ist, würde hier das Monitoring und die Validierung aller Custom Solutions noch bei der Abteilung aufschlagen welche für das Hosting verantwortlich ist, würde dies zu einer mehr als hohen Auslastung führen. Daher ist es in PrivateCloud Szenarien üblich SharePoint’s Full-Trusted Proxies einzusetzen und somit bewusst Wege aus der Sandbox heraus zu öffnen.

Full-Trusted Proxies

In SharePoint 2010 stellt ein „Full-Trusted-Proxy“ genau eine Methode zur Verfügung welche aus Sandboxed Lösungen heraus aufgerufen werden können. Das Deployment eines Full-Trusted-Proxies geschieht über eine WSP – welche nur von einem Farmadministrator installiert und aktiviert werden kann.

Analog zur eigentlichen Sandbox Solution läuft auch der Proxy nicht im IIS Prozess (w3wp.exe) sondern im Prozess SPUCWorkerProcessProxy.exe, in dem auch die Standard Microsoft.SharePoint.dll zur Verfügung steht. Abbildung 1 zeigt wie das Zusammenspiel der Komponenten an dieser Stelle ist.

clip_image002

Abbildung 1 – Full-Trusted Proxies Quelle www.microsoft.com

 

Wichtig ist darüber hinaus, dass die Full-Trusted-Proxy Operation mit der Sandbox-Lösung nur über Ihren eigenen Rückgabewert kommunizieren kann.

 

Die Implementierung

Im folgenden Beispiel möchte ich die Anforderung aufgreifen, die ich zu Beginn angesprochen habe. Einen RSS Feed innerhalb einer Sandboxed Solution abfragen. Innerhalb der Sandbox ist es via CAS verboten die Load Methode der Klasse XElement aufzurufen, deshalb muss diese Operation als Full-Trusted-Proxy realisiert werden.

 

Abbildung2

Wie in Abbildung 2 zu sehen ist, muss das Projekt für den Proxy als Full-Trusted-SharePoint Projekt angelegt werden. Die Realisierung als Full-Trusted-Proxy kann im Wesentlichen auf drei elementare Bestandteile reduziert werden.

 

SPProxyOperationArgs

Zunächst sollte man eine Klasse erstellen, die von SPProxyOperationArgs abgeleitet ist. Diese neue Klasse wird im späteren Verlauf für den Übergabewert der Execute Methode verwendet. Alles was für den RSS-Feed-Reader benötigt wird ist die zugrundeliegende URL, welche aggregiert werden soll.

Abbildung3

 

SPProxyOperation

Der zweite und wichtigste Bestandteil ist die Implementierung des Proxy’s selbst. Hierzu wird eine weitere Klasse erstellt, die von SPProxyOperation abgeleitet ist. Innerhalb der Execute Methode wird die Logik platziert, die den RSS Feed lädt.

 

Abbildung4

 

Hierbei sind zwei Dinge zu beachten. Erstens muss der Parameter der Methode von SPProxyOperationArgs in unseren zuvor erstellten Typ RssFeedReaderArgument gecasted werden. Zweitens kann der Rückgabewert der Methode nur ein serialisierbares Objekt sein.

Registrierung des eigenen Full-Trusted Proxies

Der dritte und letzte Bestandteil des Full-Trusted-Proxies ist die Registrierung des Proxies beim gewünschten UserCodeService. Hierzu kann der FeatureEventReceiver des Farm-Features verwendet werden. Zur Vollständigkeit hier ebenfalls der Code zum Entfernen des Proxies bei der Deaktivierung des Features.

Abbildung5

Die Verwendung in einer Sandboxed Solution

Dank der Methode ExecuteRegisteredProxyOperation der Klasse SPUtility, ist die eigene Proxy-Operation im Handumdrehen aufgerufen. Die Methode bekommt lediglich drei Parameter

· FullQualifiedAssemblyName der Proxy-Operation

· FullQualifiedTypeName der Proxy-Operation

· Eine Instanz der RssFeedReaderArgument Klasse

Abbildung6

Als Resultat des Aufrufes erhält der Sandbox-Entwickler den RSSFeed als String, genau wie zuvor implementiert.

 

Fazit

Full-Trusted-Proxies bieten einen einfachen, sicheren und kontrollierten Weg aus der Sandbox heraus. Gerade in PrivateCloud Szenarien bieten Full-Trusted-Proxies ein gutes Mittel um Herr aller Custom Solutions zu werden.

 

-Thorsten

Hinter dem Türchen im SharePoint Adventskalender verbirgt sich heute eine Kostprobe des SharePointPodcasts, dem auditiven Update für den engagierten SharePoint-Anwender mit Themen, Trends, Tipps, Tricks und Talk. Ich produziere den SharePointPodcast seit fast 7 Jahren in mittlerweile 197 Ausgaben, in denen ich aktuelle News, Tools, Veranstaltungstipps und mehr aus dem SharePoint-Land vorstelle.

Ein wesentlicher Bestandteil dces SharePointPodcasts sind auch die Gespräche und Interviews, die ich mit Menschen wie du und ich aus dem SharePoint-Land führe.

Mit Chris Müller haben ich eine kleine Reihe begonnen, in der wir unter dem Stichwort AlpenPodcast uns über SharePoint und die Welt unterhalten.

Hier ein Auschnitt aus unserem Talk auf den CollaborationDays 2011 in Luzern, die vollständige Episode könnt ihr im SharePointPodcast 197 hören.

 

Mit dem Release von SharePoint 2010 wurde auch die Komponente LINQ 2 SharePoint ausgerollt. Der LINQ Provider für SharePoint 2010 erlaubt es, streng typisierte und kompilierbare Abfragen für SharePoint Listen zu schreiben.

Vor SharePoint 2010 musste jeder SharePoint Entwickler CAML – eine XML basierte SharePoint Abfragesprache – Abfragen erstellen um damit Elemente aus Listen zu selektieren. Der LINQ Context bietet nun einen Wrapper um die Sprache CAML Abfragen an. LINQ 2 SharePoint soll gerade auf einfache Customizings zielen und unerfahrenen SharePoint Entwickler den Einstieg auf die Anwendungsplattform erleichtern.

 

LINQ

Wer zu diesem Zeitpunkt noch keine LINQ Kentnisse hat, der sollte sich eventuell 30 Minuten Zeit nehmen um kurz die Syntax und die Möglichkeiten von LINQ kennenzulernen.

Das kostenlose LINQPad (http://www.linqpad.net/) bietet einen direkten Einstieg in den LINQ Syntax. Wer gerade keinen SQL Server zur Hand hat, oder das ganze bequem auf seinem Netbook machen möchte, der kann mit wenig Aufwand eine Demodatenbank auf SQL Azure erstellen, um eine Datenquelle für die LINQ Queries zu haben. (http://windowsazure.com/)

Auf der MSDN findet sich auch eine Sammlung von 101 LINQ Beispielen in C# und VB.NET (http://msdn.microsoft.com/en-us/vstudio/aa336746), meine Empfehlung ist es an dieser Stelle einfach die ersten N Beispiele sich online anzuschauen und einfach ein wenig mit dem genialen LINQPad zu experimentieren.

 

SPMetal

SPMetal ist ein kleines CommandLineTool, welches dazu verwendet wird, den LINQ 2 SharePoint Context für eine bestimmte SharePoint Webseite zu erstellen. Das Tool kann im Bin Folder des SharePoint Roots gefunden werden. (%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\BIN\SPMetal.exe)

SPMetal wird lediglich über ein paar Parameter konfiguriert und somit an die Umgebung angepasst.

 

Parameter

Beschreibung

web

URL der SharePoint Webseite

code

Absoluter Pfad für die Ausgabedatei. (den generierten LINQ DataContext)

language

Gibt die Programmiersprache an, in welcher der Context generiert werden soll.

namespace

Git den Namensraum an, der für den Context und die Entity-Klassen verwendet werden soll

user

Definiert den Benutzer, in dessen Kontext der Code generiert werden soll.

password

Das Passwort des optional angegebenen Benutzers

parameters

Wird verwendet um den Pfad zu einer XML Konfigurationsdatei anzugeben. Durch die Verwendung dieses Parameters können die Standardeinstellungen von SPMetal überschreiben werden

 

Ein LINQ Kontext in C# kann in der einfachsten Variante über folgenden Aufruf erstellt werden:

SPMetal.exe /web:http://sp2010dev /code:IntranetSite.cs

Um für die gleiche Seite einen LINQ Kontext in Visual Basic zu erstellen sieht der Aufruf wie folgt aus:

SPMetal.exe /web:http://sp2010dev /code:IntranetSite.vb

SPMetal ermittelt, falls nicht explizit angegeben, die gewünschte Programmiersprache über die FileExtension des Code Parameters. Wenn man die Extension des Outputfiles nicht explizit angibt, so muss der Aufruf um den Parameter Language erweitert werden

SPMetal.exe /web:http://sp2010dev /language:vb /code:IntranetSite

Integration in ein SharePoint Projekt

Ein bereits erstellter LINQ 2 SharePoint DataContext kann recht einfach in ein vorhandenes SharePoint Projekt integriert werden.

clip_image002Die generierte Datei kann einfach mittels Drag and Drop zum Projekt hinzugefügt werden. Versucht man sein Projekt an dieser Stelle zu kompilieren, so werden prompt diverse Fehlermeldungen präsentiert. Der Grund hierfür ist recht schnell gefunden, das SharePoint Projekt benötigt einen AssemblyVerweis auf Microsoft.SharePoint.Linq.dll. Wie die meisten SharePoint spezifischen DLLs findet man auch diese im ISAPI Ordern unterhalb des SharePoint Roots.

Mit der neu hinzugefügten Referenz auf die LINQ Assembly sollte sich das SharePoint Projekt jetzt wieder problemlos kompilieren lassen.

 

Stay up-to-date

Bereits an dieser Stelle kann man mit sehr wenig Aufwand nachhaltige Fehlerprävention betreiben. Die von mir zuvor beschriebene Erstellung des LINQ 2 SharePoint Contextes sollte man als PreBuild Ereignis eintragen.
Dadurch kann sehr einfach sichergestellt werden, dass der LINQ 2 SharePoint Kontext stets aktuell ist und sofern sich an der Umgebung etwas ändert, man als Entwickler unmittelbares Feedback erhält.

Die in den Build-Ereignissen existierenden MSBuild Parameter erlauben es darüber hinaus auch, die Dateien noch vor dem Kompilierungsprozess im Projektordner zu überschreiben.

clip_image003

Somit sind alle Voraussetzungen für den Einsatz von LINQ 2 SharePoint gegeben, jetzt kann mit der Entwicklung begonnen werden.

 

Getting started

In Abbildung 3 sieht man eine einfache LINQ 2 SharePoint Abfrage. Es werden hier sämtliche Kunden, die aus Deutschland stammen ermittelt und deren Name wird auf der Console ausgegeben.

clip_image005

Eigentlich nichts spektakuläres, dennoch lassen sich unter genauerer Betrachtung einige Fehler, Probleme und Unschönheiten finden, die man als SharePoint Entwickler im täglichen Leben auslassen bzw. umgehen sollte.

 

Daily LINQ 2 SharePoint

Das erste Problem, welches unser einfaches LINQ 2 SharePoint Beispielscript beinhaltet ist, dass der Context nicht freigegeben wird. Man kann den LINQ 2 SharePoint DataContext mit einer Datenquellenverbindung gleichsetzen, auch hier werden unmanaged Resourcen verwendet, die es wieder freizugegeben gilt.

Analog zum Disposing von SPWeb und SPSite, bietet sich auch hier das using-Schlüsselwort an.

 

clip_image007

 

Gut, jetzt sollte zumindest das offensichtliche Speicherproblem behoben sein, doch analysieren wir das kleine Codefragment weiter.

Die Select() Methode von IEnumerable<T> wird dazu verwendet den Rückgabetyp des gesamten LINQ Ausdrucks zu definieren. Weil diese Abfrage gegen eine Kontaktliste in SharePoint ausgeführt wird, ist unser Rückgabetyp hier Contact. – Das generierte Gegenstück zum Inhaltstyp unserer SharePoint Seite.

An dieser Stelle ist es wichtig, dass man sich wieder darauf besinnt, dass der LINQ Provider für SharePoint lediglich ein Wrapper um CAML darstellt.

Wenn man in Umgebungen arbeitet wo man auf Datentransfermengen und/oder Performance achten muss, dann sollte man unbedingt die Abfrage anpassen, so dass lediglich die benötigten Werte von der Datenquelle abgefragt und zurückgegeben werden.

 

clip_image009

 

Aktivert man auf dem LINQ 2 SharePoint Context das Logging, so sieht man bei der Ausführung unmittelbar, dass sich die CAML Query geändert hat. Durch das hinzufügen des Anonymen Typs in der Select() Methode, wurden in der CAML Query ViewFields integriert. Durch das Verwenden von ViewFields in CAML wir dem SharePoint signalisisert, dass lediglich die angegebenen Felder an den Aufrufer übertragen werden sollen. Ohne ViewFields werden alle Spalten eines Elementes zurückgegeben.

Das dritte Problem des Snippets ist eher ein strukturelles Problem. In diesem Snippet wird eine Abfrage direkt auf dem LINQ 2 SharePoint Context abgesetzt.
Diese direkte Interaktion mit dem LINQ 2 SharePoint Context sollte durch ein Repository Pattern (http://msdn.microsoft.com/en-us/library/ff649690.aspx) gekapselt sein, so dass nicht an beliebigen Stellen im Anwendungscode der Context verwendet wird.

Vielmehr sollte es einen Service gegeben, welcher von den jeweiligen Komponenten verwendet wird um die benötigten Objekte aus der SharePoint Liste zu erhalten.

clip_image010

 

Die neuste Version des Snippets verwendet den CustomerService. Der CustomerService übernimmt die Domainlogik und fragt die Elemente beim CustomerRepository nacht. Erst das CustomerRepository hat dann einen direkten Zugriff auf den LINQ 2 SharePoint Context.

In diesem Stadium kann das LINQ Query ohne weitere Bedenken eingesetzt werden. Doch LINQ 2 SharePoint hat noch ein paar weitere Interessante Aspekte.

 

Semi-Efficient-Queries

Die Feautres von LINQ wirken auf den ersten Blick schier unbegrenzt. Alles scheint möglich zu sein, sämtliche Aspekte, die man im Kontext der Datenabfrage oder Datenaggregation erwartet, bietet LINQ nun auch dem SharePoint Entwickler direkt auf der Basis von SharePoint Listen an.

Nun, so ganz stimmt dies nicht. LINQ 2 SharePoint fungiert als Wrapper um CAML und kann somit auf effiziente Weise nur die Abfragen und Aggregationen ausführen, welche auch nativ in CAML möglich sind.

Damit aber auch der SharePoint Entwickler Werte einer Gruppierung summieren, oder eine bestimmte Anzahl von Elementen aus der Ergebnismenge überspringen kann, gibt es in LINQ 2 SharePoint ein Konzept welches sich Semi-Efficient-Queries nennt.

Einfach erklärt bedeutet dies, das Abfragen in zwei Schritten ausgeführt werden, sobald sie eine von CAML nicht unterstützte Funktion beinhalten.

Eine genaue List der Methoden, die nicht nativ von CAML unterstützt werden findet ihr auf der MSDN (http://msdn.microsoft.com/en-us/library/ee536585.aspx).

 

Der RunWithElevatedPrivileges Bug

Wer kennt sie nicht, die RunWithElevatedPrivileges() Methode der Klasse SPSecurity? Dank dieser Methode ist es uns möglich direkt in einen anderen Benutzerkontext zu impersonieren.
Gerne wird hier der SharePoint Farm Kontext genommen, da dieser natürlich über weitgehende Rechte verfügt. Doch wenn man mit LINQ 2 SharePoint arbeitet, existiert hier noch ein Problem in der SharePoint API.

So führt dieses Script

 

clip_image012

nicht dazu, dass der linqContext im Kontext der Farm läuft.

Sofern dieser Code aus SharePoint selbst aufgerufen wird, ist linqContext immernoch im Kontext des ursprünglichen Benutzers und kann somit vielleicht nicht auf die gewünschten SharePoint Elemente zugreifen.

Die Ursache liegt wie bereits gesagt in der SharePoint API selbst, genauer gesagt in der Klasse SPServerDataConnection aus dem Namespace Microsoft.SharePoint.Linq.Provider.

clip_image014

Der Screenshot zeigt die Klasse im .NET Reflector. Hier ist zu sehen dass, falls der SPContext gefüllt ist, einfach dessen Werte (Current.Site, Current.Web) verwendet werden, unabhängig davon ob eventuell eine Impersonierung vorliegt.

Der zweite Fehler findet sich im If Statement welches der Variable defaultWeb zugewiesen wird.

Angenommen es wird impersoniert auf ein SPWeb, welches sich auf einer anderen SiteCollection befindet, so erhalten wir hier sogar eine FileNotFoundException zur Laufzeit, weil die API immer die SiteCollection aus dem SPContext als Grundlage nimmt.

 

Glücklicherweise lässt sich der Bug mit etwas Mehraufwand umfahren. Damit wir korrekt impersonieren können im Zusammenhang mit LINQ, muss der SPContext neu gesetzt werden. Da die Current Property von SPContext ReadOnly ist, muss zuerst der gesamte HttpContext gesichert! und überschrieben werden. Mit dem neuen HttpContext kann dank SPControl auch der SPContext neu initialisiert werden. Ganz wichtig ist es, nach der eigenen Logik den ursprünglichen Context wieder herzustellen (hier der finally Block)

 

clip_image016

 

 

Mein Fazit

Durch LINQ 2 SharePoint wird .NET Entwickler natürlich der Einstieg auf die SharePoint Plattform etwas einfacher gemacht und für den erfahrenen SharePoint Entwickler sind es sicherlich die qualitätssteigernden Aspekte wie StronglyTyped- und Compiled- Queries.

Dennoch ist es wichtig um die hier beschriebenen Probleme und Stolperfallen zu wissen, weil sonst der Zeitgewinn schnell aufgesogen wird.

Beachtet man jedoch diese einfachen Regeln, so kann LINQ 2 SharePoint euren Code sicherer, lesbarer und sicherlich auch einfacher machen, als es die großen CAML-String-Blöcke noch in SharePoint 2007 gemacht haben :)

 

Thorsten

Hinweis zum Kommentar

Zum Kommentieren der Beiträge (und damit zur Teilnahme am Gewinnspiel) bitte auf die Zahl in der Bubble neben dem Titel des Blogeintrags klicken, dies öffnet das Kommentarformular!

Sponsored by

Subscribe

Über

Der SharePoint Advent

Ein Gemeinschaftsprojekt der deutschsprachigen SharePoint MVP's

Rubriken

Impressum

(c) 2011 SharePointCommunity