[ASP.NET MVC] Model Binding With NameValueCollectionValueProvider

本篇文章說明HTTP Request封包內容,如何被ASP.NET MVC的Model Binding機制使用,並且剖析成為Action的函式參數。

[ASP.NET MVC] Model Binding With NameValueCollectionValueProvider

範例下載

範例程式碼:點此下載

問題情景

一般Web網站,都是以HTTP Request做為資料輸入、HTTP Response做為資料輸出,來完成一個網頁要求回應的工作流程。

而ASP.NET MVC所建構的網站,在收到HTTP Request封包之後,會依照HTTP Request封包的Request URL內容,來選擇對應的Controller以及Action,並且透過Model Binding機制來將HTTP Request封包剖析成為Action的函式參數。最後ASP.NET MVC會使用這些函式參數來執行Action函式,並且依照Action執行結果以及對應的View內容,來產生HTTP Response封包回傳給瀏覽器,藉此完成HTTP Request輸入、HTTP Response輸出的工作流程。

本篇文章說明HTTP Request封包內容,如何被ASP.NET MVC的Model Binding機制使用,並且剖析成為Action的函式參數,為自己留個紀錄也希望能幫助到有需要的開發人員。

問題情景01

資料來源

HTTP Request封包內容,如何被ASP.NET MVC的Model Binding機制使用,並且剖析成為Action的函式參數;這一連串的工作流程,可以從使用者點擊瀏覽器頁面中Sumit按鈕來開始說明。

下列範例是一個HTML網頁,這個網頁中的Form表單包含許多排版標籤、兩個Text標籤以及一個 Submit標籤。其中用來提供使用者輸入資料的兩個Text標籤,名稱分別為companyId及productId。

<form action="/Receive/Echo_Multi_DataTypeArgument/" method="post">

    CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
    <br />

    ProductId : <input type="text" name="productId" value="BBBBB" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料來源01

當使用者輸入資料完畢之後,可使用滑鼠點擊頁面上的Submit按鈕,通知瀏覽器將Form表單中的內容,封裝成為HTTP Request封包來傳送給Web伺服器。

在這個階段,瀏覽器會將Form表單中輸入標籤的標籤名稱、標籤內容,以Name-Value的方式編碼成為一個資料字串。接著依照Form表單上所定義的Method模式,來將這個資料字串封裝成為HTTP Request封包。

companyId=AAAAA&productId=BBBBB
  • 當Method模式定義為Post的時候,瀏覽器會將HTTP Request封包的Content-Type內容定義為application/x-www-form-urlencoded,並且將資料字串設定為HTTP Request封包的Form Data內容。

    <form action="/Receive/Echo_Multi_DataTypeArgument/" method="post">
    
        CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
        <br />
    
        ProductId : <input type="text" name="productId" value="BBBBB" /><br />
        <br />
    
        <input type="submit" value="Submit" />
        <br />
    
    </form>
    

    資料來源02

  • 當Method模式定義為Get的時候,瀏覽器會將資料字串設定為HTTP Request封包的Query String內容。

    <form action="/Receive/Echo_Multi_DataTypeArgument/" method="get">
    
        CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
        <br />
    
        ProductId : <input type="text" name="productId" value="BBBBB" /><br />
        <br />
    
        <input type="submit" value="Submit" />
        <br />
    
    </form>
    

    資料來源03

伺服器端的ASP.NET在收到HTTP Request封包之後,會擷取HTTP Request封包所定義的Form Data內容、Query String內容,以Name-Value的方式解碼成為資料內容,並且使用這些資料內容建立為對應的NameValueCollection物件。

  • Form Data內容以Name-Value的方式解碼成為資料內容之後,伺服器端的ASP.NET會將資料內容建立為NameValueCollection物件,並且定義為System.Web.HttpContext.Current.Request.Form屬性的內容。

    資料來源04

  • Query String內容以Name-Value的方式解碼成為資料內容之後,伺服器端的ASP.NET會將資料內容建立為NameValueCollection物件,並且定義為System.Web.HttpContext.Current.Request.QueryString屬性的內容。

    資料來源05

