iT邦幫忙

2021 iThome 鐵人賽

1
自我挑戰組

.NET Core WebApi網頁應用開發系列 第 24

.Net Core Web Api_筆記24_api結合EFCore資料庫操作part2_產品分類資料新增_資料查詢呈現(帶入非同步API修飾)

接續上一篇

在Startup.cs中啟用靜態資源
於專案新增目錄命名為wwwroot(會自動變成地球的圖示)

https://ithelp.ithome.com.tw/upload/images/20220113/201074523oUhhs8Tpr.png

對wwwroot去進行
引入bs4跟jquery3.6
測試Client端有UI時的互動存取(透過jQuery)
https://ithelp.ithome.com.tw/upload/images/20220113/20107452aOFUgSB7Vd.png

https://ithelp.ithome.com.tw/upload/images/20220113/20107452Co4aVhcdOu.png

https://ithelp.ithome.com.tw/upload/images/20220113/20107452M2YPgnWlfh.png

https://ithelp.ithome.com.tw/upload/images/20220113/20107452xu5aJz3LaE.png
接著要實作
產品分類資料查詢與增加
新增PCategoryController.cs和對應的新增Action及查詢Action
~\Controllers\PCategoryController.cs

同步形式的API存取

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Net5EFCoreWebApiApp.Data;
using Net5EFCoreWebApiApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5EFCoreWebApiApp.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PCategoryController : ControllerBase
    {        
        //Startup.cs中註冊EF服務後,就可在特定控制器藉由.net core預設DI,透過建構子去實踐存取ProductDbContext。
        private readonly ProductDbContext _dbContext;
        public PCategoryController(ProductDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        [HttpPost("Add")]
        public ActionResult<int> AddProductCategory(PCategory pCategory)
        {
            if (pCategory == null)
                return NotFound();

            if (string.IsNullOrEmpty(pCategory.CTitle))
                return NotFound();

            pCategory.CId = Guid.NewGuid();
            _dbContext.PCategories.Add(pCategory);
            int RowCount = _dbContext.SaveChanges();
            return CreatedAtAction(nameof(AddProductCategory),RowCount);
        }

        [HttpGet("Show")]
        public ActionResult<List<PCategory>> ShowProductCategory()
        {
            var categories = _dbContext.PCategories.ToList();
            return categories;
        }

    }
}

透過.net core DI我們在建構子注入DbContext就能在整個Controller程式中進行存取異動

新增對應靜態資源頁面

~\wwwroot\PCategory\Add.html

<!DOCTYPE html>
<html>
<head>
    <title>Add ProductType</title>
    <link href="../css/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <script src="../js/jquery/jquery.min.js"></script>
</head>
<body>
    <div style="padding:20px;border:1px solid #0094ff;width:600px;margin:30px;">
        <h3>產品類別</h3>
        <hr />
        <div class="form-horizontal">
            <div class="form-group col-4">
                <label>產品類別</label>
                <input type="text" class="form-control" id="CategoryTitle">
            </div>
            <div class="form-group">
                <div class="col-md-2 col-md-10">
                    <button type="submit" id="btnSubmit" class="btn btn-primary">Submit</button>
                </div>
                <div>
                    <span id="msg" class="danger"></span>
                </div>
            </div>
        </div>
    </div>

    <script type="text/javascript">
        $('#btnSubmit').click(function () {
            $.ajax({
                type: 'post',
                url: "/api/pcategory/add",
                dataType: "text",
                data: JSON.stringify({                    
                    CTitle: $('#CategoryTitle').val()
                }),
                contentType: 'application/json',
                success: function (result) {
                    if (result == "1") {
                        $('#msg').text('成功添加');
                    }
                }
            });
        });
    </script>
</body>
</html>

