code it

Martins Tech Blog

SharePoint Dispose Checker Tool veröffentlicht

Das schon länger angekündigte SharePoint Dispose Checker Tool wurde heute von Microsoft veröffentlicht. Dieses Tool prüft den Code daraufhin, ob für alle SharePoint-Objekte korrekt Dispose-Methode aufgerufen wurde. Unabhängig davon, dass dies als Best Practice gilt, wissen SharePoint-Entwickler, dass diese Methode in den meisten Fällen aufgerufen werden muss, um sicherzustellen, dass es zu keinen ungewollten Nebenwirkungen kommt.

InvalidOperationException in First()-Methode vermeiden

In einigen meiner Linq-Anweisungen hab in der Vergangenheit die First()-Methode verwendet, um sicherzugehen, dass ich genau ein Element zurückbekomme - analog zu TOP 1 in SQL. Allerdings hab ich lernen müssen, dass Linq zwar so ähnlich aussieht und so ähnlich funktioniert, aber eben doch nicht gleichzusetzen ist. Die genannte Methode verhält sich nämlich unterschidlich zu ihrem SQL-Pendant. Gibt es gar keine Datensätze, die den Kriterien entsprechen, gibt SQL auch keine Datensätze zurück. Linq hingegen wirft eine InvalidOperationException, wo ich mir null erhofft hätte: 

Die Lösung in diesem Fall ist, dass nicht First() verwendet wird, sondern FirstOrDefault(). Da der Standardwert eines Objekts null ist, bekomm ich nun auch ohne Exception null zurückgegeben: 

Unauthorized Access bei anonymem Zugriff im SharePoint

Heute bin ich über ein sehr interessantes Phänomen in Zusammenhang mit anonymem Zugriff im SharePoint gestoßen. Die Einrichtung von anonymen Bereichen ist recht einfach. Bil Simser hat dazu beispielweise in seinem Blog eine schöne Anleitung geschrieben.

Nachdem ich den anonymen Zugriff allerdings auf diese Art und weise eingerichtet hatte, bekam ich beim Klick auf den Link statt meines eben eingerichteten Portals eine sehr spartanische weiße Seite mit der Information "401 Unauthorized Access".

Was war passiert? Bei der Einrichtung der Sitecollection wurde die Masterpage nochmal angepasst. Dabei wurde zwar darauf geachtet, dass die Änderungen eingecheckt wurden, aber die letzte Version wurde nicht veröffentlicht und genehmigt. Über das gleiche Problem ist auch Michael schon gestolpert - mit dem gleichen Lösungsansatz.

Ich hätte zumindest erwartet, dass SharePoint dann den letzten veröffentlichten Stand anzeigt. Aber es ist leider nicht an dem.

SharePoint "richtig" lizenzieren

Nicht immer ist es einfach, herauszufinden, welches Lizenzierungsmodell gerade vorliegt, wenn man in SharePoint-Projekten ein bestimmtes Architektur-Szenario entwickelt.

Heute bin ich über eine interessante Blogreihe von Fabian gestolpert, der sich dieses Themas annimmt:

SharePoint "richtig" lizenzieren (Teil 1) 
SharePoint "richtig" lizenzieren (Teil 2)

Aufgrund unterschiedlicher Lizenzprogramme von Microsoft, kann das natürlich nur eine grobe Richtlinie sein, aber es hilft, um einen Überblick zu bekommen.

back to basics: Geschweifte Klammern in string.Format

Geschweifte Klammern verwendet man in string.Format, um Parameter in Strings unterzubringen und diese ggf. noch zu formatieren. Den meisten sollten Ausdrücke wie dieser bekannt vorkommen:

int i = 23;
string s = string.Format("{0}", i); // Ergebnis: "23"

Wie geht man nun vor, wenn man wirklich einmal geschweifte Klammern ausgeben möchte? Die Escapesequenz für geschweifte Klammern sind 2 geschweifte Klammern:

