Möchte man programmatisch Felder zu einer SharePoint-Liste hinzufügen, so stolpert man früher oder später über die Methoden Add bzw. AddFieldAsXml von SPFieldCollection. In vielen Fällen führen beide Methoden zum Ziel, wobei AddFieldAsXml den Vorteil hat, dass man recht einfach das Schema-Xml aus bereits bestehenden Listen übernehmen kann, es auch recht komplexe Szenarien zulässt und dann in meinen Augen besser lesbar ist als Quellcode, der über mehrere Zeilen oder Klassen verteilt versucht, ein Objekt vom Typ SPField zu erzeugen und mit den passenden Eigenschaften zu bestücken.
Damit möchte ich auch schon zum Problem kommen: Ein Objekt vom Typ SPField verfügt über zwei Eigenschaften, die in diesem Kontext eine Rolle spielen: Title stellt in der Liste den Spaltennamen dar, den der Nutzer zu Gesicht bekommt. Dieser kann natürlich auch Leerzeichen oder Sonderzeichen beinhalten. Im Gegensatz dazu ist InternalName die interne Referenz auf die Spalte und als solche ist sie in der jeweiligen Liste eindeutig und readonly. Zudem werden hier sämtliche Sonderzeichen maskiert dargestellt. Um es mal plastisch darzustellen im folgenden das Beispiel aus der MSDN.
using (var site = new SPSite("http://localhost/"))
{
using (var web = site.RootWeb)
{
var list = web.Lists["Shared Documents"];
var displayName = "My Custom Field";
var staticName = "MyStaticName";
var strInternalName = list.Fields.Add(displayName, SPFieldType.Text, false);
var field = list.Fields.GetFieldByInternalName(strInternalName);
field.StaticName = staticName;
field.Update();
}
}
In diesem Fall ist Title nun wie erwartet My Custom Field und der Internal Name My_x0020_Custom_x0020_Field.
Wie bereits angedeutet, geht das ganze auch mit AddFieldAsXml:
using (var site = new SPSite("http://localhost/"))
{
using (var web = site.RootWeb)
{
var list = web.Lists["Shared Documents"];
var fieldXml = "<Field Type=\"Text\" MaxLength=\"50\" DisplayName=\"My Custom Field\" ID=\"15C0D97B-3735-4AD9-8FE2-8A01E5B43486\" StaticName=\"MyStaticName\" Name=\"MyInternalName\" />";
var strInternalName = list.Fields.AddFieldAsXml(fieldXml);
var field = list.Fields.GetFieldByInternalName(strInternalName);
field.Update();
}
}
Was bei der Ausführung nun auffällt: Obwohl ich im XML einen Internal Name vorgegeben habe, wird dieser nicht verwendet, sondern weiterhin auf Basis des Display Name ein Internal Name generiert. Das ist insofern schlecht, da wie beschrieben der Internal Name ja der Identifier der Spalte ist und deshalb auch in CAML-Queries verwendet wird.
Aber mal unabhängig davon gibt es natürlich auch hier mehrere Arten das Problem zu lösen: Erster Ansatz und einer der auch häufig verwendet wird, ist, im Aufruf von AddFieldAsXml DisplayName und InternalName auf den künftigen InternalName zu setzen und im Nachhinein den DisplayName programmatisch auf den eigentlichen Wert zu setzen. Diesen Ansatz verfolgen zum Beispiel Bil und auch Torsten.
Wenn man sich die Blogbeiträge so anschaut und sieht, dass dieses Verhalten schon mindestens seit 2005 besteht, so stellt sich hier doch die Frage nach Bug oder Feature und warum es dafür keine saubere Lösung gibt. Gibt es nicht? Doch, die gibt es, aber man muss drauf kommen.
AddFieldAsXml hat noch eine zweite Überladung und hier liegt der Schlüssel zum Erfolg:
using (var site = new SPSite("http://localhost/"))
{
using (var web = site.RootWeb)
{
var list = web.Lists["Shared Documents"];
var fieldXml = "<Field Type=\"Text\" MaxLength=\"50\" DisplayName=\"My Custom Field\" ID=\"15C0D97B-3735-4AD9-8FE2-8A01E5B43486\" StaticName=\"MyStaticName\" Name=\"MyInternalName\" />";
var strInternalName = list.Fields.AddFieldAsXml(fieldXml, true, SPAddFieldOptions.AddFieldInternalNameHint);
var field = list.Fields.GetFieldByInternalName(strInternalName);
field.Update();
}
}
Verwendet man hier explizit die Option AddFieldInternalNameHint, nur dann wird der im Xml angegebene interne Name auch verwendet.

Ich hätte erwartet, dass man das auch direkt anhand des Schema-XMLs hätte ermitteln können - à la: Attribut Name vorhanden, dann verwenden, sonst anhand des DisplayNames. Aber so ist es leider nicht. Nehmen wir es also als Sicherheits-Feature hin, dass man die Vergabe des Internal Names explizit noch einmal mit setzen der Option AddFieldInternalNameHint bestätigen muss.
Englische Version