dotnet/aspnetcore

TransformOutbound of route constraint is not called when the route segment is optional

Open

#23,063 opened on 2020年6月17日

GitHub で見る
 (5 comments) (2 reactions) (0 assignees)C# (10,653 forks)batch import
affected-fewarea-mvcbugfeature-routinghelp wantedseverity-major

Repository metrics

Stars
 (37,933 stars)
PR merge metrics
 (平均マージ 16d 9h) (30d で 258 merged PRs)

説明

Describe the bug

TransformOutbound is not callled when generating url when the constraint in the route template is is optional.

To Reproduce

https://github.com/vjacquet/bugs/blob/3fbc2924345021175b911b651b5afe3524cde361/aspnetcore/RouteConstraint/Startup.cs#L51

The Index page show that the last segment of the 2 urls are different when they shouldn't Route.cshtml as the route definition @page "{id:hex}" RouteWithOptionalSegment.cshtml as the route definition @page "{id:hex?}"

The problem is that OptionalRouteConstraint, that wrap the specified route contraint, does not implement IOutboundParameterTransformer, therefore _parameterTransformers in TemplateBinder is not initialized correctly.

One possible fix is to define

class OutboundParameterTransformerOptionalRouteConstraint : OptionalRouteConstraint, IOutboundParameterTransformer
{
    public OutboundParameterTransformerOptionalRouteConstraint(IRouteConstraint innerConstraint) : base(innerConstraint)
    {
    }

    public string TransformOutbound(object value) => ((IOutboundParameterTransformer)InnerConstraint).TransformOutbound(value);
}

and have the DefaultParameterPolicy's InitializeRouteConstraint method return an instance of it when the constraint is optional and the routeConstraint implements IOutboundParameterTransformer.

private IParameterPolicy InitializeRouteConstraint(bool optional, IRouteConstraint routeConstraint)
{
    if (!optional)
        return routeConstraint;
    else if (routeConstraint is IOutboundParameterTransformer)
        return new OutboundParameterTransformerOptionalRouteConstraint(routeConstraint);
    else
        return new OptionalRouteConstraint(routeConstraint);
}

Further technical details

  • ASP.NET Core version 3.1

.NET Core SDK (reflecting any global.json): Version: 3.1.301 Commit: 7feb845744

Runtime Environment: OS Name: Windows OS Version: 10.0.18362 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\3.1.301\

Host (useful for support): Version: 3.1.5 Commit: 65cd789777

.NET Core SDKs installed: 1.1.14 [C:\Program Files\dotnet\sdk] 2.1.401 [C:\Program Files\dotnet\sdk] 2.1.802 [C:\Program Files\dotnet\sdk] 2.2.103 [C:\Program Files\dotnet\sdk] 3.1.200 [C:\Program Files\dotnet\sdk] 3.1.202 [C:\Program Files\dotnet\sdk] 3.1.301 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed: Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 1.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 1.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

コントリビューターガイド