int i = 23;
string s = string.Format("{{{0}}}", i); // Ergebnis: "{23}"..

So weit ist das alles ganz einfach. Interessant wird es, wenn man den Ausdruck etwas komplexer gestaltet und Formatoptionen verwendet:

int i = 23;
string s = string.Format("{0:N}", i); // Ergebnis: "23.00"

int i = 23;
string s = string.Format("{{{0:N}}}", i); // Ergebnis: "{N}"

Das erste Beispiel erschließt sich von selbst. Mittels "N" wird spezifiziert, dass es sich um eine Zahl handelt, die in Standardformatierung angezeigt wird. Warum aber klappt es im zweiten Beispiel nicht, um diese Zahl geschweifte Klammern zu setzen?

Dazu muss man sich anschauen, wie string.Format vorgeht: Wird ein Format angegeben, wird zunächst geprüft, ob die Formatzeichenfolge länger als ein Zeichen ist. Ist das der Fall, geht die Methode davon aus, dass es sich um eine benutzerdefinierte Formatzeichenfolge handelt. Dabei wird versucht, diese bestmöglich zu interpretieren und Ersetzungen vorzunehmen. Kann ein Zeichen nicht interpretiert werden, wird es einfach ausgedruckt. Wird eine Formatzeichenfolge mit einer Länge von 1 Zeichen angegeben (wie P für Prozent- oder N für Zahlenformatierung), wird die Zeichenfolge entsprechend formatiert oder - wenn ein unbekanntes Zeichen übergeben wird - eine ArgumentException geworfen.

Beim Versuch, geschweifte Klammern zu ersetzen, geht die Methode in Reihenfolge der Vorkommen vor.

Gerüstet mit diesen Informationen können wir uns das zweite Beispiel nochmal näher anschauen: Die ersten beiden Zeichen werden zu "{" ersetzt. Die dritte geschweifte Klammer zeigt an, dass hier die Formatzeichenfolge beginnt. Die ersten beiden schließenden geschweiften Klammern werden wieder durch "}" ersetzt und die letzte schließende Klammer zeigt an, dass die Formatzeichenfolge hier endet. Damit bleibt folgender Ausdruck übrig "{0:N}}", wobei "N}" die Formatzeichenfolge ist. Da es sich hier um mehr als 1 Zeichen handelt, wird nun von einem benutzerdefinierten Format ausgegangen - und dort haben weder "N" noch "}" eine besondere Bedeutung. Daher werden diese beiden Zeichen ausgedruckt. Zusammen mit der schon anfangs ersetzten "{" kommt das Ergebnis "{N}" zustande.

Um das Ganze an einem einfacheren Beispiel ohne Escapesequenz zu verdeutlichen:

int i = 23;
string s = string.Format("{0:N*}", i); // Ergebnis: "N*"

Auch hierbei handelt es sich um ein benutzerdefiniertes Format, dass nicht interpretiert werden kann und deshalb ausgegeben wird.

Treffen der .NET Usergroup Dresden

Am 04.02.2009 18:00 findet das nächste Treffen der .NET Usergroup Dresden in der HTW statt.

Bisher geplante Themen:

  • Ist ADO.NET EntityFramework das bessere LINQ? von Robert Meyer(Visual World)
  • (Keine) Zeit für Herzrasen! von Torsten Weber (MVP für Device Application Development)
  • Mobile Computing Einführung von Torsten Weber (MVP für Device Application Development)

Weitere Infos auf der Homepage der .NET Usergroup Dresden.

Wo sind meine Code Coverage-Ergebnisse?

Unittests find ich ja auch eine sehr sinnvolle Möglichkeit, die Qualität des eigenen Codes sicherzustellen und Probleme schon recht frühzeitig zu merken. Nun wollte ich heute mal schauen, wie hoch eigentlich meine Code Coverage ist und was muss ich da sehen? Code Coverage ist nicht verfügbar - oder wie es Visual Studio ausdrückt: "Code coverage is not enabled for this test run."....

