Skip to content

Commit 8ba7574

Browse files
committed
Rebase on Safia's changes.
1 parent 2495d89 commit 8ba7574

File tree

2 files changed

+176
-73
lines changed

2 files changed

+176
-73
lines changed

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs

Lines changed: 73 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ internal static string EmitQueryOrHeaderParameterPreparation(this EndpointParame
3636
if (endpointParameter.IsOptional)
3737
{
3838
builder.AppendLine($$"""
39-
var {{endpointParameter.EmitHandlerArgument()}} = {{endpointParameter.EmitAssigningCodeResult()}}.Count > 0 ? {{endpointParameter.EmitAssigningCodeResult()}}.ToString() : null;
40-
var {{endpointParameter.Name}}_temp = {{endpointParameter.Name}}_raw.Count > 0 ? {{endpointParameter.Name}}_raw.ToString() : null;
39+
var {{endpointParameter.Name}}_temp = {{endpointParameter.EmitAssigningCodeResult()}}.Count > 0 ? {{endpointParameter.Name}}_raw.ToString() : null;
4140
""");
4241
}
4342
else
@@ -47,7 +46,6 @@ internal static string EmitQueryOrHeaderParameterPreparation(this EndpointParame
4746
{
4847
wasParamCheckFailure = true;
4948
}
50-
var {{endpointParameter.EmitHandlerArgument()}} = {{endpointParameter.EmitAssigningCodeResult()}}.ToString();
5149
var {{endpointParameter.Name}}_temp = {{endpointParameter.EmitAssigningCodeResult()}}.ToString();
5250
""");
5351
}
@@ -76,136 +74,138 @@ internal static string EmitParsingBlock(this EndpointParameter endpointParameter
7674
{{endpointParameter.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}} {{endpointParameter.EmitHandlerArgument()}} = {{endpointParameter.Name}}_temp!;
7775
""");
7876

77+
}
78+
79+
return builder.ToString();
7980
}
8081

