详解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框架对它做了什么?以及前面有的篇幅 ...
随机推荐
- MVC中的Ajax与增删改查
自入手新项目以来,一直处于加班状态,博客也有两周没更,刚刚完成项目的两个模组,稍有喘息之机,写写关于项目中 的增删改查,这算是一个老生常谈的问题了,就连基本的教材书上都有.刚看书的时候,以为 没什么可 ...
- Visual Studio Package 插件开发之自动生成实体工具
前言 这一篇是VS插件基于Visual Studio SDK扩展开发的,可能有些朋友看到[生成实体]心里可能会暗想,T4模板都可以做了.动软不是已经做了么.不就是读库保存文件到指定路径么…… 我希望做 ...
- 省市联动_简单的Demo,适用于各种二级菜单联动
最近搞了一个功能,是查询页面需要用到二级菜单联动,获取到选中的属性value传入到后台. 平常都是用AJAX或者JQuery ,通过XML或者JSON的方式,这样的话需要调用数据库,像典型得到省市联动 ...
- java 上传2(使用java组件fileupload和uploadify)
项目关键包和插件
- 前端技术API手册(2) -- CSS API 的实现
微信小程序 jQuery每日经典 第二阶段已经发布,截至目前收录的技术有jQuery和CSS.其他技术正在不断的填充完善中. CSS技术手册实现的方法: 资料来源 所有的CSS资料均参考自网址:htt ...
- docker安装与学习
docker学习 以ubuntu为实例 第一步检查系统内核>3.80 第二步 安装Docker 之前先更新apt-get update 在执行安装命令 apt-get install -y do ...
- 一步一步实现android studio代码上传到github。
本文只注重代码上传能成功就好,不解释什么是git什么事github,git有什么优势. 1,先创建一个android应用, 第二步:创建github账户 和 安装git.网上的文章多如牛毛.唯一要说的 ...
- 设计模式一:关于C++写观察者模式的一些收获
先贴上部分代码: #include "stdafx.h" #include<iostream> #include<string> #include<v ...
- docker - win7下构建swarm nodes实现跨host的容器之间的通信
前言 之前在Linux环境下尝试了swarm,通过将不同host以swarm nodes 的方式连接到一起(构建Overlay 子网),从而实现跨host的container通信. 今天我们就来说说如 ...
- Python3.6_x86通过FFpmeg获取视频或音频的时长和分辨率
前言 前段时间公司在做流媒体服务,与许多厂家合作拿了许多视频过来,现在要对这些视频文件进行整理,通过特殊的编码排列,获取他们的时长以及分辨率,这里我遇到一个大坑,请往下面看. # -*- coding ...