SharePoint Designer 2013 stürzt beim Website öffnen ab

Das Problem: SharePoint Designer 2013 stürzt beim Klick auf Website öffnen ab. Dieses Problem hatte ich bereits vor längerer Zeit und konnte es nach einer relativ kurzen Suche im Web auch beseitigen. Jetzt trat es hier erneut auf und ich mußte wieder nach der Lösung suchen. Deshalb dieser Beitrag in der Hoffnung beim nächsten Mal schneller zur Lösung zu gelangen.

Der Fehler tritt nur auf, wenn auf einer Maschine mehrere Versionen von SharePoint Designer installiert sind. Da ich leider immer noch alle möglichen Versionen supporten muß, habe ich hier also SharePoint Designer 2007, 2010 und 2013, was normalerweise auch problemlos funktioniert. Die kürzliche Installation von SP2 für SharePoint Designer 2010 hat dann diesen Fehler wieder zutage gefördert. Die Lösung hatte ich hier bei Marc D Anderson gefunden, aber es gibt inzwischen viele Beiträge dazu.

Die Lösung besteht darin, zwei Werte aus der Windows Registry zu löschen. Es handelt sich dabei um

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Website öffnen\ClientGUID

und

HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Website öffnen\ClientGUID

Einfach die beiden Werte löschen (Rechtsklick – Löschen), SharePoint Designer neu starten und alles funktioniert wieder 🙂

DateTimeControl und Zugriff verweigert

Wenn man das SharePoint-DateTimeControl in einem eigenen Webpart oder in einer eigenen Anwendungsseite verwendet, kann es passieren, daß man beim Aufklappen des Kalenders eine Zugriff verweigert / Access Denied Meldung bekommt. Das passiert, wenn man sich in einer Unterwebsite befindet und wenn der Benutzer auf die Root-Websitesammlung keine Zugriffsrechte hat.

Man sollte dieses Szenario ohnehin vermeiden und immer dafür sorgen, daß alle Benutzer auf die Root-Websitesammlung zumindest minimale Berechtigungen besitzen. Es kann sonst zu weiteren unerwarteten Fehlern kommen, weil innerhalb von SharePoint immer wieder Dateien Server-relativ von dort referenziert werden.

Beim DateTimeControl wird der aufklappende Kalender ebenfalls Server-relativ als <iframe> gerendert und deshalb bekommen Benutzer ohne Berechtigungen auf die Root-Websitesammlung eben die Zugriff verweigert Meldung. Als Entwickler kann man das umgehen, indem man die Eigenschaft DatePickerFrameUrl mit dem richtigen Pfad innerhalb der aktuellen Website belegt.

Wenn das Control z.B. innerhalb eines Webparts per Code generiert wird, fügt man einfach folgende zusätzliche Codezeile ein:

myDateTimeControl.DatePickerFrameUrl = SPUrlUtility.CombineUrl(SPContext.Current.Web.ServerRelativeUrl, "_layouts/iframe.aspx");

Wenn das Control z.B. innerhalb einer Anwendungseite deklarativ generiert wird, kann man es ebenfalls wie oben im Code-behind der Seite erledigen oder auch gleich deklarativ beim Erzeugen des Controls:

<SharePoint:DateTimeControl DatePickerFrameUrl="<% $SPUrl:~Site/_layouts/iframe.aspx %>" ID="myDateTimeControl" runat="server" />

Vorsicht mit KB2844286 bzw KB2844287

Achtung: ein beim letzten Patchday am 09.07.2013 veröffentlichtes Update KB2844286 bzw. KB2844287 Sicherheitsupdate für Microsoft .NET Framework 3.5.1 verursacht Probleme in SharePoint.

Wenn eine Ansicht mit SharePoint Designer bearbeitet wurde, verursacht diese Ansicht nach der Installation des Updates die bekannt lapidare Fehlermeldung "Dieses Webpart kann nicht angezeigt werden. Öffnen Sie diese Webseite in einem mit Microsoft SharePoint Foundation kompatiblen HTML-Editor, z.B. in Microsoft SharePoint Designer, um dieses Problem zu behandeln". Natürlich zeigt sich das Problem innerhalb von SharePoint Designer nicht. Die Seite wird dort ganz normal dargestellt.

