天天看點

ASP.NET Core Actions

作者:opendotnet

Action方法是在Controllers中定義公共方法使用路由規則将用戶端的請求和action方法做映射

public IActionResult NameofAction()              {              return View();              }           

這個方法傳回一個IActionResult并且方法的名稱為NameofAction, action 方法的傳回類型可以是像C#函數中的任何類型,IActionResult,ActionResult,JsonResult,string,StatusCodeResult是常用的類型

IActionResult VS ActionResult - IActionResult 是一個接口 ,ActionResult是一個抽象類繼承自IActionResult接口,在WebAPI中你将使用ActionResult傳回用戶端響應

1 Action将Model傳遞給View

Action方法通常做一些特定的工作像資料庫操作,數學計算等,最後将工作的結果輸出給使用者,是以工作結果傳回到終端View,以至于能在UI上顯示

一個Action方法能傳回2種類型的Models到View:

1 Models包含C#資料類型像string,int,float 等

2 Models包含C#類像Employee.cs , Person.cs 等讓我們了解一下Action方法,Models和Views針對這兩種場景是如何工作的

1.1 Action方法傳回String類型

在Controllers檔案夾下建立一個新的Controller檔案名字為EmployeeController.cs并且在添加Index方法,POST版本的Index方法有2個參數-一個接受Id另一個是name,代碼如下:

using AspNetCore.Action.Models;              using Microsoft.AspNetCore.Mvc;              namespace AspNetCore.Action.Controllers              {              public class EmployeeController : Controller              {              public IActionResult Index()              {              return View();              }              [HttpPost]              public IActionResult Index(int id, string name)              {              string welcomeMessage = $"Welcome Employee: {name} with id: {id}";              return View((object)welcomeMessage);              }              }              }           

Action方法傳回IActionResult類型,調用View()方法傳回一個字元串到View,注意我們如果将string類型傳遞到View,需要将它轉換成object類型- View((object)string)

在Views->Employee檔案夾下添加Index.cshtml視圖,Index試圖的代碼如下

@model string;              <h2>填充并且送出表單</h2>              @{              if (Model != )              {              <h3 class="p-3 mb-2 bg-success text-white">@Model</h3>              }              }              <form class="form-horizontal" method="post">              <div class="mb-3 row">              <label class="col-sm-1 control-label">編号</label>              <div class="col-sm-11">              <input class="form-control" name="id" />              </div>              </div>              <div class="mb-3 row">              <label class="col-sm-1 control-label">姓名</label>              <div class="col-sm-11">              <input class="form-control" name="name" />              </div>              </div>              <div class="mb-3 row">              <div class="col-sm-11 offset-sm-1">              <button type="submit" class="btn btn-primary">送出</button>              </div>              </div>              </form>           

這裡有幾個值得注意的點:

1 在視圖中通過使用@model string指令指定視圖包含的類2 視圖中表單送出員工編号和姓名3 Action方法傳回字元串到視圖,在視圖判斷表達式是否為空,如果不為空将執行内部表單式現在測試一下我們應用程式,運作應用程式,在輸入框中輸入Id和姓名并點選送出按鈕

ASP.NET Core Actions

通過這種方式,我們可以從action方法到視圖傳輸另外一些資料類型像int,float等

1.2 Action方法傳回Class類型如果我們想傳回多個值到視圖,最好的方式通過使用Class類型來完成,我們在Models檔案加下建立一個Employee.cs類,這個類中定義了如下字段

namespace AspNetCore.Action.Models              {              public class Employee              {              public int Id { get; set; }              public string Name { get; set; }              public int Salary { get; set; }              public string Designation { get; set; }              public string Address { get; set; }                  }              }               

現在将類傳回給視圖,在EmployeeController中添加一個新的action方法Detail

[HttpGet]              public IActionResult Detail()              {              return View();              }              [HttpPost]              public IActionResult Detail(int id, string name)              {              var employee=new Employee();              employee.Id = id;              employee.Name = name;              employee.Salary = 1000;              employee.Designation = "Manager";              employee.Address = "New York";              return View(employee);              }           

HttpGet 版本的 Detail方法不會向視圖傳回任何内容,HttpPost版本的Detail方法中給客戶傳回一個Employee對象,最後我們将該對象傳回給視圖

