UriTemplate dan UriTemplateTable
Pengembang web memerlukan kemampuan untuk menggambarkan bentuk dan tata letak URI yang direspons layanan mereka. Windows Communication Foundation (WCF) menambahkan dua kelas baru untuk memberi pengembang kontrol atas URI mereka. UriTemplate dan UriTemplateTable membentuk dasar mesin pengiriman berbasis URI di WCF. Kelas-kelas ini juga dapat digunakan sendiri, memungkinkan pengembang untuk memanfaatkan templat dan mekanisme pemetaan URI tanpa menerapkan layanan WCF.
Templat
Templat adalah cara untuk menjelaskan sekumpulan URI relatif. Kumpulan templat URI dalam tabel berikut menunjukkan bagaimana sistem yang mengambil berbagai jenis informasi cuaca mungkin ditentukan.
Data | Templat |
---|---|
Prakiraan Nasional | cuaca/nasional |
Prakiraan Status | weather/{state} |
Prakiraan Kota | weather/{state}/{city} |
Prakiraan Aktivitas | weather/{state}/{city}/{activity} |
Tabel ini menjelaskan sekumpulan URI yang serupa secara struktural. Setiap entri adalah templat URI. Segmen dalam kurung kurawal menggambarkan variabel. Segmen yang tidak dalam kurung kurawal menggambarkan string harfiah. Kelas templat WCF memungkinkan pengembang untuk mengambil URI masuk, misalnya, "/weather/wa/seattle/cycling", dan mencocokkannya dengan templat yang menjelaskannya, "/weather/{state}/{city}/{activity}".
UriTemplate
UriTemplate adalah kelas yang merangkum templat URI. Konstruktor mengambil parameter string yang menentukan templat. String ini berisi templat dalam format yang dijelaskan di bagian berikutnya. Kelas UriTemplate menyediakan metode yang memungkinkan Anda mencocokkan URI yang masuk ke templat, menghasilkan URI dari templat, mengambil kumpulan nama variabel yang digunakan dalam templat, menentukan apakah dua templat setara, dan mengembalikan string templat.
Match(Uri, Uri) mengambil alamat dasar dan URI kandidat dan mencoba mencocokkan URI dengan templat. Jika kecocokan berhasil, instans UriTemplateMatch dikembalikan. Objek UriTemplateMatch berisi URI dasar, kandidat URI, kumpulan nama/nilai dari parameter kueri, array segmen jalur relatif, kumpulan nama/nilai variabel yang cocok, instans UriTemplate yang digunakan untuk melakukan pencocokan, string yang berisi bagian kandidat URI yang tidak cocok (digunakan saat templat memiliki wildcard), dan objek yang terkait dengan templat.
Catatan
Kelas UriTemplate mengabaikan skema dan nomor port saat mencocokkan URI kandidat dengan templat.
Ada dua metode yang memungkinkan Anda menghasilkan URI dari templat, BindByName(Uri, NameValueCollection) dan BindByPosition(Uri, String[]). BindByName(Uri, NameValueCollection) mengambil alamat dasar dan kumpulan nama/nilai parameter. Parameter ini menggantikan variabel ketika templat terikat. BindByPosition(Uri, String[]) mengambil pasangan nama/nilai dan menggantinya dari kiri ke kanan.
ToString() mengembalikan string templat.
Properti PathSegmentVariableNames berisi kumpulan nama variabel yang digunakan dalam segmen jalur dalam string templat.
IsEquivalentTo(UriTemplate) mengambil UriTemplate sebagai parameter dan mengembalikan nilai Boolean yang menentukan apakah kedua templat tersebut setara. Untuk informasi selengkapnya, lihat bagian Kesetaraan Templat setelahnya dalam topik ini.
UriTemplate dirancang untuk bekerja dengan skema URI apa pun yang sesuai dengan tata bahasa URI HTTP. Berikut ini adalah contoh skema URI yang didukung.
http://
https://
net.tcp://
net.pipe://
sb://
Skema seperti file:// dan urn:// tidak sesuai dengan tata bahasa HTTP URI dan menyebabkan hasil yang tidak dapat diprediksi saat digunakan dengan templat URI.
Sintaks String Templat
Templat memiliki tiga bagian: jalur, kueri opsional, dan fragmen opsional. Sebagai contoh, lihat templat berikut:
"/weather/{state}/{city}?forecast={length)#frag1
Jalur terdiri dari "/weather/{state}/{city}", kueri terdiri dari "?forecast={length}, dan fragmen terdiri dari "#frag1".
Garis miring di awal dan akhir bersifat opsional dalam ekspresi jalur. Ekspresi kueri dan fragmen dapat dihilangkan sepenuhnya. Jalur terdiri dari serangkaian segmen yang dibatasi oleh '/', setiap segmen dapat memiliki nilai harfiah, nama variabel (ditulis dalam {kurung kurawal}), atau wildcard (ditulis sebagai '*'). Pada templat sebelumnya, segmen "\weather\ adalah nilai harfiah sedangkan "{state}" dan "{city}" adalah variabel. Variabel mengambil namanya dari isi kurung kurawalnya dan nantinya dapat diganti dengan nilai konkret untuk membuat URI tertutup. Wildcardi bersifat opsional, tetapi hanya dapat muncul di akhir URI, yang secara logis cocok dengan "jalur lainnya".
Ekspresi kueri, jika ada, menentukan serangkaian pasangan nama/nilai yang tidak diurutkan yang dibatasi oleh '&'. Elemen ekspresi kueri dapat berupa pasangan harfiah (x=2) atau pasangan variabel (x={var}). Hanya sisi kanan kueri yang dapat memiliki ekspresi variabel. ({someName} = {someValue} tidak diperbolehkan. Nilai yang tidak berpasangan (?x) tidak diizinkan. Tidak ada perbedaan antara ekspresi kueri kosong dan ekspresi kueri yang hanya terdiri dari satu '?' (keduanya berarti "kueri apa pun").
Ekspresi fragmen dapat terdiri dari nilai harfiah, tidak ada variabel yang diizinkan.
Semua nama variabel templat dalam string templat harus unik. Nama variabel templat tidak peka huruf besar/kecil.
Contoh string templat yang valid:
""
"/shoe"
"/shoe/*"
"{shoe}/boat"
"{shoe}/{boat}/bed/{quilt}"
"shoe/{boat}"
"shoe/{boat}/*"
"shoe/boat?x=2"
"shoe/{boat}?x={bed}"
"shoe/{boat}?x={bed}&y=band"
"?x={shoe}"
"sepatu?x=3&y={var}
Contoh string templat yang tidak valid:
"{shoe}/{SHOE}/x=2" – Nama variabel duplikat.
"{shoe}/boat/?bed={shoe}" – Nama variabel duplikat.
"?x=2&x=3" – Pasangan nama/nilai dalam string kueri harus unik, bahkan jika itu harfiah.
"?x=2&" – String kueri salah bentuk.
"?2&x={shoe}" – String kueri harus berupa pasangan nama/nilai.
"?y=2&&X=3" – String kueri harus berupa pasangan nilai nama, nama tidak dapat dimulai dengan '&'.
Segmen Jalur Campuran
Segmen jalur campuran memungkinkan segmen jalur URI tunggal berisi banyak variabel serta variabel yang digabungkan dengan harfiah. Berikut ini adalah contoh segmen jalur campuran yang valid.
/filename.{ext}/
/{filename}.jpg/
/{filename}.{ext}/
/{a}.{b}someLiteral{c}({d})/
Berikut ini adalah contoh segmen jalur yang tidak valid.
/{} - Variabel harus diberi nama.
/{shoe}{boat} - Variabel harus dipisahkan oleh harfiah.
Segmen Jalur Pencocokan dan Campuran
Segmen jalur campuran memungkinkan Anda untuk menentukan UriTemplate yang memiliki banyak variabel dalam satu segmen jalur. Misalnya, dalam string templat berikut: "Addresses/{state}. {city}" dua variabel (negara bagian dan kota) didefinisikan dalam segmen yang sama. Templat ini akan cocok dengan URL seperti http://example.com/Washington.Redmond
tetapi juga akan cocok dengan URL seperti http://example.com/Washington.Redmond.Microsoft
. Dalam kasus terakhir, variabel negara bagian akan berisi "Washington" dan variabel kota akan berisi "Redmond.Microsoft". Dalam hal ini, teks apa pun (kecuali '/') akan cocok dengan variabel {city}. Jika Anda menginginkan templat yang tidak cocok dengan teks "ekstra", tempatkan variabel di segmen templat terpisah, misalnya: "Addresses/{state}/{city}.
Segmen Wildcard Bernama
Segmen wildcard bernama adalah segmen variabel jalur apa pun yang nama variabelnya dimulai dengan wildcard '*'. String templat berikut berisi segmen wildcard bernama "shoe".
"literal/{*shoe}"
Segmen wildcard harus mengikuti aturan berikut:
Paling banyak ada satu segmen wildcard bernama untuk setiap string templat.
Segmen wildcard bernama harus muncul di segmen paling kanan di jalur tersebut.
Segmen wildcard bernama tidak dapat berdampingan dengan segmen wildcard anonim dalam string templat yang sama.
Nama segmen wildcard bernama harus unik.
Segmen wildcard bernama tidak boleh memiliki nilai default.
Segmen wildcard bernama tidak dapat diakhir dengan "/".
Nilai Variabel Default
Nilai variabel default memungkinkan Anda menentukan nilai default untuk variabel dalam templat. Variabel default dapat ditentukan dengan kurung kurawal yang mendeklarasikan variabel atau sebagai kumpulan yang diteruskan ke konstruktor UriTemplate. Templat berikut ini memperlihatkan dua cara untuk menentukan UriTemplate dengan variabel dengan nilai default.
UriTemplate t = new UriTemplate("/test/{a=1}/{b=5}");
Templat ini mendeklarasikan variabel bernama a
dengan nilai default 1
dan variabel bernama b
dengan nilai default 5
.
Catatan
Hanya variabel segmen jalur yang diizinkan untuk memiliki nilai default. Variabel string kueri, variabel segmen campuran, dan variabel wildcard bernama tidak diizinkan memiliki nilai default.
Kode berikut menunjukkan bagaimana nilai variabel default ditangani saat mencocokkan kandidat URI.
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
Catatan
URI seperti http://localhost:8000///
tidak cocok dengan templat yang tercantum dalam kode sebelumnya, namun URI seperti http://localhost:8000/
cocok dengan templat yang tercantum sebelumnya.
Kode berikut menunjukkan bagaimana nilai variabel default ditangani saat membuat URI dengan templat.
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
Ketika variabel diberikan nilai default null
, ada beberapa batasan tambahan. Variabel dapat memiliki nilai default null
jika variabel terkandung dalam segmen paling kanan dari string templat atau jika semua segmen di sebelah kanan segmen memiliki nilai default null
. Berikut ini adalah string templat yang valid dengan nilai default null
:
UriTemplate t = new UriTemplate("shoe/{boat=null}");
UriTemplate t = new UriTemplate("{shoe=null}/{boat=null}");
UriTemplate t = new UriTemplate("{shoe=1}/{boat=null}");
Berikut ini adalah string templat yang tidak valid dengan nilai default 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
Nilai Default dan Pencocokan
Saat mencocokkan kandidat URI dengan templat yang memiliki nilai default, nilai default ditempatkan dalam kumpulan BoundVariables jika nilai tidak ditentukan dalam kandidat URI.
Kesetaraan Templat
Dua templat dikatakan setara secara struktural ketika semua harfiah templat cocok dan mereka memiliki variabel dalam segmen yang sama. Misalnya, templat berikut secara struktural setara:
/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
Beberapa hal yang perlu diperhatikan:
Jika templat berisi garis miring di depan, hanya yang pertama yang diabaikan.
Saat membandingkan string templat untuk kesetaraan struktural, kasus diabaikan untuk nama variabel dan segmen jalur, string kueri peka huruf besar/kecil.
String kueri tidak diurutkan.
UriTemplateTable
Kelas UriTemplateTable mewakili tabel objek UriTemplate asosiatif yang terikat ke objek yang dipilih pengembang. UriTemplateTable harus berisi setidaknya satu UriTemplate sebelum panggilan MakeReadOnly(Boolean). Konten UriTemplateTable dapat diubah hingga MakeReadOnly(Boolean) dipanggil. Validasi dilakukan ketika MakeReadOnly(Boolean) dipanggil. Jenis validasi yang dilakukan tergantung pada nilai parameter allowMultiple
ke MakeReadOnly(Boolean).
Ketika MakeReadOnly(Boolean) dipanggil melewati false
, pemeriksaan UriTemplateTable untuk memastikan tidak ada templat dalam tabel. Jika menemukan templat yang setara secara struktural, itu akan menampilkan pengecualian. Ini digunakan bersama dengan MatchSingle(Uri) ketika Anda ingin memastikan hanya satu templat yang cocok dengan URI yang masuk.
Ketika MakeReadOnly(Boolean) disebut melewati true
, UriTemplateTable memungkinkan beberapa templat yang setara secara struktural terkandung dalam UriTemplateTable.
Jika sekumpulan objek UriTemplate yang ditambahkan ke UriTemplateTable berisi string kueri, objek tersebut tidak boleh ambigu. String kueri identik diizinkan.
Catatan
Sementara UriTemplateTable memungkinkan alamat dasar yang menggunakan skema selain HTTP, skema dan nomor port diabaikan saat mencocokkan kandidat URI dengan templat.
Ambiguitas String Kueri
Templat yang berbagi jalur yang setara berisi string kueri yang ambigu jika ada URI yang cocok dengan lebih dari satu templat.
Kumpulan string kueri berikut ini tidak ambigu didalamnya:
?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
Kumpulan templat string kueri berikut ini ambigu didalam:
?x=1
?x={var}
"x=1" - Cocok dengan kedua templat.
?x=1
?y=2
"x=1&y=2" cocok dengan kedua templat. Hal ini dikarenakan string kueri mungkin berisi lebih banyak variabel string kueri maka templatnya yang cocok.
?x=1
?x=1&y={var}
"x=1&y=3" cocok dengan kedua templat.
?x=3&y=4
?x=3&z=5
Catatan
Karakter á dan Á dianggap sebagai karakter yang berbeda ketika muncul sebagai bagian dari jalur URI atau UriTemplate segmen jalur harfiah (tetapi karakter a dan A dianggap sama). Karakter á dan Á dianggap sebagai karakter yang sama ketika muncul sebagai bagian dari {variableName} UriTemplate atau string kueri (dan a dan A juga dianggap sebagai karakter yang sama).