控制器、过滤器和路由


一、控制器

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
    


    
  • 001
  • 002
  • 003
  • 004
  • 005
  • 006

【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" >
    // 
    return View();
}


    
    Demo04Login
    


    
用户登录
用户名:
密码:
@TempData["ErrInfo"]

配置文件的配置:(在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
    


    
用户登录
用户名:
密码:
@TempData["ErrInfo"]

响应登录请求的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


    

账号:

密码:

@ViewBag.ErrInfo

退出的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
mvc