UriTemplate 和 UriTemplateTableUriTemplate and UriTemplateTable

Web 开发人员需要能够描述其服务所响应的 URI 的形状和布局。Web developers require the ability to describe the shape and layout of the URIs that their services respond to. Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) 添加了两个新类,让开发人员控制他们的 URI。 added two new classes to give developers control over their URIs. UriTemplateUriTemplateTable 构成 WCFWCF 中基于 URI 的调度引擎的基础。UriTemplate and UriTemplateTable form the basis of the URI-based dispatch engine in WCFWCF. 这些类还可单独使用,使开发人员能够利用模板和 URI 映射机制,而无需实现 WCFWCF 服务。These classes can also be used on their own, allowing developers to take advantage of templates and the URI mapping mechanism without implementing a WCFWCF service.

模板Templates

模板是一种描述一组相对 URI 的方法。A template is a way to describe a set of relative URIs. 下表中的一组 URI 模板演示如何定义一个检索各类天气信息的系统。The set of URI templates in the following table shows how a system that retrieves various types of weather information might be defined.

数据Data 模板Template
全国预报National Forecast weather/nationalweather/national
州预报State Forecast weather/{state}weather/{state}
城市预报City Forecast weather/{state}/{city}weather/{state}/{city}
活动预报Activity Forecast weather/{state}/{city}/{activity}weather/{state}/{city}/{activity}

上表描述了一组结构相似的 URI。This table describes a set of structurally similar URIs. 每一项都是一个 URI 模板。Each entry is a URI template. 大括号中的各段描述变量;The segments in curly braces describe variables. 大括号之外的各段描述文本字符串。The segments not in curly braces describe literal strings. 通过使用 WCFWCF 模板类,开发人员可以获取一个传入 URI,例如“/weather/wa/seattle/cycling”,并将其与描述它的模板“/weather/{state}/{city}/{activity}”进行匹配。The WCFWCF template classes allow a developer to take an incoming URI, for example, "/weather/wa/seattle/cycling", and match it to a template that describes it, "/weather/{state}/{city}/{activity}".

UriTemplateUriTemplate

UriTemplate 是包装 URI 模板的类。UriTemplate is a class that encapsulates a URI template. 其构造函数接受一个定义模板的字符串参数。The constructor takes a string parameter that defines the template. 此字符串包含具有下节所述格式的模板。This string contains the template in the format described in the next section. UriTemplate 类提供一些方法,用于将传入的 URI 与模板进行匹配,根据模板生成 URI,检索在模板中使用的变量名集合,确定两个模板是否等效,返回模板的字符串。The UriTemplate class provides methods that allow you match an incoming URI to a template, generate a URI from a template, retrieve a collection of variable names used in the template, determine whether two templates are equivalent, and return the template's string.

Match(Uri, Uri) 接受一个基址和一个候选 URI,并尝试将该 URI 与模板进行匹配。Match(Uri, Uri) takes a base address and a candidate URI and attempts to match the URI to the template. 如果匹配成功,则返回一个 UriTemplateMatch 实例。If the match is successful, a UriTemplateMatch instance is returned. UriTemplateMatch 对象包含一个基准 URI、候选 URI、查询参数的名称/值集合、相对路径段数组、匹配变量的名称/值集合、用于执行匹配操作的 UriTemplate 实例、包含候选 URI 中任意不匹配部分的字符串(在模板有通配符时使用),以及一个与模板关联的对象。The UriTemplateMatch object contains a base URI, the candidate URI, a name/value collection of the query parameters, an array of the relative path segments, a name/value collection of variables that were matched, the UriTemplate instance used to perform the match, a string that contains any unmatched portion of the candidate URI (used when the template has a wildcard), and an object that is associated with the template.

备注

将候选 URI 与模板进行匹配时,UriTemplate 类将忽略方案和端口号。The UriTemplate class ignores the scheme and port number when matching a candidate URI to a template.

从模板生成 URI 的方法有两个,即 BindByName(Uri, NameValueCollection)BindByPosition(Uri, String[])There are two methods that allow you to generate a URI from a template, BindByName(Uri, NameValueCollection) and BindByPosition(Uri, String[]). BindByName(Uri, NameValueCollection) 接受一个基址和一个参数的名称/值集合。BindByName(Uri, NameValueCollection) takes a base address and a name/value collection of parameters. 模板绑定后,这些参数将替换变量。These parameters are substituted for variables when the template is bound. BindByPosition(Uri, String[]) 接受名称/值对,并从左向右替换他们。BindByPosition(Uri, String[]) takes the name/value pairs and substitutes them left to right.

