asp.net core系列 40 Web 應用MVC 介紹與詳細示例

来源:https://www.cnblogs.com/MrHSR/archive/2019/03/11/10509469.html
-Advertisement-
Play Games

一. MVC介紹 MVC架構模式有助於實現關註點分離。視圖和控制器均依賴於模型。 但是,模型既不依賴於視圖,也不依賴於控制器。 這是分離的一個關鍵優勢。 這種分離允許模型獨立於可視化展示進行構建和測試。ASP.NET Core MVC 包括以下功能: 路由、模型綁定、模型驗證、依賴關係註入、篩選器、 ...


一. MVC介紹

  MVC架構模式有助於實現關註點分離。視圖和控制器均依賴於模型。 但是,模型既不依賴於視圖,也不依賴於控制器。 這是分離的一個關鍵優勢。 這種分離允許模型獨立於可視化展示進行構建和測試。ASP.NET Core MVC 包括以下功能:

    路由、模型綁定、模型驗證、依賴關係註入、篩選器、區域、Web API、可測試性、Razor 視圖引擎、強類型視圖、標記幫助程式、 視圖組件。

 

  (1) 路由

    ASP.NET Core MVC 建立在 ASP.NET Core 的路由之上,是一個功能強大的 URL 映射組件,可用於生成具有易於理解和可搜索 URL 的應用程式。關於路由知識,請查看asp.net core 系列第5,6章。

 

  (2) 模型綁定(Model)

    ASP.NET Core MVC 模型綁定將客戶端請求數據(窗體值(form)、路由數據、查詢字元串參數、HTTP 頭)轉換到控制器(Controller)可以處理的對象中。 因此,控制器邏輯不必找出傳入的請求數據;它只需具備作為其Action方法的參數的數據。下麵的LoginViewModel就是一個模型類。

  public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)

 

  (3) 模型驗證

    ASP.NET Core MVC 通過使用數據註釋驗證屬性。 驗證屬性在值發送到服務端前,在客戶端上進行檢查。併在調用控制器action前在服務端上進行檢查。

using System.ComponentModel.DataAnnotations;
public class LoginViewModel
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

//服務端控制器action驗證
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    //驗證模型 
    if (ModelState.IsValid)
    {
      // work with the model
    }
    return View(model);
}

 

  (4) 依賴註入

    依賴關係註入除了在控制器上通過構造函數請求所需服務,還可以使用@inject 指令,應用在視圖文件上。下麵是視圖頁面上通過依賴註入獲取服務對象。

@inject SomeService ServiceName
<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ServiceName.GetTitle</title>
</head>
<body>
    <h1>@ServiceName.GetTitle</h1>
</body>
</html>

 

  (5) 篩選器

    篩選器幫助開發者封裝,橫切關註點,例如異常處理或授權。篩選器允許action方法運行自定義預處理和後處理邏輯,並且可以配置為在給定請求的執行管道內的特定點上運行。篩選器可以作為屬性應用於控制器或Action(也可以全局運行)。例如MVC 授權篩選器。

    [Authorize]
    public class AccountController : Controller

 

  (6) 區域

    區域用在大型Web開發上, 是功能分組的方法。區域是應用程式內的一個 MVC 結構。  例如,具有多個業務單位(如結賬、計費、搜索等)的電子商務應用。每個單位都有自己的邏輯組件視圖、控制器和模型。

 

  (7) Web API

    除了作為生成網站的強大平臺,ASP.NET Core MVC 還對生成 Web API 提供強大的支持。 可以生成可連接大量客戶端(包括瀏覽器和移動設備)的服務,前面章節有講過。

 

  (8) 可測試性

    框架對界面和依賴項註入的使用非常適用於單元測試,並且該框架還包括使得集成測試快速輕鬆的功能(例如 TestHost 和實體框架的 InMemory 提供程式)

 

  (9) Razor 視圖引擎

    ASP.NET Core MVC 視圖使用 Razor 視圖引擎呈現視圖。 Razor 是一種緊湊、富有表現力且流暢的模板標記語言,用於使用嵌入式 C# 代碼定義視圖。 Razor 用於在伺服器上動態生成 Web 內容。 可以完全混合伺服器代碼與客戶端內容和代碼。例如下麵嵌入 C#代碼,迴圈輸出5組li標記

<ul>
  @for (int i = 0; i < 5; i++) {
    <li>List item @i</li>
  }
</ul>

 

  (10) 強類型視圖

    可以基於模型強類型化 MVC 中的 Razor 視圖。 控制器可以將強類型化的模型傳遞給視圖,使視圖具備類型檢查和 IntelliSense 支持。例如,以下視圖呈現類型為 IEnumerable<Product> 的模型:

@model IEnumerable<Product>
<ul>
    @foreach (Product p in Model)
    {
        <li>@p.Name</li>
    }
</ul>

 

  (11) 標記幫助程式

    標記幫助程式使伺服器端代碼可以在 Razor 文件中參與創建和呈現 HTML 元素。 例如,內置 LinkTagHelper 可以用來創建指向 AccountsController控制器中  Login的方法鏈接

    <p>
         Thank you for confirming your email.
        Please <a asp-controller="Account" asp-action="Login">Click here to Log in</a>.
    </p>

 

  (12) 視圖組件

    通過視圖組件可以包裝呈現邏輯併在整個應用程式中重用它。 這些組件類似於分部視圖,但具有關聯邏輯。

     

二. 完整示例介紹(項目StudyMVCDemo)

 

   2.1 安裝EF數據提供程式

    這裡使用記憶體資料庫Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和記憶體資料庫一起使用, 這對測試非常有用。

    PM> Install-Package Microsoft.EntityFrameworkCore.InMemory

 

  2.2 新建數據模型類(POCO )和EF上下文類

    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext(DbContextOptions options)
            : base(options)
        {
        }
        public DbSet<Movie> Movie { get; set; }
    }    
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }

 

   2.3 初始化數據

     public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    //var context = services.GetRequiredService<MvcMovieContext>();
                    //程式運行時,使用EF遷移生成數據,用在關係型資料庫
                    //context.Database.Migrate();
SeedData.Initialize(services); } catch (Exception ex) { var logger = services.GetRequiredService<ILogger<Program>>(); logger.LogError(ex, "An error occurred seeding the DB."); } } host.Run(); }
    public static class SeedData
    {
        /// <summary>
        /// 初始化數據
        /// </summary>
        /// <param name="serviceProvider"></param>
        public static  void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new MvcMovieContext(
                serviceProvider.GetRequiredService<DbContextOptions<MvcMovieContext>>()))
            {
                // 如果有數據返回
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
View Code

  

  2.4 添加控制器類(MoviesController)

  public class MoviesController : Controller
    {

        private readonly  MvcMovieContext _MvcMovieContext;

        public MoviesController(MvcMovieContext MvcMovieContext)
        {
            this._MvcMovieContext = MvcMovieContext;
        }
    }

 

  2.5 列表頁Movies/index.cshtml

        // GET: /<controller>/
        public IActionResult Index()
        {
            var movies = _MvcMovieContext.Movie.ToList();
            return View(movies);
        }
@model IEnumerable<StudyMVCDemo.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.ReleaseDate)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Genre)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Price)
                </td>
                <td>
                    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

   啟動程式,在瀏覽器中輸入http://localhost:18084/Movies,如下圖所示:

    上圖中菜單佈局是在 Views/Shared/_Layout.cshtml 文件中實現的,該_Layout.cshtml頁中@RenderBody()是視圖頁面的占位符。

    Views/_ViewStart.cshtml 文件將 Views/Shared/_Layout.cshtml 文件引入到每個視圖中。 可以使用 Layout屬性設置不同的佈局視圖,或將它設置為 null,這樣將不會使用任何佈局文件。後面詳細瞭解佈局。

 

   2.6 詳細頁Movies/ Details.cshtml

        /// <summary>
        /// 詳細頁 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var movie = await _MvcMovieContext.Movie
                .FirstOrDefaultAsync(m => m.Id == id);
            if (movie == null)
            {
                return NotFound();
            }
            return View(movie);
        }
