in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

This Blog

Syndication

News

Ein guter Blog lebt auch vom Feedback der Leser. Aus diesem Grund möchte ich alle Leser bitten und auffordern, Feedback und Bewertung für einzelne Posts abzugeben. Ich freue mich natürlich auch, wenn mein Blog oder auch einzelne Posts verlinkt werden. Dies hilft anderen Leser und ist zugleich auch Ansporn für mich!

Meine SharePoint-Notizen

SharePoint-Notizen aus meiner täglichen Projektarbeit mit dem Microsoft Office SharePoint Server 2007

September 2007 - Posts

  • SharePoint-Benutzergruppen mit AD-Benutzergruppen kombinieren

    Obwohl es sich bei dem kleinen Bestellwesen eigentlich um keine große Sache handeln sollte, liefert es doch tatsächlich Stoff für mittlerweile 3 Posts in meinem Blog. Smile

    Das besagte und bereits öfters erwähnte Bestellwesen benutzt Workflows und EventHandler, um das Genehmigen von Bestellungen zu realisieren. Da es mehrere Personengruppen und auch Einzelpersonen gibt, die eine Bestellung genehmigen dürfen, haben wir eine SharePoint-Benutzergruppe erzeugt und hier einige Einzelpersonen und zwei ActiveDirectory-Benutzergruppen hinzugefügt.

    In einem EventHandler ging es nun darum, zu prüfen, ob der aktuelle Benutzer das Recht hat, eine Bestellung zu genehmigen. Prinzipiell ist diese Abfrage nicht besonders schwierig: sobald der aktuelle Benutzer ein Mitglied der SharePoint-Gruppe "Genehmiger" ist, darf er Bestellungen genehmigen. Da ein EventHandler beim Aufruf über den Parameter SPItemEventProperties auch den aktuellen Benutzer bzw. seinen LoginNamen bekommt, beschränkt sich die Abfrage auf die Mitgliedschaft in der SharePoint-Gruppe "Genehmiger".

    Der erste Ansatz, diese Abfrage zu realisieren, war dieser: über den LoginNamen bestimmt man das zugehörige SPUser-Objekt. Dies könnte man z.B. über die AllUsers-Collection des Webs machen, zu dem die Liste gehört, die den Event ausgelöst hat. Auch diese Informationen bekommt man über die SPItemEventProperties. Hat man das SPUser-Objekt gefunden, kann man die Groups-Collection des SPUsers nach der Gruppe "Genehmiger" durchsuchen. Dieses Verfahren ist zwar naheliegend, funktioniert aber leider nur mit den als Einzelperson in der SharePoint-Gruppe "Genehmiger" eingetragenen Personen. Die ebenfalls dort eingetragenen ActiveDirectory-Gruppen werden hierbei nicht berücksichtigt.

    Wie schafft man es aber nun, dass bei der Abfrage der Gruppenzugehörigkeit auch ActiveDirectory-Gruppen innerhalb einer SharePoint-Gruppe berücksichtigt werden?

    Das klappt, wenn man den umgekehrten Weg aus dem ersten Ansatz wählt. Dies bedeutet: man geht nicht über den SPUser und dessen Groups-Collection, sondern besorgt sich z.B. über die SiteGroups-Collection des RootWebs des aktuellen Webs die ID der Gruppe "Genehmiger". Anschließend kann man die Methode IsCurrentUserMemberOfGroup() des RootWeb-Objekts benutzen, um herauszufinden, ob der aktuelle Benutzer Mitglied der SharePoint-Gruppe "Genehmiger" ist. Dazu gibt man der Methode IsCurrentUserMemberOfGroup() nur die zuvor besorgte ID der SharePoint-Gruppe "Genehmiger" mit. Mit diesem Aufruf werden dann auch die ActiveDirectory-Gruppen innerhalb der Sharepoint-Gruppe berücksichtigt.

  • Eventhandler in SharePoint - einige interessante Informationen

    Für das bereits im vorherigen Post angesprochene kleine Bestellwesen mußte ich noch einen Eventhandler programmieren. Dieser sollte beim Hinzufügen einer neuen Bestellung aktiviert werden und den zu der eingegebenen Kostenstelle gehörenden Teamleiter aus einer anderen Liste auslesen und zur aktuellen Bestellung hinzufügen. Und dabei hatte ich wieder das Vergnügen, mich mit den Sharepoint-Eventhandlern zu beschäftigen Embarrassed

    Der eben beschriebene Eventhandler sollte also an das Listen-Event ItemAdding gekoppelt werden und benötigt einen Wert aus der Spalte Kostenstelle - also aus den Daten, die der momentane Benutzer gerade eben vor Auslösen des Events eingegeben hat. Um herauszufinden, wie man an diese eben eingegebenen Daten kommt, habe ich mir den Übergabeparameter eines Sharepoint-Eventhandlers einmal genauer angesehen. Ein Eventhandler bekommt bei seinem Aufruf genau einen Parameter vom Typ SPItemEventProperties mit. Als ich mir diesen Parameter näher angesehen habe, bemerkte ich, dass hier auch ein Element vom Typ SPListItem enthalten ist. Leider stellte sich aber beim Debuggen heraus, dass dieses Element zumindest beim Event ItemAdding null ist. OK, bei näherem Nachdenken macht das auch Sinn, denn schließlich wurde die Verarbeitung der eingegebenen Daten noch nicht abgeschlossen und der eigentliche Speichern-Vorgang steht noch aus.

    Aber wie komme ich dann an die eben eingegebenen Daten? Ein weiterer Blick auf die SPEventProperties ... ok, versuchen wir es doch mal mit den BeforeProperties. Im SDK werden die BeforeProperties folgendermaßen beschrieben:"Gets a hash table of properties consisting of string/value pairs that correspond to fields in the Sharepoint.SPItem object before the event occurred." Das ist doch genau das, was ich gesucht habe: die Spaltennamen mit ihren Werten zum Zeitpunkt, bevor der Event gefeuert wurde. Um es kurz zu machen: beim ItemAdding-Event sind die BeforeProperties ebenfalls null. Confused

    Bleiben mir nur noch die AfterProperties. Die SDK-Beschreibung sagt dazu: "Gets a hash table of properties consisting of string/value pairs that correspond to fields in the Sharepoint.SPItem object after the event occurred." Dies klingt etwas seltsam, denn das ItemAdding-Event wird genau dann gefeuert, wenn ein neuer Datensatz gerade eben hinzugefügt werden soll. Der Event läuft also eigentlich noch und eigentlich sollte es deswegen keine AfterProperties geben können. Aber weit gefehlt: hier stehen genau die Daten die ich gesucht habe. Hmm

    Mein Eventhandler sucht also jetzt den Teamleiter, der zu der angegebenen Kostenstelle gehört. Um den Namen des Teamleiters zu den Daten, die der momentane Benutzer gerade eben eingegeben hat, hinzuzufügen, benutze ich auch wieder die AfterProperties. In der Bestelllisten gibt es eine versteckte Spalte 'Teamleiter', die ausschließlich vom Eventhandler ausgefüllt werden soll. Mein Eventhandler hat anhand der Kostenstelle den Namen des Teamleiters gefunden und schreibt diese wie folgt in die Listendaten zurück:

    SPEventProperties myProperties = properties;

    myProperties.AfterProperties["Teamleiter"] = "Max Mustermann";

    Weil mir die Sache mit den Eventproperties etwas seltsam vorkam, habe ich noch etwas Zeit für einen kleinen "Drill down" investiert. Beim Entwicklen von Eventhandlern ist es sehr wichtig, nicht die für den Anwender sichtbaren Spalten-Namen zu verwenden (also die Display Names), sondern die sprachunabhängigen internen Spaltennamen (Internal Name). Wenn man den display name einer Spalte kennt, bekommt man den internal name z.B. so:

    string strInternalname = myList.Fields[strDisplayname].InternalName;

    Zurück zu den Eventhandlern und den Übergabeparametern vom Typ SPItemEventProperties! Ich habe mir diese Properties auch beim Event ItemUpdating angesehen. Hier ist das Element ListItem nicht null und enthält die Daten vor der Änderung durch den Benutzer (also die ursprünglichen, unveränderten Daten). Die BeforeProperties sind wieder null - (hätte ich in diesem Fall nicht erwartet) - und die AfterProperties enthalten die neuen, veränderten Daten. Bis auf die leeren BeforeProperties ist also alles, wie erwartet. Warum aber werden die BeforeProperties nicht gesetzt? Um diese Frage zu klären, habe ich meinen "Drill down" fortgesetzt und nun keine Liste mehr verwendet, sondern eine Dokumentenbiliothek. Und siehe da: bei einer Dokumentenbiliothek werden die BeforeProperties verwendet und hier enthalten diese auch den alten, unveränderten Wert.

    Fazit: durchgängig konsistent scheint die Sache mit den SPItemEventProperties noch nicht zu sein. Warum BeforeProperties offensichtlich nur bei Dokumentbiliotheken, nicht aber bei Listen verwendet werden, ist mir unverständlich. Vielleicht bringt eine Nachfrage bei Microsoft eine Erklärung - ich werde dies machen und über das Ergebnis zw. die Antwort hier im Blog berichten.

  • Individuelles Ein-/Ausblenden von Spalten bei SharePoint Listen und Bibliotheken

    Bei einem Projekt wurde gefordert, dass wir ein kleines Bestellwesen für Büromaterial auf einer Seite eines SharePoint-Portals implementieren. 'Keine große Sache' dachte ich mir und begann mit dem Design. Das Bestellwesen sollte auf einer einfachen SharePoint-Liste basieren und die Benachrichtigungen an die User sollten über Workflows erfolgen, die mit dem SharePoint-Designer erstellt werden. Wie gesagt - keine große Sache! (Anmerkung: die Anforderungen an das Bestellwesen waren natürlich größer, als hier dargestellt. Es soll hier nur als Beispiel dienen.)

    Die Probleme begannen aber, als ich mir Gedanken über ein Status-Feld machte. Zu jeder Bestellung sollte es ein Status-Feld geben, in dem der Status der Bestellung (z.B. offen / genehmigt / bestellt / eingetroffen / abgelehnt) hinterlegt ist. Dieses Statusfeld sollte auch als Trigger für die Workflows benutzt werden. Gepflegt werden sollte dieses Statusfeld ausschließlich vom Sekretariat, weil hier auch die Bestellungen bearbeitet werden. Ein Mitarbeiter sollte nur eine neue Bestellung aufgeben, nicht aber seine Bestellung -und somit das Statusfeld- nachträglich bearbeiten können.

    Somit war das Problem klar: bei der Eingabe einer neuen Bestellung sollte das Feld (bzw. die Spalte) 'Status' nicht veränderbar sein, beim Bearbeiten einer Bestellung hingegen schon. Beim Ansehen einer Bestellung sollte der Status natürlich auch ganz normal angezeigt werden.

    Nach einigem Recherchieren und dem Hinweis eines Entwicklerkollegen habe ich eine Lösung gefunden.

    SharePoint verwendet spezielle Forms, wenn Daten einer Liste hinzugefügt, editiert oder betrachtet werden. Beim Eingeben eines neuen Datensatzes in eine Liste wird die Form NewForm.aspx verwendet, beim Editieren eines Datensatzes wird EditForm.aspx verwendet und beim Betrachten eines Datensatzes wird DispForm.aspx verwendet.

    Für das geschilderte Problem wäre es hilfreich, wenn die Status-Spalte nur bei 'EditForm' und 'DispForm' angezeigt werden würde, nicht aber bei 'NewForm'. Mitarbeiter verwenden beim Aufgeben einer neuen Bestellung 'NewForm'. Das Sekretariat verwendet 'EditForm' zum Ändern des Wertes der Status-Spalte (Mitarbeiter können eine einmal aufgegebene Bestellung nicht mehr verändern) und beide verwenden 'DispForm', um sich über den Stand einer Bestellung zu informieren.

    Leider findet man eine entsprechende Einstellmöglichkeit nicht in den Eigenschaften einer SharePoint-Liste oder Bibliothek. Dennoch ist es aber möglich, für einzelne Listen festzulegen, welche Spalten in welcher Form angezeigt werden sollen - ein Blick in das SDK bzw. das Objektmodell von SharePoint hilft hier weiter.

    Eine Liste wird im SharePoint-Objektmodell durch das Objekt SPList repräsentiert. Spalten werden durch das Objekt SPField repäsentiert und alle Spalten einer Liste werden in der Collection Fields des Objekts SPList zusammengefasst.

    Um  eine spezielle Spalte bzw. deren SPField-Objekt aus dieser Collection zu bekommen, gibt es zwei Möglichkeiten. Die erste Möglichkeit besteht im bekannten Array-Zugriff (z.B. Fields["Status"]). Hierbei ist zu beachten, dass als Spaltenname der sprachabhängige Anzeigename (display name) verwendet wird. Die zweite Möglichkeit besteht darin, die Methode GetFieldByInternalName() der Collection Fields aufzurufen. Wie der Methodenname schon vermuten läßt, wird hier nicht der sprachabhängige Anzeigename als Parameter verwendet, sondern der sprachunabhängige interne Spaltenname (internal name). Die Unterscheidung zwischen display name und internal name ist also sehr wichtig und sollte bei der Programmierung beachtet werden!

    Hat man nun das gewünschte SPField-Objekt und schaut es sich etwas genauer an, findet man u.a. diese drei Eigenschaften: ShowInEditForm, ShowInNewForm und ShowInDisplayForm. Alle drei sind vom Typ bool und sind standardmäßig auf null gesetzt. Um eine Spalte z.B. in der NewForm auszublenden, setzt man einfach die Eigenschaft ShowInNewForm der entsprechenden Spalte auf false. Um eine bestimmte Spalte wieder einzublenden, setzt man die entsprechende Eigenschaft auf true und um die Eigenschaft wieder auf ihren Standardwert zurückzusetzen, weist man dieser den Wert null zu. Diese Einstellungen brauchen nur ein einziges Mal vorgenommen zu werden, da sie wie alle anderen Listeneigenschaften auch gespeichert werden.

    Zur Illustration (und weil ich es sicherlich auch noch öfters brauchen werde) habe ich eine kleine Windows-Applikation geschrieben (siehe Screenshot). Nach dem Starten der Applikation wählt man eine Site und eine Liste aus. Jetzt werden alle Spalten der ausgewählten Liste angezeigt und man kann einstellen, bei welcher Form welche Spalte angezeigt bzw. ausgeblendet werden soll. Zusätzlich kann man noch die Breite der Spalte (für NewForm und EditForm) einstellen und festlegen, ob diese read only sein soll. Um die Sache mit den unterschiedlichen Spaltenname (display name und internal name) zu verdeutlichen, kann zwischen beiden umgeschaltet werden. Dieses Tool kann man sich von unserer Homepage kostenlos (gegen eine kleine Registrierung) herunterladen - hier der Link.

     

    Ich möchte an dieser Stelle noch erwähnen, dass es sich hierbei um ein Entwickler-Tool, welches direkt auf einem SharePoint-Server gestartet werden muss, handelt. Es dient ausschließlich als Anschauungsobjekt, kann und die Benutzung erfolgt auf eigenes Risiko!

    Das SPField Objekt bietet aber noch einige weitere interessante Eigenschaften und Methoden. In nächster Zeit werde ich mich sicherlich noch mehrmals mit dem SPField Objekt beschäftigen. Weitere Erkenntnisse oder Updates zum genannten Tool werde ich dann hier posten.

     

    Add to Technorati Favorites

Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts