UriTemplate und UriTemplateTable

Webentwickler müssen in der Lage sein, die Form und das Layout der URIs zu beschreiben, auf die ihre Dienste reagieren. Windows Communication Foundation (WCF) hat zwei neue Klassen hinzugefügt, um Entwicklern die Kontrolle über ihre URIs zu geben. UriTemplate und UriTemplateTable bilden die Grundlage der URI-basierten Dispatch-Engine in WCF. Diese Klassen können auch alleine verwendet werden und geben so den Entwicklern die Möglichkeit, Vorlagen und den URI-Abbildungsmechanismus zu nutzen, ohne einen WCF-Dienst implementieren zu müssen.

Vorlagen

Eine Vorlage ist eine Möglichkeit, einen Satz relativer URIs zu beschreiben. Der Satz von URI-Vorlagen in der folgenden Tabelle zeigt, wie ein System, das verschiedene Arten von Wetterdaten abruft, definiert werden könnte.

Daten Vorlage
Nationale Vorhersage Wetter/national
Bundeslandvorhersage Wetter/{Staat}
Ortsvorhersage Wetter/{Bundesland}/{Stadt}
Aktivitätsvorhersage Wetter/{Bundesland}/{Stadt}/{Aktivität}

In dieser Tabelle wird ein Satz strukturell ähnlicher URIs beschrieben. Jeder Eintrag ist eine URI-Vorlage. Die Segmente in geschweiften Klammern beschreiben Variablen. Die Segmente, die nicht in geschweifte Klammern eingefasst sind, beschreiben Literalzeichenfolgen. Die WCF-Vorlagenklassen ermöglichen dem Entwickler, einen eingehenden URI (z. B. "/Wetter/BW/Mannheim/wechselhaft") anzunehmen und ihn mit einer Vorlage abzugleichen, die ihn beschreibt, "/Wetter/{Bundesland}/{Stadt}/{Aktivität}".

UriTemplate

UriTemplate ist eine Klasse, die eine URI-Vorlage kapselt. Der Konstruktor nimmt einen Zeichenfolgenparameter, der die Vorlage definiert. Diese Zeichenfolge enthält die Vorlage in dem im nächsten Abschnitt beschriebenen Format. Die UriTemplate-Klasse bietet Methoden, die die Zuordnung eines eingehenden URI zu einer Vorlage, die Generierung eines URI aus einer Vorlage, das Abrufen einer Sammlung von Variablennamen, die in der Vorlage verwendet werden, die Bestimmung, ob zwei Vorlagen gleichwertig sind, und die Ausgabe der Zeichenfolge der Vorlage ermöglichen.

Match(Uri, Uri) nimmt eine Basisadresse und einen möglichen URI und versucht, den URI der Vorlage zuzuweisen. Wenn die Zuordnung erfolgreich ist, wird eine UriTemplateMatch-Instanz zurückgegeben. Das UriTemplateMatch-Objekt enthält einen Basis-URI, den möglichen URI, eine Name-Wert-Sammlung der Abfrageparameter, eine Matrix der Segmente des relativen Pfads, eine Name-Wert-Sammlung der Variablen, die zugeordnet wurden, die UriTemplate-Instanz, die zum Durchführen der Zuordnung verwendet wurde, eine Zeichenfolge, die jeden nicht zugeordneten Teil des Kandidaten-URI enthält (wird verwendet, wenn die Vorlage über einen Platzhalter verfügt), und ein Objekt, das der Vorlage zugewiesen ist.

Hinweis

Beim Vergleichen eines möglichen URIs mit einer Vorlage ignoriert die UriTemplate-Klasse das Schema und die Portnummer.

Zum Generieren eines URI aus einer Vorlage stehen zwei Methoden zur Verfügung: BindByName(Uri, NameValueCollection) und BindByPosition(Uri, String[]). BindByName(Uri, NameValueCollection) akzeptiert eine Basisadresse und eine Name-Wert-Auflistung der Parameter. Wenn die Vorlage gebunden ist, werden diese Parameter durch Variablen ersetzt. BindByPosition(Uri, String[]) akzeptiert die Name-Wert-Paare und ersetzt sie von links nach rechts.

ToString() gibt die Vorlagenzeichenfolge zurück,