@model StudyMVCDemo.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

   啟動程式,從列表頁的超連接Details點擊進入,如下圖所示:

  

  2.7 編輯頁Movies/ Edit.cshtml

    對於編輯頁有二個action, 一個是Get用來提取數據填充到表單,一個是Post用來提交修改的表單數據。

    (1) post中的Bind特性是對需要的屬性進行更新。

    (2) ValidateAntiForgeryToken特性用於防止請求偽造, 生成的隱藏的 XSRF 標記 Input name="__RequestVerificationToken"。用在Post提交的比如修改和刪除功能等。

    (3) 模型驗證asp-validation-for是指表單Post到伺服器之前,客戶端驗證會檢查欄位上的任何驗證規則。 如果有任何驗證錯誤,則將顯示錯誤消息,並且不會Post表單,內部是輸入標記幫助程式使用 DataAnnotations 特性,併在客戶端上生成 jQuery 驗證所需的 HTML 特性。

       public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var movie = await _MvcMovieContext.Movie.FindAsync(id);
            if (movie == null)
            {
                return NotFound();
            }
            return View(movie);
        }
        
       [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie)
        {
            if (id != movie.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _MvcMovieContext.Update(movie);
                    await _MvcMovieContext.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw;
                }
                return RedirectToAction("Index");
            }
            return View(movie);
        }
@model StudyMVCDemo.Models.Movie

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ReleaseDate" class="control-label"></label>
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genre" class="control-label"></label>
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

     啟動程式,從列表頁的Edit點擊進入,如下圖所示:

   2.8 刪除

 // 刪除沒有對應的頁面,從列表頁的Delete點擊進入,下麵是刪除的關鍵代碼
public async Task<IActionResult> DeleteConfirmed(int id)
{
    var movie = await _context.Movie.FindAsync(id);
    _context.Movie.Remove(movie);
    await _context.SaveChangesAsync();
    return RedirectToAction(nameof(Index));
}

 

   參考文獻

    MVC教程

    


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 滿課一天,做25的時候還瘋狂WA,進度可以說是很慢了 哭泣 L1-025 正整數A+B 題的目標很簡單,就是求兩個正整數A和B的和,其中A和B都在區間[1,1000]。稍微有點麻煩的是,輸入並不保證是兩個正整數。 輸入格式: 輸入在一行給出A和B,其間以空格分開。問題是A和B不一定是滿足要求的正整數 ...
  • Z字形編排問題詳解(C++): 問題描述:給定一個矩陣matrix,輸出矩陣matrix進行Z字形編排後的內容。 原矩陣: 輸出形式: 演算法分析與詳細解答: 要解決這樣一個問題,可能一開始無從下手,但是我們只要認真觀察Z字形矩陣的走向過程,就不難發現其中的規律。對於原始矩陣matrix中的任意元素  ...
  • 1.北斗協議的具體格式如下圖 2.數據包類型 根據北斗協議類型定義如下枚舉類型 3.基礎類封裝 BDBaseFrame,使用 IByteBuffer 類來封裝數據包,IByteBuffer 內置提供了很多位元組操作方法(read,write) 4.具體數據包類型封裝 PositionFrame 5.d ...
  • 參考資料 [1] 毛星雲【《Effective C 》提煉總結】 https://zhuanlan.zhihu.com/p/24553860 [2] 《C 捷徑教程》 [3] 什麼時候使用值類型?什麼時候使用引用類型? https://www.cnblogs.com/LittleFeiHu/p/44 ...
  • 就用查省市為例,別人還沒查就把所有都弄好,很浪費資源和時間,redis是為了存儲常用的查詢操作的[結果],以此來減少直接查詢資料庫的次數,以下內容僅供參考,請勿照抄。(如有說得不好之處,請指點。) 言歸正傳,第一個方法也就是查省市的入口,這個方法可以依照各自的需要寫成自己需要的方法如:(provin ...
  • 問題 將 SignalR 集成到 ASP.NET Core MVC 程式的時候,按照官方 DEMO 配置完成,但使用 DEMO 頁面建立連接一直提示如下信息。 原始代碼: 原因 出現該問題的原因是由於 CORS 策略設置不正確造成的,原始設置我是允許所有 Origin 來源。但是由於 dotnetC ...
  • split的使用: 1、使用char()字元分隔:根據單個的char()類型的進行分隔 代碼如下: 2、利用多個字元來分隔字元串 代碼如下: 3、用字元串進行分隔 使用字元串進行分隔需要藉助C#的正則表達式,也就是需要使用Regex類。在Regex的Split方法中:第一個參數為需要分隔的字元串、第 ...
  • string類型不能被繼承,它是密封類,sealed。 一、字元串的特性。 1、不可變性。 2、字元串池。 二、常用方法。 方法不一一寫出來了。 tringbuilder的使用。 大量拼接字元串的時候用。效率比string高。使用: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...