MVC專案實踐,在三層架構下實現SportsStore-09,ASP.NET MVC呼叫ASP.NET Web API的查詢服務

Darren Ji發表於2014-07-04

ASP.NET Web API和WCF都體現了REST軟體架構風格。在REST中,把一切資料視為資源,所以也是一種面向資源的架構風格。所有的資源都可以通過URI來唯一標識,通過對資源的HTTP操作(GET/HEAD、POST、PUT和DELETE),使資源的表徵狀態發生了改變,即Representational State Transfer,縮寫為REST。

 

WCF從3.5以來,也體現了REST的架構風格,但對於一般的訊息通訊來說,顯得"過重",所以,微軟推出ASP.NET Web API,提供一種"輕量級"的服務,並且借鑑了MVC,以Controller的形式來定義服務,而Controller中的Action方法對應著不同的HTTP操作。

 

本篇為"在三層架構下實現SportsStore"系列的第九篇,包括:

■ 11、ASP.NET MVC呼叫ASP.NET Web API的增刪改查服務
    □ 11.1 呼叫查詢服務
        ※ 11.1.1 建立ASP.NET Web API專案 引入Ninject
        ※ 11.1.2 提供ASP.NET WEB API增刪改查服務
        ※ 11.1.3 ASP.NET MVC呼叫ASP.NET WEB API查詢服務

 

  11、ASP.NET MVC呼叫ASP.NET Web API提供增刪改查服務

  11.1 呼叫查詢服務

  11.1.1 建立ASP.NET Web API專案 引入Ninject

在解決方案下建立一個空的"ASP.NET Web API 2空專案",名稱為"MySportsStore.WebApi":

40

 

在MySportsStore.WebApi"下新增如下引用:
● MySportsStore.BLL
● MySportsStore.IBLL
● MySportsStore.Model
● 通過GuGet安裝最新版的EntityFramework
● 通過NuGet安裝Ninject
37

 

在即將建立的控制器中,會用到IProductService及其實現,我們需要藉助Ninject來管理介面和實現類。在"MySportsStore.WebApi"下,建立一個System.Web.Http.Dependencies.IDependencyResolver介面的類:

using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Ninject;

namespace MySportsStore.WebApi.Extension
{
    public class NinjectDependencyResolver : IDependencyResolver
    {
        private List<IDisposable> disposableServices = new List<IDisposable>();
        public IKernel Kernel { get; private set; }

        public NinjectDependencyResolver(NinjectDependencyResolver parent)
        {
            this.Kernel = parent.Kernel;
        }

        public NinjectDependencyResolver()
        {
            this.Kernel = new StandardKernel();
        }

        public void Register<TFrom, TTO>() where TTO : TFrom
        {
            this.Kernel.Bind<TFrom>().To<TTO>();
        }

        public IDependencyScope BeginScope()
        {
            return new NinjectDependencyResolver(this);
        }

        public object GetService(System.Type serviceType)
        {
            return this.Kernel.TryGet(serviceType);
        }

        public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType)
        {
            foreach (var service in this.Kernel.GetAll(serviceType))
            {
                this.AddDisposableService(service);
                yield return service;
            }
        }

        public void Dispose()
        {
            foreach (IDisposable disposable in disposableServices)
            {
                disposable.Dispose();
            }
        }

        private void AddDisposableService(object service)
        {
            IDisposable disposable = service as IDisposable;
            if (null != disposable && !disposableServices.Contains(disposable))
            {
                disposableServices.Add(disposable);
            }
        }
    }
}

然後在全域性中註冊:

using System.Web.Http;
using MySportsStore.BLL;
using MySportsStore.IBLL;
using MySportsStore.WebApi.Extension;

namespace MySportsStore.WebApi
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);

            NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver();
            dependencyResolver.Register<IProductService, ProductService>();
            GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
        }
    }
}

 

  11.1.2 提供ASP.NET WEB API增刪改查服務

在"MySportsStore.WebApi"下,建立ProductApi控制器,提供增刪改查服務,實現如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using MySportsStore.IBLL;
using MySportsStore.Model;
using Ninject;

namespace MySportsStore.WebApi.Controllers
{
    public class ProductApiController : ApiController
    {
        [Inject]
        public IProductService ProductService { get; set; }

        public ProductApiController()
        {
            this.DisposableObjects = new List<IDisposable>();
            this.AddDisposableObject(ProductService);
        }

        // GET api/productapi
        public IEnumerable<Product> Get()
        {
            return ProductService.LoadEntities(p => true).AsEnumerable();
        }

        // GET api/productapi/5
        public Product Get(int id)
        {
            return ProductService.LoadEntities(p => p.Id == id).FirstOrDefault();
        }

        // POST api/productapi
        public void Post(Product product)
        {
            var dbProduct = ProductService.LoadEntities(p => p.Id == product.Id).FirstOrDefault();
            ProductService.UpdateEntity(dbProduct);
        }

        // PUT api/productapi/5
        public void Put(Product product)
        {
            ProductService.AddEntity(product);
        }

