控制器、过滤器和路由
一、控制器
ActionResult概述:
(1)在ASP.NET MVC中,一个控制器可以包含多个操作方法。 每一个操作方法都返回一个ActionResult实例对象。
(2)nActionResult是一个抽象的基类,其最常用的派生类如下:
| ActionResult派生类型 | 作用 |
|---|---|
| ViewResult | 用于返回标准的视图页面 |
| EmptyResult | 不返回任何数据 |
| ContentResult | 以字符串的形式指定响应的内容 |
| FileResult | 返回任意文档内容 |
| JavaScriptResult | 响应一段JavaScript脚本内容 |
| JsonResult | 返回一段Json内容 |
(1)ViewResult
ViewResult:用户返回标准的视图页面。
视图模型类:
public class Student
{
public string StuId { get; set; }
public string StuName { get; set; }
}
Action:
public ActionResult Test()
{
Student stu = new Student();
stu.StuId = "001";
stu.StuName = "刘备";
return View(stu);
}
View:
@model WebApplication2.Controllers.Student
@{
Layout = null;
}
Test
学号: @Model.StuId
姓名: @Model.StuName
(2)EmptyResult
EmptyResult:不返回任何数据。
Action:
//此Action即使有对应的视图,也不会显示视图内容,显示空页面
public ActionResult Test()
{
return new EmptyResult();
}
(3)ContentResult
ContentResult:以字符串的形式指定响应的内容。
Action:
public ActionResult Test()
{
return Content("我是ContentResult返回的标题标签!
","text/html");
}
利用ContentResult制作多页面风格切换:
【样式表文件如下】:
spring.css
/*春天风格*/
body {
background-image:url(/Img/spring.jpg);
background-repeat:no-repeat;
background-size:cover;
}
summer.css
/*夏天风格*/
body {
background-image:url(/Img/summer.jpg);
background-repeat:no-repeat;
background-size:cover;
}
autumn.css
/*秋天风格*/
body {
background-image:url(/Img/autumn.jpg);
background-repeat:no-repeat;
background-size:cover;
}
winter.css
/*冬天风格*/
body {
background-image:url(/Img/winter.jpg);
background-repeat:no-repeat;
background-size:cover;
}
【Action:】
#region 使用ContentResult制作多页面风格切换
public ActionResult Demo01()
{
return View();
}
[HttpPost]
public ActionResult Demo01(string themesName)
{
HttpCookie c = new HttpCookie("theme", themesName);
c.Expires = DateTime.MaxValue;
Response.SetCookie(c);
//return View();
//此处Response.SetCookie等页面刷新完了之后才进行设置cooike,必须让页面重新刷新一次
//下列的脚本让页面重新刷新到Demo01
return Content("", "text/html");
}
public ActionResult Demo01TestPage(string themesName)
{
return View();
}
public ActionResult CssResult()
{
string cssFileName = "";
if (Request.Cookies["theme"] == null || Request.Cookies["theme"].Value.Equals(""))
cssFileName = "spring.css";
else
cssFileName = Request.Cookies["theme"].Value + ".css";
return Content(cssFileName, "text/html");
}
#endregion
【View:】
Demo01
风格切换
跳转到其它页面测试风格
Demo01TestPage
风格切换测试页面
(4)FileResult
【1】使用FileResult加载图片:
Action:
public ActionResult Demo02()
{
return View();
}
public ActionResult GetImg(string id)
{
string path = Server.MapPath("~/Img/" + id + ".png");
return File(path, "image/png");
}
View:
Demo02
-
-
-
-
-
-
【2】使用FileResult实现文件下载:
Action:
public ActionResult Demo03()
{
return View();
}
public ActionResult GetFile()
{
//如需对下载文件进行权限判断
//1-将文件迁移至Web服务以外的路径(也可以是单独文件服务器)。
//2-在下载之前进行权限的逻辑判断。
string path = Server.MapPath("~/File/ASP.NET MVC 5高级编程.rar");
return File(path, "application/octet-stream", "ASP.NET MVC 5高级编程.rar");
}
View:
Demo03
学习资料下载
ASP.NET MVC 5高级编程
(5)JavaScriptResult
JavaScriptResult:用于响应一段JavaScript脚本内容
Action:
public ActionResult Test()
{
return View();
}
public ActionResult JsResult()
{
return JavaScript("alert('hello,world!');");
}
View:
Test
JavaScriptResult的使用!
(6)JsonResult
JsonResult:用于返回Json内容。
模型实体类:
public class Student
{
public Student() { }
public Student(string id,string name,string sex)
{
this.StuId = id; this.StuName = name; this.StuSex = sex;
}
public string StuId { get; set; }
public string StuName { get; set; }
public string StuSex { get; set; }
}
Action:
public ActionResult Test()
{
return View();
}
public ActionResult JsonResult()
{
List list = new List();
list.Add(new Student("001", "刘备", "男"));
list.Add(new Student("002", "关羽", "男"));
list.Add(new Student("003", "张飞", "男"));
return Json(list);
}
View:
Test
学号
姓名
性别
二、过滤器
通常控制器的操作方法在执行前后,需要处理运行过程中所产生的状况,为了满足此要求,ASP.NET MVC提供过滤器来处理。
支持的过滤器类型有四种,分别是:Authorization(授权),Action(行为),Result(结果)和Exception(异常)。
| 过滤器类型 | 接口 | 继承类 | 描述 |
|---|---|---|---|
| Authorization | IAuthorizationFilter | AuthorizeAttribute | 此类型(或过滤器)用于限制执行控制器或控制器的某个操作方法 |
| Exception | IExceptionFilter | HandleErrorAttribute | 用于指定一个操作,用于处理控制器中抛出的异常 |
| Action | IActionFilter | ActionFilterAttribute | 用于执行操作之前或之后的处理 |
| Result | IResultFilter | ActionFilterAttribute | 用于返回结果的之前或之后的处理 |
(1)授权过滤器
Authorize:授权过滤器是最先运行的过滤器,可以用于对操作方法在正式运行前做一些额外的判断,例如,授权检查、是否为SSL完全链接、验证输入信息是否包含攻击字符串等。
示例1:使用Authorize过滤器实现页面的访问授权
用户登录授权之后才能访问的Action和View:
[Authorize]
public ActionResult Demo04()
{
return View();
}
Demo04
我是授权过滤器的测试页面,未登录情况无法访问,登录之后才能访问!
退出
用户登录页面的Action和View:
public ActionResult Demo04Login()
{
//需要在根目录的web.config文件中做默认登录验证页面的设置
//< authentication mode = "Forms" >
// < forms loginUrl = "~/Home/Demo04LoginForm/" timeout = "2000" > forms >
// authentication >
return View();
}
Demo04Login
配置文件的配置:(在system.web节点中进行配置)
响应登录请求的Action:
[HttpPost]
public ActionResult Demo04Login(string txtAccount,string txtPwd)
{
//假设用户名 admin,密码 admin 才能登录成功,其它登录失败
string acc = txtAccount;
string pwd = txtPwd;
if (acc.Equals("admin") && pwd.Equals("admin"))
{
//第二个参数,true:持久化cookie,false:会话性cookie(即关闭浏览器后消失)
FormsAuthentication.SetAuthCookie(acc, false);
//return RedirectToAction("Demo04");
//此处如果需要优化,跳转到成功登录前的最后历史记录的地址
if (Request.QueryString["ReturnUrl"] == null)
{
return RedirectToAction("Demo04");
}
else
{
return Redirect("~/" + Request.QueryString["ReturnUrl"]);
}
}
else
{
TempData["ErrInfo"] = "用户名或密码错误"; //TempData可以在跳转后保存接受数据,但只会在一次跳转中保存。
return View();
}
}
退出登录的Action:
public ActionResult Demo04LoginOut()
{
FormsAuthentication.SignOut();
return Redirect("Demo04Login");
}
示例2:垃圾话过滤
自己编写一个过滤器实现垃圾话判断:
namespace Chp09_Action_过滤器_路由.Filters
{
public class MyAuthorizeAttribute: AuthorizeAttribute
{
//授权的逻辑处理
public override void OnAuthorization(AuthorizationContext filterContext)
{
//直接跳转到警告页面
for (int i = 0; i < filterContext.HttpContext.Request.Form.Count; i++)
{
if (filterContext.HttpContext.Request.Form[i].ToString().Contains("垃圾"))
{
filterContext.Result = new RedirectResult("~/Home/Demo05WarningForm");
return;
}
}
}
}
}
留言板页面Action和View:
public ActionResult Demo05CommentForm()
{
return View();
}
处理留言提交数据的Action和View:
//我们不一定要用MVC默认的Authorize授权验证规则,规则可以自己来定,
//自定义授权过滤器可以继承AuthorizeAttribute这个类,这个类里面有两个重要函数可以重写
// bool AuthorizeCore(HttpContextBase httpContext):这里主要是授权验证的逻辑处理,返回true的则是通过授权,返回了false则不是。
// void HandleUnauthorizedRequest(AuthorizationContext filterContext):这个方法是处理授权失败的事情。
[MyAuthorizeAttribute]
//此示例运行Demo05CommentForm进行测试
public ActionResult Demo05()
{
ViewBag.Info = Request["MyWord"].Replace("\r", "
").Replace("\n", "
").Replace("\r\n", "
");
return View();
}
Demo05
留言内容:
@Html.Raw(ViewBag.Info)
警告信息显示的Action和View:
public ActionResult Demo05WarningForm()
{
return View();
}
Demo05WarningForm
您的留言内容不符合互联网文明规范
警告:如发现您多次违规,将对您进行封号处理!
(2)行为过滤器
ActionFilterAttribute是Action过滤类,该属于会在执行一个action之前先执行.而ActionFilterAttribute是 MVC的一个专门处理action过滤的类。
示例一:行为过滤器实现页面访问授权
自己编写一个过滤器实现页面访问授权:
namespace Chp09_Action_过滤器_路由.Filters
{
public class MyActionFilter : ActionFilterAttribute
{
public string LoginOutUrl { get; set; }
//当请求执行的时候
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session["Account"] == null)
{
string url = filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(this.LoginOutUrl+ "?ReturnUrl="+url);
return;
}
}
}
}
用户登录授权之后才能访问的Action和View:
[MyActionFilter(LoginOutUrl = "/Home/Demo06Login", Order = 1)]
public ActionResult Demo06()
{
return View();
}
Demo06
欢迎来到**系统,当前用户:@Session["Account"]
退出系统
用户登录页面的Action和View:
public ActionResult Demo06Login()
{
return View();
}
Demo06Login
响应登录请求的Action:
[HttpPost]
public ActionResult Demo06Login(string txtAccount, string txtPwd)
{
//假设用户名 admin,密码 admin 才能登录成功,其它登录失败
string acc = txtAccount;
string pwd = txtPwd;
if (acc.Equals("admin") && pwd.Equals("admin"))
{
Session["Account"] = acc;
if (Request.QueryString["ReturnUrl"] == null)
{
return RedirectToAction("Demo06");
}
else
{
return Redirect("~/" + Request.QueryString["ReturnUrl"]);
}
}
else
{
TempData["ErrInfo"] = "用户名或密码错误"; //TempData可以在跳转后保存接受数据,但只会在一次跳转中保存。
return View();
}
}
退出登录的Action:
public ActionResult Demo06OutForm()
{
Session.Abandon();
return RedirectToAction("Demo06Login");
}
示例二:行为过滤器实现权限判断
此案例单独执行的时候必须登录成功才能测试其权限,如果没有登录,直接打开需要权限的页面会报错,解决此报错可以和验证是否登录的过滤器结合使用。
用户信息模型实体类:
public class Member
{
public string Acc { get; set; }
public string Pwd { get; set; }
public string Power { get; set; }
public Member() { }
public Member(string acc, string pwd, string power)
{
this.Acc = acc; this.Pwd = pwd; this.Power = power;
}
}
自己编写一个过滤器实现权限判断:
public class PowerFilter: ActionFilterAttribute
{
public string PowerOutUrl { get; set; } //没有权限跳转的地址
public string PowerName { get; set; } //当前Action的权限编号
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string[] arrPower = filterContext.HttpContext.Session["Power"].ToString().Split(',');
if (!arrPower.Contains(this.PowerName))
{
filterContext.Result = new RedirectResult(this.PowerOutUrl);
return;
}
}
}
需要权限才能访问的Action:
// 具有001权限可以进入的Action
[PowerFilter(Order =1,PowerName ="001",PowerOutUrl = "PowerOut")]
public ActionResult Demo01()
{
return View();
}
//具有002权限可以进入的Action
[PowerFilter(Order = 1, PowerName = "002", PowerOutUrl = "PowerOut")]
public ActionResult Demo02()
{
return View();
}
具有权限才能访问的View:
Demo01
我是具有001权限的人可以进入的页面!
退出
Demo02
我是具有002权限的人可以进入的页面!
退出
登录相关的Action:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(string Acc, string Pwd)
{
List listMem = new List();
listMem.Add(new Member("admin", "admin", "001,002"));
listMem.Add(new Member("liubei", "123456", "001"));
var result = listMem.SingleOrDefault(p => p.Acc.Equals(Acc) && p.Pwd.Equals(Pwd));
if (result != null)
{
Session["Acc"] = result.Acc;
Session["Power"] = result.Power;
return RedirectToAction("Demo01");
}
else
{
ViewBag.ErrInfo = "用户名或密码错误!";
return View();
}
}
登录页面View:
Login
退出的Action:
public ActionResult LoginOut()
{
Session.Abandon();
return RedirectToAction("Login");
}
判断没有权限之后跳转的Action和View:
public ActionResult PowerOut()
{
return View();
}
PowerOut
对不起,您没有此权限!
(3)异常过滤器
在asp.net mvc中除了使用try...catch/finally来处理异常外,它提供了HandleErrorAttribute类,通过在Controller或者Action上添加特性的方式来处理异常。
示例:编写通用的异常处理操作
自己编写处理异常的过滤器:
namespace Chp09_Action_过滤器_路由.Filters
{
public class MyExceptionFilter : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.Result = new RedirectResult("/Home/Demo07ErrorForm?Message=" + filterContext.Exception.Message.Replace("\r\n", "").Replace("\r", "").Replace("\n", ""));
filterContext.ExceptionHandled = true;
return;
}
}
}
异常信息显示的Action和View:
public ActionResult Demo07ErrorForm()
{
ViewBag.Message = Request["Message"];
return View();
}
Demo07ErrorForm
不好意思,程序产生异常了,请尽快与本公司进行联系,异常信息如下:
@ViewBag.Message
编写异常的Action和View来测试过滤器:
[MyExceptionFilter]
public ActionResult Demo07()
{
int a = 10;
int b = 0;
int c = a / b;
return View();
}
Demo07
测试异常过滤器
三、路由
路由用于设计访问的URL地址。
(1)默认路由
.NET MVC默认路由如下(App_Start/RouteConfig.cs):
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
解释:
name:路由的名称;
url:路由URL的格式形式;
defaults:对URL格式进行默认值等的设置;
id = UrlParameter.Optional:代表id为可选参数;
访问规则一:
假设有HomeController控制器,控制器里面有Index操作方法:
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
那么如下地址都是可以访问到此Action的:
http://localhost:65447/
http://localhost:65447/Home
http://localhost:65447/Home/Index
http://localhost:65447/Home/Index/100 --此地址虽然可以访问,但是在控制器里无法接受最后的id=100
访问规则二:
假设有HomeController控制器,控制器里面有Index操作方法:
public class HomeController : Controller
{
// GET: Home
public ActionResult Index(int? id)
{
ViewBag.Id = id;
return View();
}
}
那么如下地址都是可以访问到此Action的:
http://localhost:65447/
http://localhost:65447/Home
http://localhost:65447/Home/Index
http://localhost:65447/Home/Index/100 --此情况下Action可以接受到id=100的参数
(2)路由冲突
路由代码如下:
routes.MapRoute(
name: "Test",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Demo01", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
假设有HomeController控制器,有如下控制器:
public ActionResult Index()
{
return View();
}
public ActionResult Demo01()
{
return View();
}
那么如下的Action的访问如下:
http://localhost:65447/ --访问Demo01
http://localhost:65447/Home --访问Demo01
http://localhost:65447/Home/Index --访问Index
(3)自定义路由规则
案例一:
路由定义如下:
routes.MapRoute(
name: "News",
url: "{controller}/{action}/{year}-{month}-{day}",
defaults: new { controller = "Home", action = "News", id = UrlParameter.Optional }
);
假设有HomeController控制器,如下Action:
public ActionResult Demo02(int year, int month, int day)
{
ViewBag.News = "新闻:" + year + "-" + month + "-" + day;
return View();
}
那么可以通过如下地址访问此Action:
http://localhost:50477/Home/Demo02/2002-8-9
案例二:
路由定义如下:
routes.MapRoute(
name: "News",
url: "{controller}/{action}/{year}/{month}/{day}",
defaults: new { controller = "Home", action = "News", id = UrlParameter.Optional }
);
如下Action:
public ActionResult Demo02(int year, int month, int day)
{
ViewBag.News = "新闻:" + year + "-" + month + "-" + day;
return View();
}
那么可以通过如下地址访问此Action:
http://localhost:50477/Home/Demo02/2002/8/9
案例三:
路由定义如下:
routes.MapRoute(
name: "Admin",
url: "Admin/{action}/{id}",
defaults: new { controller = "Manage", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
假设有ManageController控制器,有如下Action:
public ActionResult Index()
{
return View();
}
那么可以通过如下地址访问此Action:
http://localhost:50477/Manage/Index
http://localhost:50477/Admin
http://localhost:50477/Admin/Index