In den SharePoint-Logs finden sich unterschiedliche NullReferenceException, die alle auf Probleme bei der XSL-Transformation hindeuten.

Nach derzeitigem Kenntnisstand kann man also nur empfehlen dieses Update nicht auf SharePoint Servern zu installieren. Falls es bereits installiert wurde und der Fehler auftritt, kann man das Update deinstallieren und der Fehler ist verschwunden.

Update 06.08.2013: es gibt inzwischen auch einen Fix zum Download, der das Problem offenbar ebenfalls behebt. Ich habe es aber noch nicht selbst getestet. Der Fix kann hier heruntergeladen werden. Danke an Markus Hiller, der das hier gepostet hat.

XML Rohdaten im IE anzeigen

Wenn man mit dem Internet Explorer die Daten eines Webdienstes, z.B. eines WCF-Dienstes von SharePoint 2010 oder der REST-API von SharePoint 2013 anzeigen möchte, erkennt der IE das als Feed und stellt es ungefähr so dar:

Als Entwickler ist man natürlich mehr an den rohen Daten interessiert, weil man sie wie auch immer weiterverarbeiten möchte. Die Einstellung dazu findet man in den Internetoptionen im Reiter Inhalte

Unter Feeds und Web Slices klickt man auf Einstellungen

Dort den Haken bei Feedleseanzeige entfernen und der IE stellt dieselben Daten so dar:

Versionen / Patchlevel in SharePoint 2010

Ein kurzer Beitrag zum Versionsstand in SharePoint 2010, der (einmal mehr) als Erinnerungshilfe für mich selbst dienen soll.

Die aktuelle Version einer SharePoint Farm kann man in der Zentraladministration auf der Seite System Settings Servers in Farm sehen:

Dieselbe Versionsnummer kann man auch per PowerShell ermitteln:

$farm = Get-SPFarm
$farm.BuildVersion

Eine detaillierte Übersicht findet man in der Zentraladministration unter Upgrade and Migration Check product and patch installation status.

Und hier noch ein Link, der eine Übersicht der Versionsnummern und der zugehörigen CUs bietet (auch für SharePoint 2007).

Gültigkeitsprüfungen mit mehreren Bedingungen

Die Syntax der Formeln für Gültigkeitsprüfungen ist manchmal etwas verwirrend. Deshalb dieser kurze Beitrag zur Erklärung (und als Gedankenstütze für mich selbst).

Eine einfache Gültigkeitsprüfung mit nur einer Bedingung sieht z.B. so aus:

=[Zahlenfeld]>0

In einer Liste oder Bibliothek mit dieser Gültigkeitsprüfung kann ein Element nur gespeichert werden, wenn in der Spalte Zahlenfeld ein Wert größer als Null eingegeben wurde. Die Prüfung gilt also immer dann als bestanden, wenn die angegebene Formel wahr zurückliefert.

Das von Microsoft direkt auf der Seite der Gültigkeitsprüfungseinstellungen angegeben Beispiel zeigt, wie man ganz einfach zwei Spalten in die Prüfung einbeziehen kann:

=[Rabatt]<[Kosten]

Dadurch können Elemente nur gespeichert werden, wenn in die Spalte Rabatt ein kleinerer Wert als in die Spalte Kosten eingegeben wurde.

Schwieriger wird es, wenn die Formel mehrere Bedingungen enthalten soll, die entweder mit UND oder mit ODER verknüpft werden sollen. Die allgemeine Syntax dafür sieht so aus:

=AND(<Bedingung1>;<Bedingung2>)

<Bedingung1> und <Bedingung2> können dabei irgendwelche Ausdrücke sein, die entweder wahr oder falsch liefern, wie die beiden Beispiele oben. Statt AND kann natürlich auch OR verwendet werden.

Ein Beispiel: eine Liste enthält ein Zahlenfeld und eine Auswahlspalte mit den Optionen Auswahl1, Auswahl2 und Auswahl3. Wenn Auswahl1 gewählt wird, soll das Zahlenfeld eine Zahl größer Null enthalten. Bei jeder anderen Auswahl ist die Zahl egal. Die Formel dafür sieht so aus:

=OR([Auswahlfeld]<>"Auswahl1";[Zahlenfeld]>0)

