實作HTTP服務與Action方法

HTTP服務與Action方法中PUT請求時碰到response.EnsureSuccessStatusCode()的錯誤

這邊主要是參考自ASP.NET MVC 4網站開發美學的第7章:Web API-HTTP服務提供者
 

其中7.6.4的HTTP服務與Action方法有部份程式碼有錯,所以我就改寫一下,作為日後複習的筆記。

首先要有Northwind的範例資料庫,並放在Models資料夾下,另外在Controller資料夾建立HomeController.cs,以及各cshtml是透過建立強型別檢視並以Scaffold樣板建在Views\Home資料夾下。

完整程式碼如下:

HomeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

//自訂宣告
using System.Net.Http;
using System.Net.Http.Headers;
using Web_API.Models;
using System.Threading.Tasks;

namespace Web_API.Controllers
{
    public class HomeController : Controller
    {
        //----------------------------------------
        //TODO:HTTP服務與Action方法
        //----------------------------------------

        //副程式
        private HttpClient GetClient()
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://localhost:12560/");
            return client;
        }

        //GET請求
        public ActionResult GetProducts()
        {
            HttpClient client = GetClient();
            var response = client.GetAsync("api/Product").Result;
            var products = response.Content.ReadAsAsync>().Result;

            return View(products);
        }

        //Details
        public ActionResult GetProductById(string id)
        {
            HttpClient client = GetClient();
            var response = client.GetAsync("api/Product/" + id).Result;
            var product = response.Content.ReadAsAsync().Result;

            return View(product);
        }

        //POST請求
        public ActionResult PostProduct()
        {
            return View();
        }

        [HttpPost]
        public ActionResult PostProduct(Products product)
        {
            HttpClient client = GetClient();
            var response = client.PostAsJsonAsync("api/Product", product).Result;
            response.EnsureSuccessStatusCode();

            return RedirectToAction("GetProducts");

        }

        //PUT請求
        public ActionResult PutProduct(string id)
        {
            HttpClient client = GetClient();
            var response = client.GetAsync("api/Product/" + id).Result;
            var product = response.Content.ReadAsAsync().Result;
            return View(product);
        }

        [HttpPost()]
        public ActionResult PutProduct(string id, Products product)
        {
            HttpClient client = GetClient();
            var response = client.PutAsJsonAsync("api/Product/" + id, product).Result;
            response.EnsureSuccessStatusCode();

            return RedirectToAction("GetProducts");
        }

        //Delete請求
        public ActionResult DeleteProduct()
        {
            return View();
        }

        [HttpPost()]
        public ActionResult DeleteProduct(string id)
        {
            HttpClient client = GetClient();
            var response = client.DeleteAsync("api/Product/"+id).Result;
            response.EnsureSuccessStatusCode();

            return RedirectToAction("GetProducts");
        }
    }

    
}

GetProducts.cshtml

@model IEnumerable<Web_API.Models.Products>

@{
    ViewBag.Title = "GetProducts";
}

<h2>GetProducts</h2>

<p>
    @Html.ActionLink("Create New", "PostProduct")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.ProductID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ProductName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.SupplierID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.CategoryID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.QuantityPerUnit)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.UnitPrice)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.UnitsInStock)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.UnitsOnOrder)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReorderLevel)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Discontinued)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.ProductID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ProductName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.SupplierID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.CategoryID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.QuantityPerUnit)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.UnitPrice)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.UnitsInStock)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.UnitsOnOrder)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReorderLevel)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Discontinued)
        </td>
        <td>
            @Html.ActionLink("Edit", "PutProduct", new {id=item.ProductID }) |
            @Html.ActionLink("Details", "GetProductById",new{id=item.ProductID}) |
            @Html.ActionLink("Delete", "DeleteProduct", new {id=item.ProductID})
        </td>
    </tr>
}

</table>

GetProductById.cshtml

@model Web_API.Models.Products

@{
    ViewBag.Title = "GetProductById";
}

<h2>GetProductById</h2>

