1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System ;
4
5
using System . Text ;
5
6
6
7
namespace Microsoft . AspNetCore . Http . Generators . StaticRouteHandlerModel . Emitters ;
@@ -9,22 +10,22 @@ internal static class EndpointParameterEmitter
9
10
internal static string EmitSpecialParameterPreparation ( this EndpointParameter endpointParameter )
10
11
{
11
12
return $ """
12
- var { endpointParameter . Name } _local = { endpointParameter . AssigningCode } ;
13
+ var { endpointParameter . EmitHandlerArgument ( ) } = { endpointParameter . AssigningCode } ;
13
14
""" ;
14
15
}
15
16
16
- internal static string EmitQueryParameterPreparation ( this EndpointParameter endpointParameter )
17
+ internal static string EmitQueryOrHeaderParameterPreparation ( this EndpointParameter endpointParameter )
17
18
{
18
19
var builder = new StringBuilder ( ) ;
19
-
20
- // Preamble for diagnostics purposes.
21
20
builder . AppendLine ( $ """
22
21
{ endpointParameter . EmitParameterDiagnosticComment ( ) }
23
22
""" ) ;
24
23
25
- // Grab raw input from HttpContext.
24
+ var assigningCode = endpointParameter . Source is EndpointParameterSource . Header
25
+ ? $ "httpContext.Request.Headers[\" { endpointParameter . Name } \" ]"
26
+ : $ "httpContext.Request.Query[\" { endpointParameter . Name } \" ]";
26
27
builder . AppendLine ( $$ """
27
- var {{ endpointParameter . Name }} _raw = {{ endpointParameter . AssigningCode }} ;
28
+ var {{ endpointParameter . EmitAssigningCodeResult ( ) }} = {{ assigningCode }} ;
28
29
""" ) ;
29
30
30
31
// If we are not optional, then at this point we can just assign the string value to the handler argument,
@@ -34,35 +35,103 @@ internal static string EmitQueryParameterPreparation(this EndpointParameter endp
34
35
if ( endpointParameter . IsOptional )
35
36
{
36
37
builder . AppendLine ( $$ """
37
- var {{ endpointParameter . HandlerArgument }} = {{ endpointParameter . Name }} _raw .Count > 0 ? {{ endpointParameter . Name }} _raw .ToString() : null;
38
+ var {{ endpointParameter . EmitHandlerArgument ( ) }} = {{ endpointParameter . EmitAssigningCodeResult ( ) }} .Count > 0 ? {{ endpointParameter . EmitAssigningCodeResult ( ) }} .ToString() : null;
38
39
""" ) ;
39
40
}
40
41
else
41
42
{
42
43
builder . AppendLine ( $$ """
43
- if (StringValues.IsNullOrEmpty({{ endpointParameter . Name }} _raw ))
44
+ if (StringValues.IsNullOrEmpty({{ endpointParameter . EmitAssigningCodeResult ( ) }} ))
44
45
{
45
46
wasParamCheckFailure = true;
46
47
}
47
- var {{ endpointParameter . HandlerArgument }} = {{ endpointParameter . Name }} _raw .ToString();
48
+ var {{ endpointParameter . EmitHandlerArgument ( ) }} = {{ endpointParameter . EmitAssigningCodeResult ( ) }} .ToString();
48
49
""" ) ;
49
50
}
50
51
51
52
return builder . ToString ( ) ;
52
53
}
53
54
54
- internal static string EmitJsonBodyParameterPreparationString ( this EndpointParameter endpointParameter )
55
+ internal static string EmitRouteParameterPreparation ( this EndpointParameter endpointParameter )
55
56
{
56
57
var builder = new StringBuilder ( ) ;
58
+ builder . AppendLine ( $ """
59
+ { endpointParameter . EmitParameterDiagnosticComment ( ) }
60
+ """ ) ;
57
61
58
- // Preamble for diagnostics purposes.
62
+ // Throw an exception of if the route parameter name that was specific in the `FromRoute`
63
+ // attribute or in the parameter name does not appear in the actual route.
64
+ builder . AppendLine ( $$ """
65
+ if (options?.RouteParameterNames?.Contains("{{ endpointParameter . Name }} ", StringComparer.OrdinalIgnoreCase) != true)
66
+ {
67
+ throw new InvalidOperationException($"'{{ endpointParameter . Name }} ' is not a route parameter.");
68
+ }
69
+ """ ) ;
70
+
71
+ var assigningCode = $ "httpContext.Request.RouteValues[\" { endpointParameter . Name } \" ]?.ToString()";
72
+ builder . AppendLine ( $$ """
73
+ var {{ endpointParameter . EmitAssigningCodeResult ( ) }} = {{ assigningCode }} ;
74
+ """ ) ;
75
+
76
+ if ( ! endpointParameter . IsOptional )
77
+ {
78
+ builder . AppendLine ( $$ """
79
+ if ({{ endpointParameter . EmitAssigningCodeResult ( ) }} == null)
80
+ {
81
+ wasParamCheckFailure = true;
82
+ }
83
+ """ ) ;
84
+ }
85
+ builder . AppendLine ( $ """
86
+ var { endpointParameter . EmitHandlerArgument ( ) } = { endpointParameter . EmitAssigningCodeResult ( ) } ;
87
+ """ ) ;
88
+
89
+ return builder . ToString ( ) ;
90
+ }
91
+
92
+ internal static string EmitRouteOrQueryParameterPreparation ( this EndpointParameter endpointParameter )
93
+ {
94
+ var builder = new StringBuilder ( ) ;
59
95
builder . AppendLine ( $ """
60
96
{ endpointParameter . EmitParameterDiagnosticComment ( ) }
61
97
""" ) ;
62
98
63
- // Grab raw input from HttpContext.
99
+ var parameterName = endpointParameter . Name ;
100
+ var assigningCode = $@ "options?.RouteParameterNames?.Contains(""{ parameterName } "", StringComparer.OrdinalIgnoreCase) == true";
101
+ assigningCode += $@ "? new StringValues(httpContext.Request.RouteValues[$""{ parameterName } ""]?.ToString())";
102
+ assigningCode += $@ ": httpContext.Request.Query[$""{ parameterName } ""];";
103
+
64
104
builder . AppendLine ( $$ """
65
- var (isSuccessful, {{ endpointParameter . Name }} _local) = {{ endpointParameter . AssigningCode }} ;
105
+ var {{ endpointParameter . EmitAssigningCodeResult ( ) }} = {{ assigningCode }} ;
106
+ """ ) ;
107
+
108
+ if ( ! endpointParameter . IsOptional )
109
+ {
110
+ builder . AppendLine ( $$ """
111
+ if ({{ endpointParameter . EmitAssigningCodeResult ( ) }} is StringValues { Count: 0 })
112
+ {
113
+ wasParamCheckFailure = true;
114
+ }
115
+ """ ) ;
116
+ }
117
+
118
+ builder . AppendLine ( $ """
119
+ var { endpointParameter . EmitHandlerArgument ( ) } = { endpointParameter . EmitAssigningCodeResult ( ) } ;
120
+ """ ) ;
121
+
122
+ return builder . ToString ( ) ;
123
+ }
124
+
125
+ internal static string EmitJsonBodyParameterPreparationString ( this EndpointParameter endpointParameter )
126
+ {
127
+ var builder = new StringBuilder ( ) ;
128
+ builder . AppendLine ( $ """
129
+ { endpointParameter . EmitParameterDiagnosticComment ( ) }
130
+ """ ) ;
131
+
132
+ var assigningCode = $ "await GeneratedRouteBuilderExtensionsCore.TryResolveBody<{ endpointParameter . Type . ToDisplayString ( EmitterConstants . DisplayFormat ) } >(httpContext, { ( endpointParameter . IsOptional ? "true" : "false" ) } )";
133
+ builder . AppendLine ( $$ """
134
+ var (isSuccessful, {{ endpointParameter . EmitHandlerArgument ( ) }} ) = {{ assigningCode }} ;
66
135
""" ) ;
67
136
68
137
// If binding from the JSON body fails, we exit early. Don't
@@ -88,14 +157,32 @@ internal static string EmitServiceParameterPreparation(this EndpointParameter en
88
157
""" ) ;
89
158
90
159
// Requiredness checks for services are handled by the distinction
91
- // between GetRequiredService and GetService in the AssigningCode.
160
+ // between GetRequiredService and GetService in the assigningCode.
161
+ // Unlike other scenarios, this will result in an exception being thrown
162
+ // at runtime.
163
+ var assigningCode = endpointParameter . IsOptional ?
164
+ $ "httpContext.RequestServices.GetService<{ endpointParameter . Type } >();" :
165
+ $ "httpContext.RequestServices.GetRequiredService<{ endpointParameter . Type } >()";
166
+
92
167
builder . AppendLine ( $$ """
93
- var {{ endpointParameter . HandlerArgument }} = {{ endpointParameter . AssigningCode }} ;
168
+ var {{ endpointParameter . EmitHandlerArgument ( ) }} = {{ assigningCode }} ;
94
169
""" ) ;
95
170
96
171
return builder . ToString ( ) ;
97
172
}
98
173
99
174
private static string EmitParameterDiagnosticComment ( this EndpointParameter endpointParameter ) =>
100
- $ "// Endpoint Parameter: { endpointParameter . Name } (Type = { endpointParameter . Type } , IsOptional = { endpointParameter . IsOptional } , Source = { endpointParameter . Source } )";
175
+ $ "// Endpoint Parameter: { endpointParameter . Name } (Type = { endpointParameter . Type . ToDisplayString ( EmitterConstants . DisplayFormat ) } , IsOptional = { endpointParameter . IsOptional } , Source = { endpointParameter . Source } )";
176
+
177
+ private static string EmitHandlerArgument ( this EndpointParameter endpointParameter ) => $ "{ endpointParameter . Name } _local";
178
+ private static string EmitAssigningCodeResult ( this EndpointParameter endpointParameter ) => $ "{ endpointParameter . Name } _raw";
179
+
180
+ public static string EmitArgument ( this EndpointParameter endpointParameter ) => endpointParameter . Source switch
181
+ {
182
+ EndpointParameterSource . JsonBody or EndpointParameterSource . Route or EndpointParameterSource . RouteOrQuery => endpointParameter . IsOptional
183
+ ? endpointParameter . EmitHandlerArgument ( )
184
+ : $ "{ endpointParameter . EmitHandlerArgument ( ) } !",
185
+ EndpointParameterSource . Unknown => throw new Exception ( "Unreachable!" ) ,
186
+ _ => endpointParameter . EmitHandlerArgument ( )
187
+ } ;
101
188
}
0 commit comments