接下來在Views->Employee檔案夾中建立Detail.cshtml的Razor視圖

注意這次我們在視圖的頂端定義了一個Employee類型-@model Employee

@model Employee;              <h2>填充并且送出表單</h2>              @{              if (Model != )              {              <h3 class="p-3 mb-2 bg-success text-white">              員工詳細資訊:@Model.Id,@Model.Name,@Model.Salary,@Model.Designation,@Model.Address              </h3>              }              }              <form class="form-horizontal" method="post">              <div class="mb-3 row">              <label class="col-sm-1 control-label">編号</label>              <div class="col-sm-11">              <input class="form-control" name="id" />              </div>              </div>              <div class="mb-3 row">              <label class="col-sm-1 control-label">姓名</label>              <div class="col-sm-11">              <input class="form-control" name="name" />              </div>              </div>              <div class="mb-3 row">              <div class="col-sm-11 offset-sm-1">              <button type="submit" class="btn btn-primary">送出</button>              </div>              </div>              </form>           

接下來我們将Employee對象的值顯示在頁面上,運作應用程式并填充表單,送出表單你将會看到employee所有的值,如下圖所示:

ASP.NET Core Actions

2 ViewResult對象

我們之前一直使用View()方法,讓我們看一些這個方法别的重載版本,View方法建立了一個ViewResult對象,我們前面已經示範如何使用該方法給視圖傳遞字元串和類對象,View()方法有4個不同的版本,具體如下:

方法 描述
View() 使用預設視圖來渲染,例如:如果一個action方法是List并且你使用了沒有參數View()方法,List.cshtml視圖被呈現
View("name_of_view") 這個版本在參數中傳遞一個視圖名稱并且呈現該視圖,例如如果你使用View("Show"),然而你Show.cshtml視圖将被呈現
View(model) 這個版本給預設視圖提提供model資料,這個通常被使用在View中呈現強類型
View("name_of_view",model) 指定一個視圖的名稱并且給指定的視圖提供model資料

3 将資料從Action傳遞到View

我們可以使用Model傳遞任何類型的資料從action方法到view, 前面有例子,如果你不想使用這個方式傳遞資料,我們還可以使用下面幾種方式将資料傳輸到View,我們這裡介紹另外三種方式從Action方法傳遞資料到View

1 ViewBag

2 TempData

3 Session Variable

3.1 ViewBag

ViewBag是一個dynamic的對象,允許你自定義屬性,ViewBag的值能被傳輸到視圖并展示在UI上,在ExampleController.cs檔案中添加一個ViewBagExample的方法,代碼如下:

using Microsoft.AspNetCore.Mvc;              namespace AspNetCore.Action.Controllers              {              public class ExampleController : Controller              {              public IActionResult Index()              {              return View();              }              public IActionResult ViewBagExample()              {              ViewBag.CurrentDateTime = DateTime.Now;              ViewBag.CurrentYear = DateTime.Now.Year;              return View();              }              }              }           

我們需要注意如下幾點:

1 ViewBag是一種輕量化方式從Controllers到Views傳輸資料2 ViewBag隻能傳輸資料從action到view,如果在action方法發生跳轉,ViewBag資料會丢失3 它可以包含原始類型或者複雜類型對象4 每次ViewBag值讀取之後,dotnet會從記憶體中移除,如何你想重複使用這些值,你必須将它們存儲在變量中3.2 TempData

ViewBag的值在發生跳轉時會丢失,是以針對這種場景你可以使用TempData,TempData和ViewBag非常相識除了在調轉過程中TempData值能夠保持不丢失與ViewBag一樣,DOTNET在讀取TempData的值後立即自動删除這些值

在Example控制器中添加下面兩個新的方法,TempDataExample&TempDataShow, 代碼如下:

public IActionResult TempDataExample()              {              TempData["CurrentDateTime"] = DateTime.Now;              TempData["CurrentYear"] = DateTime.Now.Year;              return RedirectToAction("TempDataShow");              }              public IActionResult TempDataShow()              {              return View();              }           

TempDataExample方法給TempData添加目前時間和當年年份

1 CurrentDateTime

2 CurrentYear

通過使用RedirectToAction跳轉方法,調轉到TempDataShow方法,TempDataShow方法僅僅調用了預設的View而沒有傳遞任何Model

