到达应用程序的每一个请求都是由控制器处理的。今天我们来说一下控制器和控制器里的动作。
在ASP.NETMVC框架中,控制器是含有请求处理逻辑的.NET类。控制器的作用是封装应用程序逻辑。这意味着控制器要负责处理输入请求、执行域模型上的操作,并选择渲染给用户的视图。
为了方便演示,我们先创建一个项目。
1、准备项目
1、我们使用“Empty(空)”模板创建一个名为”ControllersAndActions”的新项目,并检查MVC文件夹和引用选项。
2、控制器
a、创建派生与controller类的控制器
为了编写更好、更快且更雅致的请求处理方式,可以在微软公司MVC框架团队提供的特性之上来进行构建,这可以通过System.Web.Mvc.Controller类来派生你的控制器。
System.web.Mvc·Controller是大多数MVC开发人员需要熟悉的,用来对请求处理提供支持的一个类,它是我们日常编程中一直在使用的类。Controller类提供了以下三个关键特性。
动作方法(ActionMethod):一个控制器的行为被分解成多个方法(而不是只有一个单一的Execute()方法)。每个动作方法被暴露给不同的URL,并通过从输入请求提取的参数进行调用。
动作结果(ActionResult):你可以返回一个描述动作结果的对象(例如,渲染一个视图,或重定向到一个不同的URL或动作方法),然后通过该对象实现你的目的。这种指定结果和执行它们之间的分离简化了单元测试。
·过滤器(Filter):你可以把可重用的行为封装成过滤器,然后通过在源代码中放置一个注解属性的办法,把这种行为标注到一个或多个控制器或动作方法上。
下面我们创建的一个简单控制器,名称为DerivedController,使用”MVC5 Controller一Empty(MVC5控制器.空)”选项生成,并做了一些简单的修改以设置ViewBag属性和选择一个视图。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ControllersAndActions.Controllers
{
public class DerivedController : Controller
{
// GET: Derived
public ActionResult Index()
{
ViewBag.Message = "Hello from the DerivedController IndexMethod";
return View("MyView");
}
}
}
上述代码中返回了View方法的结果,在其中传递了希望渲染给客户端的视图名。为了创建这个视图,创建Views/Derived文件夹,右击该文件夹并从菜单中选择“Add WC5ViewPage(Razor)(添加MVC5视图页(Razor))”。设置名称为MyView.cshtml,然后单击”OK(确定)”按钮以创建一个视图文件。设置视图文件内容如下:
@{
ViewBag.Title = "MyView";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<h2>MyView</h2>
Message:@ViewBag.Message
</body>
</html>
如果启动这个应用程序,并导航到/Derived/index,己定义的这个动作方法将被执行,所命名的这个视图也将被渲染。
作为Controller类的一个派生类,所要做的工作是实现动作方法、获取所需要的各种输入,以对请求进行处理,并生成一个适当的响应。下面小编将带着大家一起了解做这些事情的一些办法。
3、接收请求数据
控制器经常需要访问来自于输入请求的数据,如查询字符串值、表单值,以及由路由系统根据输入URL解析所得到的参数。访问这些数据有三个主要的途径:
- 通过一组上下文对象(ContextObjects)进行提取。
- 作为参数(Parameters)被传递给动作方法而形成的数据。
明确地调用框架的模型绑定(ModelBinding)特性。
在此,我们主要了解使用上下文对象以及动作方法参数两种方法。
a、通过上下文对象获取数据
当控制器是通过Controller基类派生而来的时候,便得到了一组便利属性(ConvenienceProperty),可以用来访问与请求相关的信息。这些便利属性包括Request、Response、RouteData、Httpcontext以及Server。每一个属性都包含了请求不同方面的信息。这些属性称为“便利属性”(ConvenienceProperties),是因为它们每一个都从请求的Controllercontext实例(可以通过Controller.ControllerContext属性对其进行访问)接收了不同类型的数据。下表描述了一些常用的上下文对象。
属性 | 类型 | 描述 |
---|---|---|
Request.QueryString | NameValueCollection | 随该请求发送的GET变量 |
Request.Form | NameVaIueCollection | 随该请求发送的POST变量 |
Request.Cookies | HttpCookieCollection | 由浏览器随该请求发送的Cookies |
Request.HttpMethod | string | 用于该请求的Http方法(动词,如GET或POST) |
Request.Headers | NameValueCollection | 随该请求发送的整个HTTP报头 |
Request.Url | Url | 所请求的URL |
Request.userHostAddress | string | 形成该请求的用户IP地址 |
RouteData.Route | RouteBase | 为该请求所选择的RouteTable.Routes条目 |
RouteData.Values | RouteVaIueDictionary | 当前路由的参数(从URL或默认值提取) |
HttpContext.Application | HttpApplicationStateBase | 应用程序状态库 |
HttpContext.Cache | Cache | 应用程序缓存厍 |
HttpContext.items | IDictionary | 当前请求的状态库 |
HttpContext·Session | HttpSessionStateBase | 访问者的会话状态库 |
TempData | TempDataDictionary | 为当前用户存储的临时数据项 |
user | IPrincipal | 已登录用户的认证信息 |
这里提到的每个单独的属性一一一Request,Httpcontext等都提供了上下文对象。这里就不一一介绍了。
但是为了演示,我们仅仅做一个简单的例子,在一个动作方法中,可以用这些上下文(Context)对象中的任意一个,来获取与请求相关的信息。
string username = User.Identity.Name;
string servername = Server.MachineName;
string clientip = Request.UserHostAddress;
DateTime datestamp = HttpContext.Timestamp;
string oldproductname = Request.Form["oldname"];
string oldnewproductname = Request.Form["newname"];
b.使用动作方法参数
在工作 中,动作方法可以采用一些参数。这是一种比通过上下文对象手工提取数据更灵活的接收输入数据的办法,而且这使你的动作方法更易于阅读。例如,假设有一个动作方法,它像下面这样使用上下文对象:
public ActionResult ShowWeatherForecast(){
string city=(string)RouteData.Va1ues["city"];
DateTime forDate=DateTime.Parse(Request.Form["forDate"]);
//todo something
returnView();
}
为此我们可以这样写:
public ActionResult ShowWeatherForecast( string city,datetime forDate){
//todo something
returnView();
这不仅更易于阅读,而且也有助于单元测试。
另外,之所以能这样替换,是因为通过自动检查上下文对象和属性,MVC框架会给动作方法参数提供值,这些对象包括Request.QueryString、Request.Form以及RouteData.Valueso,对参数名的处理不区分大小写,因此,例如名称为”city”的动作方法参数能够被Request.Form[“City”]的值所填充。
1.理解参数对象实例化
Controller基类使用叫作“值提供器(ValueProvider)”和“模型绑定器(ModelBinder)”的
MVC框架组件来获取动作方法的参数值。值提供器表现一组可用于控制器的数据项。有一组内建的值提供器,它们会抓取Request.Form、Request.QueryString、Request.Fi1es以及RouteData.Va1ues的数据项。然后这些值被传递给模型绑定器,模型绑定器会尝试将这些数据映射成动作方法参数的数据类型。
默认的模型绑定器能够创建并填充任何.NET类型的对象,包括集合和项目专用的自定义类型。
2.理解可选参数与强制参数
如果MVC框架找不到引用类型参数(如string或object)的值,动作方法仍然会被调用,但对该参数会使用一个null值。若找不到值类型参数(如int或double)的值,则会抛出一个异常,并且不会调用动作方法。以下是考虑这种情况的另一种方式:
值类型参数是强制的。为了使它们成为可选的,可以为其指定一个默认值,或者将该参数的类型改为可空(nullable)类型(如int或DateTime),那么MVC框架在无值可用的情况下会传递null值。
引用类型参数是可选的。为了使它们成为必需的(以保证传递一个非空值),可以把一些代码添加到该动作方法的顶部,以拒绝null值。例如,在该值等于null的情况下,抛出一个ArgumentNullException异常。
3.指定默认参数值
如果希望处理不含动作方法参数值的请求,但又不想在代码中检查null值或抛出异常,可以用C#的可选参数特性来代替。
public ActionResult Search(string query=”all”,int page=1)
{
//一.处理请求一
returnView();
}
在定义参数时,通过对参数赋值的办法,可以将参数标记为可选的。给query和page参数提供了默认值。MVC框架会试图通过请求为这些参数获取值,但如果无值可用,那么将用所指定的默认值来替代。
对于string型参数query(注意,这是引用类型参数),这意味着不需要检查null值。如果所处理的请求未指定查询字符串,那么该动作方法将以字符串all进行调用。对于int型参数(注意,这是值类型参数),在没有page值时,请求不会导致错误。该方法将以默认值“1”进行调用。