详解ASP.NET MVC 控制器
ASP.NET MVC系列文章
【02】浅谈Google Chrome浏览器(操作篇)(上)
【03】浅谈Google Chrome浏览器(操作篇)(下)
【04】浅谈ASP.NET框架
【07】浅谈ASP.NET MVC 路由
【08】浅谈ASP.NET MVC 视图
【10】浅谈jqGrid 在ASP.NET MVC中增删改查
【13】浅谈NuGet在VS中的运用
【14】浅谈ASP.NET 程序发布过程

1 概述
在阅读本篇博文时,建议结合上篇博文:详解ASP.NET MVC 路由 一起阅读,效果可能会更好些。
Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务端的交互,并且负责协调Model与View之间数据传递,是ASP.NET MVC框架核心。Controller为ASP.NET MVC框架的核心组成部分,其主要负责处理浏览器请求,并决定响应什么内容给浏览器,但并不负责决定内容应如何显示(View的职责)。
文章内容包括:Controller概述、Controller类别和方法、Controller运行过程、Controller方法类别、ViewData\ViewBag\TempData分析、ActionResult解说、Controller定义和参考文献,剩下有关Controller其他内容在本篇文章中不讲,如Controller激活机制(Controller类型解析、Controller类型缓存、Controller的释放和会话状态行为控制等)、ControllerFactory、ControllerBuilder等,除此之外,文中有些过于涉及到底层的内容,考虑篇幅等因素,只是简要提及了一下,并未做深入分析,根据后期情况,会酌情考虑是否再写一篇彻底深入的底层Controller的。
2 Controller类别和方法
Controller本身就是一个类(Class),该类别有许多方法(Method),这些方法中只要是公开方法(public method)就会被视为是一个动作(Action)或动作方法(Action Method),只要动作存在,就可以通过该动作方法接收客户端传来的要求与决定响应的检视(View)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCControllerDemo.Controllers
{
public class ControllerDemoController : Controller
{
//
// GET: /ControllerDemo/ [HttpGet]
public ActionResult Index()
{
return View();
}
}
}
从如上代码可以总结出Controller应具备如下几个基本条件:
(1)Controller必须为公开类别;
(2)Controller名称必须以Controller结尾;
(3)必须继承自ASP.NET MVC内建的Controller类别,或实现IController自定义类别;
(4)所以动作方法必须为公开方法,任何非公开的方法如声明为private或protected的方法都不会被视为一个动作方法;
3 Controller的运行过程
当Controller被MvcHandler选中之后,下一步就是通过ActionInvoker选定适当的Action来运行。在Controllr中的每个Action可以定义0到多个参数,ActionInvoker会依据当下的RouteValue与客户端传来的数据准备好可传入Action参数的数据,最后正式调用Controller中被选中的那个Action方法。参数传入的属性都是通过一种称为模型绑定(Model Binding)机制,从RequestContext取得数据,并将数据对应或传入方法的参数中,让Action不用再像之前ASP或ASP.NET Web Forms中经常使用的Request.Fomr或Request.QueryString等对象来取得客户端的数据,通过自定义的模型绑定,甚至可以让你对应除了Request.Form或Request.QueryString以外的数据来源,例如:HTTP Cookies、HTTP Headers等等。
Action运行完后的回传值通常是ActionResult类别或其衍生类别(Derived Class),事实上,ActionResult是一个抽象类,如ViewResult用来回传一个View、RedirectResult用来将网页重定向、Content回传文字内容、FileResult回传二进制文档等,这些均是继承ActionResult。MvcHandler从Controller得到ActionResult之后,就会开始运行ActionResult提供的ExecuteResult方法,并将运行结果响应到客户端,这时Controller的任务就算完成。
以上为Controller的基本运行过程。Controller在运行时还有一层所谓的动作过滤器机制,分为如下四种基本类型:
(1)授权过滤器(Authorization Filters);
(2)动作过滤器(Action Filters);
(3)结果过滤器(Result Filters);
(4)例外过滤器(Exception Fiters);
4 控制器方法类别
4.1 动作方法选定器
当通过ActionInvoker选定Controller内的公开方法时,ASP.NET MVC还有另一个特性称为"动作方法选定器(Action Method Selector)",该选定器可以套用在动作方法上,以便ActionInvoker"选定"适当的Action。
(1)NonAction属性
若控制器某个方法特性为NonAction,即使该Action方法是“公开方法”,也会告知ActionInvoker不要选定这个Action来运行。主要用途:a.保护Controller中的特定公开方法不要发布到Web上;b.功能尚未开发完成就要进行部署,暂时不想将此方法删除。
[NonAction]
public ActionResult Index()
{
return View();
}
也可将public改为private,达到保护的效果。
private ActionResult Index()
{
return View();
}
(2)HTTP动词限定属性
HttpGet、HttpPost、HttpDelete、HttpPut、HttpHead、HttpOptions、HttpPatch属性(Attributes)都是动作方法选定器的一部分。如下例子讲解HttpGet属性,即代表只有当客户端浏览器发送HTTP GET要求时,ActionInvoker才会选定到这个Action:
[HttpGet]
public ActionResult Index()
{
return View();
}
若将[HttpGet]改为[HttpPost],浏览器将找不到资源。
[HttPost]
public ActionResult Index()
{
return View();
}