Die PathSegmentVariableNames-Eigenschaft enthält eine Sammlung der Namen der Variablen, die innerhalb der Pfadsegmente in der Vorlagenzeichenfolge verwendet werden.

IsEquivalentTo(UriTemplate) akzeptiert UriTemplate als Parameter und gibt einen booleschen Wert zurück, der angibt, ob die beiden Vorlagen gleichwertig sind. Weitere Informationen finden Sie im Abschnitt über die Gleichwertigkeit von Vorlagen weiter unten in diesem Thema.

UriTemplate wurde für die Zusammenarbeit mit einem URI-Schema entwickelt, das der HTTP URI-Grammatik entspricht. Im Folgenden finden Sie Beispiele für unterstützte URI-Schemas:

  • http://

  • https://

  • net.tcp://

  • net.pipe://

  • sb://

Schemas wie "file://" und "urn://" entsprechen nicht der HTTP-URI-Grammatik und führen bei der Verwendung mit URI-Vorlagen zu unvorhersehbaren Ergebnissen.

Vorlagenzeichenfolgen-Syntax

Eine Vorlage besteht aus drei Teilen: einem Pfad, einer optionalen Abfrage und einem optionalen Fragment. Ein Beispiel finden Sie in der folgenden Vorlage:

"/weather/{state}/{city}?forecast={length)#frag1

Der Pfad besteht aus "/Wetter/{Bundesland}/{Ort}", die Abfrage besteht aus "?forecast={Länge}, und das Fragment besteht aus "#frag1."

Führende und nachstehende Schrägstriche sind im Pfadausdruck optional. Sowohl der Abfrage- als auch der Fragmentausdruck kann vollständig weggelassen werden. Ein Pfad besteht aus einer Reihe von Segmenten, die durch "/" voneinander getrennt sind; jedes Segment kann einen Literalwert, einen Variablennamen (der in {geschweiften Klammern} steht) oder einen Platzhalter (der als "*" geschrieben wird) besitzen. In der vorherigen Vorlage ist das "\Wetter\"-Segment ein Literalwert, während "{Bundesland}" und "{Ort}" Variablen sind. Variablen erhalten ihren Namen von den Inhalten der geschweiften Klammern und können später durch einen bestimmten Wert ersetzt werden, um einen geschlossenen URI zu erschaffen. Der Platzhalter ist optional, kann aber nur am Ende des URI eingesetzt werden, wo er logisch "dem Rest des Pfads" entspricht.

