在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C#/ 前言
前言
在本節(jié),你將開(kāi)始為app定義HTML,并在HTML和視圖模型間添加數(shù)據(jù)綁定。
在本節(jié),你將使用HTML、JavaScript和Knockout.js庫(kù)為應(yīng)用程序創(chuàng)建客戶端。我們將按如下步驟建立客戶端應(yīng)用:
前言
前言
http://www.asp.net/web-api/overview/formats-and-model-binding/mo
在本節(jié),你將添加讓用戶可以創(chuàng)建新book的功能。在app.js中,添加如下代碼到視圖模型:
在本節(jié),你將添加查看每本書(shū)的詳細(xì)信息的功能。在app.js中,添加以下代碼到視圖模型:
前言
這篇文章描述了ASP.NET Web API如何將HTTP請(qǐng)求發(fā)送(路由)到控制器。
前言
前言
這篇文章描述了ASP.NET Web API如何將HTTP請(qǐng)求路由到控制器上的特定動(dòng)作。
前言
在這最后一節(jié)中,你將把應(yīng)用程序發(fā)布到Azure。在Solution Explorer中,右擊項(xiàng)目并選擇Publish。
前言
總結(jié)

前言

前言

路由是指Web API如何匹配到具體的動(dòng)作。Web API 2支持一個(gè)新的路由類型,它被稱為屬性路由。正如其名,屬性路由使用屬性來(lái)定義路由。屬性路由給予你在web API的URI上的更多控制。例如,你能輕易的創(chuàng)建用于描述層級(jí)資源的URI。

早期的路由風(fēng)格被稱為基于約定的路由,現(xiàn)在仍然被完整支持,你可以將這兩種技術(shù)用于同一個(gè)項(xiàng)目中。

本主題演示如何啟用屬性的路由,并描述屬性路由的各種選項(xiàng)。關(guān)于使用屬性路由的實(shí)戰(zhàn)教程,請(qǐng)查看Create a REST API with Attribute Routing in Web API 2。

? Why Attribute Routing? ? Enabling Attribute Routing ? Adding Route Attributes ? Route Prefixes ? Route Constraints ? Optional URI Parameters and Default Values ? Route Names ? Route Order

前提條件(Prerequisites)

Visual Studio 2013 或 Visual Studio Express 2013

或者,使用NuGet Package Manager來(lái)安裝必要的包。在Visual Studio的Tools目錄下,選擇Library Package Manager,然后選擇Package Manager Console。在Package Manager Console窗口輸入以下命令:

Install-Package Microsoft.AspNet.WebApi.WebHost

Why Attribute Routing?

Web API的首個(gè)發(fā)行版使用基于約定的路由。在那種路由中,你定義一個(gè)或多個(gè)路由模板,它們是一些基本的參數(shù)字符串。當(dāng)框架收到一個(gè)請(qǐng)求時(shí),它會(huì)將URI匹配到路由模板中。(關(guān)于基于約定的路由的更多信息,請(qǐng)查看Routing in ASP.NET Web API)

基于約定的路由的一個(gè)優(yōu)勢(shì)是模板是定義在單一地方的,并且路由規(guī)則會(huì)被應(yīng)用到所有的控制器。不幸的是,基于約定的路由很難去支持一個(gè)在RESTful API中很常見(jiàn)的URI模式。例如,資源通常包含著子資源:客戶包含著訂單,電影包含著演員,書(shū)籍包含著作者等等。所以很自然地創(chuàng)建映射這些關(guān)系的URI: /customers/1/orders 有了屬性路由,就可以很輕易地定義一個(gè)針對(duì)該URI的路由。你只需要簡(jiǎn)單的添加一個(gè)屬性到控制器動(dòng)作上:

[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }

這里還有些因?yàn)橛辛藢傩月酚啥兊酶尤菀椎钠渌J剑?/p>

API versioning

在本例中,”api/v1/products”相對(duì)于”api/v2/products”可能會(huì)路由到不同的控制器。 /api/v1/products /api/v2/products

Overloaded URI segments

在本例中,”1”是個(gè)訂單數(shù)字,但是“pending”映射到一個(gè)集合。 /orders/1 /orders/pending

