@@ -22,100 +22,94 @@ namespace JsonApiDotNetCore.Middleware
22
22
public sealed class CurrentRequestMiddleware
23
23
{
24
24
private readonly RequestDelegate _next ;
25
- private HttpContext _httpContext ;
26
- private ICurrentRequest _currentRequest ;
27
- private IResourceGraph _resourceGraph ;
28
- private IJsonApiOptions _options ;
29
- private RouteValueDictionary _routeValues ;
30
- private IControllerResourceMapping _controllerResourceMapping ;
31
25
32
26
public CurrentRequestMiddleware ( RequestDelegate next )
33
27
{
34
28
_next = next ;
35
29
}
36
30
37
31
public async Task Invoke ( HttpContext httpContext ,
38
- IControllerResourceMapping controllerResourceMapping ,
39
- IJsonApiOptions options ,
40
- ICurrentRequest currentRequest ,
41
- IResourceGraph resourceGraph )
32
+ IControllerResourceMapping controllerResourceMapping ,
33
+ IJsonApiOptions options ,
34
+ ICurrentRequest currentRequest ,
35
+ IResourceGraph resourceGraph )
42
36
{
43
- _httpContext = httpContext ;
44
- _currentRequest = currentRequest ;
45
- _controllerResourceMapping = controllerResourceMapping ;
46
- _resourceGraph = resourceGraph ;
47
- _options = options ;
48
- _routeValues = httpContext . GetRouteData ( ) . Values ;
49
- var requestResource = GetCurrentEntity ( ) ;
37
+ var routeValues = httpContext . GetRouteData ( ) . Values ;
38
+ var requestContext = new RequestContext ( httpContext , currentRequest , resourceGraph , options , routeValues ,
39
+ controllerResourceMapping ) ;
40
+
41
+ var requestResource = GetCurrentEntity ( requestContext ) ;
50
42
if ( requestResource != null )
51
43
{
52
- _currentRequest . SetRequestResource ( requestResource ) ;
53
- _currentRequest . IsRelationshipPath = PathIsRelationship ( ) ;
54
- _currentRequest . BasePath = GetBasePath ( requestResource . ResourceName ) ;
55
- _currentRequest . BaseId = GetBaseId ( ) ;
56
- _currentRequest . RelationshipId = GetRelationshipId ( ) ;
44
+ requestContext . CurrentRequest . SetRequestResource ( requestResource ) ;
45
+ requestContext . CurrentRequest . IsRelationshipPath = PathIsRelationship ( requestContext . RouteValues ) ;
46
+ requestContext . CurrentRequest . BasePath = GetBasePath ( requestContext , requestResource . ResourceName ) ;
47
+ requestContext . CurrentRequest . BaseId = GetBaseId ( requestContext . RouteValues ) ;
48
+ requestContext . CurrentRequest . RelationshipId = GetRelationshipId ( requestContext ) ;
57
49
}
58
50
59
- if ( await IsValidAsync ( ) )
51
+ if ( await IsValidAsync ( requestContext ) )
60
52
{
61
- await _next ( httpContext ) ;
53
+ await _next ( requestContext . HttpContext ) ;
62
54
}
63
55
}
64
56
65
- private string GetBaseId ( )
57
+ private static string GetBaseId ( RouteValueDictionary routeValues )
66
58
{
67
- if ( _routeValues . TryGetValue ( "id" , out object stringId ) )
59
+ if ( routeValues . TryGetValue ( "id" , out object stringId ) )
68
60
{
69
61
return ( string ) stringId ;
70
62
}
71
63
72
64
return null ;
73
65
}
74
- private string GetRelationshipId ( )
66
+
67
+ private static string GetRelationshipId ( RequestContext requestContext )
75
68
{
76
- if ( ! _currentRequest . IsRelationshipPath )
69
+ if ( ! requestContext . CurrentRequest . IsRelationshipPath )
77
70
{
78
71
return null ;
79
72
}
80
- var components = SplitCurrentPath ( ) ;
73
+ var components = SplitCurrentPath ( requestContext ) ;
81
74
var toReturn = components . ElementAtOrDefault ( 4 ) ;
82
75
83
76
return toReturn ;
84
77
}
85
- private string [ ] SplitCurrentPath ( )
78
+
79
+ private static string [ ] SplitCurrentPath ( RequestContext requestContext )
86
80
{
87
- var path = _httpContext . Request . Path . Value ;
88
- var ns = $ "/{ _options . Namespace } ";
81
+ var path = requestContext . HttpContext . Request . Path . Value ;
82
+ var ns = $ "/{ requestContext . Options . Namespace } ";
89
83
var nonNameSpaced = path . Replace ( ns , "" ) ;
90
84
nonNameSpaced = nonNameSpaced . Trim ( '/' ) ;
91
85
var individualComponents = nonNameSpaced . Split ( '/' ) ;
92
86
return individualComponents ;
93
87
}
94
88
95
- private string GetBasePath ( string resourceName = null )
89
+ private static string GetBasePath ( RequestContext requestContext , string resourceName = null )
96
90
{
97
- var r = _httpContext . Request ;
98
- if ( _options . RelativeLinks )
91
+ var r = requestContext . HttpContext . Request ;
92
+ if ( requestContext . Options . RelativeLinks )
99
93
{
100
- return _options . Namespace ;
94
+ return requestContext . Options . Namespace ;
101
95
}
102
96
103
- var customRoute = GetCustomRoute ( r . Path . Value , resourceName ) ;
104
- var toReturn = $ "{ r . Scheme } ://{ r . Host } /{ _options . Namespace } ";
97
+ var customRoute = GetCustomRoute ( requestContext . Options , r . Path . Value , resourceName ) ;
98
+ var toReturn = $ "{ r . Scheme } ://{ r . Host } /{ requestContext . Options . Namespace } ";
105
99
if ( customRoute != null )
106
100
{
107
101
toReturn += $ "/{ customRoute } ";
108
102
}
109
103
return toReturn ;
110
104
}
111
105
112
- private object GetCustomRoute ( string path , string resourceName )
106
+ private static object GetCustomRoute ( IJsonApiOptions options , string path , string resourceName )
113
107
{
114
108
var trimmedComponents = path . Trim ( '/' ) . Split ( '/' ) . ToList ( ) ;
115
109
var resourceNameIndex = trimmedComponents . FindIndex ( c => c == resourceName ) ;
116
110
var newComponents = trimmedComponents . Take ( resourceNameIndex ) . ToArray ( ) ;
117
111
var customRoute = string . Join ( '/' , newComponents ) ;
118
- if ( customRoute == _options . Namespace )
112
+ if ( customRoute == options . Namespace )
119
113
{
120
114
return null ;
121
115
}
@@ -125,23 +119,23 @@ private object GetCustomRoute(string path, string resourceName)
125
119
}
126
120
}
127
121
128
- private bool PathIsRelationship ( )
122
+ private static bool PathIsRelationship ( RouteValueDictionary routeValues )
129
123
{
130
- var actionName = ( string ) _routeValues [ "action" ] ;
124
+ var actionName = ( string ) routeValues [ "action" ] ;
131
125
return actionName . ToLowerInvariant ( ) . Contains ( "relationships" ) ;
132
126
}
133
127
134
- private async Task < bool > IsValidAsync ( )
128
+ private static async Task < bool > IsValidAsync ( RequestContext requestContext )
135
129
{
136
- return await IsValidContentTypeHeaderAsync ( _httpContext ) && await IsValidAcceptHeaderAsync ( _httpContext ) ;
130
+ return await IsValidContentTypeHeaderAsync ( requestContext ) && await IsValidAcceptHeaderAsync ( requestContext ) ;
137
131
}
138
132
139
- private async Task < bool > IsValidContentTypeHeaderAsync ( HttpContext context )
133
+ private static async Task < bool > IsValidContentTypeHeaderAsync ( RequestContext requestContext )
140
134
{
141
- var contentType = context . Request . ContentType ;
135
+ var contentType = requestContext . HttpContext . Request . ContentType ;
142
136
if ( contentType != null && ContainsMediaTypeParameters ( contentType ) )
143
137
{
144
- await FlushResponseAsync ( context , new Error ( HttpStatusCode . UnsupportedMediaType )
138
+ await FlushResponseAsync ( requestContext , new Error ( HttpStatusCode . UnsupportedMediaType )
145
139
{
146
140
Title = "The specified Content-Type header value is not supported." ,
147
141
Detail = $ "Please specify '{ HeaderConstants . ContentType } ' for the Content-Type header value."
@@ -152,9 +146,9 @@ private async Task<bool> IsValidContentTypeHeaderAsync(HttpContext context)
152
146
return true ;
153
147
}
154
148
155
- private async Task < bool > IsValidAcceptHeaderAsync ( HttpContext context )
149
+ private static async Task < bool > IsValidAcceptHeaderAsync ( RequestContext requestContext )
156
150
{
157
- if ( context . Request . Headers . TryGetValue ( HeaderConstants . AcceptHeader , out StringValues acceptHeaders ) == false )
151
+ if ( requestContext . HttpContext . Request . Headers . TryGetValue ( HeaderConstants . AcceptHeader , out StringValues acceptHeaders ) == false )
158
152
return true ;
159
153
160
154
foreach ( var acceptHeader in acceptHeaders )
@@ -164,7 +158,7 @@ private async Task<bool> IsValidAcceptHeaderAsync(HttpContext context)
164
158
continue ;
165
159
}
166
160
167
- await FlushResponseAsync ( context , new Error ( HttpStatusCode . NotAcceptable )
161
+ await FlushResponseAsync ( requestContext , new Error ( HttpStatusCode . NotAcceptable )
168
162
{
169
163
Title = "The specified Accept header value is not supported." ,
170
164
Detail = $ "Please specify '{ HeaderConstants . ContentType } ' for the Accept header value."
@@ -195,11 +189,11 @@ private static bool ContainsMediaTypeParameters(string mediaType)
195
189
) ;
196
190
}
197
191
198
- private async Task FlushResponseAsync ( HttpContext context , Error error )
192
+ private static async Task FlushResponseAsync ( RequestContext requestContext , Error error )
199
193
{
200
- context . Response . StatusCode = ( int ) error . StatusCode ;
194
+ requestContext . HttpContext . Response . StatusCode = ( int ) error . StatusCode ;
201
195
202
- JsonSerializer serializer = JsonSerializer . CreateDefault ( _options . SerializerSettings ) ;
196
+ JsonSerializer serializer = JsonSerializer . CreateDefault ( requestContext . Options . SerializerSettings ) ;
203
197
serializer . ApplyErrorSettings ( ) ;
204
198
205
199
// https://github.com/JamesNK/Newtonsoft.Json/issues/1193
@@ -212,34 +206,59 @@ private async Task FlushResponseAsync(HttpContext context, Error error)
212
206
}
213
207
214
208
stream . Seek ( 0 , SeekOrigin . Begin ) ;
215
- await stream . CopyToAsync ( context . Response . Body ) ;
209
+ await stream . CopyToAsync ( requestContext . HttpContext . Response . Body ) ;
216
210
}
217
211
218
- context . Response . Body . Flush ( ) ;
212
+ requestContext . HttpContext . Response . Body . Flush ( ) ;
219
213
}
220
214
221
215
/// <summary>
222
216
/// Gets the current entity that we need for serialization and deserialization.
223
217
/// </summary>
224
218
/// <returns></returns>
225
- private ResourceContext GetCurrentEntity ( )
219
+ private static ResourceContext GetCurrentEntity ( RequestContext requestContext )
226
220
{
227
- var controllerName = ( string ) _routeValues [ "controller" ] ;
221
+ var controllerName = ( string ) requestContext . RouteValues [ "controller" ] ;
228
222
if ( controllerName == null )
229
223
{
230
224
return null ;
231
225
}
232
- var resourceType = _controllerResourceMapping . GetAssociatedResource ( controllerName ) ;
233
- var requestResource = _resourceGraph . GetResourceContext ( resourceType ) ;
226
+ var resourceType = requestContext . ControllerResourceMapping . GetAssociatedResource ( controllerName ) ;
227
+ var requestResource = requestContext . ResourceGraph . GetResourceContext ( resourceType ) ;
234
228
if ( requestResource == null )
235
229
{
236
230
return null ;
237
231
}
238
- if ( _routeValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
232
+ if ( requestContext . RouteValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
239
233
{
240
- _currentRequest . RequestRelationship = requestResource . Relationships . SingleOrDefault ( r => r . PublicRelationshipName == ( string ) relationshipName ) ;
234
+ requestContext . CurrentRequest . RequestRelationship = requestResource . Relationships . SingleOrDefault ( r => r . PublicRelationshipName == ( string ) relationshipName ) ;
241
235
}
242
236
return requestResource ;
243
237
}
238
+
239
+ private sealed class RequestContext
240
+ {
241
+ public HttpContext HttpContext { get ; }
242
+ public ICurrentRequest CurrentRequest { get ; }
243
+ public IResourceGraph ResourceGraph { get ; }
244
+ public IJsonApiOptions Options { get ; }
245
+ public RouteValueDictionary RouteValues { get ; }
246
+ public IControllerResourceMapping ControllerResourceMapping { get ; }
247
+
248
+ public RequestContext ( HttpContext httpContext ,
249
+ ICurrentRequest currentRequest ,
250
+ IResourceGraph resourceGraph ,
251
+ IJsonApiOptions options ,
252
+ RouteValueDictionary routeValues ,
253
+ IControllerResourceMapping controllerResourceMapping )
254
+ {
255
+ HttpContext = httpContext ;
256
+ CurrentRequest = currentRequest ;
257
+ ResourceGraph = resourceGraph ;
258
+ Options = options ;
259
+ RouteValues = routeValues ;
260
+ ControllerResourceMapping = controllerResourceMapping ;
261
+ }
262
+ }
244
263
}
245
264
}
0 commit comments