天天看点

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