Alternative to Server.Transfer in ASP.NET Core

前端 未结 3 975
我在风中等你
我在风中等你 2020-12-31 16:14

I am migrating an ASP.NET application to ASP.NET Core and they have some calls to HttpServerUtility.Transfer(string path). However, HttpServerUtility does not

相关标签:
3条回答
  • 2020-12-31 16:45

    I believe you are looking for a "named view" return in MVC. Like so,

    [HttpPost]
    public ActionResult Index(string Name)
    {
     ViewBag.Message = "Some message";
     //Like Server.Transfer() in Asp.Net WebForm
     return View("MyIndex");
    }
    

    The above will return that particular view. If you have a condition that governs the view details you can do that too.

    0 讨论(0)
  • 2020-12-31 16:55

    You are correct. Server.Transfer and Server.Redirect are quite different. Server.Transfer executes a new page and returns it's results to the browser but does not inform the browser that it returned a different page. So in such a case the browser url will show the original url requested but the contents will come from some other page. This is quite different than doing a Server.Redirect which will instruct the browser to request the new page. In such a case the url displayed in the browser will change to show the new url.

    To do the equivalent of a Server.Transfer in Asp.Net Core, you need to update the Request.Path and Request.QueryString properties to point to the url you want to transfer to and you need to instantiate the controller that handles that url and call it's action method. I have provided full code below to illustrate this.

    page1.html

     <html>
        <body>
            <h1>Page 1</h1>
        </body>
    </html>
    

    page2.html

     <html>
        <body>
            <h1>Page 2</h1>
        </body>
    </html>
    

    ExampleTransferController.cs

        using Microsoft.AspNetCore.Diagnostics;
        using Microsoft.AspNetCore.Http;
        using Microsoft.AspNetCore.Mvc;
    
        namespace App.Web.Controllers {
    
            public class ExampleTransferController: Controller {
    
                public ExampleTransferController() {
    
                }
    
                [Route("/example-transfer/page1")]
                public IActionResult Page1() {
                    bool condition = true;
    
                    if(condition) {
    
                        //Store the original url in the HttpContext items
                        //so that it's available to the app.
                        string originalUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}{HttpContext.Request.QueryString}";
                        HttpContext.Items.Add("OriginalUrl", originalUrl);
    
                        //Modify the request to indicate the url we want to transfer to
                        string newPath = "/example-transfer/page2";
                        string newQueryString = "";
                        HttpContext.Request.Path = newPath;
                        HttpContext.Request.QueryString = new QueryString(newQueryString);
    
                        //Now call the action method for that new url
                        //Note that instantiating the controller for the new action method
                        //isn't necessary if the action method is on the same controller as 
                        //the action method for the original request but
                        //I do it here just for illustration since often the action method you
                        //may want to call will be on a different controller.
                        var controller = new ExampleTransferController();
                        controller.ControllerContext = new ControllerContext(this.ControllerContext);
                        return controller.Page2();
                    }
    
                    return View();
                }
    
    
                [Route("/example-transfer/page2")]
                public IActionResult Page2() {
    
                    string originalUrl = HttpContext.Items["OriginalUrl"] as string;
                    bool requestWasTransfered = (originalUrl != null);
    
                    return View();
                }
    
            }
        }
    

    Placing the original url in HttpContext.Items["OriginalUrl"] isn't strictly necessary but doing so makes it easy for the end page to know if it's responding to a transfer and if so what the original url was.

    0 讨论(0)
  • 2020-12-31 17:03

    I see some options for you, depending on your case:

    • Returning another View: So just the HTML. See answer of Muqeet Khan
    • Returning another method of the same controller: This allows also the execution of the business logic of the other action. Just write something like return MyOtherAction("foo", "bar").
    • Returning an action of another controller: See the answer of Ron C. I am a bit in troubles with this solution since it omits the whole middleware which contains like 90% of the logic of ASP.NET Core (like security, cookies, compression, ...).
    • Routing style middleware: Adding a middleware similar to what routing does. In this case your decision logic needs to be evaluated there.
    • Late re-running of the middleware stack: You essentially need to re-run a big part of the stack. I believe it is possible, but have not seen a solution yet. I have seen a presentation of Damian Edwards (PM for ASP.NET Core) where he hosted ASP.NET Core without Kestrel/TCPIP usage just for rendering HTML locally in a browser. That you could do. But that is a lot of overload.

    A word of advice: Transfer is dead ;). Differences like that is the reason for ASP.NET Core existence and performance improvements. That is bad for migration but good for the overall platform.

    0 讨论(0)
提交回复
热议问题