注释:如果动作方法上没有嵌套任何限定属性,那么客户端浏览器发送任意HTTP动词都会自动选定到对应的Action。
当需要显示接收窗体信息时,可以创建两个同名的Action,分别用[HttpGet](显示窗体HTML)和[HttpPost](接收窗体输出的值)属性来限定。
[HttpGet]
public ActionResult Index()
{
return View();
} [HttpGet]
public ActionResult Create()
{
return View();
} [HttpPost]
public ActionResult Create(FormCollection fc)
{
//UpdateToDB(fc);
return RedirectToAction("Index");
}
4.2 操作过滤器
一个操作方法一旦被选中就会立即执行,并且如果它返回一个结果,返回的结果也会随后执行,ASP.NET MVC 5提供五种方式,分别列于如下:
- 即身份验证
- 授权
- 操作前后处理
- 结果前后处理
- 错误处理。
除此之外,还有另外一种过滤器,即重写过滤器,它允许为全局或控制器的默认集合制定例外情况。
操作过滤器可以作为直接运用于操作方法或控制器类的特性来编写,或作为在全局过滤器列表中注册的单独类来编写。如果打算将编写的操作过滤器作为特性来使用,那么它必须继承自FilterAttribute或它的任何子类,如ActionFilterAttribute。不作为特性使用的全局操作过滤器没有对这个基类的要求。无论采用哪个路由,操作过滤器支持的过滤活动都由实现的接口决定。
5 Controller动作结果
5.1 控制器动作结果类型(ActionResult)
通常,在定义一个方法时,我们常规性地根据方法是否有返回值归结为有返回值和无返回值两大类,控制器的本质是类,控制器的action本质是方法,如果按照数学集合来定义,那么控制器是类的一个子集,同理,控制器action是方法的一个子集,因此,在研究控制器以及控制器action时,我们是可以才用研究类和方法的一般思维的。
控制器动作(具体的action)返回的结果叫做控制器动作结果,动作结果是控制器返回给浏览器请求的内容。ASP.NET MVC框架支持六种标准类型的动作结果。
(1)继承ActionResult的动作结果

(2)继承关系

(3)例子
eg1:ViewResult
//方法1: ViewResult作为返回类型
public ViewResult Index()
{
return View();
} //方法二: ViewResultBase作为返回类型
public ViewResultBase Index()
{
return View();
} //方法三: ActionResult作为返回类型
public ActionResult Index()
{
return View();
}
eg2:EmptyResult
// GET: /ControllerDemo/
public EmptyResult Index()
{
return null;
}
eg3:ContentResult
//方法1:ContentResult作为返回类型
public ContentResult Index()
{
return Content("Hello World");
} //方法2:ActionResult作为返回类型
public ActionResult Index()
{
return Content("Hello World");
}
eg4:JsonResult
public JsonResult jsonResult()
{
TechInfoCompanay jsonCompany=new TechInfoCompanay(){id="S001",CompanyName="信息科技有限公司"};
return Json(jsonCompany,JsonRequestBehavior.AllowGet);
} //定义一个公司类
public class TechInfoCompanay
{
public string id { set; get; }
public string CompanyName { set; get; }
}
eg5:RedirectResult
//方法1:RedirectResult作返回类型
public RedirectResult redirectResult()
{
return Redirect("https://www.google.com.hk/");//具体的URL
} //方法1: ActionResult作返回类型
public ActionResult redirectResult()
{
return Redirect("https://www.google.com.hk/");//具体的URL
}
eg6:RedirectToRouteResult
public ActionResult redirectResult()
{
return Redirect("https://www.google.com.hk/");//具体的URL
} public RedirectToRouteResult redirectToRouteResult()
{
return RedirectToAction("Index");
}
5.2一般方法
(1)如下只是给出方法样式,不做具体代码。
//无返回类型
public void functionName(形参)
{
//to add your content
} //有返回类型
public 返回类型 functionName(形参)
{
//to add your content
return 与方法返回类型相匹配的结果;
}
(2)例子
eg:举个自定义返回string的方法
RouteConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing; namespace MVCControllerDemo
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { Controller = "ControllerDemo", action = "Index", id = UrlParameter.Optional }
);
}
}
}
ControllerDemoController.action
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCControllerDemo.Controllers
{
public class ControllerDemoController : Controller
{ public string GeneralFunction()
{
return "自定义一般方法";
}
}
}
测试结果

6 ViewBag、ViewData和TempData概述
6.1 三者在MVC框架里的定义
在MVC框架中,System.Web.Mvc命名空间下的ControllerBase中,对ViewBag、ViewData和TempData三个属性的定义如下
ViewBag
[Dynamic]
public object ViewBag
{
[return: Dynamic]
get
{
Func<ViewDataDictionary> viewDataThunk = null;
if (this._dynamicViewDataDictionary == null)
{
if (viewDataThunk == null)
{
viewDataThunk = () => this.ViewData;
}
this._dynamicViewDataDictionary = new DynamicViewDataDictionary(viewDataThunk);
}
return this._dynamicViewDataDictionary;
}
}
ViewData
public ViewDataDictionary ViewData
{
get
{
if (this._viewDataDictionary == null)
{
this._viewDataDictionary = new ViewDataDictionary();
}
return this._viewDataDictionary;
}
set
{
this._viewDataDictionary = value;
}
}
TempData
public TempDataDictionary TempData
{
get
{
if ((this.ControllerContext != null) && this.ControllerContext.IsChildAction)
{
return this.ControllerContext.ParentActionViewContext.TempData;
}
if (this._tempDataDictionary == null)
{
this._tempDataDictionary = new TempDataDictionary();
}
return this._tempDataDictionary;
}
set
{
this._tempDataDictionary = value;
}
}
6.2 三者比较
(1)ViewData和TempData属性均返回一个具有字典结构的数据容器,即字典类型的key/Value对,ViewBag为Dynamic类型。
三者方法签名为:
public TempDataDictionary TempData { get; set; }
public ViewDataDictionary ViewData { get; set; }
3 public object ViewBag { [return: Dynamic] get; }
(2)TempData存储临时数据,并且设置的变量在被第一次读取后会被移除,即TempData设置的变量只能被读取一次。(why?)
(3)ViewBag和ViewData属性是同一份数据的不同表现形式,二者的不同之处在于前者是一个动态对象,可以为其指定任意属性(动态属性名将作为数据字典的Key)。
(4)三者均是容器,即能存储常量,变量,也能存储集合。
7 ActionResult解说
在ASP.NET MVC框架中,对ActionResult定义如下:
// Generated by .NET Reflector from C:\Users\WJM\documents\visual studio 2013\Projects\DEMOMVC\packages\Microsoft.AspNet.Mvc.5.0.0\lib\net45\System.Web.Mvc.dll
namespace System.Web.Mvc
{
using System; public abstract class ActionResult
{
protected ActionResult()
{
} public abstract void ExecuteResult(ControllerContext context);
}
}
ActionResult是Action运行后的回传型别,但是当Action回传ActionResult的时候,其实并不包含这个ActionResult(例如ViewResult)的运行结果,而是包含运行这个ActionResult时所需的数据,当MvcHandler从Controller取得ActionResult之后才会去运行出ActionResult的结果。在ActionResult抽象类中仅仅定义了一个ExecuteResult()方法。
ASP.NET 定义了以下几种衍生型别。

