在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做的修改都不能被保留,因为执行的是一个新的控制器实例。

转载于:https://www.cnblogs.com/hnsongbiao/p/7453462.html

在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能相关推荐

  1. 在ASP.NET MVC应用程序中随机获取一个字符串

    在开发ASP.NET MVC应用程序时,有可能需要一个随机字符串,作为密码或是验证码等. 如果你需要的是SQL版本,可以参考<密码需要带特殊字符(二)>http://www.cnblogs ...

  2. ASP.NET MVC应用程序展示RDLC报表

    ASP.NET MVC应用程序展示RDLC报表 原文:ASP.NET MVC应用程序展示RDLC报表 学习ASP.NET MVC这样久,在学习,练习与应用过程中,觉得很多知识与以前的ASP.NET多有 ...

  3. 使用mvc模式读取服务器上的文件,关于C#:如何使用asp.net MVC应用程序从服务器上的网络路径读取...

    我已经在运行.net MVC应用程序的Web服务器上设置了到另一台用于存储上载文件的服务器的网络路径.为了允许通过应用程序将文件上传到网络路径,我修改了IIS中的应用程序池,以便该应用程序有权上传到它 ...

  4. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序使用高级功能...

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十二篇:为ASP.NET MVC应用程 ...

  5. 使用asp.net mvc开发应用程序,页面中的page.IsPostback还有用处吗?

    本来我对asp.net mvc也研究了一段时间了,我也使用了asp.net mvc开发了两套应用程序,虽然都不是什么大的系统. 今天也想特别提出一个疑问,不知道是我不知道呢,还是本身很难实现在asp. ...

  6. 超级简单:一步一步教你创建一小型的asp.net mvc 应用程序

    超级简单:一步一步教你创建一小型的asp.net mvc 应用程序 这本教程中将帮助你创建一个小型的asp.net mvc示例. 在本教程中,我们将创建自己的 Model , View 和Contro ...

  7. ASP.NET安全[开发ASP.NET MVC应用程序时值得注意的安全问题](转)

    概述 安全在web领域是一个永远都不会过时的话题,今天我们就来看一看一些在开发ASP.NET MVC应用程序时一些值得我们注意的安全问题.本篇主要包括以下几个内容 : 认证 授权 XSS跨站脚本攻击 ...

  8. 将终结点图添加到你的ASP.NET Core应用程序中

    在本文中,我将展示如何使用DfaGraphWriter服务在ASP.NET Core 3.0应用程序中可视化你的终结点路由.上面文章我向您演示了如何生成一个有向图(如我上篇文章[译]使用DOT语言和G ...

  9. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序处理并发

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十篇:为ASP.NET MVC应用程序 ...

最新文章

  1. Assembly--及相关内容
  2. python把dict转为dataframe,将python OrderedDict转换为datafram
  3. GDCM:Traverse Modules的测试程序
  4. lsof/netstat命令的一个重要作用: 根据进程查端口, 根据端口查进程
  5. .NET Core 2.0应用程序大小减少50%
  6. php while循环次数,php while循环得到循环次数
  7. 个人linux版本管理,浅谈各个Linux版本的个人看法
  8. js获取/设置任意元素中间内容的兼容方法
  9. android 输出字节数组,Android蓝牙通信字节数组的数据类型转换 求教!
  10. echarts r 地图_使用echarts实现省市区地图
  11. 【分形理论、分形维数、多重分形、Matlab程序等整理】
  12. 黑程序员黑的最好的段子是什么?
  13. 代码随想录第四天 leetcode 24、19、206
  14. 电脑鼠标左键按下去没反应怎么办
  15. Java笔试 系列一
  16. 房价整体下降已成定局
  17. JavaSE学习(1)
  18. 照片做视频哪个软件好?简单但好用
  19. 如何参与到GitHub开源项目中
  20. 用win7的NT6引导Ubuntu12.04手动设置方法和错误修复

热门文章

  1. 开滦二中2021高考成绩查询,2021年唐山查询中考成绩
  2. 文件上传漏洞原理/方式/防护
  3. 全球搜索引擎盛会在即 呼叫搜索模式呼之欲出
  4. MongoDB入门(一)——数据库概述
  5. 在Anaconda中实现多版本Python共存
  6. RhinoMock入门(6)——安装结果和约束
  7. 新奇漂亮的Ajax/CSS表格设计汇集
  8. c 语言 二维数组地址,C/C++ 关于一维或二维数组首地址表示含义
  9. Pytho——装饰器五大实例
  10. php分页基于oracle,PHP实现的oracle分页函数实例