在 .Net Core 3.1 中更改请求路径 [英] Changing Request Path in .Net Core 3.1

查看:26
本文介绍了在 .Net Core 3.1 中更改请求路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 3.0 之前,我可以通过访问 HttpContextHttpRequest 属性来更改请求的路径(无需任何形式的浏览器重定向),然后更改Path 的值.

Prior to 3.0, I could change the path of a request (without any form of browser redirection) by just accessing the HttpRequest property of the HttpContext and then changed the value of the Path.

例如,为了向需要更改密码的用户显示一个页面(无论用户打算访问哪个页面),我扩展了 HttpContext

As an example, to display a page for a user who needed to change his/her password (irrespective of the page the user intended to visit), I extended the HttpContext

public static void ChangeDefaultPassword(this HttpContext context) 
=> context.Request.Path = "/Account/ChangePassword";

这段代码将用户带到AccountController中的操作方法ChangePassword不执行用户打算访问的操作方法.

This piece of code takes the user to the action method ChangePassword in the AccountController without executing the action method the user intends to visit.

然后进入 dotnet core 3.1.

Then enters dotnet core 3.1.

在3.1中,扩展方法改变了路径.但是,它从不执行 action 方法.它忽略更新的路径.

In 3.1, the extension method changes the path. However, it never executes the action method. It ignores the updated path.

我知道这是由于路由的变化.现在可以使用扩展方法 HttpContext.GetEndpoint() 访问端点.还有一个扩展方法 HttpContext.SetEndpoint 这似乎是设置新端点的正确方法.但是,没有关于如何完成此操作的示例.

I am aware this is due to the changes in the routing.The endpoint can now be accessed with the extension method HttpContext.GetEndpoint(). There is also an extension method HttpContext.SetEndpoint which seems to be the right way to set a new endpoint. However, there is no sample of how to accomplish this.

问题

如何更改请求路径,而不执行原路径?

How do I change the request path, without executing the original path?

我的尝试

  1. 我尝试更改路径.dotnet core 3.1 中的路由似乎忽略了 HttpRequest 路径值的值.
  2. 我尝试使用 context.Response.Redirect("/Account/ChangePassword"); 进行重定向.这行得通,但它首先执行用户请求的原始操作方法.这种行为违背了目的.
  3. 我尝试使用扩展方法 HttpContext.SetEndpoint,但没有可用的示例.
  1. I tried changing the path. It seems routing in dotnet core 3.1 ignores the value of the HttpRequest path value.
  2. I tried redirecting with context.Response.Redirect("/Account/ChangePassword");. This worked but it first executed the original action method requested by the user. This behavior defeated the purpose.
  3. I tried using the extension method HttpContext.SetEndpoint, but there was no example available to work with.

推荐答案

我找到了可行的解决方案.我的解决方案通过使用 SetEndpoint 扩展方法手动设置新端点来工作.

I was able to find a working solution. My solution works by manually setting a new endpoint with the SetEndpoint extension method.

这是我为解决此问题而创建的扩展方法.

Here is an extension method I created to resolve this issue.

    private static void RedirectToPath(this HttpContext context, string controllerName, string actionName )
    {
        // Get the old endpoint to extract the RequestDelegate
        var currentEndpoint = context.GetEndpoint();

        // Get access to the action descriptor collection
        var actionDescriptorsProvider =
            context.RequestServices.GetRequiredService<IActionDescriptorCollectionProvider>();

        // Get the controller aqction with the action name and the controller name.
        // You should be redirecting to a GET action method anyways. Anyone can provide a better way of achieving this. 
        var controllerActionDescriptor = actionDescriptorsProvider.ActionDescriptors.Items
            .Where(s => s is ControllerActionDescriptor bb
                        && bb.ActionName == actionName
                        && bb.ControllerName == controllerName
                        && (bb.ActionConstraints == null
                            || (bb.ActionConstraints != null
                               && bb.ActionConstraints.Any(x => x is HttpMethodActionConstraint cc
                               && cc.HttpMethods.Contains(HttpMethods.Get)))))
            .Select(s => s as ControllerActionDescriptor)
            .FirstOrDefault();

        if (controllerActionDescriptor is null) throw new Exception($"You were supposed to be redirected to {actionName} but the action descriptor could not be found.");

        // Create a new route endpoint
        // The route pattern is not needed but MUST be present. 
        var routeEndpoint = new RouteEndpoint(currentEndpoint.RequestDelegate, RoutePatternFactory.Parse(""), 1, new EndpointMetadataCollection(new object[] { controllerActionDescriptor }), controllerActionDescriptor.DisplayName);

        // set the new endpoint. You are assured that the previous endpoint will never execute.
        context.SetEndpoint(routeEndpoint);
    }

重要

  1. 您必须将操作方法​​的视图放置在 Shared 文件夹中,以使其可用.或者,您可以决定提供 IViewLocationExpander
  2. 的自定义实现
  3. 在访问端点之前,路由中间件必须已执行.
  1. You must make the view of the action method available by placing it in the Shared folder. Alternatively, you may decide to provide a custom implementation of IViewLocationExpander
  2. Before accessing the endpoint, the routing middleware must have executed.

用法

public static void ChangeDefaultPassword(this HttpContext context) 
=> context.RedirectToPath("Account","ChangePassword");

这篇关于在 .Net Core 3.1 中更改请求路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