Selbstverständlich können auch mehrere dieser Konstrukte geschachtelt werden, was dann z.B. so aussehen kann:

=AND(OR(<Bedingung1>;<Bedingung2>);OR(<Bedingung3>;<Bedingung4>))

Diese Prüfung gilt nur dann als bestanden, wenn <Bedingung1> oder <Bedingung2> wahr ist und gleichzeitig <Bedingung3> oder <Bedingung4> wahr ist. Natürlich können auch drei oder alle vier Bedingungen wahr sein.

Eigener Button zum Dateidownload

Folgende Situation: man hat ein selbstentwickeltes Webpart, das über einen Button eine Datei erstellt und dem Benutzer zum Download anbietet. Ein Benutzer klickt den Button und alles funktioniert, d.h. er bekommt die gewünschte Datei. Wenn er jetzt wieder in den Browser wechselt, reagiert kein Button mehr – auch der eigene nicht.

Die Ursache ist eine JavaScript-Variable von SharePoint, die beim Absenden des Formulars auf true gesetzt wird (um zu signalisieren, daß das Formular bereits gesendet wurde). Wenn der Code hinter einem eigenen Button jetzt eine Datei in den ResponseStream schreibt, bleibt dieser Variablenwert erhalten und verhindert weitere Postbacks. Man muß also nur diese Variable wieder auf false setzen und alles funktioniert wie gewünscht.

Getestet habe ich das mit folgendem einfachen Code in einem Webpart, der beim Klick auf einen Button eine einfache Textdatei an den Browser schickt. Der Browser reagiert mit seinem Download-Dialog darauf:

private void Button_Click(object sender, EventArgs e) {

  string text = "Hallo Welt";

  HttpResponse response = this.Page.Response;

  response.Clear();

  response.AddHeader("content-disposition", "attachment;filename=myfile.txt");

  response.ContentType = "application/text";

  response.Output.Write(text);

  response.End();

}

Der Button wurde dabei ebenso einfach erzeugt:

protected override void CreateChildControls() {

  Button btn = new Button();

  this.Controls.Add(btn);

  btn.ID = "myButton";

  btn.Text = "Download";

  btn.Click += Button_Click;

}

Man muß dem Button jetzt einfach noch ein wenig clientseitiges JavaScript mitgeben, das (nach einer kurzen Verzögerung) die SharePoint-Variable zurücksetzt und man kann auf den Button klicken so oft man möchte. Und auf alle anderen auch. Erreicht wird das durch eine weitere Zeile Code:

btn.OnClientClick = "window.setTimeout(function(){_spFormOnSubmitCalled=false;},10);";

Dynamische Titel bei benutzerdefinierten Formularen

Wenn man mit SharePoint Designer benutzerdefinierte Formulare anlegt, wird für den Titel, also für den Namen der Spalten, immer der aktuelle Wert fest eingetragen. Für den eigentlichen Feldwert, also für den Teil mit dem die Benutzer später interagieren (z.B. eine Textbox oder Checkbox) wird ein FieldControl eingefügt. Ebenso für den Beschreibungstext einer Spalte. Wenn man dann später etwas ändert, indem man z.B. bei einem Auswahlfeld von DropDown auf Radiobuttons umschaltet, dann sind diese Änderungen auch sofort in den benutzerdefinierten Formularen zu sehen. Wenn man aber den Spaltennamen ändert, wird im benutzerdefinierten Formular immer noch der alte Name angezeigt. Außerdem wird dieser Name immer nur in einer Sprache angezeigt und paßt sich nicht an, wenn ein Benutzer eine andere Sprache auswählt.

Um dieses Problem zu lösen, kann man in der Codeansicht von SharePoint Designer den fest eingefügten Text durch ein in SharePoint immer vorhandenes Control ersetzen:

<SharePoint:FieldLabel ControlMode="Display" runat="server" FieldName="Title" />

Für das FieldName-Attribut gibt man wie immer den internen Namen der Spalte an. Das ControlMode-Attribut muß angegeben werden, aber es macht keinen Unterschied, ob man Display, Edit oder New einträgt.

Das war’s auch schon. Es ist mir (mal wieder) ein Rätsel, warum SharePoint Designer das nicht gleich so macht.

