Skip to content

Add RouteValueDictionary overloads to Http.Results #46542

Closed
@JamesNK

Description

@JamesNK

Background and Motivation

Results and TypedResults have methods that use reflection to create route values. These have all been annotated as unsafe.

public static partial class Results
{
    [RequiresUnreferencedCode(RouteValueDictionaryTrimmerWarning.Warning)]
    public static IResult CreatedAtRoute(string? routeName = null, object? routeValues = null, object? value = null);
}

We have previously worked around this problem by adding overloads that take RouteValueDictionary. Values can be explicitly added to the dictionary, and the dictionary is then passed to routing. This is a trimming and AOT-safe alternative.

Proposed API

namespace Microsoft.AspNetCore.Http;

public static partial class Results
{
+    public static IResult RedirectToRoute(string? routeName, RouteValueDictionary? routeValues, bool permanent = false, bool preserveMethod = false, string? fragment = null);
+    public static IResult CreatedAtRoute(string? routeName, RouteValueDictionary routeValues, object? value = null);
+    public static IResult CreatedAtRoute<TValue>(string? routeName, RouteValueDictionary routeValues, TValue? value = default);
+    public static IResult AcceptedAtRoute(string? routeName, RouteValueDictionary routeValues, object? value = null);
+    public static IResult AcceptedAtRoute<TValue>(string? routeName, RouteValueDictionary routeValues, TValue? value = default);
}

public static partial class TypedResults
{
+    public static RedirectToRouteHttpResult RedirectToRoute(string? routeName, RouteValueDictionary? routeValues, bool permanent = false, bool preserveMethod = false, string? fragment = null);
+    public static CreatedAtRoute CreatedAtRoute(string? routeName, RouteValueDictionary routeValues);
+    public static CreatedAtRoute<TValue> CreatedAtRoute<TValue>(TValue? value, string? routeName, RouteValueDictionary routeValues);
+    public static AcceptedAtRoute AcceptedAtRoute(string? routeName, RouteValueDictionary routeValues);
+    public static AcceptedAtRoute<TValue> AcceptedAtRoute<TValue>(TValue? value, string? routeName, RouteValueDictionary routeValues);
}

Usage Examples

app.MapGet("/old-path", () => Results.CreatedAtRoute("RouteName", new RouteValueDictionary { ["routeValue1"] = "value!" }));

Alternative Designs

Generic type parameter for route values was explored in #46082. For example:

public static partial class Results
{
+    public static IResult CreatedAtRoute<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TRouteValues>(string? routeName, TRouteValues routeValues, object? value = null);
}

It doesn't require converting the route values object into a RouteValueDictionary, but it has some problems:

  1. It doesn't work with polymorphism. Property values are gotten from the route value type based on its runtime type. If the route value instance is cast to object and then used with CreatedAtRoute<TRouteValues>, its properties aren't preserved.
  2. It could be a source-breaking change. There will now be a CreatedAtRoute<TRouteValues> overload and a CreatedAtRoute<TValue> overload. Code that explicitly specifies the generic type when calling CreatedAtRoute could cause an ambiguous method compiler error.

For example:

return Results.CreatedAtRoute<object>("RouteName", new { param1 = "param1Value" }, new User());

Risks

There are a lot of overloads, optional parameters and nullable types. It is possible to create method overloads that are ambiguous.

To avoid that:

  1. RouteValueDictionary args never have a default value. It must be specified.
  2. Tests for methods must be extensive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions