《Pro ASP.NET MVC 3 Framework》学习笔记之二十二【Controllers和Actions】

简介: Controllers入门(Introducing the Controller) 每一个针对应用程序的请求都是通过Controller处理的,controller自由地选择合适的方式来处理这些请求,只要它不偏离到View和Model所负责的区域。

Controllers入门(Introducing the Controller)

每一个针对应用程序的请求都是通过Controller处理的,controller自由地选择合适的方式来处理这些请求,只要它不偏离到View和Model所负责的区域。这样意味着我们不要把业务或数据存储的逻辑放到Controllers里面,也不要创建用户接口。

在ASP.NET MVC框架里面,Controllers是包含必要的处理请求的.NET类。前面有解释Controller的角色是封装我们的应用程序逻辑。这意味着Controller是负责处理请求,实行对Model的操作,选择View呈现给用户。本次的笔记会介绍Controllers是怎样被实现的以及我们能够接收和创建输出的不同方式。

MVC框架本身并没有限定我们通过View创建HTML,并且会讨论其他可用的选择。同时也会展示Actions方法是如何让单元测试变得简单,以及阐释怎样测试每一种由Actions产生的Results。

下面通过新建一个Project来说明,创建一个ControllersAndActions的项目,选择Empty Template.

1.创建一个实现IController的Controller

在MVC框架里面,Controller类必须实现IController接口:如下

public interface IController { void Execute(RequestContext requestContext); }

这是一个非常简单的接口,只有一个Execute方法,当一个请求在Controller类里面被命中时调用。MVC框架通过读取由routing data创建的Controller属性的值来知道哪一个Controller类被命中。我们能够通过实现IController接口来创建一个Controller类,但是这是非常低级的接口,并且我们要做很多的工作来让Controller变成可用的。

下面的BasicController提供了一个展示。

View Code
namespace ControllersAndActions.Controllers
{
public class BasicController:IController
{
public void Execute(RequestContext requestContext)
{
string controller = (string)requestContext.RouteData.Values["controller"];
string action = (string)requestContext.RouteData.Values["action"];
requestContext.HttpContext.Response.Write(string.Format("Controller:{0},Action:{1}", controller, action));
}
}
}

在上面的Execute方法里面,我们从关联请求的RouteData对象里面读取了controller和action变量的值并写入了输出的结果里面。这时如果我们运行程序并输入:
/Basic/Index,会显示如下:

通过实现IController接口能够让我们创建一个类,这个类是被MVC框架识别为Controller并发送请求给它的。但是要写一个负责的应用程序,这就变得非常艰难。MVC框架不具体到一个controller是如何处理请求的,这也意味着我们能够创建任何方法。

2.创建一个继承Controller类的Controller

MVC框架是无限制地可定制和看扩展的,我们能够实现IController接口创建任何一种我们需要的请求处理和结果生成的Controller类.如果我们不想操作方法,不想关注呈现的视图,那么我们可以把一切事情掌握在自己手里并写出一个更好的,更快的,更加优雅的处理请求的方式,或者我们也可以将controller从System.Web.Mvc.Controller派生,这样就可以使用MVC框架提供的功能。

System.Web.Mvc.Controller类提供了三个关键的功能:

①Action Methods:一个controller类的行为会划分到多个方法里面,每一个方法暴露给不同的URL并使用从请求中提取的参数来调用,这些方法称为Action Methods。
②Action Results:Action Methods的返回值
③Filters:封装一些可重用的行为,使用时只需要在controller和action方法上面添加[Attributes]。

接下来,创建一个DerivedController类并继承Controller,如下:

View Code
    public class DerivedController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Hello from DerivedController Index Method";
return View("Index");
}
}

接收输入(Receiving Input)

Controller需要频繁的访问传入进来的数据,比如querystring,通过路由系统解析参数的值等等。有三种主要的方式来访问这样的数据:

①从context对象提取  ②作为参数传递给action方法的  ③明确的调用框架的模型绑定功能

ps:参数名是忽略大小写的,如Request.Form["City"]跟Request.Form["city"]是一样的。

这里我们主要用前面两种方式,模型绑定会在后面的章节介绍。

