UriTemplate und UriTemplateTable

Webentwickler benötigen die Fähigkeit, die Form und das Layout der URIs zu beschreiben, auf die ihre Dienste reagieren. In Windows Communication Foundation (WCF) wurden zwei neue Klassen hinzugefügt, mit denen die Entwickler ihre URIs gut kontrollieren können. UriTemplate und UriTemplateTable bilden die Basis des URI-basierten Dispatchmoduls 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 in nicht geschweiften Klammern beschreiben Literalzeichenfolgen. Die WCF-Vorlagenklassen ermöglichen es einem 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 Klasse UriTemplate 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 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.

Tipp

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 und BindByPosition. BindByName akzeptiert eine Basisadresse und eine Name-Wert-Sammlung der Parameter. Wenn die Vorlage in einer Bindung ist, werden diese Parameter durch Variablen ersetzt. BindByPosition nimmt die Name-Wert-Paare und ersetzt sie von links nach rechts.

ToString gibt die Vorlagenzeichenfolge zurück,

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

IsEquivalentTo nimmt eine UriTemplate als Parameter und gibt einen Booleschen Wert zurück, der angibt, ob die beiden Vorlagen gleichwertig sind. Weitere Informationen finden Sie unter dem Abschnitt "Vorlagenäquivalenz" weiter unten in diesem Thema.

"T:System.UriTemplate" wurde für die Arbeit mit einem beliebigen 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 sind:

  • ""
  • "/Schuh"
  • "/Schuh/*"
  • "{Schuh}/Boot"
  • " {Schuh}/{Boot}/Bett/{Steppdecke}"
  • "Schuh/{Boot}"
  • "Schuh/{Boot}/*"
  • "Schuh/Boot?x=2"
  • "Schuh/{Boot}?x={Bett}"
  • "Schuh/{Boot}?x={Bett}&y=band"
  • "?x={Schuh}"
  • "Schuh?x=3&y={var}

Beispiele für ungültige Vorlagenzeichenfolgen sind:

  • "{Schuh}/{SCHUH}/x=2" – doppelte Variablennamen.
  • "{Schuh}/Boot/?Bett={SCHUH}" – 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={Schuh}" – 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.

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 "shoe".

“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}”);
Dictionary<string,string> defVals = new Dictionary<string,string> {{"a","1"}, {"b", "5"}};
UriTemplate t = new UriTemplate("/test/{a}/{b}", defVals);

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

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("https://localhost:8000");
UriTemplate t = new UriTemplate("/{state=WA}/{city=Redmond}/", true);
Uri candidate = new Uri("https://localhost:8000/OR");

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

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

Tipp

Der URI "https://localhost:8000///" entspricht der im oben gezeigten Code enthaltenen Vorlage nicht, der URI "https://localhost:8000/" dagegen schon.

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

Uri baseAddress = new Uri("https://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 above code is
// BaseAddress: https://localhost:8000/
// Template: /test/{a}/{b}
// Values:
//     Key = a, Value = 10
// Bound URI: https://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 MakeReadOnly mindestens eine UriTemplate enthalten. Der Inhalt einer UriTemplateTable kann geändert werden, bis MakeReadOnly aufgerufen wird. Die Überprüfung wird ausgeführt, wenn MakeReadOnly aufgerufen wird. Der Typ der ausgeführten Prüfung hängt vom Wert des Parameters allowMultiple zur MakeReadOnly ab.

Wenn MakeReadOnly 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 verwendet, wenn sichergestellt werden soll, dass nur eine Vorlage einem eingehenden URI entspricht.

Wenn MakeReadOnly 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.

Tipp

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 Sätze von Abfragezeichenfolgenvorlagen sind in sich selbst mehrdeutig:

  • ?x=1
  • ?x={Var.}

"x=1" – passt zu beiden Vorlagen.

  • ?x=1
  • ?y=2

"x=1&y=2" passt zu 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" passt zu beiden Vorlagen.

  • ?x=3&y=4
  • ?x=3&z=5

Tipp

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).

Siehe auch

Konzepte

Überblick über WCF-Webprogrammiermodelle
Objektmodell für WCF-Webprogrammierung

Weitere Ressourcen

UriTemplate Sample
UriTemplate Table Sample
UriTemplate Table Dispatcher Sample