@@ -36,7 +36,8 @@ public void AddEndpoints(
36
36
HashSet < string > routeNames ,
37
37
ActionDescriptor action ,
38
38
IReadOnlyList < ConventionalRouteEntry > routes ,
39
- IReadOnlyList < Action < EndpointBuilder > > conventions )
39
+ IReadOnlyList < Action < EndpointBuilder > > conventions ,
40
+ bool createInertEndpoints )
40
41
{
41
42
if ( endpoints == null )
42
43
{
@@ -63,6 +64,27 @@ public void AddEndpoints(
63
64
throw new ArgumentNullException ( nameof ( conventions ) ) ;
64
65
}
65
66
67
+ if ( createInertEndpoints )
68
+ {
69
+ var requestDelegate = CreateRequestDelegate ( ) ;
70
+ var builder = new InertEndpointBuilder ( )
71
+ {
72
+ DisplayName = action . DisplayName ,
73
+ RequestDelegate = requestDelegate ,
74
+ } ;
75
+ AddActionDataToBuilder (
76
+ builder ,
77
+ routeNames ,
78
+ action ,
79
+ routeName : null ,
80
+ dataTokens : null ,
81
+ suppressLinkGeneration : false ,
82
+ suppressPathMatching : false ,
83
+ conventions ,
84
+ Array . Empty < Action < EndpointBuilder > > ( ) ) ;
85
+ endpoints . Add ( builder . Build ( ) ) ;
86
+ }
87
+
66
88
if ( action . AttributeRouteInfo == null )
67
89
{
68
90
// Check each of the conventional patterns to see if the action would be reachable.
@@ -81,18 +103,22 @@ public void AddEndpoints(
81
103
82
104
// We suppress link generation for each conventionally routed endpoint. We generate a single endpoint per-route
83
105
// to handle link generation.
84
- var builder = CreateEndpoint (
106
+ var requestDelegate = CreateRequestDelegate ( ) ;
107
+ var builder = new RouteEndpointBuilder ( requestDelegate , updatedRoutePattern , route . Order )
108
+ {
109
+ DisplayName = action . DisplayName ,
110
+ } ;
111
+ AddActionDataToBuilder (
112
+ builder ,
85
113
routeNames ,
86
114
action ,
87
- updatedRoutePattern ,
88
115
route . RouteName ,
89
- route . Order ,
90
116
route . DataTokens ,
91
117
suppressLinkGeneration : true ,
92
118
suppressPathMatching : false ,
93
119
conventions ,
94
120
route . Conventions ) ;
95
- endpoints . Add ( builder ) ;
121
+ endpoints . Add ( builder . Build ( ) ) ;
96
122
}
97
123
}
98
124
else
@@ -109,18 +135,22 @@ public void AddEndpoints(
109
135
throw new InvalidOperationException ( "Failed to update route pattern with required values." ) ;
110
136
}
111
137
112
- var endpoint = CreateEndpoint (
138
+ var requestDelegate = CreateRequestDelegate ( ) ;
139
+ var builder = new RouteEndpointBuilder ( requestDelegate , updatedRoutePattern , action . AttributeRouteInfo . Order )
140
+ {
141
+ DisplayName = action . DisplayName ,
142
+ } ;
143
+ AddActionDataToBuilder (
144
+ builder ,
113
145
routeNames ,
114
146
action ,
115
- updatedRoutePattern ,
116
147
action . AttributeRouteInfo . Name ,
117
- action . AttributeRouteInfo . Order ,
118
148
dataTokens : null ,
119
149
action . AttributeRouteInfo . SuppressLinkGeneration ,
120
150
action . AttributeRouteInfo . SuppressPathMatching ,
121
151
conventions ,
122
152
perRouteConventions : Array . Empty < Action < EndpointBuilder > > ( ) ) ;
123
- endpoints . Add ( endpoint ) ;
153
+ endpoints . Add ( builder . Build ( ) ) ;
124
154
}
125
155
}
126
156
@@ -262,49 +292,17 @@ private static (RoutePattern resolvedRoutePattern, IDictionary<string, string> r
262
292
return ( attributeRoutePattern , resolvedRequiredValues ?? action . RouteValues ) ;
263
293
}
264
294
265
- private RouteEndpoint CreateEndpoint (
295
+ private void AddActionDataToBuilder (
296
+ EndpointBuilder builder ,
266
297
HashSet < string > routeNames ,
267
298
ActionDescriptor action ,
268
- RoutePattern routePattern ,
269
299
string routeName ,
270
- int order ,
271
300
RouteValueDictionary dataTokens ,
272
301
bool suppressLinkGeneration ,
273
302
bool suppressPathMatching ,
274
303
IReadOnlyList < Action < EndpointBuilder > > conventions ,
275
304
IReadOnlyList < Action < EndpointBuilder > > perRouteConventions )
276
305
{
277
-
278
- // We don't want to close over the retrieve the Invoker Factory in ActionEndpointFactory as
279
- // that creates cycles in DI. Since we're creating this delegate at startup time
280
- // we don't want to create all of the things we use at runtime until the action
281
- // actually matches.
282
- //
283
- // The request delegate is already a closure here because we close over
284
- // the action descriptor.
285
- IActionInvokerFactory invokerFactory = null ;
286
-
287
- RequestDelegate requestDelegate = ( context ) =>
288
- {
289
- var routeData = new RouteData ( ) ;
290
- routeData . PushState ( router : null , context . Request . RouteValues , dataTokens ) ;
291
-
292
- var actionContext = new ActionContext ( context , routeData , action ) ;
293
-
294
- if ( invokerFactory == null )
295
- {
296
- invokerFactory = context . RequestServices . GetRequiredService < IActionInvokerFactory > ( ) ;
297
- }
298
-
299
- var invoker = invokerFactory . CreateInvoker ( actionContext ) ;
300
- return invoker . InvokeAsync ( ) ;
301
- } ;
302
-
303
- var builder = new RouteEndpointBuilder ( requestDelegate , routePattern , order )
304
- {
305
- DisplayName = action . DisplayName ,
306
- } ;
307
-
308
306
// Add action metadata first so it has a low precedence
309
307
if ( action . EndpointMetadata != null )
310
308
{
@@ -399,8 +397,47 @@ private RouteEndpoint CreateEndpoint(
399
397
{
400
398
perRouteConventions [ i ] ( builder ) ;
401
399
}
400
+ }
401
+
402
+ private static RequestDelegate CreateRequestDelegate ( )
403
+ {
404
+ // We don't want to close over the retrieve the Invoker Factory in ActionEndpointFactory as
405
+ // that creates cycles in DI. Since we're creating this delegate at startup time
406
+ // we don't want to create all of the things we use at runtime until the action
407
+ // actually matches.
408
+ //
409
+ // The request delegate is already a closure here because we close over
410
+ // the action descriptor.
411
+ IActionInvokerFactory invokerFactory = null ;
412
+
413
+ return ( context ) =>
414
+ {
415
+ var endpoint = context . GetEndpoint ( ) ;
416
+ var dataTokens = endpoint . Metadata . GetMetadata < IDataTokensMetadata > ( ) ;
402
417
403
- return ( RouteEndpoint ) builder . Build ( ) ;
418
+ var routeData = new RouteData ( ) ;
419
+ routeData . PushState ( router : null , context . Request . RouteValues , new RouteValueDictionary ( dataTokens ? . DataTokens ) ) ;
420
+
421
+ // Don't close over the ActionDescriptor, that's not valid for pages.
422
+ var action = endpoint . Metadata . GetMetadata < ActionDescriptor > ( ) ;
423
+ var actionContext = new ActionContext ( context , routeData , action ) ;
424
+
425
+ if ( invokerFactory == null )
426
+ {
427
+ invokerFactory = context . RequestServices . GetRequiredService < IActionInvokerFactory > ( ) ;
428
+ }
429
+
430
+ var invoker = invokerFactory . CreateInvoker ( actionContext ) ;
431
+ return invoker . InvokeAsync ( ) ;
432
+ } ;
433
+ }
434
+
435
+ private class InertEndpointBuilder : EndpointBuilder
436
+ {
437
+ public override Endpoint Build ( )
438
+ {
439
+ return new Endpoint ( RequestDelegate , new EndpointMetadataCollection ( Metadata ) , DisplayName ) ;
440
+ }
404
441
}
405
442
}
406
443
}
0 commit comments