8 控制器定义
一般地,在定义Controller时,采用两种方式,即实现IController和继承Controller。
8.1 实现IController
RouteConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing; namespace MVCControllerDemo
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { Controller = "ControllerDemo", action = "Index", id = UrlParameter.Optional }
);
}
}
}
RouteDemoController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; using System.Reflection;
namespace MVCControllerDemo.Controllers
{
public class ControllerDemoController : IController
{
public String Index()
{
return "<h1>Index</h1>";
} public void Execute(System.Web.Routing.RequestContext requestContext)
{
string action = requestContext.RouteData.Values["action"].ToString();
Type typ = typeof(ControllerDemoController);
MethodInfo md = typ.GetMethod(action, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (md == null)
{
requestContext.HttpContext.Response.Write("<h1>404</h1>");
}
else
{
string s = md.Invoke(this, null).ToString();
requestContext.HttpContext.Response.Write(s);
}
}
}
}
8.2 继承Controller
这种方法比较常用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCControllerDemo.Controllers
{
public class ControllerDemoController : Controller
{
//
// GET: /ControllerDemo/ [HttpGet]
public ActionResult Index()
{
return View();
}
}
}
9 参考文献
【01】http://www.cnblogs.com/wangiqngpei557/p/3390812.html
【02】http://www.cnblogs.com/yaozhenfa/p/asp_net_mvc_controller.html
【03】http://www.360doc.com/content/12/0611/15/29831_217456312.shtml
【04】http://blog.csdn.net/yw1688/article/details/51280665
【05】Professional Asp.net MVC 5
【06】Professional Asp.net MVC 4
【07】The framework of revelation of Professional Asp.net MVC 5
【08】 https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/controllers-and-routing/aspnet-mvc-controllers-overview-cs
10 版权
- 感谢您的阅读,若有不足之处,欢迎指教,共同学习、共同进步。
- 博主网址:http://www.cnblogs.com/wangjiming/。
- 极少部分文章利用读书、参考、引用、抄袭、复制和粘贴等多种方式整合而成的,大部分为原创。
- 如您喜欢,麻烦推荐一下;如您有新想法,欢迎提出,邮箱:2016177728@qq.com。
- 可以转载该博客,但必须著名博客来源。
详解ASP.NET MVC 控制器的更多相关文章
- 详解ASP.NET MVC的请求生命周期
本文的目的旨在详细描述asp.net mvc请求从开始到结束的每一个过程. 我希望能理解在浏览器输入url并敲击回车来请求一个asp.net mvc网站的页面之后发生的任何事情. 为什么需要关心这些? ...
- 详解ASP.NET MVC应用程序请求生命周期
------转载当一个ASP.NET MVC应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在ASP.NET MVC应用程序Http request 和Http response 过程中, ...
- jquery.uploadify上传文件配置详解(asp.net mvc)
页面源码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...
- 详解Asp.net MVC DropDownLists
Asp.net MVC中的DropDownLists貌似会让一开始从Asp.net Forms转过来的程序员造成不少迷惑.这篇文章讲述了为了使用DropDownLists,你需要在Asp.Net MV ...
- 详解ASP.NET MVC Model验证
ASP.NET mvc的最好的优点之一就是支持Model验证,这个特性很方便你可以选择在定义Model的时候在字段中采用特性进行注解约定,也可以在代码中自己进行手动验证.下面就来细说一下ASP.NET ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 控制器
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射
使用Code First建模自引用关系笔记 原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasR ...
- ASP.NET MVC 控制器激活(一)
ASP.NET MVC 控制器激活(一) 前言 在路由的篇章中讲解了路由的作用,讲着讲着就到了控制器部分了,从本篇开始来讲解MVC中的控制器,控制器是怎么来的?MVC框架对它做了什么?以及前面有的篇幅 ...
随机推荐
- memcache 启动 failed to start
以为是 端口冲突,到注册表中直接改了memcache的注册表,还是启动不了.memcache运行不了,还能咋办,看防火墙有没有阻止程序运行呗 勾上,我的windows 上的memcache 就可以运行 ...
- 从编译器角度理解C++中的引用和指针
欲分析指针和引用,则要分析变量名和地址之间的关系(不管你理解还是不理解,无论你是从老师那里听到的,还是网上看到的,应该都知道两句话:1. 指针就是地址,2.引用就是给变量起个别名) 所以我们就要来分析 ...
- Unity中提升像素字体清晰度
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Unity5.6.0f3 Unity UI系统是非常好的,但默认情况下,使用像像素艺术风格游戏那样需要非常锋利的边框的字体 ...
- 学习笔记TF012:卷积网络简述
ImageNet http://www.image-net.org ,图像标注信息数据库.每年举办大规模视觉识别挑战赛(ILSVRC).基于ImageNet数据库构建完成目标自动检测分类任务系统.20 ...
- 初码-Azure系列-迁移PHP应用至Azure的一些实践记录和思考
最近客户在逐步迁移应用从阿里云到Azure,这次又轮到一个PHP+MySQL应用了,顺便也记一下流水账. 需求:迁移部署在阿里云上的ECS服务器(系列2,IO优化+2核4G+50G的SSD云盘+10M ...
- Linux下Samba服务器的安装和配置
第一步:sudo apt-get install samba smbclient 安装samba服务器. 第二步:打开/etc/samba/smb.conf文件,在末尾添加下面的字段: [用户名] c ...
- MySQL索引和查询优化
对于任何DBMS,索引都是进行优化的最主要的因素.对于少量的数据,没有合适的索引影响不是很大,但是,当随着数据量的增加,性能会急剧下降. 如果对多列进行索引(组合索引),列的顺序非常重要,MySQL仅 ...
- hadoop2.7.2单机与伪分布式安装
环境相关 系统:CentOS 6.8 64位 jdk:1.7.0_79 hadoop:hadoop 2.7.2 安装java环境 详见:linux中搭建java开发环境 创建hadoop用户 # 以r ...
- SQL SERVER大话存储结构(4)_复合索引与包含索引
索引这块从存储结构来分,有2大类,聚集索引和非聚集索引,而非聚集索引在堆表或者在聚集索引表都会对其 键值有所影响,这块可以详细查看本系列第二篇文章:SQL SERVER大话存储结构 ...
- Python爬虫学习(二) ——————爬取前程无忧招聘信息并写入excel
作为一名Pythoner,相信大家对Python的就业前景或多或少会有一些关注.索性我们就写一个爬虫去获取一些我们需要的信息,今天我们要爬取的是前程无忧!说干就干!进入到前程无忧的官网,输入关键字&q ...