如何将ASP.NET Core 6 MVC路由系统挂接以自定义URL生成

发布于 2025-01-27 14:27:43 字数 1205 浏览 2 评论 0原文

在旧的.NET框架MVC实现中,我自己创建了路线,以便我也可以影响URL的生成。代码的一部分:

public class RouteBase : Route
{
    public RouteBase(string url, IRouteHandler routeHandler) : base(url, routeHandler) { }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        if (Url.Contains("{segment}") && !values.ContainsKey("segment"))
            values["segment"] = requestContext.HttpContext.Items["segmentValue"];

        return base.GetVirtualPath(requestContext, values);
    }
}

感谢GetVirtualPath,我能够在路由模板中检测一个特定段,并在路由值字典中注入适当的值,以便客户端应用程序在拨打实例url.routeurl时不必指定它( Rutename)。

在ASP.NET Core 6中,我现在使用基于属性的路由,我不知道如何将其连接到此过程中,以便在生成URL时可以将一些值注入路由值字典中。如果我有一个类似的路由模板:

[Route("{segment}/test", Name = "name"]

当我调用此功能时,我希望从代码中的其他某个地方进行注入机制,以便将已知段值注入用于构建URL的路由值:

var url = Url.RouteUrl("name"); // Not passing new { segment = value } as second param

为了进行信息,我只需使用此信息在启动中:

app.MapControllers();

In the old .Net Framework MVC implementations, I was creating routes by myself so that I could also influence urls generation. Part of the code:

public class RouteBase : Route
{
    public RouteBase(string url, IRouteHandler routeHandler) : base(url, routeHandler) { }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        if (Url.Contains("{segment}") && !values.ContainsKey("segment"))
            values["segment"] = requestContext.HttpContext.Items["segmentValue"];

        return base.GetVirtualPath(requestContext, values);
    }
}

Thanks to GetVirtualPath, I was able to detect a particular segment in the route template and inject a proper value in the route values dictionary so that the client app did not have to specify it when calling for instance Url.RouteUrl(routeName).

In asp.net core 6, I'm now using attributes based routing and I don't know how to hook into this so that I can inject some value into the route values dictionary when I generate urls. If I have a route template like so:

