在ASP.NET MVC中我们很多时候都会在拦截器和Controller中直接使用Response.Redirect方法做跳转,但是实际上Response.Redirect方法执行后ASP.NET并不会立即结束当前请求的执行,而是要过一段时间才会终止当前请求的执行,然后命令客户端浏览器去访问Response.Redirect方法中传入的新的URL地址。这会导致一个问题,有时候我们希望Response.Redirect方法执行后后面的代码就取消执行了,因为这并不是我们预期的行为,当代码执行了Response.Redirect方法后,如果其后面的部分代码还继续在执行甚至有可能报错。

比如在下面的代码中我们演示了在MVC的IAuthorizationFilter拦截器中,如果用户没有登录应该立刻停止当前页面的请求,然后跳转到登录页面。我们使用了Response.Redirect方法来做跳转。

 public class AuthenticationFilterAttribute:ActionFilterAttribute,IAuthorizationFilter,IActionFilter
{
#region IAuthorizationFilter Members public void OnAuthorization(AuthorizationContext filterContext)
{ string curActionName = filterContext.ActionDescriptor.ActionName;
string curControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; if (!filterContext.HttpContext.Request.IsAuthenticated && (curControllerName.ToLower() != "login" || curActionName.ToLower() != "index"))
{
filterContext.HttpContext.Response.Redirect(LoginHelper.LoginPageUrl, true);
return;
}
} #endregion
}

结果我惊讶的发现即便代码在上面13行Response.Redirect了,ASP.NET还是执行了当前请求URL对应Controller的Action中的代码,甚至执行了Action返回的View的Razor引擎代码。。。虽然最终这个view的内容没有呈现给客户端浏览器,浏览器最后还是正确跳转到了登录页。但是根据调试我们发现即便是我们执行了Response.Redirect方法,ASP.NET之后还是执行了一大堆本不该执行的代码

所以这个时候我们需要用到EmptyResult这个对象,我们将上面的代码改成如下所示:

 public class AuthenticationFilterAttribute:ActionFilterAttribute,IAuthorizationFilter,IActionFilter
{
#region IAuthorizationFilter Members public void OnAuthorization(AuthorizationContext filterContext)
{ string curActionName = filterContext.ActionDescriptor.ActionName;
string curControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; if (!filterContext.HttpContext.Request.IsAuthenticated && (curControllerName.ToLower() != "login" || curActionName.ToLower() != "index"))
{
filterContext.HttpContext.Response.Redirect(LoginHelper.LoginPageUrl, true);
filterContext.Result = new EmptyResult();//加入EmptyResult就告诉ASP.NET MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码
return;
}
} #endregion
}

那么ASP.NET MVC在执行完上面的IAuthorizationFilter拦截器后,就会发现EmptyResult被赋值在了参数filterContext的Result属性上,就会终止执行Controller的Action,立即结束当前请求的执行,不会再去执行多余的代码了。其实filterContext的Result属性只要在IAuthorizationFilter拦截器中被赋值了不为null,就不会执行Controller的Action了,同时在该IAuthorizationFilter拦截器之后注册的其它Filter拦截器也都不会被执行了。

比如在ASP.NET Core MVC(由于在ASP.NET MVC中JsonResult的构造函数不带参数,所以在拦截器中使用JsonResult的意义不大,不如就用EmptyResult)中的IAuthorizationFilter拦截器中,我们也可以选择给context的Result属性赋值为JsonResult:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System; namespace WebApi.Filters
{
public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
{
public AuthorizationFilterAttribute()
{ } public void OnAuthorization(AuthorizationFilterContext context)
{
context.Result = new JsonResult(new { message = "Http请求被AuthorizationFilter拦截" });//加入JsonResult来告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器,此外会通过Http的Response返回一个{"message":"Http请求被AuthorizationFilter拦截"}的Json对象到客户端浏览器
}
}
}

只不过这样会同时返回一个Json对象给客户端浏览器。

在拦截器中,还可以结合设置StatusCode和EmptyResult,来返回特定状态码的Http响应,例如下面我们就展示了如何在IAuthorizationFilter拦截器中,返回401状态的Http响应

using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; namespace WebApi.Filters
{
public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
{
public AuthorizationFilterAttribute()
{ } /// <summary>
/// 设置StatusCode和EmptyResult,返回401状态的Http响应,并发送一段html为Http响应体
/// </summary>
public void OnAuthorization(AuthorizationFilterContext context)
{
context.HttpContext.Response.ContentType = "text/html; charset=utf-8";//设置Http响应类型为text/html,编码为utf-8
context.HttpContext.Response.StatusCode = ;//设置Http响应状态码为401 using (StreamWriter sw = new StreamWriter(context.HttpContext.Response.Body, Encoding.UTF8))
{
sw.Write("<html><head></head><body><h1>Unauthorized!</h1></body></html>");
} context.Result = new EmptyResult();//加入EmptyResult就告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器
} /// <summary>
/// 设置UnauthorizedResult,返回401状态的Http响应
/// </summary>
//public void OnAuthorization(AuthorizationFilterContext context)
//{
// context.Result = new UnauthorizedResult();//加入UnauthorizedResult就告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器,并且返回401状态的Http响应
//}
}
}