        // DELETE api/productapi/5
        public void Delete(int id)
        {
            var product = ProductService.LoadEntities(p => p.Id == id).FirstOrDefault();
            ProductService.DeleteEntity(product);
        }

        #region 手動垃圾回收邏輯
        protected IList<IDisposable> DisposableObjects { get; private set; }

        protected void AddDisposableObject(object obj)
        {
            IDisposable disposable = obj as IDisposable;
            if (disposable != null)
            {
                this.DisposableObjects.Add(disposable);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (IDisposable obj in this.DisposableObjects)
                {
                    if (null != obj)
                    {
                        obj.Dispose();
                    }
                }
            }
            base.Dispose(disposing);
        } 
        #endregion
    }
}

以上,通過Ninject把IProductService注入到ProductService屬性上,然後使用ProductService實現增刪改查,並實現了手動垃圾回收。


把"MySportsStore.WebApi"設定為啟動專案,在瀏覽器輸入:http://localhost:1577/api/productapi
38

 

以上,說明AP.NET WEB API查詢資料服務是正常的。這裡的地址,也就是代表查詢狀態的唯一URI,通過這個URI,無論你使用何種語言,無論是通過手機客戶端、平板客戶端、電腦客戶端......你都可以呼叫這個REST風格的服務。

 

  11.1.3 ASP.NET MVC呼叫ASP.NET WEB API查詢服務

在MVC中,使用HttpClient來獲取ASP.NET WEB API的服務,以下通過非同步方式查詢來自ASP.NET WEB API的資料:

using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using MySportsStore.Model;
using Newtonsoft.Json;

namespace MySportsStore.WebUI.RESTServices
{
    public class ProductRESTService
    {
        readonly string uri = "http://localhost:1577/api/productapi";

        public async Task<List<Product>> GetProductsAsync()
        {
            using (HttpClient httpClient = new HttpClient())
            {
                return JsonConvert.DeserializeObject<List<Product>>(
                    await httpClient.GetStringAsync(uri)
                );
            }
        } 
    }
}

在"MySportsStore.WebUI"下,建立Home控制器:

using System.Threading.Tasks;
using System.Web.Mvc;
using MySportsStore.WebUI.RESTServices;

namespace MySportsStore.WebUI.Controllers
{
    public class HomeController : Controller
    {
        private ProductRESTService service = new ProductRESTService();

        public async Task<ActionResult> Index()
        {
            return View("Index",
                await service.GetProductsAsync()
            );
        }

    }
}

在"MySportsStore.WebUI"下,建立Home/Index.cshtml檢視:

@model IEnumerable<MySportsStore.Model.Product>
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-1.8.2.js"></script>
    <style type="text/css">
        table {
            width: 1000px;
            border: 1px solid #000000;
            background-color: #eee;
        }

        table tr {
            line-height: 20px;
            border-bottom: 1px solid black;
        }

        table th {
            background-color: #ccc;
            color: #fff;
        }

        .oddRow {
            background-color: #fff;
        }

        #products {
            border: 0px solid red;
        }
    </style>
</head>
<body>
    <div id="products">
        <table>
            <tr class="oddRow">
                <th>編號</th>
                <th>類別</th>
                <th>名稱</th>
                <th>價格</th>
                <th>描述</th>
            </tr>
            @foreach (var product in Model)
            {
                <tr>
                    <td>@product.Id</td>
                    <td>@product.Category</td>
                    <td>@product.Name</td>
                    <td>@product.Price.ToString("c")</td>
                    <td>@product.Description</td>
                </tr>
            }
        </table>
    </div>
</body>
</html>

把"MySportsStore.WebUI"設定為啟動專案,執行:
39

至此,ASP.NET MVC呼叫ASP.NET Web API的查詢服務結束。

 

參考資料:
引入Ninject部分,參考了蔣金楠(Artech)的"IoC在ASP.NET Web API中的應用"

 

原始碼在這裡

 

“MVC專案實踐,在三層架構下實現SportsStore”系列包括:

MVC專案實踐,在三層架構下實現SportsStore,從類圖看三層架構

MVC專案實踐,在三層架構下實現SportsStore-01,EF Code First建模、DAL層等

MVC專案實踐,在三層架構下實現SportsStore-02,DbSession層、BLL層

MVC專案實踐,在三層架構下實現SportsStore-03,Ninject控制器工廠等

MVC專案實踐,在三層架構下實現SportsStore-04,實現分頁

MVC專案實踐,在三層架構下實現SportsStore-05,實現導航

MVC專案實踐,在三層架構下實現SportsStore-06,實現購物車

MVC專案實踐,在三層架構下實現SportsStore-07,實現訂單提交

MVC專案實踐,在三層架構下實現SportsStore-08,部署到IIS伺服器

MVC專案實踐,在三層架構下實現SportsStore-09,ASP.NET MVC呼叫ASP.NET Web API的查詢服務

MVC專案實踐,在三層架構下實現SportsStore-10,連線字串的加密和解密

MVC專案實踐,在三層架構下實現SportsStore-11,使用Knockout實現增刪改查

相關文章