~\wwwroot\PCategory\Show.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link href="../css/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <script src="../js/jquery/jquery.min.js"></script>
</head>
<body style="margin:20px;">
    <table id="tbProductCategory" class="table table-bordered">
        <thead>
            <tr>
                <td>產品類別ID</td>
                <td>產品類別名稱</td>                
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>

    <script type="text/javascript">
        $(function () {
            var tbody = $('#tbProductCategory tbody');
            $.ajax({
                type: 'get',
                url: '/api/pcategory/show',
                dataType: 'json',
                success: function (result) {
                    $.each(result, function (n, value) {
                        var tr_val = "";
                        tr_val += "<tr><td>" + value.cId
                            + "</td><td>" + value.cTitle
                            + "</td></tr>";
                        tbody += tr_val;
                    });
                    $('#tbProductCategory').append(tbody);
                }
            });
        });
    </script>

</body>
</html>

運行效果

https://ithelp.ithome.com.tw/upload/images/20220113/20107452jpvUPK8EIT.png

https://ithelp.ithome.com.tw/upload/images/20220113/20107452IXPFtJGLjy.png

而在過去用ado.net搭配寫法或者上述寫法
基本上都是採用同步的API存取方式
所以基本上單位時間內能處理消化的請求量或稱為「吞吐(流通)量Throughput」有限
因此會有阻塞問題

由於EFCore有支援異步存取的相關API(方法名Async後綴)
這裡可以再改為非同步的API存取

非同步(異步)形式的API存取

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Net5EFCoreWebApiApp.Data;
using Net5EFCoreWebApiApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5EFCoreWebApiApp.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PCategoryController : ControllerBase
    {        
        //Startup.cs中註冊EF服務後,就可在特定控制器藉由.net core預設DI,透過建構子去實踐存取ProductDbContext。
        private readonly ProductDbContext _dbContext;
        public PCategoryController(ProductDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        [HttpPost("Add")]
        public async Task<ActionResult<int>> AddProductCategory(PCategory pCategory)
        {
            if (pCategory == null)
                return NotFound();

            if (string.IsNullOrEmpty(pCategory.CTitle))
                return NotFound();

            pCategory.CId = Guid.NewGuid();
            _dbContext.PCategories.Add(pCategory);
            int RowCount = await _dbContext.SaveChangesAsync();
            return CreatedAtAction(nameof(AddProductCategory),RowCount);
        }

        [HttpGet("Show")]
        public async Task<ActionResult<List<PCategory>>> ShowProductCategory()
        {
            var categories = await _dbContext.PCategories.ToListAsync();
            return categories;
        }

    }
}

Ref:

The Ultimate Guide to Async and Await in C# and ASP.NET
https://exceptionnotfound.net/async-await-in-asp-net-csharp-ultimate-guide/

[效能調教] 使用 Async / Await 非同步機制加快 Web API 回應時間
https://dotblogs.com.tw/wasichris/2017/06/08/101137#%E7%B5%90%E8%AB%96

網站測試工具-JMeter教學
https://www.astralweb.com.tw/website-test-tool-jmeter-teaching/

JMeter-網頁壓力測試教學
https://www.astralweb.com.tw/jmeter-website-stress-testing-tutorial/

.NET Web应用中为什么要使用async/await异步编程
https://www.cnblogs.com/xhznl/p/13064731.html

為什麼需要使用非同步程式設計,真的可以提升整體應用程式的執行效能嗎?
https://csharpkh.blogspot.com/2019/07/Asynchronous-ThreadPool-programming-synchronous-NET-Core-Framework-async-await.html

ASP.NET async 基本心法
https://blog.darkthread.net/blog/async-aspnet/

本篇已同步發表至個人部落格
https://coolmandiary.blogspot.com/2022/01/net-core-web-api24apiefcorepart2api.html


上一篇
.Net Core Web Api_筆記23_api結合EFCore資料庫操作part1_專案前置準備
下一篇
.Net Core Web Api_筆記25_api結合EFCore資料庫操作part3_產品分類資料的編輯與刪除(EF的更新寫法怎麼這麼多種!如何觀察EF產生的SQL)
系列文
.NET Core WebApi網頁應用開發25

尚未有邦友留言

立即登入留言