所以很多时候我们在ASP.NET中使用Response.Redirect方法时要相当小心,一定要知道Response.Redirect方法执行后并不等于代码就结束执行了,还要考虑到后面的代码一旦被误执行会有什么后果,有什么办法可以避免。在MVC中使用EmptyResult就是个不错的选择。

在MVC里面使用Response.Redirect方法后记得返回EmptyResult的更多相关文章

  1. 重定向语句Response.Redirect()方法与Response.RedirectPermanent()对搜索引擎页面排名的影响

    在ASP.NET中,开发人员经常使用Response.Redirect()方法,用编程的手法,将对老的URL的请求转到新的URL上.但许多开发人员没有意识到的是,Response.Redirect() ...

  2. Server.Transfer方法,Server.Execute方法和Response.Redirect方法有什么异同

    (1)Server.Transfer方法: Server.Transfer("m2.aspx");//页面转向(服务器上执行). 服务器停止解析本页,保存此页转向前的数据后,再使页 ...

  3. 如何解决Response.Redirect方法传递汉字丢失或乱码问题?

    为了确保传递的汉字被正确地接收,可以在传值之前使用Server对象的UrlEncode方法对所传递的汉字进行URL编码.代码如下: String name = Server.UrlEncode(&qu ...

  4. 在类中使用Response.Redirect()方法

    问题来自:"我在app_code 定义了user.cs类:其中作了跳转:Httpcontect.Current.Response.Redirect("/c/index.aspx&q ...

  5. MVC二级联动使用$.ajax方法获取后端返回的字符串

    在"MVC二级联动使用$.getJSON方法"中使用$.getJSON()获取后端返回的JSon. 本篇使用jQuery的$.ajax()获取后端返回的字符串,实现二级联动.   ...

  6. 关于Response.redirect()方法

    1. sendRedirect 后面要加上return.2. sendRedirect 执行过程是先转向还是先执行后续代码再转向?答: 先执行代码再转向,在一个sendRedirect后面不能再有其他 ...

  7. Server编解码 解决Response.Redirect方法传递汉字丢失或乱码

  8. 【#】Spring3 MVC (三)---请求处理方法 参数及返回值总结

    博客分类:  spring MVCJSPServletCC++ @RequestMapping("/xxxx") public String  aaa(){ } 在处理用户请求的方 ...

  9. Response.Redirect 打开新窗体的两种方法

    普通情况下,Response.Redirect 方法是在server端进行转向,因此,除非使用 Response.Write("<script>window.location=' ...

随机推荐

  1. SQL Server 用SQL语句查找某个表的触发器

    select   *   from   sysobjects   where   xtype='TR'   and   parent_obj=object_id('表名') 再用sp_helptext ...

  2. Selenium2学习-013-WebUI自动化实战实例-011-WebElement.getText()值为空问题探索及解决

    今天有个朋友在群里问 WebElement.getText() 值为空,当你发现取到的值为空的时候,会不会郁闷呢?明明看到的值不为空,脚本看着也没有问题啊,为何取到的值为空呢!!!万千纠结啊,若是长时 ...

  3. imx6 framebuffer 分析

    分析imx6 framebuffer设备和驱动的注册过程. Tony Liu, 2016-8-31, Shenzhen 相关文件: arch/arm/mach-mx6/board-mx6q_sabre ...

  4. ORACLE十进制与十六进制的转换

    十进制与十六进制的转换 十进制-->十六进制 select to_char(100,'XX') from dual; 十六进制-->十进制select to_number('7D','XX ...

  5. 30天,O2O速成攻略【8.29杭州站】

    活动概况 时间:2015年8月29日13:30-16:30 地点:123茶楼(杭州上城区青年路27号2楼) 主办:APICloud.UPYUN.一起火 网址:www.apicloud.com 费用:免 ...

  6. 分布式消息系统Kafka初步

    终于可以写kafka的文章了,Mina的相关文章我已经做了索引,在我的博客中置顶了,大家可以方便的找到.从这一篇开始分布式消息系统的入门. 在我们大量使用分布式数据库.分布式计算集群的时候,是否会遇到 ...

  7. 第十篇 Replication:故障排除

    本篇文章是SQL Server Replication系列的第十篇,详细内容请参考原文. 复制故障排除是一项艰巨的任务.在任何复制设置中,都涉及到很多移动部件,而可用的工具并不总是很容易识别问题.Th ...

  8. C#读写BitMap及颜色相乘

    C#读写BitMap及颜色相乘 private Bitmap ReadBitMapAndMultipy(Bitmap bitmap0) { int x1width = bitmap0.Width; i ...

  9. ThinkPHP 自动验证与自动填充无效可能的原因(转)

    自动验证与自动填充是在使用ThinkPHP时经常用到的功能,但偶尔会遇到自动验证与自动填充无效的情况,本文就ThinkPHP 自动验证与自动填充无效可能的原因做一些分析. create() Think ...

  10. iOS -Swift 3.0 -UILabel属性大全

    昨天研究了一下苹果近两年新出的Swift语言,感觉学起来并不是很吃力,毕竟自己有过Objective-C的语言功底,所以各方面的属性控件还是一眼就可以认出的,只是Swift的写法与Objective- ...