1.从Context对象获取数据
当我们创建一个从Controller基类派生的controller时,我们就能够访问一套非常便捷的属性,这些属性包括:Request,  Response ,  RouteData,  HttpContext, Server
每一个属性提供请求的一个方面的信息,这些属性都是在ControllerContext实例里面的。在action方法里面是可以使用任何context对象来访问这些属性的,例如:

View Code
        public ActionResult RenameProduct()
{
//仅仅为了演示部分属性
string userName = User.Identity.Name;
string serverName = Server.MachineName;
string clientIP = Request.UserHostAddress;
DateTime dateStamp = HttpContext.Timestamp;
string oldProductName = Request.Form["OldName"];
string newProductName = Request.Form["NewName"];
return View("Index");
}

2.使用Action方法的参数
这种方式比上一种方式要优雅,它让我们的Action方法更易读,下面是一个对比:

View Code
//显示天气预备
public ActionResult ShowWeatherForecast(){
string city = RouteData.Values["city"];
DateTime forDate = DateTime.Parse(Request.Form["forDate"]);
//实现部分...
}
//我们可以重写下
public ActionResult ShowWeatherForecast(string city, DateTime forDate){
//实现部分
}
//下面这种方式是不是比上面的要优雅易读呢?

其实不仅仅是易读而且有利于单元测试,有一点需要我们注意,action方法里面不允许有ref或out型的参数,这个编译时不会报错,但是运行会抛异常。如下面的实例:

        public ActionResult Index(out int a)
{
ViewBag.Message = "Hello from DerivedController Index Method";
a = 1;
ViewBag.Num = a;
return View("Index");
}

Index视图里面的代码如下:

View Code
@{
ViewBag.Title = "MyView";
}
<h2>
MyView</h2>
Message:@ViewBag.Message<br />
Num:@ViewBag.Num

运行抛如下异常:

理解参数对象是怎样被实例化的

Controller基类使用MVC框架的Value Providers(值提供程序)和Model Binders(模型绑定)两个组件来获取action方法参数的值
Value Providers将可用的数据项集合呈现给controller,有内置的value providers从Request.Form,  Request.QueryString,  Request.Files,RouteData.Values获取数据项。然后这些值会被传递给模型绑定(Model Binders)——将这些值映射到action方法需要的参数的类型。默认的model binders能够创建和填充任何.NET类型的对象,并包含自定义的类型和集合。

理解可选和必须的参数

如果MVC框架不能找到一个引用类型参数的值,action方法仍然会被调用,但是使用的null值。如果是一个值类型的值没有找到,那么会发生异常并且action方法不会被调用。

①值类型的从参数是必须的被赋值的。如果想让这个跟引用类型一样,可以这样定义int?,当依然没有找到值时,不会发生异常,而是会传递null值。
②引用类型的参数是可选的。为了让它变成必选的(保证一个非空的值被传递),在action方法的上面添加一些代码拒绝null值

指定默认参数的值

如果我们要处理不包含action方法参数值的请求,但是又不想去检查null值。这时可以使用C#可选参数的特性,如下:
public ActionResult Search(string query="all",int page=1){...}

今天的笔记就到这里,后面一篇笔记还是关于这部分的内容。笔记里面不对的地方还请路过的朋友指正,谢谢!
晚安!

相关文章
|
7月前
|
并行计算 算法 调度
(学习笔记)U-net++代码解读
python: 3.10 U-net++结构图
340 0
|
开发框架 前端开发 .NET
ASP.NET Core 核心特性学习笔记「下」
ASP.NET Core 核心特性学习笔记「下」
|
开发框架 前端开发 中间件
ASP.NET Core 核心特性学习笔记「上」
ASP.NET Core 核心特性学习笔记「上」
|
传感器 设计模式 开发框架
ASP.NET MVC5学习笔记01
ASP.NET MVC5学习笔记01
126 0
ASP.NET MVC5学习笔记01
|
消息中间件 Cloud Native 安全
.NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 详解)--学习笔记
Consumer 消费者 Producer 生产者 Request-Response 请求-响应
357 1
.NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 详解)--学习笔记