Link zum Erstellen eines Detaildatensatzes

Wenn man zwei 1:n-verbundene Listen hat, wird oft ein Link gewünscht, über den man einen Detaildatensatz erstellen kann und bei dem das Nachschlagefeld zum zugehörigen Elterndatensatz bereits vorbelegt ist. Hier wird gezeigt wie man das mit Hilfe von etwas JavaScript umsetzen kann.

Das grundsätzliche Vorgehen dabei ist folgendes: man erstellt einen eigenen Link, mit dem ausgehenden von einem Elternelement ein neues Detailelement erstellt werden kann. Der Link verweist dabei auf das Formular zur Neuanlage der Detailliste und enthält als zusätzlichen Parameter die ID des Elternelements. In das Formular zur Neuanlage wird JavaScript eingebaut, das diesen Parameter wieder aus der URL abholt und das Nachschlagefeld damit vorbelegt. Falls gewünscht kann man das Nachschlagefeld dann auch ausblenden.

Ausgangslage

Es gibt eine Parentliste, die hier zu Demozwecken ganz einfach aufgebaut ist und nur die Titelspalte enthält:

Dazu gibt es eine Detailliste, die ebenso einfach aufgebaut ist und außer dem Titel nur ein Nachschlagefeld auf die Parentliste enthält:

Man hat dadurch, ähnlich wie bei einem klassischen relationalen Datenmodell, eine 1:n-Verbindung zwischen den Listen. Jedem Elterndatensatz können mehrere Kinddatensätze zugeordnet sein. Jeder Kinddatensatz ist genau einem Elterndatensatz zugeordnet. In der Praxis wird so etwas z.B. bei Rechnungen (ein Datensatz Rechnungskopf mit Rechnungsnummer, Anschrift usw. und mehrere Datensätze Rechnungspositionen mit Artikelnummer, Preis usw.) oder bei Kontaktdaten (ein Datensatz Firma mit Kundennummer, Anschrift usw. und mehrere Datensätze Ansprechpartner mit Name, Telefonnummer usw.) verwendet.

Darstellung

Um die Daten jetzt immer schön im Zusammenhang darzustellen, kann man sehr einfach zu jedem Elterndatensatz die zugehörigen Kinddatensätze anzeigen lassen. Man fügt dazu einfach eine Ansicht der Detailliste auf das Anzeige- und das Ändern-Formular (DispForm und EditForm) der Elternliste ein. SharePoint sorgt dafür, daß diese Ansicht korrekt gefiltert wird.

Zum Einfügen geht man so vor: man geht auf die Elternliste, klickt auf Liste, öffnet den Menüpunkt Formularwebparts ändern und wählt das anzupassende Formular aus:

Die Menüpunkte der einzelnen Formulare sind meiner Meinung nach etwas unglücklich übersetzt. Neues Standardformular meint das Formular zur Neuanlage (NewForm.aspx), Standardanzeigeformular meint das Formular zur Anzeige (DispForm.aspx) und Standardformular bearbeiten meint das Formular zum Ändern (EditForm.aspx).

Wenn das gewünschte Formular geöffnet ist, klickt man irgendwo in die Seite, damit der Reiter Einfügen sichtbar wird. Dort gibt es dann einen Menüpunkt Verwandte Liste, der beim Aufklappen alle Listen anzeigt, die ein Nachschlagefeld auf die aktuelle Liste enthalten:

Man wählt die einzufügende Liste aus und es wird eine automatisch gefilterte Ansicht dieser Liste eingefügt. Die Ansicht kann jetzt wie gewohnt über die Webparteinstellungen angepaßt werden (Menüpunkt Webpart bearbeiten). Für uns ist hier wichtig den standardmäßig unter der Ansicht angezeigten Link Neues Element hinzufügen zu entfernen, damit wir ihn durch einen eigenen Link ersetzen können. Damit der Link nicht mehr angezeigt wird, setzt man in den Webparteinstellungen den Symbolleistentyp auf Keine Symbolleiste:

Der Neues Element erstellen Link

Um den ausgeblendeten Link durch einen eigenen zu ersetzen, gibt es zwei Möglichkeiten: man kann das Formular in SharePoint Designer öffnen und die Änderungen dort direkt in der Codeansicht machen. Oder man fügt im Browser noch ein Inhalts-Editor-Webpart ein und bearbeitet das in der HTML-Ansicht. Dieser Weg wird hier gezeigt.

Das Webpart findet sich in der Kategorie Medien und Inhalt und man fügt es am Sinnvollsten direkt unter der neu eingefügten Ansicht ein. Eventuell muß man es dazu im Browser nach unten verschieben. Nachdem man in das Webpart geklickt hat, wählt man im Reiter Text formatieren aus dem Menü HTML den Punkt HTML-Quelle bearbeiten:

Wir brauchen zunächst eine Funktion, die uns einen bestimmten Parameter aus der URL liefert:

function getQueryStringParameter(paramName) {
  var params = document.URL.split(„?“)[1].split(„&“),
      i,
      singleParam;
  for (i = 0; i < params.length; i++) {
    singleParam = params[i].split(„=“);
    if (singleParam[0] == paramName)
      return singleParam[1];
  }
  return „“;
}

Diese Funktion benutzen wir, um die ID aus der URL zu holen:

var lookupId = getQueryStringParameter(„ID“);

Damit setzen wir uns die URL zusammen, über die wir das Formular zur Neuanlage eines Kindelements aufrufen:

var newFormUrl = „/site/Lists/ChildList/NewForm.aspx?LookupId=“ + lookupId;

Wenn man möchte, daß der Benutzer nach dem Speichern des neuen Elements (oder nach einem Klick auf Abbrechen) wieder auf die ursprüngliche Seite zurückgeleitet wird, kann man die dafür in SharePoint vorgesehene Standardtechnik benutzen und einen zusätzlichen Source-Parameter mitgeben. Der Parameter muß die Adresse der ursprünglichen Seite und zusätzlich wieder die ID als Parameter enthalten. Man kann das durch folgende Zeile erreichen:

newFormUrl += „&Source=“ + encodeURI(window.location.pathname + „?ID=“ + lookupId);

Diese URL benutzen wir, um einen vorher definierten Anker mit dem korrekten Link zu versorgen. Außerdem packen wir das Ganze in eine Funktion, damit man es nach dem vollständigen Laden der Seite aufrufen kann:

function createNewLink() {
  var lookupId = getQueryStringParameter(„ID“),
      newFormUrl = „/site/Lists/ChildList/NewForm.aspx?LookupId=“ + lookupId,
      link = document.getElementById(„myNewLink“);
  newFormUrl += „&Source=“ + encodeURI(window.location.pathname + „?ID=“ + lookupId);
  link.href = newFormUrl;
}

Achtung: dieses Verfahren funktioniert nur, wenn das aktuelle Formular nicht in einem Dialog geöffnet wurde. Dialoge kann man in den Listeneinstellungen unter Erweiterte Einstellungen abschalten. Eleganter ist es natürlich, wenn es auch von einem Dialog aus funktioniert und wenn das Formular zum Erstellen des neuen Elements ebenfalls in einem Dialog geöffnet wird.

Das zu erreichen ist aber relativ einfach: man gibt dem Anker einfach ein zusätzliches onclick-Attribut und ruft darin die von SharePoint vorgesehene Funktion auf:

link.onclick = function (event) { NewItem2(event, newFormUrl); return false; };

Dabei muß man der NewItem2-Funktion allerdings die absolute URL übergeben, die man so erzeugen kann:

newFormUrl = window.location.protocol + „//“ + window.location.hostname + newFormUrl;

Hier nochmal zusammengefaßt der gesamte Code zum Kopieren und Einfügen in die HTML-Quelle des Webparts. Nicht vergessen, die newFormUrl auf die eigene Umgebung anzupassen!

<a href=“#“ id=“myNewLink“>Neues Element erstellen</a>
<script type=“text/javascript“>
_spBodyOnLoadFunctionNames.push(„createNewLink“);
function createNewLink() {
  var lookupId = getQueryStringParameter(„ID“),
      newFormUrl = „/site/Lists/ChildList/NewForm.aspx?LookupId=“ + lookupId,
      link = document.getElementById(„myNewLink“);
  link.href = newFormUrl;
  newFormUrl = window.location.protocol + „//“ + window.location.hostname + newFormUrl;
  link.onclick = function (event) { NewItem2(event, newFormUrl); return false; };
}
function getQueryStringParameter(paramName) {
  var params = document.URL.split(„?“)[1].split(„&“),
      i,
      singleParam;
  for (i = 0; i < params.length; i++) {
    singleParam = params[i].split(„=“);
    if (singleParam[0] == paramName)
      return singleParam[1];
  }
  return „“;
}
</script>

