在ASP.NET MVC應用程式中實現Server.Transfer()類似的功能

來源:互聯網
上載者:User

標籤:存在   參數   建立   value   nbsp   dex   this   return   中轉   

在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()類似的功能

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.