Multiple parameter types

在本例中,“1”是個(gè)訂單數(shù)字,但是“2013/06/10”卻是個(gè)日期。 /orders/1 /orders/2013/06/10

啟用屬性路由(Enabling Attribute Routing)

為了啟用屬性路由,需要在配置時(shí)調(diào)用MapHttpAttributeRoutes。這個(gè)擴(kuò)展方法被定義在System.Web.Http.HttpConfigurationExtensions類中。

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

屬性路由也可以和基于約定的路由結(jié)合起來(lái)。為了定義基于約定的路由,調(diào)用MapHttpRoute方法。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

        // Convention-based routing.
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

關(guān)于配置Web API的更多信息,請(qǐng)查看Configuring ASP.NET Web API 2。

在Web API 2之前,Web API項(xiàng)目目標(biāo)生成的代碼像是這樣:

protected void Application_Start()
{
    // WARNING - Not compatible with attribute routing.
    WebApiConfig.Register(GlobalConfiguration.Configuration);
}

如果屬性路由沒(méi)有被啟用,這個(gè)代碼將會(huì)拋出異常。如果你升級(jí)一個(gè)已有的Web API項(xiàng)目來(lái)使用屬性路由,請(qǐng)確保像下面這樣升級(jí)了配置代碼:

protected void Application_Start()
{
    // Pass a delegate to the Configure method.
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

備注:關(guān)于更多信息,請(qǐng)查看Configuring Web API with ASP.NET Hosting

添加路由屬性(Adding Route Attributes)

這里是一個(gè)使用屬性定義路由的示例:

public class OrdersController : ApiController
{
    [Route("customers/{customerId}/orders")]
    [HttpGet]
    public IEnumerable<Order> FindOrdersByCustomer(int customerId) { ... }
}

字符串“customers/{customerId}/orders”是一個(gè)用于路由的URI模板。Web API會(huì)盡力將請(qǐng)求的URI匹配到模板中。在本例中,”customers“和”orders“都是字面字段,而”{customerId}”是變量參數(shù)。以下這些URI會(huì)匹配這個(gè)模板:

1,  http://localhost/customers/1/orders
2,  http://localhost/customers/bob/orders
3,  http://localhost/customer/1234-5678/orders

你能夠使用約束來(lái)限制這些匹配,這將會(huì)在本主題的后面進(jìn)行介紹。

注意到路由模板“{customerId}”參數(shù)匹配到方法中的customerId參數(shù)名。當(dāng)Web API執(zhí)行控制器動(dòng)作時(shí),它會(huì)盡力綁定路由參數(shù)。例如,當(dāng)URI是 http: //example.com/customers/1/orders 時(shí),Web API會(huì)盡力將值”1“和動(dòng)作中的customerId參數(shù)進(jìn)行綁定。

一個(gè)URI模板可以有多個(gè)參數(shù):

[Route("customers/{customerId}/orders/{orderId}")]
public Order GetOrderByCustomer(int customerId, int orderId) { ... }

任何沒(méi)有路由屬性的控制器方法都使用基于約定的路由。在此基礎(chǔ)上,你能夠在同一個(gè)項(xiàng)目中同時(shí)使用這兩種路由類型。

HTTP Methods

Web API也會(huì)基于HTTP方法的請(qǐng)求(GET、POST等)來(lái)選擇動(dòng)作。默認(rèn)地,Web API會(huì)根據(jù)控制器方法名且不區(qū)分大小寫(xiě)地查找匹配。例如,一個(gè)控制器方法名為PutCustomers,它匹配一個(gè)HTTP的PUT請(qǐng)求。

你也可以通過(guò)給方法加上這些屬性來(lái)重載這個(gè)規(guī)則:

? [HttpDelete] ? [HttpGet] ? [HttpHead] ? [HttpOptions] ? [HttpPatch] ? [HttpPost] ? [HttpPut]

下面的例子映射CreateBook方法到HTTP的POST請(qǐng)求。

[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }

對(duì)于所有的HTTP方法,包括非標(biāo)準(zhǔn)方法,可以使用AcceptVerbs屬性,它需要傳入一個(gè)HTTP方法的列表。

// WebDAV method
[Route("api/books")]
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }

路由前綴(Route Prefixes)

通常,控制器中的路由都以同樣的前綴開(kāi)始。例如:

public class BooksController : ApiController
{
    [Route("api/books")]
    public IEnumerable<Book> GetBooks() { ... }

    [Route("api/books/{id:int}")]
    public Book GetBook(int id) { ... }

    [Route("api/books")]
    [HttpPost]
    public HttpResponseMessage CreateBook(Book book) { ... }
}

你可以通過(guò)使用[RoutePrefix]屬性來(lái)為整個(gè)控制器設(shè)置一個(gè)公共前綴。

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET api/books
    [Route("")]
    public IEnumerable<Book> Get() { ... }

    // GET api/books/5
    [Route("{id:int}")]
    public Book Get(int id) { ... }

    // POST api/books
    [Route("")]
    public HttpResponseMessage Post(Book book) { ... }
}

使用在方法屬性上使用一個(gè)通配符(~)來(lái)重載路由前綴。

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET /api/authors/1/books
    [Route("~/api/authors/{authorId:int}/books")]
    public IEnumerable<Book> GetByAuthor(int authorId) { ... }

    // ...
}

路由前綴也可以包含參數(shù):

[RoutePrefix("customers/{customerId}")]
public class OrdersController : ApiController
{
    // GET customers/1/orders
    [Route("orders")]
    public IEnumerable<Order> Get(int customerId) { ... }
}

路由約束(Route Constraints)

路由約束能夠讓你限制路由模板中的參數(shù)如何被匹配。大體的語(yǔ)法是“{parameter:constraint}”。例如:

[Route("users/{id:int}"]
public User GetUserById(int id) { ... }

[Route("users/{name}"]
public User GetUserByName(string name) { ... }

在這里,第一個(gè)路由只有當(dāng)URI的“id”字段是整型時(shí)才會(huì)被選擇。否則將會(huì)選擇第二個(gè)路由。

下表列出了被支持的約束。

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)} {x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

注意到其中一些約束在括號(hào)內(nèi)還需要參數(shù),比如“min”。你可以應(yīng)用多個(gè)約束到一個(gè)參數(shù),通過(guò)冒號(hào)分隔。

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { ... }

自定義路由約束(Custom Route Constraints)

你可以通過(guò)實(shí)現(xiàn)IHttpRouteConstraint接口來(lái)創(chuàng)建一個(gè)自定義路由約束。例如,以下約束限制了一個(gè)參數(shù)到非零整型值。

public class NonZeroConstraint : IHttpRouteConstraint
{
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, 
        IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            long longValue;
            if (value is long)
            {
                longValue = (long)value;
                return longValue != 0;
            }

            string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
            if (Int64.TryParse(valueString, NumberStyles.Integer, 
                CultureInfo.InvariantCulture, out longValue))
            {
                return longValue != 0;
            }
        }
        return false;
    }
}

下面的代碼展示了如何去注冊(cè)約束:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));

        config.MapHttpAttributeRoutes(constraintResolver);
    }
}

現(xiàn)在你可以將該約束應(yīng)用到你的路由中了:

[Route("{id:nonzero}")]
public HttpResponseMessage GetNonZero(int id) { ... }

你也可以通過(guò)實(shí)現(xiàn)IInlineConstraintResolver接口來(lái)替換整個(gè)DefaultInlineConstraintResolver類。這樣做會(huì)替換掉所有的內(nèi)建約束,除非你實(shí)現(xiàn)的IInlineConstraintResolver特意添加了它們。

可選的URI參數(shù)和默認(rèn)值

你可以通過(guò)添加問(wèn)好標(biāo)記到路由參數(shù)讓一個(gè)URI參數(shù)變成可選的。如果一個(gè)路由參數(shù)是可選的,你必須為方法參數(shù)定義默認(rèn)值。

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int?}")]
    public IEnumerable<Book> GetBooksByLocale(int lcid = 1033) { ... }
}

在本例中,/api/books/locale/1033和/api/books/locale會(huì)返回相同的資源。

或者,你可以特定一個(gè)默認(rèn)值在路由模板中,如下所示:

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int=1033}")]
    public IEnumerable<Book> GetBooksByLocale(int lcid) { ... }
}