Ein wenig Suche in der Konfiguration bringen die Ursache zu Tage: Unter "Tests" -> "Edit Test Run Configurations" -> "Local Test Run" ist einfach nichts angehakt gewesen. Offenbar ist die Code Coverage-Berechnung im Standard deaktiviert und muss erst explizit aktiviert werden.

Kleiner Haken - große Wirkung:

Direkt im Anschluss daran stolperte ich auch gleich über das nächste Problem: "Empty results generated: none of the instrumented binary was used. Look at the test run details for any instrumentation problems."

Wie vorgeschlagen, werf ich einen Blick in die Details. Dort steht aber nicht wirklich etwas, das mir weiterhelfen würde. Aber dann fällt es mir ein: In meinen PostBuild-Events installiere ich meine DLL gleich in den GAC. Vermutlich wird versucht, die DLL von dort zu laden und zu prüfen. Und siehe da: Nachdem ich meine Komponente aus dem GAC deinstalliert hab, bekomm ich wieder Ergebnisse angezeigt.

The power of WPSC

Heute bin ich über einen interessanten Blogeintrag von Woody Windischman zum Thema Web Part Page Service Component (WPSC) gestolpert.

Die JavaScript-Funktionen von WPSC erlauben es Webparts, untereinander, mit SharePoint und mit dem Benutzer zu interagieren. Im oben genannten Eintrag integriert er eine Online-Hilfe für Webpartseiten in einem SharePoint-Wiki und bindet diese mittels F1-Tastendruck an.

Ich hab das Ganze gleich mal ausprobiert... Und was soll ich sagen?... Es funktioniert und zeigt Möglichkeiten dieser Technologie auf.

Kleiner Tipp aus den Kommentaren zum oben genannten Post: Damit sich nicht parallel zum eigenen Hilfetext auch die browsereigene Hilfe öffnet, muss die Callback-JavaScript-Funktion mit "return false;" enden.

Entdeckungstour im SQL-Server 2008 (Teil 5) - der Geography-Datentyp

In meinem letzten Eintrag ging es um den Geometry-Datentyp. Leider ist die Erde seit einigen hundert Jahren nicht mehr flach, sondern kugelförmig und das stellt uns vor das Problem, dass man hier mit einem rein geometrischen Datentyp nicht sehr weit kommt. Aus diesem Grund ist hier ein weiterer Datentyp notwendig, der die Krümmung der Erde berücksichtigt und Positionsangaben in Längen- und Breitengraden verarbeiten kann - der Geography-Datentyp.

Wie schon vom Geometry-Datentyp bekannt, kann ein Objekt mittels der statischen Methode STGeomFromText erzeugt werden. Allerdings spielt hier die dort recht unwichtige SRID hier eine wesentliche Rolle. Sie definiert, anhand welchen Standards Berechnungen durchgeführt werden. In der MSDN findet man zum Thema folgendes:

geometry Instances Default to Zero SRID
The default SRID for geometry instances in SQL Server is 0. With geometry spatial data, the specific SRID of the spatial instance is not required to perform calculations; thus, instances can reside in undefined planar space. To indicate undefined planar space in the calculations of geometry data type methods, the SQL Server Database Engine uses SRID 0.

geography Instances Must Use Supported SRID

SQL Server supports SRIDs based on the EPSG standards. A SQL Server-supported SRID for geography instances must be used when performing calculations or using methods with geography spatial data. The SRID must match one of the SRIDs displayed in the sys.spatial_reference_systems catalog view. As mentioned previously, when you perform calculations on your spatial data using the geography data type, your results will depend on which ellipsoid was used in the creation of your data, as each ellipsoid is assigned a specific spatial reference identifier (SRID).

SQL Server uses the default SRID of 4326, which maps to the WGS 84 spatial reference system, when using methods on geography instances. If you use data from a spatial reference system other than WGS 84 (or SRID 4326), you will need to determine the specific SRID for your geography spatial data.