ToString() 返回模板字符串。ToString() returns the template string.

PathSegmentVariableNames 属性包含变量名称的集合,这些变量就是模板字符串的路径段中所使用的变量。The PathSegmentVariableNames property contains a collection of the names of the variables used within path segments in the template string.

IsEquivalentTo(UriTemplate) 接受一个 UriTemplate 作为参数,并返回一个布尔值,该值指定两个模板是否等效。IsEquivalentTo(UriTemplate) takes a UriTemplate as a parameter and returns a Boolean value that specifies whether the two templates are equivalent. 有关详细信息,请参阅For more information, see本主题后面的“模板等效性”部分。 the Template Equivalence section later in this topic.

UriTemplate 旨在处理符合 HTTP URI 语法的任意 URI 方案。UriTemplate is designed to work with any URI scheme that conforms to the HTTP URI grammar. 下面这些示例都是支持的 URI 方案。The following are examples of supported URI schemes.

  • http://http://

  • https://https://

  • net.tcp://net.tcp://

  • net.pipe://net.pipe://

  • sb://sb://

诸如 file:// 和 urn:// 这样的方案不符合 HTTP URI 语法,它们与 URI 模板一起使用时,将导致不可预知的结果。Schemes like file:// and urn:// do not conform to the HTTP URI grammar and cause unpredictable results when used with URI templates.

模板字符串语法Template String Syntax

模板分为三个部分:路径、可选查询和可选片段。A template has three parts: a path, an optional query, and an optional fragment. 有关示例,请参见下面的模板:For an example, see the following template:

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

路径由“/weather/{state}/{city}”构成,查询由“?forecast={length}”构成,片段由“#frag1”构成。The path consists of "/weather/{state}/{city}", the query consists of "?forecast={length}, and the fragment consists of "#frag1".

在路径表达式中,首尾斜杠是可选的。Leading and trailing slashes are optional in the path expression. 查询表达式和片段表达式可完全省略。Both the query and fragment expressions can be omitted entirely. 路径由一系列由分隔的段组成 /,每个段都可以具有文本值、 一个变量名 (写在 {大括号} 中) 或通配符 (编写为*)。A path consists of a series of segments delimited by '/', each segment can have a literal value, a variable name (written in {curly braces}), or a wildcard (written as '*'). 在上一模板中,“\weather\”段为文本值,而“{state}”和“{city}”为变量。In the previous template the "\weather\ segment is a literal value while "{state}" and "{city}" are variables. 变量采用其名称从其大括号的内容和更高版本可以使用一个具体的值,以创建替换它们关闭 URIVariables take their name from the contents of their curly braces and they can later be replaced with a concrete value to create a closed URI. 通配符是可选的但只能出现在其中进行逻辑匹配"路径其余部分"的 URI 的末尾。The wildcard is optional, but can only appear at the end of the URI, where it logically matches "the rest of the path".

