Infer default sources for parameters in MapAction
See original GitHub issueHow to determine each parameter’s source
The numbered and lettered rules for determining the source of a parameter should be applied in the order. The bullet points are unordered.
- If an attribute that implements one of the “IFrom…” interfaces in
Microsoft.AspNetCore.Http.Metadatais applied to the parameter, populate the parameter from the source specified by the attribute. Only one of these attributes can be specified per parameter, and these attributes must implement no more than one of these interfaces.IFromRouteMetadata- Reads from
HttpRequest.RouteValues[name]wherenameis specified byIFromRouteMetadata.Nameor the parameter name ifIFromRouteMetadata.Nameis null.
- Reads from
IFromBodyMetadata- Reads from
HttpRequest.Body(Reader)as JSON usingHttpRequest.ReadFromJsonAsync<{ParameterType}>(). - Can only be used once per parameter list (there’s only one body)
- Cannot be used in the same parameter list as
IFromFormMetadata - Will cause requests with an empty body to be rejected without calling the action unless
IFromBodyMetadata.AllowEmptyreturns true. (The default interface implementation returns false.)
- Reads from
IFromFormMetadata- Reads from
HttpRequest.Form[name]wherenameis specified byIFromFormMetadata.Nameor the parameter name ifIFromFormMetadata.Nameis null. - Can be used multiple times in a single parameter list (presumably for different names)
- Cannot be used in the same parameter list as
IFromBodyMetadata(there’s only one body)
- Reads from
IFromHeaderMetadata- Reads from
HttpRequest.Headers[name]wherenameis specified byIFromHeaderMetadata.Nameor the parameter name ifIFromHeaderMetadata.Nameis null.
- Reads from
IFromQueryMetadata- Reads from
HttpRequest.Query[name]wherenameis specified byIFromQueryMetadata.Nameor the parameter name ifIFromQueryMetadata.Nameis null.
- Reads from
IFromServiceMetadata- Normally resolves via
HttpRequest.RequestServices.GetRequiredService<{ParameterType}>(). - If the parameter is a nullable reference type (i.e. has the
System.Runtime.CompilerServices.NullableAttribute), resolve viaHttpRequest.RequestServices.GetService<{ParameterType}>(). - If the parameter is optional (i.e. has a default value), resolve via
HttpRequest.RequestServices.GetService<{ParameterType}>() ?? parameter.DefaultValue.
- Normally resolves via
- If the parameter is a scalar value type that lives in the System namespace, first check
HttpRequest.RouteValuescontains an entry for the parameter name. If it does, useHttpRequest.RouteValues[{ParameterName}]. Otherwise, useHttpRequest.Query[{ParameterName}].- TODO: Come up with actual list of scalar value types that live in the System namespace.
- Question: Do we want to allow types to opt-in to this? Today MVC uses
TypeConverterwhich is hard to implement. - Alternatives:
- Something convention-based like the presence of a
bool TryParse(string, out T)method - The explicit implementation of an interface with that method to make it more opt in
- Something convention-based like the presence of a
- If
HttpRequest.RequestServices.GetService<{ParameterType}>()is not null, use that value.- TODO: Figure out how to make this work well with compile-time source generation. This might need to be determined at runtime no matter what.
- Otherwise, treat the parameter as if it had an attribute implementing
IFromBodyMetadatawhereIFromBodyMetadata.AllowEmptyis false.
How we will convert to the parameter type.
- For parameters bound from the body (has an
IFromBodyMetadataattribute or is treated by such by convention), we will continue to assume JSON and initialize the parameter withHttpRequest.ReadFromJsonAsync<{ParameterType}>().- We need to figure out if we want make this configurable or force people to read they body themselves if they want configurability. If we decide on configurability, we need to decide on how much.
- For all other parameters bound from the request (i.e. not a service or from the body) we need to convert from a string.
- Since there is a finite list of “scalar value who lives in the System namespace” we’ll bind to by convention, we’ll use their TryParse methods or equivalent until we decide on something different for those.
- Parameters explicitly bound by attribute to a string-based source also need to be converted much like those read from the
RouteValuesorQueryby convention. I doubt we also want to limit these parameter types to a finite list. For now, we’ll continue doing what we do today to convert from string as described below.
How we convert to the parameter type today in the “MapAction” APIs
Today, all inputs are converted to their respective parameter types as follows:
- For parameters bound from the body, we already call
HttpRequest.ReadFromJsonAsync<{ParameterType}>(). - All other parameters start as
strings from the various sources listed above.- If
{ParameterType}isstring, we’re done! - If there’s a
{ParameterType}.Parse({ValueString})method, use that.- NOTE: Going forward, prefer/require
TryParseinstead.
- NOTE: Going forward, prefer/require
- Lastly, try
Convert.ChangeType({ValueString}, typeof{ParameterType}, CultureInfo.InvariantCulture)- NOTE: Going forward, we should stop using
CultureInfo.InvariantCulture
- NOTE: Going forward, we should stop using
- If
Original issue:
- Complex type -> FromBody (See https://source.dot.net/#Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelMetadata.cs,606)
- Name appears as a route value -> FromRoute
- Everything else -> FromQuery
From: https://github.com/dotnet/aspnetcore/pull/29878#discussion_r569766403
New inference rules unique to MapAction:
[FromServices]should work implicitly for types that can be resolved from RequestServices.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:8 (7 by maintainers)
Top Results From Across the Web
Lambda improvements - C# 10.0 draft feature specifications
NET MapAction with attributes and natural types for lambda expressions: ... metadata emitted by the compiler such as default parameters.
Read more >Configuring additional parameters for notification channels
In Dev Studio, you can configure additional parameters that the notification channels may require at run time. You can define these parameters as...
Read more >How to pass an argument to functions mapped using .. ...
1 Answer. see working fiddle here: you can see passed parameter in the alert :) You can see it takes the args passed...
Read more >dotnet/aspnetcore#32378
Use nullibility to infer optionality of service and body parameters P1ASP.NET CoreASP.NET ... Add default global usings to Microsoft.NET.Sdk.Web ASP.
Read more >Tanium™ Map User Guide
By default, the Computer Group Targets setting for the Map action group ... A map is a set of parameters that are used...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

~As part of this let’s make sure optional parameters work well and that there are good error logs when non-optional parameters are missing.~
Fixed by #30434
Follow up based on yesterday’s meeting discussing #31603:
TryParseon method on any parameter first, signatures supported:static bool Enum.TryParse<T>(string, out T).static bool TryParse(string, NumberStyles, IFormatProvider, int)where theNumberStylesparameter is required to useCultureInfo.InvariantCultureas theIFormatProvider.static bool TryParse(string, IFormatProvider, out T)static bool TryParse(string, out T)[FromServices]