81-
internal static string EmitRouteParameterPreparation(this EndpointParameter endpointParameter)
82-
{
83-
var builder = new StringBuilder();
84-
builder.AppendLine($"""
82+
internal static string EmitRouteParameterPreparation(this EndpointParameter endpointParameter)
83+
{
84+
var builder = new StringBuilder();
85+
builder.AppendLine($"""
8586
{endpointParameter.EmitParameterDiagnosticComment()}
8687
""");
8788

88-
// Throw an exception of if the route parameter name that was specific in the `FromRoute`
89-
// attribute or in the parameter name does not appear in the actual route.
90-
builder.AppendLine($$"""
89+
// Throw an exception of if the route parameter name that was specific in the `FromRoute`
90+
// attribute or in the parameter name does not appear in the actual route.
91+
builder.AppendLine($$"""
9192
if (options?.RouteParameterNames?.Contains("{{endpointParameter.Name}}", StringComparer.OrdinalIgnoreCase) != true)
9293
{
9394
throw new InvalidOperationException($"'{{endpointParameter.Name}}' is not a route parameter.");
9495
}
9596
""");
9697

97-
var assigningCode = $"httpContext.Request.RouteValues[\"{endpointParameter.Name}\"]?.ToString()";
98-
builder.AppendLine($$"""
98+
var assigningCode = $"httpContext.Request.RouteValues[\"{endpointParameter.Name}\"]?.ToString()";
99+
builder.AppendLine($$"""
99100
var {{endpointParameter.EmitAssigningCodeResult()}} = {{assigningCode}};
100101
""");
101102

102-
if (!endpointParameter.IsOptional)
103-
{
104-
builder.AppendLine($$"""
103+
if (!endpointParameter.IsOptional)
104+
{
105+
builder.AppendLine($$"""
105106
if ({{endpointParameter.EmitAssigningCodeResult()}} == null)
106107
{
107108
wasParamCheckFailure = true;
108109
}
109110
""");
110-
}
111-
builder.AppendLine($"""
111+
}
112+
builder.AppendLine($"""
112113
var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()};
113114
""");
114115

115-
return builder.ToString();
116-
}
116+
return builder.ToString();
117+
}
117118

118-
internal static string EmitRouteOrQueryParameterPreparation(this EndpointParameter endpointParameter)
119-
{
120-
var builder = new StringBuilder();
121-
builder.AppendLine($"""
119+
internal static string EmitRouteOrQueryParameterPreparation(this EndpointParameter endpointParameter)
120+
{
121+
var builder = new StringBuilder();
122+
builder.AppendLine($"""
122123
{endpointParameter.EmitParameterDiagnosticComment()}
123124
""");
124125

125-
var parameterName = endpointParameter.Name;
126-
var assigningCode = $@"options?.RouteParameterNames?.Contains(""{parameterName}"", StringComparer.OrdinalIgnoreCase) == true";
127-
assigningCode += $@"? new StringValues(httpContext.Request.RouteValues[$""{parameterName}""]?.ToString())";
128-
assigningCode += $@": httpContext.Request.Query[$""{parameterName}""];";
126+
var parameterName = endpointParameter.Name;
127+
var assigningCode = $@"options?.RouteParameterNames?.Contains(""{parameterName}"", StringComparer.OrdinalIgnoreCase) == true";
128+
assigningCode += $@"? new StringValues(httpContext.Request.RouteValues[$""{parameterName}""]?.ToString())";
129+
assigningCode += $@": httpContext.Request.Query[$""{parameterName}""];";
129130

130-
builder.AppendLine($$"""
131+
builder.AppendLine($$"""
131132
var {{endpointParameter.EmitAssigningCodeResult()}} = {{assigningCode}};
132133
""");
133134

134-
if (!endpointParameter.IsOptional)
135-
{
136-
builder.AppendLine($$"""
135+
if (!endpointParameter.IsOptional)
136+
{
137+
builder.AppendLine($$"""
137138
if ({{endpointParameter.EmitAssigningCodeResult()}} is StringValues { Count: 0 })
138139
{
139140
wasParamCheckFailure = true;
140141
}
141142
""");
142-
}
143+
}
143144

144-
builder.AppendLine($"""
145+
builder.AppendLine($"""
145146
var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()};
146147
""");
147148

148-
return builder.ToString();
149-
}
149+
return builder.ToString();
150+
}
150151

151-
internal static string EmitJsonBodyParameterPreparationString(this EndpointParameter endpointParameter)
152-
{
153-
var builder = new StringBuilder();
154-
builder.AppendLine($"""
152+
internal static string EmitJsonBodyParameterPreparationString(this EndpointParameter endpointParameter)
153+
{
154+
var builder = new StringBuilder();
155+
builder.AppendLine($"""
155156
{endpointParameter.EmitParameterDiagnosticComment()}
156157
""");
157158

158-
var assigningCode = $"await GeneratedRouteBuilderExtensionsCore.TryResolveBody<{endpointParameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)}>(httpContext, {(endpointParameter.IsOptional ? "true" : "false")})";
159-
builder.AppendLine($$"""
159+
var assigningCode = $"await GeneratedRouteBuilderExtensionsCore.TryResolveBody<{endpointParameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)}>(httpContext, {(endpointParameter.IsOptional ? "true" : "false")})";
160+
builder.AppendLine($$"""
160161
var (isSuccessful, {{endpointParameter.EmitHandlerArgument()}}) = {{assigningCode}};
161162
""");
162163

163-
// If binding from the JSON body fails, we exit early. Don't
164-
// set the status code here because assume it has been set by the
165-
// TryResolveBody method.
166-
builder.AppendLine("""
164+
// If binding from the JSON body fails, we exit early. Don't
165+
// set the status code here because assume it has been set by the
166+
// TryResolveBody method.
167+
builder.AppendLine("""
167168
if (!isSuccessful)
168169
{
169170
return;
170171
}
171172
""");
172173

173-
return builder.ToString();
174-
}
174+
return builder.ToString();
175+
}
175176

176-
internal static string EmitServiceParameterPreparation(this EndpointParameter endpointParameter)
177-
{
178-
var builder = new StringBuilder();
177+
internal static string EmitServiceParameterPreparation(this EndpointParameter endpointParameter)
178+
{
179+
var builder = new StringBuilder();
179180

180-
// Preamble for diagnostics purposes.
181-
builder.AppendLine($"""
181+
// Preamble for diagnostics purposes.
182+
builder.AppendLine($"""
182183
{endpointParameter.EmitParameterDiagnosticComment()}
183184
""");
184185

185-
// Requiredness checks for services are handled by the distinction
186-
// between GetRequiredService and GetService in the assigningCode.
187-
// Unlike other scenarios, this will result in an exception being thrown
188-
// at runtime.
189-
var assigningCode = endpointParameter.IsOptional ?
190-
$"httpContext.RequestServices.GetService<{endpointParameter.Type}>();" :
191-
$"httpContext.RequestServices.GetRequiredService<{endpointParameter.Type}>()";
186+
// Requiredness checks for services are handled by the distinction
187+
// between GetRequiredService and GetService in the assigningCode.
188+
// Unlike other scenarios, this will result in an exception being thrown
189+
// at runtime.
190+
var assigningCode = endpointParameter.IsOptional ?
191+
$"httpContext.RequestServices.GetService<{endpointParameter.Type}>();" :
192+
$"httpContext.RequestServices.GetRequiredService<{endpointParameter.Type}>()";
192193

193-
builder.AppendLine($$"""
194+
builder.AppendLine($$"""
194195
var {{endpointParameter.EmitHandlerArgument()}} = {{assigningCode}};
195196
""");
196197

197-
return builder.ToString();
198-
}
198+
return builder.ToString();
199+
}
199200

200-
private static string EmitParameterDiagnosticComment(this EndpointParameter endpointParameter) =>
201-
private static string EmitHandlerArgument(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_local";
202-
private static string EmitAssigningCodeResult(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_raw";
201+
private static string EmitParameterDiagnosticComment(this EndpointParameter endpointParameter) => $"// Endpoint Parameter: {endpointParameter.Name} (Type = {endpointParameter.Type}, IsOptional = {endpointParameter.IsOptional}, IsParsable = {endpointParameter.IsParsable}, Source = {endpointParameter.Source})";
202+
private static string EmitHandlerArgument(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_local";
203+
private static string EmitAssigningCodeResult(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_raw";
203204

204-
public static string EmitArgument(this EndpointParameter endpointParameter) => endpointParameter.Source switch
205-
{
206-
EndpointParameterSource.JsonBody or EndpointParameterSource.Route or EndpointParameterSource.RouteOrQuery => endpointParameter.IsOptional
207-
? endpointParameter.EmitHandlerArgument()
208-
: $"{endpointParameter.EmitHandlerArgument()}!",
209-
EndpointParameterSource.Unknown => throw new Exception("Unreachable!"),
210-
_ => endpointParameter.EmitHandlerArgument()
211-
};
205+
public static string EmitArgument(this EndpointParameter endpointParameter) => endpointParameter.Source switch
206+
{
207+
EndpointParameterSource.JsonBody or EndpointParameterSource.Route or EndpointParameterSource.RouteOrQuery => endpointParameter.IsOptional ? endpointParameter.EmitHandlerArgument() : $"{endpointParameter.EmitHandlerArgument()}!",
208+
EndpointParameterSource.Unknown => throw new Exception("Unreachable!"),
209+
_ => endpointParameter.EmitHandlerArgument()
210+
};
211+
}

src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateGeneratorTestBase.cs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,109 @@ public static IEndpointRouteBuilder MapTestEndpoints(this IEndpointRouteBuilder
212212
return app;
213213
}
214214
}
215+
216+
public enum TodoStatus
217+
{
218+
Trap, // A trap for Enum.TryParse<T>!
219+
Done,
220+
InProgress,
221+
NotDone
222+
}
223+
224+
public interface ITodo
225+
{
226+
public int Id { get; }
227+
public string? Name { get; }
228+
public bool IsComplete { get; }
229+
public TodoStatus Status { get; }
230+
}
231+
232+
public class PrecedenceCheckTodo
233+
{
234+
public PrecedenceCheckTodo(int magicValue)
235+
{
236+
MagicValue = magicValue;
237+
}
238+
public int MagicValue { get; }
239+
public static bool TryParse(string? input, IFormatProvider? provider, out PrecedenceCheckTodo result)
240+
{
241+
result = new PrecedenceCheckTodo(42);
242+
return true;
243+
}
244+
public static bool TryParse(string? input, out PrecedenceCheckTodo result)
245+
{
246+
result = new PrecedenceCheckTodo(24);
247+
return true;
248+
}
249+
}
250+
251+
public class PrecedenceCheckTodoWithoutFormat
252+
{
253+
public PrecedenceCheckTodoWithoutFormat(int magicValue)
254+
{
255+
MagicValue = magicValue;
256+
}
257+
public int MagicValue { get; }
258+
public static bool TryParse(string? input, out PrecedenceCheckTodoWithoutFormat result)
259+
{
260+
result = new PrecedenceCheckTodoWithoutFormat(24);
261+
return true;
262+
}
263+
}
264+
265+
public class ParsableTodo : IParsable<ParsableTodo>
266+
{
267+
public int Id { get; set; }
268+
public string? Name { get; set; } = "Todo";
269+
public bool IsComplete { get; set; }
270+
public static ParsableTodo Parse(string s, IFormatProvider? provider)
271+
{
272+
return new ParsableTodo();
273+
}
274+
public static bool TryParse(string? input, IFormatProvider? provider, out ParsableTodo result)
275+
{
276+
if (input == "1")
277+
{
278+
result = new ParsableTodo
279+
{
280+
Id = 1,
281+
Name = "Knit kitten mittens.",
282+
IsComplete = false
283+
};
284+
return true;
285+
}
286+
else
287+
{
288+
result = null!;
289+
return false;
290+
}
291+
}
292+
}
293+
294+
public class Todo
295+
{
296+
public int Id { get; set; }
297+
public string? Name { get; set; } = "Todo";
298+
public bool IsComplete { get; set; }
299+
public static bool TryParse(string input, out Todo? result)
300+
{
301+
if (input == "1")
302+
{
303+
result = new Todo
304+
{
305+
Id = 1,
306+
Name = "Knit kitten mittens.",
307+
IsComplete = false
308+
};
309+
return true;
310+
}
311+
else
312+
{
313+
result = null;
314+
return false;
315+
}
316+
}
317+
}
215318
""";
216319
private static Task<Compilation> CreateCompilationAsync(string sources)
217320
{

0 commit comments

Comments
 (0)