Der Abfrageausdruck gibt ggf. eine Reihe ungeordneter Name-Wert-Paare an, die durch „&“ getrennt werden. Bei den Elementen des Abfrageausdrucks kann es sich entweder um Literalpaare (x=2) oder ein Variablenpaar (x={var}) handeln. Nur die rechte Seite der Abfrage kann einen variablen Ausdruck enthalten. ({someName} = {someValue} ist nicht zulässig. Ungepaarte Werte (?x) sind nicht zulässig. Es besteht kein Unterschied zwischen einem leeren Abfrageausdruck und einem Abfrageausdruck, der aus einem einzelnen "?" besteht (beide stehen für "jede Abfrage").

Der Fragmentausdruck kann aus einem Literalwert bestehen, Variablen sind nicht zulässig.

Alle Vorlagenvariablennamen innerhalb einer Vorlagenzeichenfolge müssen eindeutig sein. Bei Namen von Vorlagenvariablen wird die Groß- und Kleinschreibung nicht berücksichtigt.

Beispiele für gültige Vorlagenzeichenfolgen:

  • ""

  • "/Schuh"

  • "/Schuh/*"

  • "{Schuh}/Boot"

  • "{shoe}/{boat}/bed/{quilt}"

  • "shoe/{boat}"

  • "shoe/{boat}/*"

  • "shoe/boat?x=2"

  • "shoe/{boat}?x={bed}"

  • "shoe/{boat}?x={bed}&y=band"

  • "?x={shoe}"

  • "shoe?x=3&y={var}

Beispiele für ungültige Vorlagenzeichenfolgen sind:

  • "{shoe}/{SHOE}/x=2" - Doppelte Variablennamen.

  • "{shoe}/boat/?bed={shoe}" - Doppelte Variablennamen.

  • "?x=2&x=3" – Name-Wert-Paare innerhalb einer Abfragezeichenfolge müssen eindeutig sein, auch wenn sie Literale sind.

  • "?x=2&" – Abfragezeichenfolge ist fehlerhaft.

  • "?2&x={shoe}" – Abfragezeichenfolge muss Name-Wert-Paar sein.

  • "?y=2&&X=3" – Abfragezeichenfolge muss Name-Wert-Paar sein; Namen dürfen nicht mit „&“ beginnen.

Zusammengesetzte Pfadsegmente

Bei zusammengesetzten Pfadsegmenten kann ein einzelnes URI-Pfadsegment mehrere Variablen sowie mit Literalwerten kombinierte Variablen enhalten. Im Folgenden finden Sie Beispiele für gültige zusammengesetzte Pfadsegmente:

  • /Dateiname.{Erw.}/

  • /{Dateiname}.jpg/

  • /{Dateiname}.{Erw.}/

  • /{a}.{b}Literalwert{c}({d})/

Im Folgenden finden Sie Beispiele für ungültige Pfadsegmente:

  • /{} – Variablen müssen benannt werden.

  • /{Schuh}{Boot} – Variablen müssen durch einen Literalwert getrennt werden.

Zuordnung und zusammengesetzte Pfadsegmente

Zusammengesetzte Pfadsegmente ermöglichen Ihnen das Definieren einer UriTemplate mit mehreren Variablen in nur einem Pfadsegment. In der Vorlagenzeichenfolge "Addresses/{state}.{city}" sind zwei Variablen (state und city) in demselben Segment definiert. Diese Vorlage entspricht einer URL wie http://example.com/Washington.Redmond, entspricht aber auch einer URL wie http://example.com/Washington.Redmond.Microsoft. In letzterem Fall enthält die state-Variable "Washington" und die city-Variable "Redmond.Microsoft". In diesem Fall entspricht jeder Text (mit Ausnahme von "/") der {city}-Variable. Wenn Sie eine Vorlage erstellen möchten, durch die der "zusätzliche" Text nicht zugeordnet wird, fügen Sie die Variable in einem separaten Vorlagensegment ein, z. B. "Addresses/{state}/{city}".

Benannte Platzhaltersegmente

Bei einem benannten Platzhaltersegment handelt es sich um ein beliebiges Pfadvariablensegment, dessen Variablenname mit dem Platzhalterzeichen "*" beginnt. Die folgende Vorlagenzeichenfolge enthält ein benanntes Platzhaltersegment mit dem Namen "Schuh".

"literal/{*shoe}"

Für Platzhaltersegmente gelten die folgenden Regeln:

  • Für jede Vorlagenzeichenfolge kann höchstens ein benanntes Platzhaltersegment vorhanden sein.

  • Ein benanntes Platzhaltersegment muss sich im am weitesten rechts stehenden Segment des Pfads befinden.

  • Ein benanntes Platzhaltersegment kann nicht zusammen mit einem anonymen Platzhaltersegment innerhalb der gleichen Vorlagenzeichenfolge verwendet werden.

  • Der Name eines benannten Platzhaltersegments muss eindeutig sein.

  • Benannte Platzhaltersegmente können keine Standardwerte besitzen.

  • Benannte Platzhaltersegmente können nicht mit "/" enden.

Standardvariablenwerte

Standardvariablenwerte ermöglichen das Angeben von Standardwerten für Variablen innerhalb einer Vorlage. Standardvariablen können mit den geschweiften Klammern, durch die die Variable deklariert wird, oder durch eine an den UriTemplate-Konstruktor weitergegebene Sammlung angegeben werden. Die folgende Vorlage zeigt zwei Möglichkeiten, eine UriTemplate mit Variablen mit Standardwerten anzugeben:

UriTemplate t = new UriTemplate("/test/{a=1}/{b=5}");  

In dieser Vorlage werden die Variable a mit dem Standardwert 1 und die Variable b mit dem Standardwert 5 deklariert.

Hinweis

Nur Pfadsegmentvariablen können Standardwerte besitzen. Bei Abfragezeichenfolgenvariablen, zusammengesetzten Segmentvariablen sowie bei benannten Platzhaltervariablen sind Standardwerte nicht zulässig.

Im folgenden Code wird die Behandlung von Standardvariablenwerten beim Abgleichen eines möglichen URI gezeigt:

Uri baseAddress = new Uri("http://localhost:8000/");

UriTemplate t = new UriTemplate("/{state=WA}/{city=Redmond}/", true);
Uri candidate = new Uri("http://localhost:8000/OR");

UriTemplateMatch m1 = t.Match(baseAddress, candidate);

Console.WriteLine($"Template: {t}");
Console.WriteLine($"Candidate URI: {candidate}");

// Display contents of BoundVariables
Console.WriteLine("BoundVariables:");
foreach (string key in m1.BoundVariables.AllKeys)
{
    Console.WriteLine($"\t{key}={m1.BoundVariables[key]}");
}
// The output of the above code is  
// Template: /{state=WA}/{city=Redmond}/
// Candidate URI: http://localhost:8000/OR
// BoundVariables:
//         STATE=OR
//         CITY=Redmond

Hinweis

Der URI http://localhost:8000/// entspricht nicht der im vorhergehenden Code enthaltenen Vorlage, der URI http://localhost:8000/ dagegen schon.

Im folgenden Code wird die Behandlung von Standardvariablenwerten beim Erstellen eines URI mit einer Vorlage veranschaulicht:

Uri baseAddress = new Uri("http://localhost:8000/");  
Dictionary<string,string> defVals = new Dictionary<string,string> {{"a","1"}, {"b", "5"}};  
UriTemplate t = new UriTemplate("/test/{a}/{b}", defVals);  
NameValueCollection vals = new NameValueCollection();  
vals.Add("a", "10");  
  
Uri boundUri = t.BindByName(baseAddress, vals);  
Console.WriteLine("BaseAddress: {0}", baseAddress);  
Console.WriteLine("Template: {0}", t.ToString());  
  
Console.WriteLine("Values: ");  
foreach (string key in vals.AllKeys)  
{  
    Console.WriteLine("\tKey = {0}, Value = {1}", key, vals[key]);  
}  
Console.WriteLine("Bound URI: {0}", boundUri);  
  
// The output of the preceding code is  
// BaseAddress: http://localhost:8000/  
// Template: /test/{a}/{b}  
// Values:  
//     Key = a, Value = 10  
// Bound URI: http://localhost:8000/test/10/5  

Erhält eine Variable den Standardwert null, gelten einige zusätzliche Einschränkungen. Eine Variable kann den Standardwert null besitzen, wenn sich die Variable im am weitesten rechts befindlichen Segment der Vorlagenzeichenfolge befindet oder wenn alle Segmente rechts des Segments jeweils den Standardwert null besitzen. Im Folgenden finden Sie gültige Vorlagenzeichenfolgen mit dem Standardwert null:

  • UriTemplate t = new UriTemplate("shoe/{boat=null}");

  • UriTemplate t = new UriTemplate("{shoe=null}/{boat=null}");

  • UriTemplate t = new UriTemplate("{shoe=1}/{boat=null}");

Im Folgenden finden Sie ungültige Vorlagenzeichenfolgen mit dem Standardwert null:

  • UriTemplate t = new UriTemplate("{shoe=null}/boat"); // null default must be in the right most path segment

  • UriTemplate t = new UriTemplate("{shoe=null}/{boat=x}/{bed=null}"); // shoe cannot have a null default because boat does not have a default null value

Standardwerte und Vergleich

Beim Vergleichen eines möglichen URI mit einer Vorlage mit Standardwerten werden die Standardwerte in der BoundVariables-Sammlung platziert, wenn im möglichen URI keine Werte angegeben sind.

Vorlagenäquivalenz

Zwei Vorlagen gelten als strukturell äquivalent, wenn alle Literalwerte der Vorlagen übereinstimmen und sie über Variablen in den gleichen Segmenten verfügen. Beispielsweise sind die folgenden Vorlagen strukturell äquivalent:

  • /a/{var1}/b b/{var2}?x=1&y=2

  • a/{x}/b%20b/{var1}?y=2&x=1

  • a/{y}/B%20B/{z}/?y=2&x=1

Hierbei müssen noch einige Punkte beachtet werden:

  • Wenn eine Vorlage führende Schrägstriche enthält, wird nur der erste ignoriert.

  • Wenn Vorlagenzeichenfolgen auf strukturelle Äquivalenz verglichen werden, wird die Groß-/Kleinschreibungen bei den Variablennamen und Pfadsegmenten ignoriert; bei den Abfragezeichenfolgen muss sie beachtet werden.

  • Abfragezeichenfolgen sind unsortiert.

UriTemplateTable

Die Klasse UriTemplateTable stellt eine assoziative Tabelle aus UriTemplate-Objekten dar, die an ein Objekt nach Wahl des Entwicklers gebunden sind. UriTemplateTable muss vor Aufruf von UriTemplate mindestens eine MakeReadOnly(Boolean) enthalten. Der Inhalt einer UriTemplateTable kann geändert werden, bis MakeReadOnly(Boolean) aufgerufen wird. Die Überprüfung wird ausgeführt, wenn MakeReadOnly(Boolean) aufgerufen wird. Der Typ der ausgeführten Validierung hängt vom Wert des Parameters allowMultiple zur MakeReadOnly(Boolean) ab.

Wenn MakeReadOnly(Boolean) bei Übergabe in false aufgerufen wird, überprüft die UriTemplateTable, dass sich keine Vorlagen in der Tabelle befinden. Wenn strukturell äquivalente Vorlagen gefunden werden, wird eine Ausnahme ausgelöst. Dies wird zusammen mit MatchSingle(Uri) verwendet, wenn sichergestellt werden soll, dass nur eine Vorlage einem eingehenden URI entspricht.

Wenn MakeReadOnly(Boolean) bei der Übergabe von true aufgerufen wird, lässt UriTemplateTable mehrere strukturell äquivalente Vorlagen in einer UriTemplateTable zu.

Wenn ein Satz UriTemplate-Objekte, die einer UriTemplateTable hinzugefügt sind, Abfragezeichenfolgen enthält, dürfen sie nicht mehrdeutig sein. Identische Abfragezeichenfolgen sind zulässig.

Hinweis

Zwar lässt die UriTemplateTable Basisadressen mit HTTP-fremden Schemas zu, Schema und Portnummer werden beim Vergleichen möglicher URIs mit Vorlagen jedoch ignoriert.

Abfragezeichenfolgenmehrdeutigkeit

Vorlagen, die einen äquivalenten Pfad teilen, enthalten mehrdeutige Abfragezeichenfolgen, wenn es einen URI gibt, der mehr als einer Vorlage entspricht.

Die folgenden Sätze von Abfragezeichenfolgen sind in sich selbst eindeutig:

  • ?x=1

  • ?x=2

  • ?x=3

  • ?x=1&y={var}

  • ?x=2&z={var}

  • ?x=3

  • ?x=1

  • ?

  • ? x={var}

  • ?

  • ?m=get&c=rss

  • ?m=put&c=rss

  • ?m=get&c=atom

  • ?m=put&c=atom

Die folgenden Abfragezeichenfolgenvorlagen sind in sich selbst mehrdeutig:

  • ?x=1

  • ?x={var}

"x=1" – passt zu beiden Vorlagen.

  • ?x=1

  • ?y=2

"x=1&y=2" entspricht beiden Vorlagen. Das liegt daran, dass eine Abfragezeichenfolge mehr Abfragezeichenfolgen-Variablen enthalten kann als die Vorlage, zu der sie passt.

  • ?x=1

  • ?x=1&y={var}

"x=1&y=3" entspricht beiden Vorlagen.

  • ?x=3&y=4

  • ?x=3&z=5

Hinweis

Die Zeichen "á" und "Á" gelten als unterschiedliche Zeichen, wenn sie als Teil eines URI-Pfads oder eines UriTemplate-Pfadsegmentliterals verwendet werden. (Die Zeichen "a" und "A" gelten hingegen als gleich.) Die Zeichen á und Á gelten als gleiche Zeichen, wenn sie als Teil einer UriTemplate {Variablenname} oder einer Abfragezeichenfolge erscheinen (a und A gelten ebenfalls als gleiche Zeichen).

Weitere Informationen