NewForm anpassen / Nachschlagefeld vorbelegen

Mit dem oben Gezeigten haben wir jetzt also einen Link auf das Formular, mit dem die neuen Kindelemente erzeugt werden. Die ID des Elternelements wird dabei in der URL übertragen. Kommen wir jetzt also zu den Anpassungen, die man dort noch machen muß, um diese ID auszulesen und das Nachschlagefeld damit vorzubelegen.

Wie man den notwendigen JavaScript-Code auf ein Listenformular bekommt, habe ich ja oben schon beschrieben und werde deshalb hier nicht weiter darauf eingehen.

Um an die ID des Elternelements zu kommen, verwenden wir wieder die oben gezeigte Funktion getQueryStringParameter. Spätestens jetzt sollte man sich überlegen, diese Funktion in eine eigene js-Datei zu packen, damit man sie einfach wiederverwenden kann.

Außerdem brauchen wir eine Hilfsfunktion getTagFromIdentifierAndTitle, die tausendfach durchs Web geistert. Ich verzichte hier auf eine Quellenangabe, da ich ohnehin nicht weiß, wer sie ursprünglich erdacht hat. Sie liefert ein HTML-Element anhand des Tagnamens, einem optionalen Feldtyp und dem Feldnamen:

function getTagFromIdentifierAndTitle(tagName, identifier, title) {
  var idLength = identifier.length,
      tags = document.getElementsByTagName(tagName),
      i,
      tagID;
  for (i = 0; i < tags.length; i++) {
    tagID = tags[i].id;
    if (tags[i].title == title && (identifier == „“ || tagID.indexOf(identifier) == tagID.length – idLength)) {
      return tags[i];
    }
  }
  return null;
}

Diese Funktion können wir jetzt benutzen, um an das Nachschlagefeld zu gelangen. Hier kommt aber eine besondere Verhaltensweise von Nachschlagefeldern hinzu, der besondere Beachtung geschenkt werden muß. Wenn die Nachschlageliste weniger als 20 Elemente enthält, wird das Nachschlagefeld als ganz normales <select> gerendert. Man muß dann einfach nur das gesuchte <option> anhand seines Values finden und auswählen. Dazu dient diese Funktion:

function setSelectedOption(select, value) {
  var opts = select.options,
      optLength = opts.length,
      i;
  for (i = 0; i < optLength; i++) {
    if (opts[i].value == value) {
      select.selectedIndex = i;
      return true;
    }
  }
  return false;
}

Wenn die Nachschlageliste mehr Elemente enthält, wird für das Nachschlagefeld ein komplizierteres DHTML-Konstrukt gerendert. Das Haupteingabefeld ist dabei ein <input type=“text“>. Der gespeicherte Wert befindet sich allerdings in einem <input type=“hidden“> und dieses wiederum findet man über seine ID, die beim Eingabefeld in einem optHid-Attribut gespeichert ist. Puh.

Da das Feld später vorbelegt und sinnvollerweise von den Benutzern nicht geändert werden soll, blenden wir es aus. Wir wollen dabei nicht nur das Feld selbst ausblenden, sondern gleich die gesamte Tabellenzeile, in der es sich befindet. Auch dabei müssen die beiden Arten unterschieden werden. Beim <select> geht es drei Ebenen nach oben, bis man die Tabellenzeile erreicht. Beim <input> sind es vier Ebenen.

Achtung: man darf die Felder nicht auf disabled oder ähnliches setzen, weil sonst ihre Werte beim POST nicht übertragen und damit nicht gespeichert werden!

Damit können wir uns jetzt eine wiederverwendbare Funktion bauen, die den Wert eines Nachschlagefeldes unabhängig von der Anzahl der Nachschlageelemente setzt und auch gleich das Feld ausblendet:

function setLookupField(fieldName, value) {
  var theSelect = getTagFromIdentifierAndTitle(„select“, „“, fieldName),
      theInput;
  if (theSelect == null) {
    theInput = getTagFromIdentifierAndTitle(„input“, „“, fieldName);
    document.getElementById(theInput.optHid).value = value;
    theInput.parentNode.parentNode.parentNode.parentNode.style.display = „none“;
  } else {
    setSelectedOption(theSelect, value);
    theSelect.parentNode.parentNode.parentNode.style.display = „none“;
  }
}

Auch hier nochmal der gesamte JavaScript-Code für die NewForm zum bequemen Kopieren und Einfügen. Nicht vergessen, den Namen des Nachschlagefelds (hier „Parent“) an die eigene Umgebung anzupassen!

Noch eine Anmerkung dazu: wenn es sich um ein Pflichtfeld handelt, wird das Wort „Pflichtfeld“ tatsächlich an den Namen angehängt.

<script type=“text/javascript“>
_spBodyOnLoadFunctionNames.push(„setLookupFromQS“);
function setLookupFromQS() {
  var lookupId = getQueryStringParameter(„LookupId“);
  setLookupField(„Parent“, lookupId);
}
function setLookupField(fieldName, value) {
  var theSelect = getTagFromIdentifierAndTitle(„select“, „“, fieldName),
      theInput;
  if (theSelect == null) {
    theInput = getTagFromIdentifierAndTitle(„input“, „“, fieldName);
    document.getElementById(theInput.optHid).value = value;
    theInput.parentNode.parentNode.parentNode.parentNode.style.display = „none“;
  } else {
    setSelectedOption(theSelect, value);
    theSelect.parentNode.parentNode.parentNode.style.display = „none“;
 }
}
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
  var idLength = identifier.length,
      tags = document.getElementsByTagName(tagName),
      i,
      tagID;
  for (i = 0; i < tags.length; i++) {
    tagID = tags[i].id;
    if (tags[i].title == title && (identifier == „“ || tagID.indexOf(identifier) == tagID.length – idLength)) {
      return tags[i];
    }
  }
  return null;
}
function setSelectedOption(select, value) {
  var opts = select.options,
      optLength = opts.length,
      i;
  for (i = 0; i < optLength; i++) {
    if (opts[i].value == value) {
      select.selectedIndex = i;
      return true;
    }
  }
  return false;
}
function getQueryStringParameter(paramName) {
  var params = document.URL.split(„?“)[1].split(„&“),
      i,
      singleParam;
  for (i = 0; i < params.length; i++) {
    singleParam = params[i].split(„=“);
    if (singleParam[0] == paramName)
      return singleParam[1];
  }
  return „“;
}
</script>

MachineKeys in der web.config von SharePoint

Wenn man SharePoint mit FBA (Formularbasierter Authentifizierung / Forms Based Authentication) arbeitet, braucht man in vielen Fällen einen sogenannten MachineKey (Computerschlüssel) wenn man Benutzerpasswörter nicht im Klartext ablegen möchte. Sobald man eine Webanwendung für FBA konfiguriert, erzeugt SharePoint einen solchen Schlüssel und trägt ihn in die web.config der Webanwendung ein.

Wenn man mehrere Webanwendungen gegen dieselbe Benutzerdatenbank fahren möchte oder auch nach einer Migration, ist es notwendig hier einzugreifen und eigene Schlüssel zu verwenden. In diesem Fall wird man sich wahrscheinlich sehr schnell wundern, weil sich am nächsten Tag kein Benutzer mehr anmelden kann. Verantwortlich dafür ist ein Timerjob, der regelmäßig jede Nacht ausgeführt wird und der den ursprünglichen Schlüssel wieder in die web.config einträgt.

Man sollte jetzt aber nicht einfach den gesamten Timerjob deaktivieren, weil dieser mehrere Integritätsanalysen (Health Analysis) ausführt. Allerdings kann man die verantwortliche Regel der Integritätsanalyse deaktivieren. Für das Zurücksetzen des Computerschlüssels ist die Regel ViewStateKeysAreOutOfSync zuständig und man kann sie mit folgenden PowerShell-Befehlen deaktivieren:

Get-SPHealthAnalysisRule ViewStateKeysAreOutOfSync | Disable-SPHealthAnalysisRule