8
8
using Microsoft . AspNetCore . Builder ;
9
9
using Microsoft . AspNetCore . Http ;
10
10
using Microsoft . AspNetCore . Http . Features ;
11
+ using Microsoft . AspNetCore . Mvc ;
11
12
using Microsoft . AspNetCore . Routing ;
13
+ using Microsoft . Extensions . DependencyInjection ;
14
+ using Microsoft . Extensions . Options ;
15
+ using Utilities . Extensions ;
12
16
13
17
/// <summary>
14
18
/// Mock of <see cref="IApplicationBuilder"/>. Used for extracting registered routes.
@@ -20,6 +24,8 @@ public class ApplicationBuilderMock : IApplicationBuilder
20
24
21
25
private readonly IList < Func < RequestDelegate , RequestDelegate > > components = new List < Func < RequestDelegate , RequestDelegate > > ( ) ;
22
26
27
+ private bool endpointsEnabled = false ;
28
+
23
29
/// <summary>
24
30
/// Initializes a new instance of the <see cref="ApplicationBuilderMock"/> class.
25
31
/// </summary>
@@ -33,13 +39,15 @@ public ApplicationBuilderMock(IServiceProvider serviceProvider)
33
39
34
40
this . Routes = new RouteCollection ( ) ;
35
41
this . ApplicationServices = serviceProvider ;
42
+
43
+ this . CheckForEndpointRouting ( serviceProvider ) ;
36
44
}
37
45
38
46
/// <summary>
39
47
/// Initializes a new instance of the <see cref="ApplicationBuilderMock"/> class.
40
48
/// </summary>
41
49
/// <param name="builder">Application builder to copy properties from.</param>
42
- public ApplicationBuilderMock ( IApplicationBuilder builder )
50
+ public ApplicationBuilderMock ( IApplicationBuilder builder )
43
51
=> this . Properties = builder . Properties ;
44
52
45
53
/// <summary>
@@ -69,15 +77,16 @@ public IServiceProvider ApplicationServices
69
77
/// </summary>
70
78
/// <value>Result of <see cref="RouteCollection"/> type.</value>
71
79
public RouteCollection Routes { get ; set ; }
72
-
80
+
73
81
/// <summary>
74
82
/// Extracts registered routes from the provided middleware, if such are found.
75
83
/// </summary>
76
84
/// <param name="middleware">Middleware delegate.</param>
77
85
/// <returns>The same <see cref="IApplicationBuilder"/>.</returns>
78
86
public IApplicationBuilder Use ( Func < RequestDelegate , RequestDelegate > middleware )
79
87
{
80
- this . ExtractRoutes ( middleware ) ;
88
+ this . ExtractEndpointRoutes ( middleware ) ;
89
+ this . ExtractLegacyRoutes ( middleware ) ;
81
90
82
91
this . components . Add ( middleware ) ;
83
92
return this ;
@@ -109,12 +118,89 @@ public RequestDelegate Build()
109
118
return app ;
110
119
}
111
120
112
- private T GetProperty < T > ( string key )
113
- => this . Properties . TryGetValue ( key , out var value ) ? ( T ) value : default ( T ) ;
121
+ private T GetProperty < T > ( string key )
122
+ => this . Properties . TryGetValue ( key , out var value ) ? ( T ) value : default ;
114
123
115
124
private void SetProperty < T > ( string key , T value ) => this . Properties [ key ] = value ;
116
125
117
- private void ExtractRoutes ( Func < RequestDelegate , RequestDelegate > middleware )
126
+ private void CheckForEndpointRouting ( IServiceProvider serviceProvider )
127
+ {
128
+ var options = serviceProvider . GetService < IOptions < MvcOptions > > ( ) ? . Value ;
129
+
130
+ this . endpointsEnabled = options ? . EnableEndpointRouting ?? false ;
131
+ }
132
+
133
+ private void ExtractEndpointRoutes ( Func < RequestDelegate , RequestDelegate > middleware )
134
+ {
135
+ var middlewareTypeField = middleware
136
+ . Target
137
+ . GetType ( )
138
+ . GetTypeInfo ( )
139
+ . DeclaredFields
140
+ . FirstOrDefault ( m => m . Name == "middleware" ) ;
141
+
142
+ if ( ! ( middlewareTypeField ? . GetValue ( middleware . Target ) is Type middlewareType )
143
+ || middlewareType . Name != "EndpointMiddleware" )
144
+ {
145
+ return ;
146
+ }
147
+
148
+ var routeOptions = this . ApplicationServices . GetService < IOptions < RouteOptions > > ( ) ? . Value ;
149
+
150
+ if ( routeOptions == null )
151
+ {
152
+ return ;
153
+ }
154
+
155
+ var routeBuilder = new RouteBuilder ( this )
156
+ {
157
+ DefaultHandler = new RouteHandler ( c => Task . CompletedTask )
158
+ } ;
159
+
160
+ var endpointDataSources = routeOptions . Exposed ( ) . EndpointDataSources ;
161
+
162
+ foreach ( EndpointDataSource endpointDataSource in endpointDataSources )
163
+ {
164
+ var routeEndpoints = endpointDataSource
165
+ . Endpoints
166
+ . OfType < RouteEndpoint > ( )
167
+ . Where ( e => e . DisplayName . StartsWith ( "Route: " ) )
168
+ . OrderBy ( e => e . Order ) ;
169
+
170
+ foreach ( var routeEndpoint in routeEndpoints )
171
+ {
172
+ var routeName = routeEndpoint
173
+ . Metadata
174
+ . OfType < RouteNameMetadata > ( )
175
+ . FirstOrDefault ( )
176
+ ? . RouteName ;
177
+
178
+ if ( routeName == null )
179
+ {
180
+ return ;
181
+ }
182
+
183
+ routeBuilder . MapRoute (
184
+ name : routeName ,
185
+ routeEndpoint . RoutePattern . RawText ) ;
186
+ }
187
+ }
188
+
189
+ var attributeRoutingType = WebFramework . Internals . AttributeRouting ;
190
+ var createAttributeMegaRouteMethod = attributeRoutingType . GetMethod ( "CreateAttributeMegaRoute" ) ;
191
+ var router = ( IRouter ) createAttributeMegaRouteMethod . Invoke ( null , new [ ] { this . ApplicationServices } ) ;
192
+
193
+ routeBuilder . Routes . Insert ( 0 , router ) ;
194
+
195
+ var routes = routeBuilder . Routes ;
196
+
197
+ for ( int i = 0 ; i < routes . Count ; i ++ )
198
+ {
199
+ this . Routes . Add ( routes [ i ] ) ;
200
+ }
201
+ }
202
+
203
+ private void ExtractLegacyRoutes ( Func < RequestDelegate , RequestDelegate > middleware )
118
204
{
119
205
var middlewareArguments = middleware
120
206
. Target
0 commit comments