7
7
using System . Reflection ;
8
8
using Microsoft . AspNetCore . Routing ;
9
9
using Microsoft . AspNetCore . Routing . Internal ;
10
+ using Microsoft . AspNetCore . Routing . Patterns ;
10
11
11
12
namespace Microsoft . AspNetCore . Builder
12
13
{
@@ -15,6 +16,12 @@ namespace Microsoft.AspNetCore.Builder
15
16
/// </summary>
16
17
public static class MapActionEndpointRouteBuilderExtensions
17
18
{
19
+ // Avoid creating a new array every call
20
+ private static readonly string [ ] GetVerb = new [ ] { "GET" } ;
21
+ private static readonly string [ ] PostVerb = new [ ] { "POST" } ;
22
+ private static readonly string [ ] PutVerb = new [ ] { "PUT" } ;
23
+ private static readonly string [ ] DeleteVerb = new [ ] { "DELETE" } ;
24
+
18
25
/// <summary>
19
26
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches the pattern specified via attributes.
20
27
/// </summary>
@@ -76,5 +83,203 @@ public static MapActionEndpointConventionBuilder MapAction(
76
83
77
84
return new MapActionEndpointConventionBuilder ( conventionBuilders ) ;
78
85
}
86
+
87
+ /// <summary>
88
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP GET requests
89
+ /// for the specified pattern.
90
+ /// </summary>
91
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
92
+ /// <param name="pattern">The route pattern.</param>
93
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
94
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
95
+ public static MapActionEndpointConventionBuilder MapGet (
96
+ this IEndpointRouteBuilder endpoints ,
97
+ string pattern ,
98
+ Delegate action )
99
+ {
100
+ return MapMethods ( endpoints , pattern , GetVerb , action ) ;
101
+ }
102
+
103
+ /// <summary>
104
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP POST requests
105
+ /// for the specified pattern.
106
+ /// </summary>
107
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
108
+ /// <param name="pattern">The route pattern.</param>
109
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
110
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
111
+ public static MapActionEndpointConventionBuilder MapPost (
112
+ this IEndpointRouteBuilder endpoints ,
113
+ string pattern ,
114
+ Delegate action )
115
+ {
116
+ return MapMethods ( endpoints , pattern , PostVerb , action ) ;
117
+ }
118
+
119
+ /// <summary>
120
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PUT requests
121
+ /// for the specified pattern.
122
+ /// </summary>
123
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
124
+ /// <param name="pattern">The route pattern.</param>
125
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
126
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that canaction be used to further customize the endpoint.</returns>
127
+ public static MapActionEndpointConventionBuilder MapPut (
128
+ this IEndpointRouteBuilder endpoints ,
129
+ string pattern ,
130
+ Delegate action )
131
+ {
132
+ return MapMethods ( endpoints , pattern , PutVerb , action ) ;
133
+ }
134
+
135
+ /// <summary>
136
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP DELETE requests
137
+ /// for the specified pattern.
138
+ /// </summary>
139
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
140
+ /// <param name="pattern">The route pattern.</param>
141
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
142
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
143
+ public static MapActionEndpointConventionBuilder MapDelete (
144
+ this IEndpointRouteBuilder endpoints ,
145
+ string pattern ,
146
+ Delegate action )
147
+ {
148
+ return MapMethods ( endpoints , pattern , DeleteVerb , action ) ;
149
+ }
150
+
151
+ /// <summary>
152
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
153
+ /// for the specified HTTP methods and pattern.
154
+ /// </summary>
155
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
156
+ /// <param name="pattern">The route pattern.</param>
157
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
158
+ /// <param name="httpMethods">HTTP methods that the endpoint will match.</param>
159
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
160
+ public static MapActionEndpointConventionBuilder MapMethods (
161
+ this IEndpointRouteBuilder endpoints ,
162
+ string pattern ,
163
+ IEnumerable < string > httpMethods ,
164
+ Delegate action )
165
+ {
166
+ if ( httpMethods is null )
167
+ {
168
+ throw new ArgumentNullException ( nameof ( httpMethods ) ) ;
169
+ }
170
+
171
+ var displayName = $ "{ pattern } HTTP: { string . Join ( ", " , httpMethods ) } ";
172
+ var builder = endpoints . Map ( RoutePatternFactory . Parse ( pattern ) , action , displayName ) ;
173
+ builder . WithMetadata ( new HttpMethodMetadata ( httpMethods ) ) ;
174
+ return builder ;
175
+ }
176
+
177
+ /// <summary>
178
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
179
+ /// for the specified pattern.
180
+ /// </summary>
181
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
182
+ /// <param name="pattern">The route pattern.</param>
183
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
184
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
185
+ public static MapActionEndpointConventionBuilder Map (
186
+ this IEndpointRouteBuilder endpoints ,
187
+ string pattern ,
188
+ Delegate action )
189
+ {
190
+ return Map ( endpoints , RoutePatternFactory . Parse ( pattern ) , action ) ;
191
+ }
192
+
193
+ /// <summary>
194
+ /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
195
+ /// for the specified pattern.
196
+ /// </summary>
197
+ /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
198
+ /// <param name="pattern">The route pattern.</param>
199
+ /// <param name="action">The delegate executed when the endpoint is matched.</param>
200
+ /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
201
+ public static MapActionEndpointConventionBuilder Map (
202
+ this IEndpointRouteBuilder endpoints ,
203
+ RoutePattern pattern ,
204
+ Delegate action )
205
+ {
206
+ return Map ( endpoints , pattern , action , displayName : null ) ;
207
+ }
208
+
209
+ private static MapActionEndpointConventionBuilder Map (
210
+ this IEndpointRouteBuilder endpoints ,
211
+ RoutePattern pattern ,
212
+ Delegate action ,
213
+ string ? displayName )
214
+ {
215
+ if ( endpoints is null )
216
+ {
217
+ throw new ArgumentNullException ( nameof ( endpoints ) ) ;
218
+ }
219
+
220
+ if ( pattern is null )
221
+ {
222
+ throw new ArgumentNullException ( nameof ( pattern ) ) ;
223
+ }
224
+
225
+ if ( action is null )
226
+ {
227
+ throw new ArgumentNullException ( nameof ( action ) ) ;
228
+ }
229
+
230
+ const int defaultOrder = 0 ;
231
+
232
+ var builder = new RouteEndpointBuilder (
233
+ MapActionExpressionTreeBuilder . BuildRequestDelegate ( action ) ,
234
+ pattern ,
235
+ defaultOrder )
236
+ {
237
+ DisplayName = pattern . RawText ?? pattern . DebuggerToString ( ) ,
238
+ } ;
239
+
240
+ // Add delegate attributes as metadata
241
+ var attributes = action . Method . GetCustomAttributes ( ) ;
242
+ string ? routeName = null ;
243
+ int ? routeOrder = null ;
244
+
245
+ // This can be null if the delegate is a dynamic method or compiled from an expression tree
246
+ if ( attributes is not null )
247
+ {
248
+ foreach ( var attribute in attributes )
249
+ {
250
+ if ( attribute is IRoutePatternMetadata patternMetadata && patternMetadata . RoutePattern is not null )
251
+ {
252
+ throw new InvalidOperationException ( $ "'{ attribute . GetType ( ) } ' implements { nameof ( IRoutePatternMetadata ) } which is not supported by this method.") ;
253
+ }
254
+ if ( attribute is IHttpMethodMetadata methodMetadata && methodMetadata . HttpMethods . Any ( ) )
255
+ {
256
+ throw new InvalidOperationException ( $ "'{ attribute . GetType ( ) } ' implements { nameof ( IHttpMethodMetadata ) } which is not supported by this method.") ;
257
+ }
258
+
259
+ if ( attribute is IRouteNameMetadata nameMetadata && nameMetadata . RouteName is string name )
260
+ {
261
+ routeName = name ;
262
+ }
263
+ if ( attribute is IRouteOrderMetadata orderMetadata && orderMetadata . RouteOrder is int order )
264
+ {
265
+ routeOrder = order ;
266
+ }
267
+
268
+ builder . Metadata . Add ( attribute ) ;
269
+ }
270
+ }
271
+
272
+ builder . DisplayName = routeName ?? displayName ?? builder . DisplayName ;
273
+ builder . Order = routeOrder ?? defaultOrder ;
274
+
275
+ var dataSource = endpoints . DataSources . OfType < ModelEndpointDataSource > ( ) . FirstOrDefault ( ) ;
276
+ if ( dataSource is null )
277
+ {
278
+ dataSource = new ModelEndpointDataSource ( ) ;
279
+ endpoints . DataSources . Add ( dataSource ) ;
280
+ }
281
+
282
+ return new MapActionEndpointConventionBuilder ( dataSource . AddEndpointBuilder ( builder ) ) ;
283
+ }
79
284
}
80
285
}
0 commit comments