而這兩個NameValueCollection物件,在ASP.NET MVC中會被統一封裝成為NameValueCollectionValueProvider物件,來做為Model Binding機制的資料來源。

資料來源06

資料來源07

資料繫結

在ASP.NET MVC中使用NameValueCollectionValueProvider物件,做為Model Binding機制的資料來源時,會依照下列規則來剖析NameValueCollectionValueProvider所提供的Name-Value資料內容,並且生成對應的Action函式參數。(為了降低學習曲線,空白前綴、陣列跳號...等等進階規則暫先排除。)

單一數值型別

當Action函式,包含一個數值型別的函式參數時。Model Binding核心會依照這個函式參數的「參數名稱」作為Key資料,來從NameValueCollectionValueProvider物件中取得對應的Value資料,並且嘗試將Value資料轉型為函式參數的「參數型別」,當成功轉型之後就生成一個「函式參數」。後續ASP.NET MVC就會使用這個函式參數執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Single_DataTypeArgument/" method="post">

    CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結01

資料繫結02

多個數值型別

當Action函式,包含多個數值型別的函式參數時。Model Binding核心透過生成單一數值型別的流程,依序生成每個對應「參數名稱」的函式參數。後續ASP.NET MVC就會使用這些函式參數執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Multi_DataTypeArgument/" method="post">

    CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
    <br />

    ProductId : <input type="text" name="productId" value="BBBBB" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結03

資料繫結04

數值型別集合

當Action函式,包含數值型別集合的函式參數時。Model Binding核心會依照這個函式參數的「參數名稱」作為Prefix資料,來從NameValueCollectionValueProvider物件中取得所有符合「Prefix資料[索引]」格式的一組Key資料。接著Model Binding核心會先依照函式參數的「參數型別」建立一個集合,並且透過生成單一數值型別的流程,依序生成每個對應「Key資料」的資料,來做為這個集合的項目。最後ASP.NET MVC就會使用這個集合作為函式參數來執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Array_DataTypeArgument/" method="post">

    CompanyIdArray[0] : <input type="text" name="companyIdArray[0]" value="AAAAA" /><br />
    CompanyIdArray[1] : <input type="text" name="companyIdArray[1]" value="BBBBB" /><br />
    <br />

    ProductIdArray[0] : <input type="text" name="productIdArray[0]" value="CCCCC" /><br />
    ProductIdArray[1] : <input type="text" name="productIdArray[1]" value="DDDDD" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結05

資料繫結06

單一參考型別

當Action函式,包含一個參考型別的函式參數時。Model Binding核心會先依照函式參數的「參數型別」建立一個物件,並且依序將函式參數的「參數名稱」、物件的「屬性名稱」,組合成為「參數名稱.屬性名稱」格式的Key資料,接著透過生成單一數值型別的流程,依序生成每個對應「Key資料」的物件屬性。最後ASP.NET MVC就會使用這個物件作為函式參數來執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Single_ObjectTypeArgument/" method="post">

    Company.Id = <input type="text" name="company.Id" value="AAAAA" /><br />
    Company.Name = <input type="text" name="company.Name" value="BBBBB" /><br />
    Company.Address = <input type="text" name="company.Address" value="12345" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結07

資料繫結08

多個參考型別

當Action函式,包含多個參考型別的函式參數時。Model Binding核心透過生成單一參考型別的流程,依序生成每個對應「參數名稱」的函式參數。後續ASP.NET MVC就會使用這些函式參數執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Multi_ObjectTypeArgument/" method="post">

    Company.Id = <input type="text" name="company.Id" value="AAAAA" /><br />
    Company.Name = <input type="text" name="company.Name" value="BBBBB" /><br />
    Company.Address = <input type="text" name="company.Address" value="12345" /><br />
    <br />

    Product.Id = <input type="text" name="product.Id" value="CCCCC" /><br />
    Pproduct.Name = <input type="text" name="product.Name" value="DDDDD" /><br />
    Product.Price = <input type="text" name="product.Price" value="67890" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結09