現在建立一個TempDataShow視圖在Views->Examlpe檔案夾下,添加下列代碼

<h2>              Current DateTime & Year: @TempData["CurrentDateTime"] and @TempData["CurrentYear"]              </h2>           

TempData按照字典的方式存儲值,通過鍵值對的方式通路,運作程式,https://localhost:7019/Example/TempDataExample,顯示目前時間和年份注意:在這個場景中我們不能使用ViewBag,因為ViewBag的值在調轉過程中會丢失,你可以使用ViewBag替換TempData做測試

ViewBag,ViewData和TempData之間有什麼不同呢?ViewBag是一個動态對象,ViewData和TempData是一個字典類型,存儲字典類型的值,ViewBag在發生跳轉時值會丢失是以在這種情況下我們可以使用TempData

3.3 Session 變量

Session 也是用來存儲資料的,Session存儲的資料可以在同一個用戶端不同的請求中共享,你可以在Session變量中存儲資料在你網站的任何地方使用

首先你需要啟用Session在ASP.NET Core 應用程式中添加下面3行代碼在Program.cs類中

ASP.NET Core Actions

添加Session中間件和一個IHttpContextAccessor服務,我們可以通過這個服務來通路Session變量在ExampleController中建立一個新的action方法名字為SessionExample,代碼如下:

public IActionResult SessionExample()              {              HttpContext.Session.SetString("CurrentDateTime", DateTime.Now.ToString());              HttpContext.Session.SetInt32("CurrentYear", DateTime.Now.Year);              return View();              }           

SetString()方法将添加任何類型作為字元創存儲在Session變量中,類似的SetInt32()方法将添加Int值,我們将目前時間和目前年份添加到Session中

在Views->Example檔案夾下建立一個新的視圖檔案SessionExample.cshtml,在視圖中添加如下代碼:

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor              <h2>              Current DateTime & Year:              @HttpContextAccessor.HttpContext.Session.GetString("CurrentDateTime"),              @HttpContextAccessor.HttpContext.Session.GetInt32("CurrentYear")              </h2>           

我們使用依賴注入指令将服務注入到視圖中,我們使用該服務能夠通路我們Session中存儲的值

@HttpContextAccessor.HttpContext.Session.GetString("CurrentDateTime"),              @HttpContextAccessor.HttpContext.Session.GetInt32("CurrentYear")           

在Session中可以存儲複雜類型的變量,例如類,你必須把類序列化成JSON,然後擷取該值是再反序列化,我們添加一個新的類:

using System.Text.Json;              namespace AspNetCore.Action.Models              {              public static class SessionExtensions              {              public static void Set<T>(this ISession session, string key, T value)              {              session.SetString(key, JsonSerializer.Serialize(value));              }                  public static T? Get<T>(this ISession session, string key)              {              var value = session.GetString(key);              return value == ? default : JsonSerializer.Deserialize<T>(value);              }              }              }           

現在在action方法序列化一個類對象,并且将該對象存儲到session中,我們使用剛才類裡面定義的序列化方法

HttpContext.Session.Set<Employee>("Employee", new Employee              {              Name = "KK",              Address= "Tokyo"              });           

在視圖中我們将json反序列成對象

@{              var employee = HttpContextAccessor.HttpContext.Session.Get<Employee>("Employee");              <p>@employee.Name, @employee.Address</p>              }           

我們可以在services.AddSession()方法中設定cookie的名字和過期時間,具體代碼如下:

builder.Services.AddSession(sessionOption =>               {              sessionOption.Cookie.Name = ".myapp";              sessionOption.IdleTimeout= TimeSpan.FromSeconds(10);              });           

4 Action方法的調轉方式

ASP.NET Core指定了很多跳轉方法,從相同的Controller不同的action方法的跳轉以及不同Controller不同action方法的跳轉,這些方法定義如下:

1 Redirect

2 RedirectPermanent

3 RedirectToRoute

4 RedirectToRoutePermanent

5 RedirectToAction

6 RedirectToActionPermanent

Redirect

Redirect方法指定一個臨時跳轉(HTTP 302), 它使用跳轉的url作為字元串參并且傳回一個RedirectResult類

