在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能
在ASP.NET MVC应用程序中,如果使用Server.Transfer()方法希望将请求转发到其它路径或者Http处理程序进行处理,都会引发“为xxx执行子请求时出错”的HttpException异常。而在最终实现Server.Transfer()操作的方法内部,我看到这样几行代码。
else if (!(handler is Page))
{
error = new HttpException(0x194, string.Empty);
}
很明显,在方法内部,所有的IHttpHandler都将被当作Page类型来处理。如果传入的处理程序不是Page类型则引发异常!即使是你传入的Url或IHttpHandler对应一个物理的ashx文件也不例外。而且这种做法在.NET 4.5框架下也未改变。
我们知道在ASP.NET程序中,除了WebService,所有对Http请求的处理都是从IHttpHandler的ProcessRequest()方法开始的,在MVC模式下也是如此;这样就给我们自已实现类似于Server.Transfer()这样的提供了条件。我们只要得到用于处理新请求的IHttpHandler的实例,并对请求的上下文做适当的修改,这样我们就可以调用ProcessRequest来强制把请求的处理切换到新的IHttpHandler中执行。
在ASP.NET MVC程序中,处理请求的IHttpHandler是从IRouteHandler的GetHttpHandler()方法获取到的;所以为了能从这个方法得到新的处理程序,我们必须创建新的路由请求上下文信息"RequestContext"。
第一步:得到目标请求处理程序所在的路由(Route)实例,创建新的路由数据(RouteData):
得到路由实例的方式有两种,一种是根据路由名称从路由表中获取;一种是根据Url、和路由处理程序,创建新的路由实例。在以上两种方式里,都必须给出明确的路由参数的值,这些值用于决定路由的目标Url。
第一种方式:根据路由名称和值生成路由数据
public void ToRoute(string routeName, object values)
{
//获得路由实例
var route = RouteTable.Routes[routeName];
if (route == null)
throw new Exception(string.Format("路由表中不存在名为 \"{0}\" 的路由", routeName));
//创建路由数据
var routeData = new RouteData(route, new MvcRouteHandler());
//添加路由参数/值
foreach (var pair in new RouteValueDictionary(values))
{
routeData.Values[pair.Key] = pair.Value;
}
Route(routeData);
}
第二种方式:根据给定的URL和值生成路由数据。(在ASP.NET MVC应用程序中,IRouteHandler的实现即是System.Web.Mvc.MvcRouteHandler)
public void ToUrl(string url, object values)
{
//创建路由处理程序实例
var routeHandler = new MvcRouteHandler();
//创建路由数据
var routeData = new RouteData(new Route(url, routeHandler), routeHandler);
//添加路由参数/值
foreach (var pair in new RouteValueDictionary(values))
{
routeData.Values[pair.Key] = pair.Value;
}
Route(routeData);
}
第二步:创建新的路由请求上下文信息(RequestContext),重写内部路径,获取IHttpHandler并调用它的ProcessRequest方法
void Route(RouteData routeData)
{
var requestContext = new RequestContext(Context, routeData); //重写内部请求路径
var newPath = routeData.Route.GetVirtualPath(requestContext, null).VirtualPath;
requestContext.HttpContext.RewritePath(newPath); //获取处理程序,处理请求
IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);
if (handler == null)
throw new Exception("未能从指定路由中获取到 IHttpHandler");
handler.ProcessRequest(HttpContext.Current);
}
完整的实现代码:
using System.Web.Mvc;
using System.Web.Routing; public class RequestRouter
{
readonly HttpContextBase _Context; public HttpContextBase Context
{
get { return this._Context; }
} public RequestRouter(HttpContextBase context)
{
this._Context = context;
} void Route(RouteData routeData)
{
var requestContext = new RequestContext(Context, routeData); //重写内部请求路径
var newPath = routeData.Route.GetVirtualPath(requestContext, null).VirtualPath;
requestContext.HttpContext.RewritePath(newPath); //获取处理程序,处理请求
IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);
if (handler == null)
throw new Exception("未能从指定路由中获取到 IHttpHandler");
handler.ProcessRequest(HttpContext.Current);
} public void ToRoute(string routeName, object values)
{
//获得路由实例
var route = RouteTable.Routes[routeName];
if (route == null)
throw new Exception(string.Format("路由表中不存在名为 \"{0}\" 的路由", routeName));
//创建路由数据
var routeData = new RouteData(route, new MvcRouteHandler());
//添加路由参数/值
foreach (var pair in new RouteValueDictionary(values))
{
routeData.Values[pair.Key] = pair.Value;
}
Route(routeData);
} public void ToUrl(string url, object values)
{
//创建路由处理程序实例
var routeHandler = new MvcRouteHandler();
//创建路由数据
var routeData = new RouteData(new Route(url, routeHandler), routeHandler);
//添加路由参数/值
foreach (var pair in new RouteValueDictionary(values))
{
routeData.Values[pair.Key] = pair.Value;
}
Route(routeData);
}
}
第三步:在控制器的Action中转发请求
public ActionResult Index()
{
var routeRequest = new RequestRouter(HttpContext);
routeRequest.ToRoute("Default", new { controller = "Home", action = "About" });
return new EmptyResult();
}
这样一来,请求上面的控制器中的Index操作方法之后,请求被转发到 Home 控制器的 About 操作方法,而且所有请求相关的数据(Forms,QueryStrings)都被保留了下来。不过,在转发请求的Action中对ViewData和ViewBag做的修改都不能被保留,因为执行的是一个新的控制器实例。
在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能的更多相关文章
- 在ASP.NET MVC应用程序中随机获取一个字符串
在开发ASP.NET MVC应用程序时,有可能需要一个随机字符串,作为密码或是验证码等. 如果你需要的是SQL版本,可以参考<密码需要带特殊字符(二)>http://www.cnblogs ...
- 连接弹性和命令拦截的 ASP.NET MVC 应用程序中的实体框架
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 上篇博客我们学习了EF 之 MVC 排序,查询,分 ...
- ASP.NET MVC应用程序中支持用户使用腾讯QQ和微信以及新浪微博的第三方登录
什么是第三方授权登录,就是一些大家都会有的帐号如QQ.微信.淘宝.微博等账户.通过那些巨头公司提供的api直接实现登录. 当然,我们是不可能得到你的用户名和密码的.不了解的人,可能会存在这个疑虑.我们 ...
- 使用区域组织 ASP.NET MVC 应用程序
MVC 模式可将应用程序的模型(数据)逻辑与其呈现逻辑和业务逻辑分离. 在 ASP.NET MVC 中,这种逻辑分离还在项目结构中以物理方式实现,在该项目结构中,控制器和视图保存在使用命名约定定义关系 ...
- ASP.NET MVC应用程序展示RDLC报表
原文:ASP.NET MVC应用程序展示RDLC报表 学习ASP.NET MVC这样久,在学习,练习与应用过程中,觉得很多知识与以前的ASP.NET多有区别,但是实现操作起来,细处又有许多相近的地方. ...
- 为ASP.NET MVC应用程序使用高级功能
为ASP.NET MVC应用程序使用高级功能 这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译, ...
- ASP.NET MVC开发学习过程中遇到的细节问题以及注意事项
1.datagrid中JS函数传值问题: columns: { field: 'TypeName', title: '分类名称', width: 120, sortable: true, format ...
- 在MVC应用程序中,怎样删除上传的文件
在ASP.NET MVC应用程序中,怎样删除上传的文件. 由于上传时,真正文件是存储在应用程序某一目录,在数据库表中,只是存储其基本信息.在删除时,需要注意一下,由于没有事务可操作.Insus.NET ...
- ASP.NET Core MVC应用程序中的后台工作任务
在应用程序的内存中缓存常见数据(如查找)可以显着提高您的MVC Web应用程序性能和响应时间.当然,这些数据必须定期刷新. 当然你可以使用任何方法来更新数据,例如Redis中就提供了设定缓存对象的生命 ...
随机推荐
- 使用OLEDB读取excel和csv文件
这是我第一次在博客上写东西,简单的为大家分享一个oledb读取文件的功能吧,这两天在做一个文件导入数据库的小demo,就想着导入前先在页面上展示一下,之前调用Microsoft.Office.Inte ...
- 关于java中普通代码块、构造代码块与静态代码块
1.普通代码块 public static void main(String[] args) { /*普通代码块: *直接定义在在方法或语句中出现”{普通代码的执行语句}“的就称为普通代码块. *普通 ...
- Android Bitmap那些事之如何优化内存
前言:”安得广厦千万间,大庇天下寒士俱欢颜“——杜甫.在帝都住的朋友们都可能会遇到租房子困难的问题(土豪请无视),找房子真是力气活,还耗费时间,占用我宝贵的写博客时间,没办法,谁让咱没钱还想住的好点, ...
- 济南学习 Day 4 T1 am
完美的序列(sequence)Time Limit:1000ms Memory Limit:64MB题目描述LYK 认为一个完美的序列要满足这样的条件:对于任意两个位置上的数都不相同.然而并不是所有的 ...
- OpenGL第15,16,17讲小结
这三讲没有什么特别的感觉,15讲把纹理贴到3D字体上,16讲讲了雾的生成,17讲是通过以事先保存好的纹理贴图的字体来显示2D文字,这样子不用调用windows的字体,而是使用纹理中的字体.这样也在一定 ...
- bzoj 1009:[HNOI2008]GT考试
这道题机房n多人好久之前就A了…… 我到现在才做出来…… 一看就是DP+矩阵乘法,但是一开始递推式推错了…… 正确的递推式应该是二维的…… f[i][j] 表示第准考证到第 i 位匹配了 j 位的方案 ...
- mysql快速上手3
上一章给大家说的是数据库的视图,存储过程等等操作,这章主要讲索引,以及索引注意事项,如果想看前面的文章,url如下: mysql快速上手1 mysql快速上手2 索引简介 索引是对数据库表中一个或多个 ...
- 把url后面的.html去掉
$url = "http://haichuang1997.bmlink.com/supply/dc_355472.html";echo rtrim($url, '.html');
- jquery.validate.js
jquery.validate.js使用记录 首先到JQ官网下载搜索validate插件,下载相关源码,附上validate官网网址 https://jqueryvalidation.org/ 找到v ...
- Jquery Slick幻灯片插件
slick 是一个基于 jQuery 的幻灯片插件,具有以下特点: 支持响应式 浏览器支持 CSS3 时,则使用 CSS3 过度/动画 支持移动设备滑动 支持桌面浏览器鼠标拖动 支持循环 支持左右控制 ...