查询表达式(如果有)指定一系列用“&”分隔的无序名称/值对。The query expression, if present, specifies a series of unordered name/value pairs delimited by '&'. 查询表达式的元素可以是文本对 (x=2) 或变量对 (x={var})。Elements of the query expression can either be literal pairs (x=2) or a variable pair (x={var}). 只有查询的右侧可以有变量表达式。Only the right side of the query can have a variable expression. 不允许 {someName} = {someValue}。({someName} = {someValue} is not allowed. 不允许使用不成对的值 (?x)。Unpaired values (?x) are not permitted. 没有任何空的查询表达式和查询表达式包含只需单个之间的区别?(同时意味着"任何查询")。There is no difference between an empty query expression and a query expression consisting of just a single '?' (both mean "any query").

片段表达式可以由文本值构成,不允许使用任何变量。The fragment expression can consist of a literal value, no variables are allowed.

模板字符串内的所有模板变量名都必须是唯一的。All template variable names within a template string must be unique. 模板变量名不区分大小写。Template variable names are case-insensitive.

有效模板字符串的示例:Examples of valid template strings:

  • """"

  • "/shoe""/shoe"

  • "/shoe/*""/shoe/*"

  • "{shoe}/boat""{shoe}/boat"

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

  • "shoe / {船}""shoe/{boat}"

  • "shoe / {船} / *""shoe/{boat}/*"

  • "shoe/boat?x=2""shoe/boat?x=2"

  • "shoe / {船}? x = {平台}""shoe/{boat}?x={bed}"

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

  • "?x={shoe}""?x={shoe}"

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

无效模板字符串的示例:Examples of invalid template strings:

  • "{shoe} / {SHOE} / x = 2"– 重复变量名。"{shoe}/{SHOE}/x=2" – Duplicate variable names.

  • "{shoe} /boat/? 平台 = {shoe}"– 重复变量名。"{shoe}/boat/?bed={shoe}" – Duplicate variable names.

  • "? x = 2&x = 3"– 查询字符串中的名称/值对必须是唯一的即使它们是文本。"?x=2&x=3" – Name/value pairs within a query string must be unique, even if they are literals.

  • "? x = 2 (& a)"– 查询字符串的格式不正确。"?x=2&" – Query string is malformed.

  • "? 2 2&x = {shoe}"– 查询字符串必须是名称/值对。"?2&x={shoe}" – Query string must be name/value pairs.

  • "? y = 2 (& a) (& a) X = 3"– 查询字符串必须是名称/值对,名称不能以开头 &。"?y=2&&X=3" – Query string must be name value pairs, names cannot start with '&'.

复合路径段Compound Path Segments

复合路径段允许单个 URI 路径段包含多个变量,以及组合有文本的变量。Compound path segments allow a single URI path segment to contain multiple variables as well as variables combined with literals. 下面这些示例都是有效的复合路径段:The following are examples of valid compound path segments.

  • /filename.{ext}//filename.{ext}/

  • /{filename}.jpg//{filename}.jpg/

  • /{filename}.{ext}//{filename}.{ext}/

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

下面这些示例都是无效的复合路径段:The following are examples of invalid path segments.

  • /{} - 必须对变量进行命名。/{} - Variables must be named.

  • /{shoe}{boat} - 必须用文本分隔变量。/{shoe}{boat} - Variables must be separated by a literal.

匹配和复合路径段Matching and Compound Path Segments

复合路径段允许定义在单个路径段内具有多个变量的 UriTemplate。Compound path segments allow you to define a UriTemplate that has multiple variables within a single path segment. 例如,在下面的模板字符串:"地址 / {state}。{city}"相同的段内定义了两个变量 (state 和 city)。For example, in the following template string: "Addresses/{state}.{city}" two variables (state and city) are defined within the same segment. 此模板将如匹配 URL"http://example.com/Washington.Redmond",但它还将匹配的 URL,如"http://example.com/Washington.Redmond.Microsoft"。This template would match a URL such as "http://example.com/Washington.Redmond" but it will also match an URL like "http://example.com/Washington.Redmond.Microsoft". 在后一种情况下,state 变量将包含"Washington",city 变量将包含"Redmond.Microsoft"。In the latter case, the state variable will contain "Washington" and the city variable will contain "Redmond.Microsoft". 这时,任何文本(“/”除外)都将与 {city} 变量相匹配。In this case any text (except ‘/’) will match the {city} variable. 如果你希望模板不要匹配"额外"的文本,可将变量放在单独的模板段中,例如:"地址 / {state} / {city}。If you want a template that will not match the "extra" text, place the variable in a separate template segment, for example: "Addresses/{state}/{city}.

命名通配符段Named Wildcard Segments

命名通配符段是其变量名称以通配符“*”开头的任何路径变量段。A named wildcard segment is any path variable segment whose variable name begins with the wildcard character ‘*’. 下面的模板字符串包含一个名为“shoe”的命名通配符段。The following template string contains a named wildcard segment named "shoe".

"literal/{*shoe}"  

通配符段必须遵循以下规则:Wildcard segments must follow the following rules:

  • 每个模板字符串最多只能有一个命名通配符段。There can be at most one named wildcard segment for each template string.

  • 命名通配符段必须位于路径中的最右段。A named wildcard segment must appear at the right-most segment in the path.

  • 命名通配符段不能与匿名通配符段共存于同一模板字符串中。A named wildcard segment cannot coexist with an anonymous wildcard segment within the same template string.

  • 命名通配符段的名称必须是唯一的。The name of a named wildcard segment must be unique.

  • 命名通配符段不能具有默认值。Named wildcard segments cannot have default values.

  • 命名的通配符段不能以结尾"/"。Named wildcard segments cannot end with "/".

默认变量值Default Variable Values

通过默认变量值,可以在模板中指定变量的默认值。Default variable values allow you to specify default values for variables within a template. 默认变量可以用声明变量的大括号来指定,也可以指定为传递到 UriTemplate 构造函数的集合。Default variables can be specified with the curly braces that declare the variable or as a collection passed to the UriTemplate constructor. 下面的模板演示用具有默认值的变量来指定 UriTemplate 的两种方法。The following template shows two ways to specify a UriTemplate with variables with default values.

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

此模板声明一个名为 a、默认值为 1 的变量和一个名为 b、默认值为 5 的变量。This template declares a variable named a with a default value of 1 and a variable named b with a default value of 5.

备注

仅允许路径段变量具有默认值。Only path segment variables are allowed to have default values. 不允许查询字符串变量、复合段变量和命名通配符变量具有默认值。Query string variables, compound segment variables, and named wildcard variables are not permitted to have default values.

下面的代码演示在匹配候选 URI 时,如何处理默认变量值。The following code shows how default variable values are handled when matching a candidate URI.

Uri baseAddress = new Uri("http://localhost:800   
Dictionary<string,string> defVals = new Dictionary<string,string> {{"a","1"}, {"b", "5"}};  
UriTemplate t = new UriTemplate("/test/{a}/{b}", defVals);0");  
UriTemplate t = new UriTemplate("/{state=WA}/{city=Redmond}/", true);  
Uri candidate = new Uri("http://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: http://localhost:8000/OR  
// BoundVariables:  
//      STATE=OR  
//       CITY=Redmond  

备注

诸如 http://localhost:8000/// 之类的 URI 与上述代码中列出的模板不匹配,但诸如 http://localhost:8000/ 之类的 URI 与其匹配。A URI such as http://localhost:8000/// does not match the template listed in the preceding code, however a URI such as http://localhost:8000/ does.

下面的代码演示在使用模板创建 URI 时,如何处理默认变量值。The following code shows how default variable values are handled when creating a URI with a template.

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  

为变量提供默认值 null 时,有一些其他约束。When a variable is given a default value of null there are some additional constraints. 如果某个变量包含在模板字符串的最右段中,或者该段右侧的所有段都具有默认值 null,则该变量可以具有默认值 nullA variable can have a default value of null if the variable is contained within the right most segment of the template string or if all segments to the right of the segment have default values of null. 下面是带有 null 默认值的有效模板字符串:The following are valid template strings with default values of null:

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

    下面是带有 null 默认值的无效模板字符串:The following are invalid template strings with default values of 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  
    

默认值和匹配Default Values and Matching

将候选 URI 与带有默认值的模板进行匹配时,如果候选 URI 中未指定值,则将在 BoundVariables 集合中放置默认值。When matching a candidate URI with a template that has default values, the default values are placed in the BoundVariables collection if values are not specified in the candidate URI.

模板等效性Template Equivalence

两个模板可认为是结构等效时所有模板的文本匹配且它们具有相同的段中的变量。Two templates are said to be structurally equivalent when all of the templates' literals match and they have variables in the same segments. 例如,以下模板是结构等效的:For example the following templates are structurally equivalent:

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

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

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

在这里需注意一些事项:A few things to notice:

  • 如果模板包含前导斜杠,则只忽略第一个。If a template contains leading slashes, only the first one is ignored.

  • 比较模板字符串以确定结构等效性时,变量名和路径段不区分大小写,查询字符串区分大小写。When comparing template strings for structural equivalence, case is ignored for variable names and path segments, query strings are case sensitive.

  • 查询字符串不分次序。Query strings are unordered.

UriTemplateTableUriTemplateTable

UriTemplateTable 类表示一个绑定到开发人员所选对象的 UriTemplate 对象的关联表。The UriTemplateTable class represents an associative table of UriTemplate objects bound to an object of the developer's choosing. 调用 UriTemplateTable 之前,UriTemplate 必须至少包含一个 MakeReadOnly(Boolean)A UriTemplateTable must contain at least one UriTemplate prior to calling MakeReadOnly(Boolean). 在调用 UriTemplateTable 之前,可以更改 MakeReadOnly(Boolean) 的内容。The contents of a UriTemplateTable can be changed until MakeReadOnly(Boolean) is called. 调用 MakeReadOnly(Boolean) 时,会执行验证。Validation is performed when MakeReadOnly(Boolean) is called. 执行的验证的类型取决于传给 allowMultipleMakeReadOnly(Boolean) 参数的值。The type of validation performed depends upon the value of the allowMultiple parameter to MakeReadOnly(Boolean).

如果在调用 MakeReadOnly(Boolean) 时传入 false,则 UriTemplateTable 将进行检查以确保表中无模板。When MakeReadOnly(Boolean) is called passing in false, the UriTemplateTable checks to make sure there are no templates in the table. 如果找到任何结构等效的模板,则引发异常。If it finds any structurally equivalent templates, it throws an exception. 如果要确保只有一个模板与传入的 URI 匹配,可将此方法与 MatchSingle(Uri) 结合使用。This is used in conjunction with MatchSingle(Uri) when you want to ensure only one template matches an incoming URI.

如果在调用 MakeReadOnly(Boolean) 时传入 true,则 UriTemplateTable 允许 UriTemplateTable 中包含多个结构等效的模板。When MakeReadOnly(Boolean) is called passing in true, UriTemplateTable allows multiple, structurally-equivalent templates to be contained within a UriTemplateTable.

如果添加到 UriTemplate 中的一组 UriTemplateTable 对象包含查询字符串,则这些字符串不得有歧义。If a set of UriTemplate objects added to a UriTemplateTable contain query strings they must not be ambiguous. 可以使用相同的查询字符串。Identical query strings are allowed.

备注

尽管 UriTemplateTable 允许使用除 HTTP 之外的方案的基址,但是将候选 URI 与模板匹配时,将忽略方案和端口号。While the UriTemplateTable allows base addresses that use schemes other than HTTP, the scheme and port number are ignored when matching candidate URIs to templates.

查询字符串多义性Query String Ambiguity

如果某个 URI 匹配多个模板,则共享等效路径的模板将包含歧义查询字符串。Templates that share an equivalent path contain ambiguous query strings if there is a URI that matches more than one template.

以下几组查询字符串在其自身范围内无歧义:The following sets of query strings are unambiguous within themselves:

  • ?x=1?x=1

  • ?x=2?x=2

  • ?x=3?x=3

  • ?x=1&y={var}?x=1&y={var}

  • ?x=2&z={var}?x=2&z={var}

  • ?x=3?x=3

  • ?x=1?x=1

  • ??

  • ?? x={var}x={var}

  • ??

  • ?m=get&c=rss?m=get&c=rss

  • ?m=put&c=rss?m=put&c=rss

  • ?m=get&c=atom?m=get&c=atom

  • ?m=put&c=atom?m=put&c=atom

以下几组查询字符串模板在其自身范围内有歧义:The following sets of query string templates are ambiguous within themselves:

  • ?x=1?x=1

  • ?x={var}?x={var}

“x=1”- 与这两个模板都匹配。"x=1" - Matches both templates.

  • ?x=1?x=1

  • ?y=2?y=2

“x=1&y=2”- 与这两个模板都匹配。"x=1&y=2" matches both templates. 这是因为查询字符串包含的查询字符串变量可能比与之匹配的模板多。This is because a query string may contain more query string variables then the template it matches.

  • ?x=1?x=1

  • ?x=1&y={var}?x=1&y={var}

“x=1&y=3”- 与这两个模板都匹配。"x=1&y=3" matches both templates.

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

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

备注

作为 URI 路径或 UriTemplate 路径段文本的组成部分时,字符 á 和 Á 视为不同的字符(但字符 a 和 A 视为相同的字符)。The characters á and Á are considered to be different characters when they appear as part of a URI path or UriTemplate path segment literal (but the characters a and A are considered to be the same). 作为 UriTemplate {variableName} 或查询字符串的组成部分时,字符 á 和 Á 被视为相同的字符(字符 a 和 A 也视为相同的字符)。The characters á and Á are considered to be the same characters when they appear as part of a UriTemplate {variableName} or a query string (and a and A are also considered to be the same characters).

另请参阅See Also

WCF Web HTTP 编程模型概述WCF Web HTTP Programming Model Overview
WCF Web HTTP 编程对象模型WCF Web HTTP Programming Object Model
UriTemplateUriTemplate
UriTemplate 表UriTemplate Table
UriTemplate 表调度程序UriTemplate Table Dispatcher