[Route("{segment}/test", Name = "name"]

When I call this, I want an injection mechanism from somewhere else in the code so that the known segment value is injected into the route values used to build the url:

var url = Url.RouteUrl("name"); // Not passing new { segment = value } as second param

For information, I simply use this in Startup:

app.MapControllers();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

昔梦 2025-02-03 14:27:43

阿米尔(Amir)的回答使我有望找到解决方案(为他赏金奖)。创建自定义Urlhelper是必经之需的方法,但不是urlhelper派生的类。对于Enpoint路由,该框架使用密封 endPointRoutingurlhelper 类。因此,我只需要源自Urlhelperbase,从EndPointRoutingurlhelper粘贴代码,然后添加我的自定义。我很幸运,那里没有内部代码...

这是解决方案。请注意:

  • 原始问题中提到的术语“段”被我在代码中实际拥有的东西IE代替。
  • httpcontext.items [“ lang”]由中间件设置。
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc;

// The custom UrlHelper is registered with serviceCollection.AddSingleton<IUrlHelperFactory, LanguageAwareUrlHelperFactory>();
public class LanguageAwareUrlHelperFactory : IUrlHelperFactory
{
    private readonly LinkGenerator _linkGenerator;
    public LanguageAwareUrlHelperFactory(LinkGenerator linkGenerator)
    {
        _linkGenerator = linkGenerator;
    }

    public IUrlHelper GetUrlHelper(ActionContext context)
    {
        return new LanguageAwareUrlHelper(context, _linkGenerator);
    }
}

// Source code is taken from https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Routing/EndpointRoutingUrlHelper.cs
// and modified to inject the desired route value
public class LanguageAwareUrlHelper : UrlHelperBase
{
    private readonly LinkGenerator _linkGenerator;

    public LanguageAwareUrlHelper(ActionContext actionContext, LinkGenerator linkGenerator) : base(actionContext)
    {
        if (linkGenerator == null)
            throw new ArgumentNullException(nameof(linkGenerator));

        _linkGenerator = linkGenerator;
    }

    public override string? Action(UrlActionContext urlActionContext)
    {
        if (urlActionContext == null)
            throw new ArgumentNullException(nameof(urlActionContext));

        var values = GetValuesDictionary(urlActionContext.Values);

        if (urlActionContext.Action == null)
        {
            if (!values.ContainsKey("action") && AmbientValues.TryGetValue("action", out var action))
                values["action"] = action;
        }
        else
            values["action"] = urlActionContext.Action;

        if (urlActionContext.Controller == null)
        {
            if (!values.ContainsKey("controller") && AmbientValues.TryGetValue("controller", out var controller))
                values["controller"] = controller;
        }
        else
            values["controller"] = urlActionContext.Controller;

        if (!values.ContainsKey("lang") && ActionContext.HttpContext.Items.ContainsKey("lang"))
            values["lang"] = ActionContext.HttpContext.Items["lang"];

        var path = _linkGenerator.GetPathByRouteValues(
            ActionContext.HttpContext,
            routeName: null,
            values,
            fragment: urlActionContext.Fragment == null ? FragmentString.Empty : new FragmentString("#" + urlActionContext.Fragment));

        return GenerateUrl(urlActionContext.Protocol, urlActionContext.Host, path);
    }

    public override string? RouteUrl(UrlRouteContext routeContext)
    {
        if (routeContext == null)
            throw new ArgumentNullException(nameof(routeContext));

        var langRouteValues = GetValuesDictionary(routeContext.Values);
        if (!langRouteValues.ContainsKey("lang") && ActionContext.HttpContext.Items.ContainsKey("lang"))
            langRouteValues.Add("lang", ActionContext.HttpContext.Items["lang"]);

        var path = _linkGenerator.GetPathByRouteValues(
            ActionContext.HttpContext,
            routeContext.RouteName,
            langRouteValues,
            fragment: routeContext.Fragment == null ? FragmentString.Empty : new FragmentString("#" + routeContext.Fragment));

        return GenerateUrl(routeContext.Protocol, routeContext.Host, path);
    }
}

Amir's answer put me on track to find a solution (bounty award for him). Creating a custom UrlHelper was the way to go, but not with a UrlHelper derived class. For enpoint routing, the framework is using the sealed EndpointRoutingUrlHelper class. So I just needed to derive from UrlHelperBase, paste the code from EndpointRoutingUrlHelper and add my customizations. I was lucky that there were no internal pieces of code in there...

Here is the solution. Note that:

  • the term "segment" mentioned in the original question is replaced by what I actually have in my code i.e. "lang".
  • HttpContext.Items["lang"] is set by a middleware.
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc;

// The custom UrlHelper is registered with serviceCollection.AddSingleton<IUrlHelperFactory, LanguageAwareUrlHelperFactory>();
public class LanguageAwareUrlHelperFactory : IUrlHelperFactory
{
    private readonly LinkGenerator _linkGenerator;
    public LanguageAwareUrlHelperFactory(LinkGenerator linkGenerator)
    {
        _linkGenerator = linkGenerator;
    }

    public IUrlHelper GetUrlHelper(ActionContext context)
    {
        return new LanguageAwareUrlHelper(context, _linkGenerator);
    }
}

// Source code is taken from https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Routing/EndpointRoutingUrlHelper.cs
// and modified to inject the desired route value
public class LanguageAwareUrlHelper : UrlHelperBase
{
    private readonly LinkGenerator _linkGenerator;

    public LanguageAwareUrlHelper(ActionContext actionContext, LinkGenerator linkGenerator) : base(actionContext)
    {
        if (linkGenerator == null)
            throw new ArgumentNullException(nameof(linkGenerator));

        _linkGenerator = linkGenerator;
    }

    public override string? Action(UrlActionContext urlActionContext)
    {
        if (urlActionContext == null)
            throw new ArgumentNullException(nameof(urlActionContext));

        var values = GetValuesDictionary(urlActionContext.Values);

        if (urlActionContext.Action == null)
        {
            if (!values.ContainsKey("action") && AmbientValues.TryGetValue("action", out var action))
                values["action"] = action;
        }
        else
            values["action"] = urlActionContext.Action;

        if (urlActionContext.Controller == null)
        {
            if (!values.ContainsKey("controller") && AmbientValues.TryGetValue("controller", out var controller))
                values["controller"] = controller;
        }
        else
            values["controller"] = urlActionContext.Controller;

        if (!values.ContainsKey("lang") && ActionContext.HttpContext.Items.ContainsKey("lang"))
            values["lang"] = ActionContext.HttpContext.Items["lang"];

        var path = _linkGenerator.GetPathByRouteValues(
            ActionContext.HttpContext,
            routeName: null,
            values,
            fragment: urlActionContext.Fragment == null ? FragmentString.Empty : new FragmentString("#" + urlActionContext.Fragment));

        return GenerateUrl(urlActionContext.Protocol, urlActionContext.Host, path);
    }

    public override string? RouteUrl(UrlRouteContext routeContext)
    {
        if (routeContext == null)
            throw new ArgumentNullException(nameof(routeContext));

        var langRouteValues = GetValuesDictionary(routeContext.Values);
        if (!langRouteValues.ContainsKey("lang") && ActionContext.HttpContext.Items.ContainsKey("lang"))
            langRouteValues.Add("lang", ActionContext.HttpContext.Items["lang"]);

        var path = _linkGenerator.GetPathByRouteValues(
            ActionContext.HttpContext,
            routeContext.RouteName,
            langRouteValues,
            fragment: routeContext.Fragment == null ? FragmentString.Empty : new FragmentString("#" + routeContext.Fragment));

        return GenerateUrl(routeContext.Protocol, routeContext.Host, path);
    }
}
风吹短裙飘 2025-02-03 14:27:43

您可以创建并注册自定义URLHELPER。它将使您能够按照用例操纵行为:

public class CustomUrlHelper : UrlHelper
{
    public CustomUrlHelper(ActionContext actionContext)
        : base(actionContext) { }

    public override string? RouteUrl(UrlRouteContext routeContext)
    {
        // if(routeContext.RouteName == "name" && routeContext.Values....)
        // routeContext.Values = ....
        return base.RouteUrl(routeContext);
    }
}

public class CustomUrlHelperFactory : IUrlHelperFactory
{
    public IUrlHelper GetUrlHelper(ActionContext context)
    {
        return new CustomUrlHelper(context);
    }
}

在您的程序中:

builder.Services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();

然后通过调用url.routeurl(“名称”),将调用您的CustomUrlhelper。

You can create and register a custom UrlHelper. It will give you the ability to manipulate the behavior as per your use case:

public class CustomUrlHelper : UrlHelper
{
    public CustomUrlHelper(ActionContext actionContext)
        : base(actionContext) { }

    public override string? RouteUrl(UrlRouteContext routeContext)
    {
        // if(routeContext.RouteName == "name" && routeContext.Values....)
        // routeContext.Values = ....
        return base.RouteUrl(routeContext);
    }
}

public class CustomUrlHelperFactory : IUrlHelperFactory
{
    public IUrlHelper GetUrlHelper(ActionContext context)
    {
        return new CustomUrlHelper(context);
    }
}

and in your Program.cs:

builder.Services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();

Then by calling the Url.RouteUrl("name"), your CustomUrlHelper will be called.

仅此而已 2025-02-03 14:27:43

在ASP.NET Core中,我使用以下两种方法,并且能够成功生成URL。

[Route("{segment}/test", Name = "name"]

var url1 = Url.RouteUrl("name", new { segment = "aa" });
var url2 = Url.Action("Action", "Controller", new { segment = "aa" });

In Asp.Net Core, I use the below two methods and it is able to successfully generate the URL.

[Route("{segment}/test", Name = "name"]

var url1 = Url.RouteUrl("name", new { segment = "aa" });
var url2 = Url.Action("Action", "Controller", new { segment = "aa" });

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文