Datenzugriff in SharePoint: Hierarchical Object Store

30. Juli 2012
Dies ist der vierte Teil einer Serie, die sich mit der Frage beschäftigt auf welche Arten Konfigurationen in Applikationen unter SharePoint gespeichert werden können. Es wird zuerst immer kurz die Methode vorgestellt, gefolgt von einem kurzen Beispiel und den Vor- und Nachteilen.

Eine vollständige Übersicht über bisherige und noch folgende Artikel ist hier zu finden.

Im letzten Teil wurde das SPPropertyBag vorgestellt. Der Nachteil des Property Bags ist, das nur string, int oder DateTime gespeichert werden können. Ist es dagegen notwendig komplexere Objekte zu speichern, müssen diese per Hand serialisiert und dann als string gespeichert werden. Wem das zu umständlich ist kann alternativ den Hierarchical Object Store verwenden. Dieser funktioniert ähnlich einem Propery Bag auf Farm-Ebene und ermöglicht das Speichern und Auslesen ganzer Objekte.

Genau wie das Property Bag ist der Hierarchical Object Store eine Grundfunktion von SharePoint und muss nicht separat installiert oder aktiviert werden. Das bedeutet jede Applikation kann auf diesen zugreifen.

Um ein Objekt im Hierarchical Object Store zu speichern, muss dieses von SPPersistedObject ableiten. Alle Felder (nicht die Properties!), welche mit dem [Persisted] Attribut gekennzeichneten sind, werden als XML serialisiert und in der SharePoint Konfigurations-Datenbank abgelegt. Das serialisierte Objekt steht dann farmweit allen Applikationen zur Verfügung.

Beispiel

Als Beispiel erstellen wir ein einfaches Objekt zum Speichern von Benutzername und Passwort. Das Objekt leitet von SPPersistedObject ab und enthält zwei Felder, welche mit dem Persisted Attribut gekennzeichnet werden. (Um das Code-Beispiel übersichtlich zu halten sparen wir uns die Properties)

public class MyCredentials : SPPersistedObject
{
    [Persisted]
    private string _connectionString;
 
 
    public string ConnectionString
    {
        get { return this._connectionString; }
        set { this._connectionString = value; }
    }
 
    public MyCredentials() { }
 
    public MyCredentials(string name, SPPersistedObject parent, Guid id)
        : base(name, parent, id)
    { }
 
    protected override bool HasAdditionalUpdateAccess()
    {
        return true;
    }
}

Nun brauchen wir noch eine Methode zum Lesen und eine zum Schreiben des Objektes:

/// <summary>
/// Liest ein Objekt aus dem Hierarchical Object Store aus.
/// Ist das Objekt noch nicht vorhanden, wird es erstellt
/// </summary>
public static MyCredentials GetObject(SPWebApplication webApplication, string name)
{
    // Mit der GetChild Methode von SPWebApplication 
    // können die persistierten Objekte wieder ausgelesen werden
    var credentials = webApplication.GetChild<MyCredentials>(name); 
    if (credentials == null)
    {
        // Neues Objekt erstellen, falls noch nicht vorhanden
        return CreateNew(webApplication, name);
    }
    return credentials;
}
 
/// <summary>
/// Persistiert das Objekt im Hierarchical Object Store 
/// </summary>
public static MyCredentials CreateNew(SPWebApplication webApplication, string name)
{
    return new MyCredentials(name, webApplication, Guid.NewGuid());
}

Zum Testen erstellen wir wieder ein WebPart, welches fast identisch mit dem letzten Beispiel ist:

[ToolboxItemAttribute(false)]
public class WebPartMitHierarchicalObjectStore : WebPart
{
    private Button _buttonSave;
    private Button _buttonLoad;
    private TextBox _textBoxConnectionString;
 
    const string PersistedObjectName = "DemoKey";
 
 
    protected override void CreateChildControls()
    {
        _buttonSave = new Button
        {
            Text = "Save data!",
            ID = "ButtonSave"
        };
 
        _buttonLoad = new Button
        {
            Text = "Load data!",
            ID = "ButtonLoad"
        };
 
        this._textBoxConnectionString = new TextBox();
 
        _buttonSave.Click += PropertySpeichern;
        _buttonLoad.Click += PropertyLaden;
 
        Controls.Add(_buttonSave);
        Controls.Add(_buttonLoad);
        Controls.Add(_textBoxConnectionString);
    }
 
    private void PropertyLaden(object sender, EventArgs e)
    {
        var web = SPContext.Current.Site.WebApplication;
        var credentials = MyCredentials.GetObject(web, PersistedObjectName);
 
        _textBoxConnectionString.Text = credentials.ConnectionString;
    }
 
 
    private void PropertySpeichern(object sender, EventArgs e)
    {
        var webApplication = SPContext.Current.Site.WebApplication;
 
        var credentials = MyCredentials.GetObject(webApplication, PersistedObjectName);
        credentials.ConnectionString = _textBoxConnectionString.Text;
        credentials.Update();
 
        _textBoxConnectionString.Text = string.Empty;
    }
}

Mehr ist auch bei dieser Variante nicht notwendig um Einstellungen zu speichern und laden.

Fazit

Der Hierarchical Object Store ist dem im letzten Artikel vorgestellten Property Bag sehr Ähnlich. Trotzdem unterscheidet es sich in in ein paar Grundlegenden Dingen, was sich in den Vor- und Nachteilen dieser Methode äussert:

Vorteile

  • Implementierung

    Gut geeignet für komplexe Datentypen. Diese müssen allerdings von SPPersistedObject ableiten, was die Einsatzmöglichkeiten limitiert.

  • Wartbarkeit

    Standardfeature von SharePoint. Es müssen keine zusätzlichen Komponenten installiert werden und nichts konfiguriert werden. Im Gegensatz zum Property Bag werden Werte aber nicht automatisch zusammen mit dem Feature entfernt. Es können also Einträge in der Datenbank zurück bleiben!

Nachteile

  • Administration

    Es gibt keine mitgelieferte Oberfläche zum Verwalten der Werte. Diese muss selbst erstellt werden. Ebenso existiert keine Möglichkeit für Versionierung oder Genehmigungsprozesse. Eine Änderung ist also sofort „live“.

  • Sicherheit Nicht geeignet um sensible Informationen zu speichern. Zum Schreiben sind außerdem Farmadministrator Rechte notwendig.
  • Scope Im Gegensatz zum Property Bag werdeb Werte im Hierarchical Object Store immer auf Farm Ebene gespeichert.