ASP.NET Core 中 Server.Transfer 的替代方案

Posted

技术标签:

【中文标题】ASP.NET Core 中 Server.Transfer 的替代方案【英文标题】:Alternative to Server.Transfer in ASP.NET Core 【发布时间】:2017-02-03 05:16:03 【问题描述】:

我正在将一个 ASP.NET 应用程序迁移到 ASP.NET Core,他们对HttpServerUtility.Transfer(string path) 进行了一些调用。但是,HttpServerUtility 在 ASP.NET Core 中不存在。

我可以使用其他替代方法吗?或者Response.Redirect 是我唯一的选择吗?

我想尽可能保持与旧应用程序相同的行为,因为Server.Transfer and Response.Redirect 之间存在差异。

【问题讨论】:

Redirecting in asp.net 5的可能重复 我会收集所有参数,然后执行RedirectRedirectToAction,如图所示on this answer @GerardoGrignoli 我想保持相同的行为。也就是说,在服务器端执行更改,这样客户端就不必做任何工作并且知道它们已被重定向到另一个页面。 Server.Transfer vs Response.Redirect 我很震惊您发现@Thomas 的答案比我的更有用。他没有提供任何工作代码,也没有提供比我运行更多管道的理论解决方案。我是唯一一个真正为您提供在由不同控制器处理的视图上运行操作方法的代码的人,这项工作花了我大约 2.5 小时为您提供。为什么你给他+50而不是我? 【参考方案1】:

我相信您正在寻找 MVC 中的“命名视图”返回。像这样,

[HttpPost]
public ActionResult Index(string Name)

 ViewBag.Message = "Some message";
 //Like Server.Transfer() in Asp.Net WebForm
 return View("MyIndex");

以上将返回该特定视图。如果您有一个管理视图详细信息的条件,您也可以这样做。

【讨论】:

【参考方案2】:

你是对的。 Server.Transfer 和 Server.Redirect 完全不同。 Server.Transfer 执行一个新页面并将其结果返回给浏览器,但不会通知浏览器它返回了不同的页面。因此在这种情况下,浏览器 url 将显示请求的原始 url,但内容将来自其他页面。这与执行 Server.Redirect 完全不同,后者将指示浏览器请求新页面。在这种情况下,浏览器中显示的 url 将更改为显示新的 url。

要在 Asp.Net Core 中执行 Server.Transfer 的等效操作,您需要更新 Request.PathRequest.QueryString 属性以指向要传输到的 url,并且您需要实例化处理该网址并将其称为操作方法。我在下面提供了完整的代码来说明这一点。

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.HostHttpContext.Request.PathHttpContext.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();
            

        
    

将原始 url 放置在 HttpContext.Items["OriginalUrl"] 中并不是绝对必要的,但这样做可以让结束页面轻松了解它是否正在响应传输以及原始 url 是什么。

【讨论】:

这仅适用于 MVC 代码(运行控制器/视图)。但是所有的中间件管道都不会被执行,所以不如Server.Transfer @J.Lennon Server.Transfer 也不会重新执行完整的管道。我只是亲自检查过,我的 HttpModules 从未被召回新页面。 没错,管道(旧asp.net中的http模块)不会再次执行。您的方法的问题在于您直接调用类方法,而忽略了控制器可能具有的属性、过滤器或任何类型的行为。 @J.Lennon 同意。但到目前为止,这是任何人都想出的最好方法(当然值得一票):-) @RonC 您的示例从控制器返回另一个视图。如果我需要返回另一个网页(在本地主机中运行的不同站点)怎么办。我如何做到这一点?【参考方案3】:

根据您的情况,我看到了一些适合您的选项:

返回另一个视图:所以只是 HTML。查看 Muqeet Khan 的回答 返回同一控制器的另一个方法:这也允许执行另一个操作的业务逻辑。写return MyOtherAction("foo", "bar")之类的东西就行了。 返回另一个控制器的动作:请参阅 Ron C 的答案。我对这个解决方案有点麻烦,因为它省略了包含 ASP.NET Core 90% 逻辑的整个中间件(比如安全、cookies、压缩……)。 路由风格的中间件:添加类似于路由的中间件。在这种情况下,您的决策逻辑需要在那里进行评估。 中间件堆栈的后期重新运行:您基本上需要重新运行堆栈的很大一部分。我相信这是可能的,但还没有看到解决方案。我看过 Damian Edwards(ASP.NET Core 的 PM)的演示文稿,他在其中托管 ASP.NET Core,而没有使用 Kestrel/TCPIP,只是为了在浏览器中本地呈现 HTML。你能做到的。但这太多了。

忠告:转移已死;)。像这样的差异是 ASP.NET Core 存在和性能改进的原因。这对迁移不利,但对整个平台有利。

【讨论】:

我的解决方案运行的中间件并不比您建议的前两个解决方案少,而且几乎可以肯定运行的中间件比您建议的后两个要多,因为您将退出中间件来实施如果你想出了这样一个解决方案的代码。此外,我的解决方案演示了如何为由不同控制器处理的不同视图运行操作逻辑。 确实如此。我制作的列表主要展示了 Transfer 可能的多种不同方式。我很确定,考虑到 ASP.NET Core 的灵活性,还有更多选择。您的解决方案看起来有点 hacky,但是,我还没有阅读 MVC 中间件实际上是如何做的细节,所以它可能是 100% 合法的。我认为我的回答中最重要的部分是最后两段;)。 Server.Transfer 在完整框架中执行页面后面的代码,用于传输到的页面并提供该页面。除了我编写的代码之外,可能还有其他选项可以在 .net 核心中做类似的事情,但我还没有看到有人为这些选项提供代码。 :-) 我同意这将是一个很酷的解决方案,而且比我的更好。理论上这应该是可能的,我希望有人发布如何做到这一点的代码。 我对“中间件堆栈的后期重新运行”路径感兴趣,有人有这方面的工作示例吗?【参考方案4】:

我知道这是一个非常古老的问题,但是如果有人使用 Razor Pages 并且正在寻找 Server.Transfer 替代方案(或根据业务规则返回不同视图的方法),您可以使用部分视图。

在本例中,我的视图模型有一个名为“UseAlternateView”的属性:

public class TestModel : PageModel

    public bool UseAlternateView  get; set; 

    public void OnGet()
    
        // Here goes code that can set UseAlternateView=true in certain conditions
    

在我的 Razor 视图中,我根据 UseAlternateView 属性的值呈现不同的局部视图:

@model MyProject.Pages.TestModel
@if (Model.UseAlternateView)

    await Html.RenderPartialAsync("_View1", Model);

else

    await Html.RenderPartialAsync("_View2", Model);

部分视图(文件“_View1.cshtml”和“_View2.cshtml”)包含如下代码:

@model MyProject.Pages.TestModel
<div>
    Here goes page content, including forms with binding to Model properties
    when necessary
</div>

Obs.:当使用像这样的局部视图时,您不能使用@Region,因此您可能需要寻找一种替代方法,以便在母版页上的正确位置插入脚本和样式。

【讨论】:

【参考方案5】:

我可以看到这是一个相当古老的线程。不知道.Net Core什么时候添加了URL重写但是答案是在中间件中重写URL,它不是重定向,不返回服务器,不改变浏览器地址栏中的url,但是确实改变了路线。

资源:

https://weblog.west-wind.com/posts/2020/Mar/13/Back-to-Basics-Rewriting-a-URL-in-ASPNET-Core

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-5.0

【讨论】:

以上是关于ASP.NET Core 中 Server.Transfer 的替代方案的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core 动作结果 - ASP.NET Core 基础教程 - 简单教程,简单编程

asp.net core1.x/asp.net core2.0中如何加载多个配置文件

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用AutoMapper进行实体映射

ASP.NET Core中的缓存[1]:如何在一个ASP.NET Core应用中使用缓存

ASP.NET Core 1.0 部署 HTTPS

ASP.NET Core (.NET Core) and ASP.NET Core (.NET Framework)区别