資料繫結10

參考型別集合

當Action函式,包含參考型別集合的函式參數時。Model Binding核心會依照這個函式參數的「參數名稱」作為Prefix資料,來從NameValueCollectionValueProvider物件中取得所有符合「Prefix資料[索引]」格式的一組Key資料。接著Model Binding核心會先依照函式參數的「參數型別」建立一個集合,並且透過生成單一參考型別的流程,依序生成每個對應「Key資料」的資料,來做為這個集合的項目。最後ASP.NET MVC就會使用這個集合作為函式參數來執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Array_ObjectTypeArgument/" method="post">

    CompanyArray[0].Id = <input type="text" name="companyArray[0].Id" value="AAAAA" /><br />
    CompanyArray[0].Name = <input type="text" name="companyArray[0].Name" value="BBBBB" /><br />
    CompanyArray[0].Address = <input type="text" name="companyArray[0].Address" value="12345" /><br />

    CompanyArray[1].Id = <input type="text" name="companyArray[1].Id" value="CCCCC" /><br />
    CompanyArray[1].Name = <input type="text" name="companyArray[1].Name" value="DDDDD" /><br />
    CompanyArray[1].Address = <input type="text" name="companyArray[1].Address" value="67890" /><br />
    <br />

    ProductArray[0].Id = <input type="text" name="productArray[0].Id" value="EEEEE" /><br />
    ProductArray[0].Name = <input type="text" name="productArray[0].Name" value="FFFFF" /><br />
    ProductArray[0].Price = <input type="text" name="productArray[0].Price" value="54321" /><br />

    ProductArray[1].Id = <input type="text" name="productArray[1].Id" value="GGGGG" /><br />
    ProductArray[1].Name = <input type="text" name="productArray[1].Name" value="HHHHH" /><br />
    ProductArray[1].Price = <input type="text" name="productArray[1].Price" value="09876" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結11

資料繫結12

多個混合型別

當Action函式,包含多個數值型別、參考型別的函式參數時。Model Binding核心會依需透過生成單一數值型別、生成單一參考型別的流程,依序生成每個對應「參數名稱」的函式參數。後續ASP.NET MVC就會使用這些函式參數執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Multi_MixTypeArgument/" method="post">

    CompanyId : <input type="text" name="companyId" value="AAAAA" /><br />
    <br />

    Product.Id = <input type="text" name="product.Id" value="BBBBB" /><br />
    Product.Name = <input type="text" name="product.Name" value="CCCCC" /><br />
    Product.Price = <input type="text" name="product.Price" value="12345" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結13

資料繫結14

混合型別集合

當Action函式,包含多個數值型別集合、參考型別集合的函式參數時。Model Binding核心會依需透過生成數值型別集合、生成參考型別集合的流程,依序生成每個對應「參數名稱」的函式參數。後續ASP.NET MVC就會使用這些函式參數執行Action函式,並且完成接續的工作流程來產生HTTP Response封包回傳給瀏覽器。

<form action="/Receive/Echo_Array_MixTypeArgument/" method="post">

    CompanyIdArray[0] : <input type="text" name="companyIdArray[0]" value="AAAAA" /><br />
    CompanyIdArray[1] : <input type="text" name="companyIdArray[1]" value="BBBBB" /><br />
    <br />

    ProductArray[0].Id = <input type="text" name="productArray[0].Id" value="CCCCC" /><br />
    ProductArray[0].Name = <input type="text" name="productArray[0].Name" value="DDDDD" /><br />
    ProductArray[0].Price = <input type="text" name="productArray[0].Price" value="12345" /><br />

    ProductArray[1].Id = <input type="text" name="productArray[1].Id" value="EEEEE" /><br />
    ProductArray[1].Name = <input type="text" name="productArray[1].Name" value="FFFFF" /><br />
    ProductArray[1].Price = <input type="text" name="productArray[1].Price" value="67890" /><br />
    <br />

    <input type="submit" value="Submit" />
    <br />

</form>

資料繫結15

資料繫結16

參考資料

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。