<fieldset>
    <legend>Products</legend>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ProductID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ProductID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ProductName)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ProductName)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.SupplierID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.SupplierID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.CategoryID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.CategoryID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.QuantityPerUnit)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.QuantityPerUnit)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitPrice)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitPrice)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitsInStock)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitsInStock)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitsOnOrder)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitsOnOrder)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ReorderLevel)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ReorderLevel)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Discontinued)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Discontinued)
    </div>
</fieldset>
<p>
    @Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) |
    @Html.ActionLink("Back to List", "Index")
</p>

PostProduct.cshtml

@model Web_API.Models.Products

@{
    ViewBag.Title = "PostProduct";
}

<h2>PostProduct</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Products</legend>

        @*<div class="editor-label">
            @Html.LabelFor(model => model.ProductID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductID)
            @Html.ValidationMessageFor(model => model.ProductID)
        </div>*@

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductName)
            @Html.ValidationMessageFor(model => model.ProductName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.SupplierID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.SupplierID)
            @Html.ValidationMessageFor(model => model.SupplierID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.CategoryID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.CategoryID)
            @Html.ValidationMessageFor(model => model.CategoryID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.QuantityPerUnit)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.QuantityPerUnit)
            @Html.ValidationMessageFor(model => model.QuantityPerUnit)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitPrice)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitPrice)
            @Html.ValidationMessageFor(model => model.UnitPrice)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitsInStock)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitsInStock)
            @Html.ValidationMessageFor(model => model.UnitsInStock)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitsOnOrder)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitsOnOrder)
            @Html.ValidationMessageFor(model => model.UnitsOnOrder)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReorderLevel)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReorderLevel)
            @Html.ValidationMessageFor(model => model.ReorderLevel)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Discontinued)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Discontinued)
            @Html.ValidationMessageFor(model => model.Discontinued)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

PutProduct.cshtml

注意:

多了一行程式碼

@Html.HiddenFor(model=>model.ProductID)
@model Web_API.Models.Products

@{
    ViewBag.Title = "PutProduct";
}

<h2>PutProduct</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Products</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductID)
        </div>
        <div class="editor-field">
            @Html.DisplayFor(model => model.ProductID)
            @Html.ValidationMessageFor(model => model.ProductID)
            @Html.HiddenFor(model=>model.ProductID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductName)
            @Html.ValidationMessageFor(model => model.ProductName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.SupplierID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.SupplierID)
            @Html.ValidationMessageFor(model => model.SupplierID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.CategoryID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.CategoryID)
            @Html.ValidationMessageFor(model => model.CategoryID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.QuantityPerUnit)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.QuantityPerUnit)
            @Html.ValidationMessageFor(model => model.QuantityPerUnit)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitPrice)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitPrice)
            @Html.ValidationMessageFor(model => model.UnitPrice)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitsInStock)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitsInStock)
            @Html.ValidationMessageFor(model => model.UnitsInStock)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UnitsOnOrder)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UnitsOnOrder)
            @Html.ValidationMessageFor(model => model.UnitsOnOrder)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReorderLevel)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReorderLevel)
            @Html.ValidationMessageFor(model => model.ReorderLevel)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Discontinued)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Discontinued)
            @Html.ValidationMessageFor(model => model.Discontinued)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

DeleteProduct.cshtml

@model Web_API.Models.Products

@{
    ViewBag.Title = "DeleteProduct";
}

<h2>DeleteProduct</h2>

<h3>Are you sure you want to delete this?</h3>
<fieldset>
    <legend>Products</legend>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ProductID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ProductID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ProductName)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ProductName)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.SupplierID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.SupplierID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.CategoryID)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.CategoryID)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.QuantityPerUnit)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.QuantityPerUnit)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitPrice)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitPrice)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitsInStock)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitsInStock)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.UnitsOnOrder)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.UnitsOnOrder)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.ReorderLevel)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.ReorderLevel)
    </div>

    <div class="display-label">
         @Html.DisplayNameFor(model => model.Discontinued)
    </div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Discontinued)
    </div>
</fieldset>
@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    <p>
        <input type="submit" value="Delete" /> |
        @Html.ActionLink("Back to List", "Index")
    </p>
}