這和前一個(gè)例子大體相同,但當(dāng)默認(rèn)值被應(yīng)用時(shí)存在細(xì)微差別。 1, 在第一個(gè)例子(“{Icid?}”),默認(rèn)值1033會(huì)被直接分配到方法參數(shù),所以參數(shù)將會(huì)擁有一個(gè)準(zhǔn)確的值。 2, 在第二個(gè)例子(“{Icid=1033}”),默認(rèn)值1033會(huì)通過(guò)模型綁定過(guò)程。默認(rèn)的模型綁定將會(huì)把1033轉(zhuǎn)換成數(shù)字值1033。然而,你可以遇到一個(gè)自定義的模型綁定,而這可能會(huì)出錯(cuò)。 (多數(shù)情況下,除非你在你的管道中有自定義模型綁定,否則這兩只表單形式是等價(jià)的。)

路由名稱(Route Names)

在Web API中,每種路由都有一個(gè)名稱。路由名稱對(duì)于生成鏈接是非常有用的,正因此你才能在HTTP相應(yīng)中包含一個(gè)鏈接。

為了指定路由名稱,在屬性上(attribute)設(shè)置Name屬性(property)。以下示例展示了如何選擇一個(gè)路由名稱,以及當(dāng)生成一個(gè)鏈接時(shí)如何使用路由名稱。

public class BooksController : ApiController
{
    [Route("api/books/{id}", Name="GetBookById")]
    public BookDto GetBook(int id) 
    {
        // Implementation not shown...
    }

    [Route("api/books")]
    public HttpResponseMessage Post(Book book)
    {
        // Validate and add book to database (not shown)

        var response = Request.CreateResponse(HttpStatusCode.Created);

        // Generate a link to the new book and set the Location header in the response.
        string uri = Url.Link("GetBookById", new { id = book.BookId });
        response.Headers.Location = new Uri(uri);
        return response;
    }
}

路由順序(Route Order)

當(dāng)框架試圖用路由匹配URI時(shí),它會(huì)得到一個(gè)特定的路由順序。為了指定順序,在路由屬性上設(shè)置RouteOrder屬性。小寫(xiě)的值在前,默認(rèn)順序值是零。

以下是如何確定所有的順序的過(guò)程:

  1. 比較每個(gè)路由屬性的RouteOrder屬性
  2. 在路由模板上查找每個(gè)URI字段。對(duì)于每個(gè)字段,順序由以下因素確定:
    • 字面字段
    • 包含約束的路由參數(shù)
    • 不包含約束的路由參數(shù)
    • 包含約束的通配符參數(shù)字段
    • 不包含約束的通配符參數(shù)字段
  3. In the case of a tie,路由的順序由路由模板的不區(qū)分大小寫(xiě)的原始字符串比較來(lái)確定。

這是一個(gè)示例。假定你定義如下控制器:

[RoutePrefix("orders")]
public class OrdersController : ApiController
{
    [Route("{id:int}")] // constrained parameter
    public HttpResponseMessage Get(int id) { ... }

    [Route("details")]  // literal
    public HttpResponseMessage GetDetails() { ... }

    [Route("pending", RouteOrder = 1)]
    public HttpResponseMessage GetPending() { ... }

    [Route("{customerName}")]  // unconstrained parameter
    public HttpResponseMessage GetByCustomer(string customerName) { ... }

    [Route("{*date:datetime}")]  // wildcard
    public HttpResponseMessage Get(DateTime date) { ... }
}

這些路由的順序如下:

  1. orders/details
  2. orders/{id}
  3. orders/{customerName}
  4. orders/{*date}
  5. orders/pending

注意到“details”是一個(gè)字面字段,并且出現(xiàn)在“{id}”的前面,而“pending”出現(xiàn)在最后是因?yàn)樗腞outeOrder是1。(這個(gè)例子假定不存在customer被命名為”details”和“pending”。通常來(lái)說(shuō),要盡量避免含糊不清的路由。在本例中,對(duì)于GetByCustomer的一個(gè)更好的路由模板是”customers/{customerName}”。)

上一篇:總結(jié)下一篇:前言