例子:下面的action方法指定調轉的RUL-/List/Search

public RedirectResult RedirectAction()              {              return Redirect("/List/Search");              }           

RedirectPermanent

該方法和Redirect方法類似,它執行一個永久調轉(HTTP 301)

例子:下面的action方法執行一個永久跳轉URL-/List/Search

public RedirectResult RedirectPermanentAction()              {              return RedirectPermanent("/List/Search");              }           

RedirectToRoute

如果你想使用基于應用程式路由的調轉你可以使用RedirectToRoute()方法,它執行一個臨時調轉并且使用匿名類型作為參數,匿名類型的參數傳遞到路由系統來生成url

RedirectToRoute()方法傳回RedirectToRouteResult,我們使用它來執行跳轉

public RedirectToRouteResult Redirect()              {              return RedirectToRoute(new { controller = "Admin", action = "Users", ID = 10 });              }           

RedirectToRoutePermanent

RedirectToRoutePermanent和RedirectToRoute類似,它執行的是一個永久調轉

public RedirectToRouteResult RedirectPermanent()              {              return RedirectToRoutePermanent(new { controller = "Admin", action = "Users", ID = 10 });              }           

RedirectToAction

RedirectToAction方法指定臨時調轉到給與的action方法,這個方法傳回一個RedirectToActionResult的一個執行個體

我們修改一下HomeController控制器的Index方法

public IActionResult Index()              {              return RedirectToAction("Privacy");              }           

我們将Index方法調轉到相同控制器下的Privacy方法,在這種情況下調轉的位址為 -/Home/Privacy

如何調用相同控制器下的action?使用RedirectToAction方法單個參數的重載,這個參數提供了相同控制器下的action方法的名稱

如何調用不同控制器下的action方法?你也可以使用RedirectToAction方法2個參數的重載,第一個參數指定控制器的名稱,第二個參數指定了控制器中action方法的名稱

如果你使用的RedirectToAction方法的單個參數,ASP.NET Core假設你指定的action方法在目前控制器中,是以調轉到不同控制器的action方法你需要指定兩個參數,在下面代碼中,我們調轉到Customer控制器的List方法

public RedirectToActionResult Index()              {              return RedirectToAction("Customer", "List");              }           

這種情況下調轉的url是/Customer/List

注意:使用RedirectToAction方法時你不能傳遞Mode,但是你可以使用TempData或者Session變量

RedirectToActionPermanentRedirectToActionPermanent方法指定永久調轉

public IActionResult Index()              {              //return RedirectToAction("Privacy");              return RedirectToActionPermanent("Privacy");              }           

5 Action方法傳回不同類型的Content

截止到現在我們已經看到Action方法傳回string和View,實際上Actions方法還可以傳回JSON和HTTP狀态碼

5.1 Action方法傳回JSON

我們使用Json()方法可以從Action方法傳回JsonResult類

我們在ExampleController下建立一個ReturnJson方法

public JsonResult ReturnJson()              {              return Json(new[] { "Brahma", "Vishnu", "Mahesh" });              }           

在Views->Example檔案夾下建立一個ReturnJson.cshtml的視圖并顯示JSON檔案

運作應用程式并測試

ASP.NET Core Actions

5.2 Action傳回BadRequest (400), Unauthorized (401), NotFound (404) 狀态碼

StatusCode()位于Microsoft.AspNetCore.Http命名空間,使用它可以傳回任何類型的狀态碼,該方法傳回類型StatusCodeResult類位于Microsoft.AspNetCore.Mvc命名空間

例子:傳回BadRequest-400 Status Code

public StatusCodeResult ReturnBadRequest()              {              return StatusCode(StatusCodes.Status400BadRequest);              }           

例子:傳回Unauthorized-401 Status Code

public StatusCodeResult ReturnUnauthorized()              {              return StatusCode(StatusCodes.Status401Unauthorized);              }           

例子:傳回NotFound -404 Status Code

public StatusCodeResult ReturnNotFound()              {              return StatusCode(StatusCodes.Status404NotFound);              }           

總結

這節我們主要講解了Action方法以及Action和View之間的關聯

源代碼位址

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.Action/AspNetCore.Action

參考文獻[1]https://www.yogihosting.com/aspnet-core-configurations/#content-generating-middleware