SharePoint 2013 – Objekt auf der Website ausblenden (Suchfeld)

In SharePoint gibt es gelegentlich die Frage, wie lassen sich bei Bedarf Objekte auf einer Website ausblenden? Hier wird eine Vorgehensweise mit geringem Aufwand in wenigen Schritten beschrieben. Die Ausgangslage und Frage lautet, wie wird das Suchfeld auf einer Website ermittelt und anschließend unsichtbar gemacht? Mit JavaScript und indem die richtige ID des Elements angesprochen wird. Indem Sie die Seite im Entwicklermodus betrachten, lässt es sich schnell herausfinden. Drücken Sie die Taste F12 und wählen Sie, nachdem Sie (Ctrl+B) gedrückt haben mit der Maus die Suchleiste aus. Rufen Sie über das Menü Einstellungen -> Seite bearbeiten aus. Mit der Registerkarte Einfügen klicken Sie auf die letzte Schaltfläche Code einbetten. Im nächsten Schritt fügen Sie in das Dialogfenster Einbetten den etwas weiter untenstehenden Code wie abgebildet hinein. Der Code zum kopieren <script type="text/javascript"> document.getElementById("ctl00_PlaceHolderSearchArea_SmallSearchInputBox1_csr_sboxdiv").style.display = "none"; </script> Nachdem die Seite gespeichert worden ist sieht das Ergebnis wie gewünscht aus, die Suchleiste fehlt. Viel Spaß damit

Sharepoint 2016–MinRoles


Andreas Rauch

Seit Sharepoint Server 2007 präsentiert sich die Installation immer auf die gleiche Weise. Gerade ma [Mehr]

Eigene Text-Styles im WIKI Editor von SharePoint

Der Wiki-Editor von SharePoint ermöglicht das einfache Erstellen von Dokumentationen und Erklärungen [Mehr]

In SharePoint eine Spaltenüberschrift ausblenden

Über die View Einstellungen kann in SharePoint leicht eine Spalte ausgeblendet werden. Möchte man aber nur gezielt eine Spaltenüberschrift ausblenden, fehlen die Einstellungen. Allerdings ist das leicht mit ein wenig JavaScript Code zu erledigen. Zunächst müssen wir uns den Aufbau der HTML Seite ansehen. Am einfachsten ist die mit den Developertools von Google Chrome zu erledigen. Einfach die Seite im Browser laden und danach F12 drücken. Im rechten Bereich des Chrome-Fensters werden nun die Developer Tools eingeblendet, die einen “Selector” für ein HTML Element haben. (links oben im Developer Tool Fenster)   Wählt man den Selector an, kann nun mit dem Cursor ein Element innerhalb der HTML Seite ausgewählt werden. Ich möchte in diesem Beispiel die “Company” Spaltenüberschrift ausblenden. Also wähle ich die auch aus: Sobald mit diesem Tool das Element ausgewählt wurde, erscheint im Developer Tools Fenster der entsprechende HTML Code. In diesem können wir erkennen, dass die Spaltenüberschrift als <DIV> Element mit dem Namen “Company” angelegt wurde: Nachdem wir diese Informationen zusammengetragen haben, können wir das JavaScript schreiben. Wir werden die Visibility dieses DIV-Elementes auf “hidden” setzen. Der Befehl dafür: document.getElementsByName("Company")[0].style.visibility="hidden"; Die JavaScript Funktion “getElementsByName” liefert eine Collection, aller Elemente mit dem Namen “Company”. Das erste gefundene, ist das richtige DIV Element und von diesem setzen wir die “Visibility”. Allerdings dürfen wir den Befehl erst ausführen nachdem die gesamte Seite in den Browser geladen wurde. In JQuery gibt es eine Document-Ready Funktion. Wenn man jedoch innerhalb einer SharePoint Seite ist, sollte die SharePoint Funktion “_spBodyOnLoadFunctionNames” verwendet werden: _spBodyOnLoadFunctionNames.push("hideColumn"); mit dieser werden JavaScript Funktionen zu einer Aufrufliste hinzugefügt. Alle in der Liste befindlichen Funktionen werden aufgerufen, sobald die Seite fertig geladen ist. Das gesamte Script sieht dann so aus: 1 <script type="text/javascript"> 2 _spBodyOnLoadFunctionNames.push("hideColumn"); 3 function hideColumn(){ 4 document.getElementsByName("Company")[0].style.visibility="hidden"; 5 } 6 </script>   Dieses Script müssen wir nun, ohne den Zeilennummern, in die Seite einbetten, in der die Spaltenüberschriften ausgeblendet werden sollen. SharePoint bietet mit dem “Script Editor”- Webpart eine einfache Möglichkeit um Scripts in eine Seite einzubetten. Das Webpart finden sie im Bereich “Media and Content”. Fügen Sie dieses Webpart wie jedes andere in die Seite ein: Sobald das WebPart eingefügt wurde, finden sie den Link “EDIT SNIPPET”. Wenn sie darauf klicken erscheint ein Editor, in den sie das Script einfügen: Nachdem Sie die Seite gespeichert haben, wird nun bei jedem Laden der Seite das Script ausgeführt und das DIV Element mit dem Namen “Company” ausgeblendet. Das Ergebnis sieht nun wie folgt aus:

WebAPI Service mit SharePoint User Authentifizierung

Ziel ist es ein WebAPI Service zu erstellen welches Daten von SharePoint zurückliefern soll. Dieses Service wird von einer App konsumiert, daher ist eine OAuth Authentifizierung notwendig und der User soll seine von der SharePoint Umgebung gewohnten Credentials (Benutzername/Passwort) für die Authentifizierung nutzen. Aber der SharePoint-Server selbst darf nicht von außerhalb der Firmennetzes angesprochen werden. Projektsetup Wir starten zunächst mit einem simplen Web-Projekt wobei wir WebAPI auswählen und darauf achten keine Authentifizierung auszuwählen. Diese werden wir gleich manuell einfügen. Im nächsten Schritt müssen nun einige Nuget Packages installiert. Über die “Package Manager Console” ist das schnell erledigt. Wir benötigen zunächst OWin. Die Befehle dafür: Install-Package Microsoft.AspNet.WebApi.Owin Install-Package Microsoft.Owin.Host.SystemWeb Weiters benötigen wir von OWin das Identity System und da wir OAuth verwenden wollen auch das OAuth Modul: install-package Microsoft.AspNet.Identity.Owin Install-package microsoft.Owin.Security Install-Package Microsoft.Owin.Security.OAuth Das Webservice soll später von JavaScript Code aufgerufen werden, der nicht in der selben Domain wie das WebAPI Service liegt. Unser WebService soll also CORS (Cross-origin resource sharing) unterstützen. Zum Glück gibt es auch hierfür bereits eine fertige OWin Implementierung. Also fügen wir noch ein NuGetPackage hinzu: Install-Package Microsoft.Owin.Cors Implementierung Nun geht es ans Coden. Wir müssen zunächst eine OWin Startup Klasse hinzufügen. Die Startup Klasse nenne ich Startup. Im Visual Studio gibt es eine Vorlage für Startup Klasse. Im Bereich Web finden wir das “OWIN Startup class”-Template. Die Klasse selbst ist einfach. Wichtig ist das OWinStartup Attribut welches für das Assembly gesetzt wird. Die Methode die wir implementieren müssen ist Configuration(IAppBuilder app) OAuth Konfiguration Um es etwas übersichtlicher zu gestalten habe ich die Konfiguration für OAuth in die Methode ConfigureOAuth(IAppBuilder app) ausgelagert. 1 private void ConfigureOAuth(IAppBuilder app) 2 { 3 OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 4 { 5 AllowInsecureHttp = true, 6 TokenEndpointPath = new PathString("/token"), 7 AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 8 Provider = new SharePointAuthorizationServerProvider() 9 }; 10 11 // Token Generation 12 app.UseOAuthAuthorizationServer(OAuthServerOptions); 13 app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 14 15 } In Zeile 5 wird definiert, dass OAuth auch über http zulässig ist. Im Produktivbetrieb muss diese Zeile raus oder mit false geschrieben werden. Wir wollen in der “freien Wildbahn” OAuth nur über https zulassen. Zeile 6 definiert den Pfad wie der Client zu einem Accesstoken kommt. Und in Zeile 7 wird die Gültigkeitsdauer des Tokens gesetzt. In Zeile 8 definieren wir welcher AuthorizationProvider verwendet werden soll. Diese Klasse gibt es noch nicht. Wir werden diese aber bald implementieren. Die eigentliche Configure Methode sieht so aus: 1 public void Configuration(IAppBuilder app) 2 { 3 ConfigureOAuth(app); 4 5 HttpConfiguration config = new HttpConfiguration(); 6 WebApiConfig.Register(config); 7 app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 8 app.UseWebApi(config); 9 } Zunächst rufen wir die OAuth Konfigurationsmethode (von oben) auf und setzen dann die HttpConfiguration. Da wir CORS verwenden wollen, kommt der Aufruf in Zeile 7 dazu. AuthorizationProvider-Klasse Im letzten Schritt müssen wir die Klasse “SharePointAuthorizationServerProvider” implementieren. Diese Klasse erbt von OAuthAuthorizationServerProvider und wir überschreiben zwei Methoden. ValidateClientAuthentication und GrantRessourceOwnerCredentials Die erste Methode bedarf keiner Erklärung. 1 public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 2 { 3 context.Validated(); 4 } In der zweiten Methode überprüfen wir Benutzername und Passwort. Diese ist schon etwas länger: 1 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 2 { 3 context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 4 // SharePoint... 5 using (ClientContext ctx = new ClientContext("http://SP/")) 6 { 7 ctx.Credentials = new NetworkCredential(context.UserName, context.Password); 8 var u = ctx.Web.CurrentUser; 9 ctx.Load(u, _ => _.Title); 10 try 11 { 12 ctx.ExecuteQuery(); 13 var identity = new ClaimsIdentity(context.Options.AuthenticationType); 14 identity.AddClaim(new Claim("user", u.Title)); 15 identity.AddClaim(new Claim("login", EncryptionHelper.Encrypt(context.UserName))); 16 identity.AddClaim(new Claim("pw", EncryptionHelper.Encrypt(context.Password))); 17 context.Validated(identity); 18 } 19 catch 20 { 21 string error = "u:{0} p:{1}"; 22 context.SetError("invalid_grant", string.Format(error, "Invalid UserName or Password")); 23 } 24 } 25 } In Zeile 3 fügen wir in den Response einen Header ein, um Aufrufe von anderen Domains zuzulassen. ab Zeile 5 verwenden wir das CSOM für SharePoint um einen Zugriff auf SharePoint durchzuführen. in Zeile 7 werden neue Networkcredentials gebildet. Dafür wird aus dem Context UserName und Passwort verwendet. Diese beiden Werte müssen bei Abruf des Tokens mitgegeben werden. In weiteren Aufrufen wird uns das AccessToken übergeben. Möchten wir später wieder auf SharePoint zugreifen müssen wir wieder den ClientContext mit NetworkCredentials bilden und benötigen daher später auch die Informationen UserName und Passwort. Da ich nichts serverseitig speichern möchte und auch Cookies ausfallen, legen ich beide Infos im AccessToken als Claims ab. (Zeile 15 und 16). Da der AccessToken aber nicht verschlüsselt ist, übernimmt das eine Hilfsklasse (EncryptionHelper) für mich und die Credentials für SharePoint werden verschlüsselt als Claims abgelegt um später wieder zur Verfügung zu stehen. Claims auslesen Um in einem ValueController wieder auf SharePoint zugreifen zu können müssen wieder UserName und Passwort aus den Claims ermittelt werden. Dafür habe ich mir eine Hilfsfunktion geschrieben, die einen ClientContext für SharePoint zurückliefert: 1 public class SharePointContextHelper 2 { 3 public static ClientContext GetClientContextForCurrentPrincipal() 4 { 5 var identity = (ClaimsPrincipal)Thread.CurrentPrincipal; 6 var claims = identity.Claims; 7 var login = EncryptionHelper.Decrypt(claims.FirstOrDefault(c => c.Type == "login").Value); 8 var pw = EncryptionHelper.Decrypt(claims.FirstOrDefault(c => c.Type == "pw").Value); 9 10 ClientContext ctx = new ClientContext("http://sp/"); 11 ctx.Credentials = new NetworkCredential(login, pw); 12 return ctx; 13 14 } 15 } Der CurrentPrincipal des Threads ist ein ClaimsPrincipial und diesen können wir nutzen um wieder die Claims des angemeldeten Benutzers zu lesen. In der Funktion werden die Claims für Passwort (pw) und Username (login) ausgelesen und mit Hilfe des EncryptionHelper wieder entschlüsselt. Testen Ein Accesstoken kann mittels POST Request auf /Token (Haben wir in der Konfiguration so festgelegt) abgerufen werden. Es müssen als x-www-form-urlencoded Parameter die Werte für username, password und grant_type übergeben werden. Ich verwende zum Testen das Tool “Postman” da damit leicht alle Arten von Requests erstellt werden können. Wenn dieser Request ausgeführt wird, erhalten wir im Response den AccessToken. Diesen verwenden wir gleich im nächsten Request, daher empfiehlt es sich diesen in die Zwischenablage zu kopieren. Um Daten vom WebAPI abzurufen muss nun der entsprechende Controller aufgerufen werden. Beim Aufruf ist im Authorization-Header mitzugeben. In diesem muss “Bearer” gefolgt von einem Leerzeichen und dann das Access-Token übergeben werden. Und nun können wir auf SharePoint Dateizugreifen, ohne SharePoint nach Außen zu veröffentlichen und die User melden sich dennoch mit ihren gewohnten Credentials an.

App Development mit SharePoint 2016

Nachdem nun die Preview zu SharePoint2016 erschienen ist, mache ich mich gleich daran App zu entwickeln. Wie schon in der letzten Version kann man nicht gleich loslegen, sondern muss zuerst die Farm vorbereiten. Für meinen ersten Test habe ich beim Setup eine “Single-Server-Farm” gewählt. In der Übersicht “Servers in Farm” ist zu sehen, dass die  Dienste “App Management Service”, “Foundation Subscription Settings Service” und “User Profile Service” bereits laufen: Möchte man nun die App URLs konfigurieren kommt die Fehlermeldung: “The Subscription Settings service and corresponding application and proxy needs to be running in order to make changes to these settings. “ Um das Subscription Setting Service und den Proxy dazu anzulegen, verwende ich folgendes Powershell Script: 1 $account = Get-SPManagedAccount "AD\SP_APP" 2 3 $appPoolSubSvc = New-SPServiceApplicationPool -Name "SettingServiceAppPool" -Account $account 4 $appSubSvc = New-SPSubscriptionSettingsServiceApplication –ApplicationPool $appPoolSubSvc –Name "SettingsServiceApp" –DatabaseName "SettingsServiceDB" 5 $proxySubSvc = New-SPSubscriptionSettingsServiceApplicationProxy –ServiceApplication $appSubSvc 6   DNS-Konfiguration Nun muss im DNS eine Forward-Lookup zone eingetragen Diese wird in der Centraladministration als App-Domain eingetragen. In dieser Zone ist ein Wildcard-Alias anzulegen der auf den SharePoint-Server zeigt. Nun kann in der Zentraladministration “sp16apps.grobl.local” als App-Domain eingetragen werden. Das AppPrefix kann beliebig gewählt werden. Einfache SharePoint-hosted Apps können nun entwickelt werden. Provider Hosted Provider Hosted, oder auch High Trust Apps werden mit Zertifikaten abgesichert. Daher müssen wir ein Zertifikat ausstellen. Das kann auch ein Selbssigniertes sein.  Das Zertifikat (die .cer-Datei) wird im SharePoint Server eingespielt. Der Private-Key (.pfx-Datei) muss dann bei dem App-Projekt angegeben werden. Einspielen am Sharepoint2016 mit folgendem PS-Script kann das Zertifikat am SharePoint Server eingespielt werden: 1 $publicCertPath = "C:\certificates\sp16apps.cer" 2 $issuerId = [GUID]"00000000-0000-0000-0000-000000000000" 3 $spurl = "http://sp16" 4 $spweb = Get-SPWeb $spurl 5 $realm = Get-SPAuthenticationRealm -ServiceContext $spweb.Site 6 $certificate = Get-PfxCertificate $publicCertPath 7 New-SPTrustedRootAuthority -Name "sp16Apps" -Certificate $certificate 8 $fullIssuerIdentifier = $issuerId.ToString() + "@" +$realm 9 New-SPTrustedSecurityTokenIssuer -Name $issuerId -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier -IsTrustBroker 10 11 Da der issuer-ID beim Anlegen eine SP APP Projektes abgefragt wird, habe ich einen gewählt der leicht zu merken ist. Im Produktivumfeld ist hier ein neuer GUID zu erstellen. Da ich die Apps nur in einer http und nicht https-Umgebung entwickle, muss die SP Farm noch konfiguriert werden um OAuth über http zuzulassen: 1 $serviceConfig = Get-SPSecurityTokenServiceConfig 2 $serviceConfig.AllowOAuthOverHttp = $true 3 $serviceConfig.Update() Das Visual Studio Projekt Nun können wir beginnen, im VS Apps für SharePoint zu entwickeln. Bei der Anlage des Projektes müssen wir die “Authentication Settings” konfigurieren. An dieser Stelle ist der Private Key und der Issuer ID anzugeben:

Promise – Versprechen für TypeScript

Wenn immer ich etwas mit SharePoint programmiere versuche ich es in TypeScript zu schreiben. Mir gefällt das Konzept von Klassen und Vererbung und das möchte ich auch in der JavaScript Welt nicht missen. Was jedoch bleibt ist die Asynchronität des Client Objekt Models. Die vielen Callback-Funktionen machen den Code doch recht unübersichtlich und das ist auch mit Klassen nicht gut zu lösen. Vor kurzem bin ich über das Promise Framework für Typescript gestoßen. Es ist leicht über NuGet zu installieren (https://www.nuget.org/packages/Promise.TypeScript/1.0.0-rc) Die Idee ist, dass eine Funktion nicht den Rückgabewert zurückliefert sondern ein “Versprechen” einen bestimmten Wert für einen Datentyp zu einem späteren Zeitpunkt zur Verfügung zu stellen. In meinem BSP habe ich eine Klasse angelegt um Listen im SharePoint Host Web anzulegen. Die gesamte Funktionalität ist in der Klasse gekapselt. Der Code der nun von auszuführen ist um eine Liste anzulegen sieht so aus: 1 function ListeAnlegen() { 2 var ctl = new ListHandler(); 3 var cth = new ContentTypeHandler(); 4 var name = $('#txtCTname').val(); 5 6 showWarten(); 7 cth.GetWebContentTypeByName("ppStandorte"). 8 done(ct => { 9 ctl.AddListToWeb(SPContextHelper.HostCTX().get_web(), name, ct) 10 .done((liste: SP.List) => { }) 11 .fail(err => { alert(err.message) }) 12 .always(() => { hideWarten() }); 13 }); 14 }   Den Zugriff auf das Hostweb habe ich ebenfalls gekapselt. Die Methode HostCTXC() stellt einen AppSiteContext ins Hostweb zur Verfügung. Die Methode AddListToWeb erwartet das Web, einen Listennamen und einen Contenttype der zur Liste hinzugefügt werden soll. Den Aufruf sieht man in Zeile 9. Danach folgt gleich die Verwendung von Promise. in Zeile 10 kommt ein Eventhandler für Done und wird aufgerufen, sobald im dem Promise die Daten bereitstehen. Sollte es zu einem Fehler kommen wird in Zeile 11 eine Eventhandler für Fail hinterlegt und zuletzt kann mit .always ein Eventhandler angelegt werden, der immer aufgerufen wird. Das macht den Code deutlich lesbarer und übersichtlicher. Jetzt stellt sich nur noch die Frage wie ist die Methode AddListToWeb zu implementieren ist: 1 class ListHandler { 2 /// Legt eine Liste an und setzt den CT in die List 3 AddListToWeb(web: SP.Web, ListName: string, ContentType: SP.ContentType) : P.Promise<SP.List> { 4 var ret: P.Deferred<SP.List> = P.defer<SP.List>(); 5 6 this.Exists(ListName).done((erg) => { 7 if (erg == true) 8 { 9 alert('exits'); 10 ret.resolve(null); 11 } 12 else { 13 var lci: SP.ListCreationInformation = new SP.ListCreationInformation(); 14 lci.set_title(ListName); 15 lci.set_templateType(SP.ListTemplateType.genericList); 16 lci.set_quickLaunchOption(SP.QuickLaunchOptions.on); 17 var liste: SP.List = web.get_lists().add(lci); 18 19 liste.get_contentTypes().addExistingContentType(ContentType); 20 var ctx: SP.AppContextSite = SPContextHelper.HostCTX(); 21 22 SPContextHelper.AppCTX().executeQueryAsync( 23 () => { 24 ret.resolve(liste); 25 }, 26 () => { 27 ret.reject({message:'Liste existiert bereits'}); 28 }); 29 } 30 }); 31 32 return ret.promise(); 33 } 34 } Zunächst sieht man, dass die Methode ein Objekt vom Typ P.Promise<> zurückgibt. Hier werden Generics verwendet, daher definiert meine Methode dass der Datentype der im Promise enthalten sein wird ein Objekt vom Typ SP.List sein wird. In Zeile 4 wird das leere Rückgabe-Element definiert. Dieses ist vom Typ Deferred<SP.List>. In Zeile 32 wird dann das entsprechende Promise Objekt zurückgegeben. Nun hat die Methode auch einen korrekten Rückgabewert. Nur wird dieses Objekt noch keinen Inhalt haben. Innerhalb der Methode wird mit dem CSOM die Liste angelegt und in Zeile 24, wird mit der Methode res.resolve() ein Datenobjekt in das Promise geladen. Dieses steht dann im Aufruf der .Done() Methode zur Verfügung. (vgl Zeile 10 vom ersten Listing) Mit der Methode .Reject kann ein Fehler gemeldet werden. Beim Aufruf wird die Methode .fail() ausgeführt. Im Reject kann noch ein weiteres Objekt übergeben werden welches beim Fail ausgelesen werden kann (Zeile 11 im ersten Listing) Diese Code ist nur ein kleiner Ausschnitt eines größeren Projektes um das Remote Provisioning zu demonstrieren. Das gesamte Projekt mit ausführlichen Erklärungen zeige ich auf der SharePoint konferenz am 17 und 18. Juni in Wien.

Visual Studio User Group Wien– Unterlagen

Danke für die Teilnahme am Usergroup Meeting in Wien gestern Abend (23.4.2015) Wie versprochen die Linksammlung: Präsentation: http://1drv.ms/1JjpvV3 ChromeControl: http://blog.ppedv.de/post/2013/06/21/ChromeControl-in-Provider-Hosted-App-einbinden.aspx Cross Domain Lib: http://blog.ppedv.de/post/2013/08/29/SharePoint-2013-App-Zugriff-auf-das-HostWeb-mittels-Javascript.aspx Konfiguration für Apps: http://blog.ppedv.de/post/2013/10/29/sharepoint-2013-server-fur-app-development-vorbereiten.aspx

Call4Papers – SharePoint konferenz Wien

Auch dieses Jahr findet wieder die SharePoint konferenz in Wien statt. Heuer wird sie vom 17.-18. Juni 2015 in der Pyramide Vösendorf über die Bühne gehen. In unserer mobilen Welt ändert sich auch die Arbeitsweise in Unternehmen. Tools wir SharePoint, Lync, Exchange, Office 365 unterstützen Firmen dabei ihren Mitarbeitern neue Arbeitsmethoden zu ermöglichen. Daher ist das heurige Motto: New Way Of Work   Die Konferenz wird in die Bereiche Business, IT Pro und Development untergliedert. Ich freue mich über Sessionvorschläge die zum Motto der Konferenz und in einen der drei Bereiche passen.  Tools wie Lync, Exchange, O365 aber auch Hyper-V sind heuer gerne gesehen. Bitte die Vorschläge mit Titel, Abstract, Level (100-400) und Angabe des Bereichs an marting@ppedv.de schicken. Der Abgabetermin ist der 20.4.

mit TypeScript strukturierten CSOM Code schreiben

TypeScript bietet Möglichkeiten um JavaScript Code in Klassen und Module strukturieren. Natürlich kann eine SharePoint Hosted App in SharePoint 2013 auch mit TypeScript erstellt werden (siehe Blog) Ich habe mir mal Gedanken gemacht, wie ich die üblichen CSOM Aufrufe in Klassen verpacken kann um das ganze etwas strukturierter im Code darzustellen. Ein üblicher CSOM Aufruf kann so aussehen: 1 var ctx: SP.ClientContext = SP.ClientContext.get_current(); 2 var user: SP.User = ctx.get_web().get_currentUser(); 3 ctx.load(user, 'Title'); 4 ctx.executeQueryAsync( 5 () => { 6 $('#message').text(user.get_title()); 7 }, 8 () => { });   Üblicherweise benötigt man den ClientContext, führt einzelne Arbeitsschritte am Context aus und wartet dann auf den Rückruf der executeQueryAsync-Methode. Meistens lasse ich mir im Failure-Callback noch die Fehlermeldung ausgeben. Meine Idee ist nun, diese wiederkehrenden Schritte in eine Basis-Klasse zu verpacken und die konkreten Aufgaben in abgeleitete Klassen zu schreiben. Ich definiere somit die Klasse “Job”: 1 class job { 2 protected ctx: SP.ClientContext = SP.ClientContext.get_current(); 3 public success: (sender : any, args: SP.ClientRequestSucceededEventArgs) => void; 4 5 public errorCallback: (sender: any, args: SP.ClientRequestFailedEventArgs) => any = 6 (sender, args) => { 7 alert(args.get_message()); 8 }; 9 10 doIt() { 11 this.work(); 12 this.ctx.executeQueryAsync(this.success,this.errorCallback); 13 } 14 15 work() { 16 } 17 }   In der Klasse werden die beiden Rückruf-Funktionen als Member der Klasse definiert. Wir finden success und errorCallback. Die errorCallback-Methode wird gleich mal mit einer Alert-Box versehen die die Fehlermeldung ausgibt. Die Success Methode bleibt zunächst leer. Mein erster Versuch sah vor, diese Methoden in den abgeleiteten Klassen zu überschreiben. Leider funktioniert das nicht, da wie in JavaScript üblich, in der CallBack Methode “this” nicht auf die Klasseninstanz zeigt. (Spaß mit this) Daher der Weg, die Methode als Properties zu definieren und später im Constructor die Methoden zuweisen. Wenn ich nun das Beispiel von oben mit meinem Job programmieren möchte, so ist eine abgeleitete Klasse “getUserNameJob” zu erstellen. In dieser Klasse muss im Constructor die “Work” und die “Success” Methode definiert werden. Um das Resultat an den Aufrufer zurück zu geben wird ein “jobCallback” definiert der dann vom Aufrufer zu übergeben ist. 1 class getUserNameJob extends job { 2 public jobCallback: (userName: string) => any; 3 4 private user: SP.User; 5 6 constructor() { 7 super(); 8 9 this.work = () => { 10 this.user =this.ctx.get_web().get_currentUser(); 11 this.ctx.load(this.user, 'Title'); 12 }; 13 14 this.success = (sender, args) => { 15 var str = this.user.get_title(); 16 this.jobCallback(this.user.get_title()); 17 } 18 } 19 } Um diesen Job nun zu verwenden wird eine Instanz gebildet, dem Callback eine Methode zugewiesen und die “doIt()” Methode aufgerufen: 1 var j: getUserNameJob = new getUserNameJob(); 2 j.jobCallback = (userName) => { 3 $('#message').text(userName); 4 }; 5 j.doIt(); Von diesem Basisgerüst ausgehend können nun diverse spezialisierte JobKlassen gebildet werden. Z.B. das Auslesen von ListItems oder auch der Zugriff auf das HostWeb kann so in handliche Basis-Klassen verpackt werden. Ein detailliertes Demo hierzu zeige ich auf der SharePoint Konferenz in Erding (10.-11.3.2015) in der Session “TypeScript – typisiertes JavaScript”