Im Gegensatz zu Geometry muss für die Initialisierung der Geography-Objekte also zwingend eine SRID angegeben werden. Eine Übersicht der gültigen SRIDs erhält man, wenn man die Systemsicht sys.spatial_reference_systems aufruft:

Es gibt noch eine weitere Einschränkung: Geography-Instanzen dürfen die Hemisphäre nicht überschreiten. Diese Einschränkung spielt natürlich erst dann eine Rolle, wenn man nicht mehr nur geographische Punkte speichert, sondern Berechnungen durchführen möchte und z.B. Entfernungen berechnet. Eine in meinen Augen gute Erklärung für diese Einschränkung liefert ein Blogeintrag von Steve Kass zum Thema.

Zur Verdeutlichung der Arbeit mit dem Datentyp möchte ich nun noch einige wenige Beispiele anbringen. Die Methoden ähneln im Grunde denen des Geometry-Datentyps.

In einem ersten Beispiel werden 2 geometrische Punkte erzeugt und im Anschluss daran mittels STDistance die Entfernung berechnet.

In einem zweiten Beispiel erfolgt eine ähnliche Berechnung mit einer Entfernungslinie.

Wichtig in diesem Zusammenhang: Sollen flächige Objekte erzeugt werden, so sind die Eckpunkte entgegen des Uhrzeigersinns anzugeben. Warum gibt es diese Einschränkung? Auf einer Kugel beschreibt ein geschlossener Linienzug genau 2 Flächen - die Fläche innerhalb des Linienzugs und die Fläche außerhalb des Linienzugs. Damit stellt sich das Problem: Welche Fläche ist gemeint? Um diesem Problem aus dem Weg zu gehen ist definiert, dass in diesen Fällen die Fläche gemeint ist, die von den Punkten entgegen des Uhrzeigersinns eingeschlossen sind.

Anderenfalls erhält man eine nette Fehlermeldung, die auf den Umstand hinweist:

Msg 6522, Level 16, State 1, Line 1 
A .NET Framework error occurred during execution of user-defined routine or 
aggregate "geography": 
Microsoft.SqlServer.Types.GLArgumentException: 24205: The specified input 
does not represent a valid geography instance because it exceeds a single hemisphere. 
Each geography instance must fit inside a single hemisphere. A common reason 
for this error is that a polygon has the wrong ring orientation.

WSP-Deployment und Shared Assemblies im GAC

Solutions im SharePoint installiert man in der Regel durch WSPs. Das ist auch ganz bequem. Dabei gibt es auch die Möglichkeit, diese im Global Assembly Cache zu installieren - z.B. wenn man bestimmte Berechtigungen braucht.

Interessant wird es, wenn nun mehrere Projekte eine Assembly gemeinsam benutzen. Grundsätzlich ist das Vorgehen in diesem Fall recht einfach - man definiert eine Trace Reference. Hier sind ein paar Sätze aus Junfeng Zhangs Blog zum Thema:

When you install an assembly to GAC, you have the option to specify an Assembly Trace Reference.

And we strongly recommend that you specify a trace reference, for the reason I will discuss below.

The idea behind trace reference is really simple. When multiple applications install the same assembly, and one application is uninstalled (thus uninstall the assembly it carries), other applications won't be broken.

Leider bietet die Installationroutine im SharePoint diese Möglichkeit nicht. Die Gründe finden sich in den SharePoint-Administration-Assemblies: 

Man erkennt recht gut, dass im InstallAssembly als Referenz immer fest IntPtr.Zero übergeben wird.

Damit besteht hier diese Möglichkeit leider nicht und man kann auch mit Konfigurationen nicht Eingriff nehmen. Von mehreren Komponenten genutzte Assemblies können somit nicht in den GAC installiert werden, nicht gemeinsam genutzt werden oder es muss technisch oder manuell geprüft werden, ob nach der Deinstallation von Solutions diese Assemblies noch im GAC sind.

Bleibt zu hoffen, dass die SharePoint-Entwickler in künftigen Versionen diese Möglichkeit noch implementieren.