@@ -23,11 +23,6 @@ namespace JsonApiDotNetCore.Middleware
23
23
public sealed class CurrentRequestMiddleware
24
24
{
25
25
private readonly RequestDelegate _next ;
26
- private HttpContext _httpContext ;
27
- private IJsonApiOptions _options ;
28
- private ICurrentRequest _currentRequest ;
29
- private IResourceGraph _resourceGraph ;
30
- private RouteValueDictionary _routeValues ;
31
26
32
27
public CurrentRequestMiddleware ( RequestDelegate next )
33
28
{
@@ -40,47 +35,44 @@ public async Task Invoke(HttpContext httpContext,
40
35
ICurrentRequest currentRequest ,
41
36
IResourceGraph resourceGraph )
42
37
{
43
- _httpContext = httpContext ;
44
- _options = options ;
45
- _currentRequest = currentRequest ;
46
- _resourceGraph = resourceGraph ;
47
- _routeValues = httpContext . GetRouteData ( ) . Values ;
38
+ var routeValues = httpContext . GetRouteData ( ) . Values ;
48
39
49
- var resourceContext = CreateResourceContext ( controllerResourceMapping ) ;
40
+ var resourceContext = CreateResourceContext ( routeValues , controllerResourceMapping , resourceGraph ) ;
50
41
if ( resourceContext != null )
51
42
{
52
- if ( ! await ValidateContentTypeHeaderAsync ( ) || ! await ValidateAcceptHeaderAsync ( ) )
43
+ if ( ! await ValidateContentTypeHeaderAsync ( httpContext , options . SerializerSettings ) ||
44
+ ! await ValidateAcceptHeaderAsync ( httpContext , options . SerializerSettings ) )
53
45
{
54
46
return ;
55
47
}
56
48
57
- SetupCurrentRequest ( resourceContext ) ;
49
+ SetupCurrentRequest ( currentRequest , resourceContext , routeValues , options , httpContext . Request ) ;
58
50
59
- _httpContext . SetJsonApiRequest ( ) ;
51
+ httpContext . SetJsonApiRequest ( ) ;
60
52
}
61
53
62
54
await _next ( httpContext ) ;
63
55
}
64
56
65
- private ResourceContext CreateResourceContext ( IControllerResourceMapping controllerResourceMapping )
57
+ private static ResourceContext CreateResourceContext ( RouteValueDictionary routeValues ,
58
+ IControllerResourceMapping controllerResourceMapping , IResourceContextProvider resourceGraph )
66
59
{
67
- var controllerName = ( string ) _routeValues [ "controller" ] ;
60
+ var controllerName = ( string ) routeValues [ "controller" ] ;
68
61
if ( controllerName == null )
69
62
{
70
63
return null ;
71
64
}
72
65
73
66
var resourceType = controllerResourceMapping . GetAssociatedResource ( controllerName ) ;
74
- var resourceContext = _resourceGraph . GetResourceContext ( resourceType ) ;
75
- return resourceContext ;
67
+ return resourceGraph . GetResourceContext ( resourceType ) ;
76
68
}
77
69
78
- private async Task < bool > ValidateContentTypeHeaderAsync ( )
70
+ private static async Task < bool > ValidateContentTypeHeaderAsync ( HttpContext httpContext , JsonSerializerSettings serializerSettings )
79
71
{
80
- var contentType = _httpContext . Request . ContentType ;
72
+ var contentType = httpContext . Request . ContentType ;
81
73
if ( contentType != null && contentType != HeaderConstants . MediaType )
82
74
{
83
- await FlushResponseAsync ( _httpContext , new Error ( HttpStatusCode . UnsupportedMediaType )
75
+ await FlushResponseAsync ( httpContext . Response , serializerSettings , new Error ( HttpStatusCode . UnsupportedMediaType )
84
76
{
85
77
Title = "The specified Content-Type header value is not supported." ,
86
78
Detail = $ "Please specify '{ HeaderConstants . MediaType } ' instead of '{ contentType } ' for the Content-Type header value."
@@ -91,9 +83,9 @@ private async Task<bool> ValidateContentTypeHeaderAsync()
91
83
return true ;
92
84
}
93
85
94
- private async Task < bool > ValidateAcceptHeaderAsync ( )
86
+ private static async Task < bool > ValidateAcceptHeaderAsync ( HttpContext httpContext , JsonSerializerSettings serializerSettings )
95
87
{
96
- StringValues acceptHeaders = _httpContext . Request . Headers [ "Accept" ] ;
88
+ StringValues acceptHeaders = httpContext . Request . Headers [ "Accept" ] ;
97
89
if ( ! acceptHeaders . Any ( ) || acceptHeaders == HeaderConstants . MediaType )
98
90
{
99
91
return true ;
@@ -121,7 +113,7 @@ private async Task<bool> ValidateAcceptHeaderAsync()
121
113
122
114
if ( ! seenCompatibleMediaType )
123
115
{
124
- await FlushResponseAsync ( _httpContext , new Error ( HttpStatusCode . NotAcceptable )
116
+ await FlushResponseAsync ( httpContext . Response , serializerSettings , new Error ( HttpStatusCode . NotAcceptable )
125
117
{
126
118
Title = "The specified Accept header value does not contain any supported media types." ,
127
119
Detail = $ "Please include '{ HeaderConstants . MediaType } ' in the Accept header values."
@@ -132,11 +124,11 @@ private async Task<bool> ValidateAcceptHeaderAsync()
132
124
return true ;
133
125
}
134
126
135
- private async Task FlushResponseAsync ( HttpContext context , Error error )
127
+ private static async Task FlushResponseAsync ( HttpResponse httpResponse , JsonSerializerSettings serializerSettings , Error error )
136
128
{
137
- context . Response . StatusCode = ( int ) error . StatusCode ;
129
+ httpResponse . StatusCode = ( int ) error . StatusCode ;
138
130
139
- JsonSerializer serializer = JsonSerializer . CreateDefault ( _options . SerializerSettings ) ;
131
+ JsonSerializer serializer = JsonSerializer . CreateDefault ( serializerSettings ) ;
140
132
serializer . ApplyErrorSettings ( ) ;
141
133
142
134
// https://github.com/JamesNK/Newtonsoft.Json/issues/1193
@@ -149,78 +141,81 @@ private async Task FlushResponseAsync(HttpContext context, Error error)
149
141
}
150
142
151
143
stream . Seek ( 0 , SeekOrigin . Begin ) ;
152
- await stream . CopyToAsync ( context . Response . Body ) ;
144
+ await stream . CopyToAsync ( httpResponse . Body ) ;
153
145
}
154
146
155
- context . Response . Body . Flush ( ) ;
147
+ httpResponse . Body . Flush ( ) ;
156
148
}
157
149
158
- private void SetupCurrentRequest ( ResourceContext resourceContext )
150
+ private static void SetupCurrentRequest ( ICurrentRequest currentRequest , ResourceContext resourceContext ,
151
+ RouteValueDictionary routeValues , IJsonApiOptions options , HttpRequest httpRequest )
159
152
{
160
- _currentRequest . SetRequestResource ( resourceContext ) ;
161
- _currentRequest . BaseId = GetBaseId ( ) ;
162
- _currentRequest . BasePath = GetBasePath ( resourceContext . ResourceName ) ;
163
- _currentRequest . IsRelationshipPath = GetIsRelationshipPath ( ) ;
164
- _currentRequest . RelationshipId = GetRelationshipId ( ) ;
153
+ currentRequest . SetRequestResource ( resourceContext ) ;
154
+ currentRequest . BaseId = GetBaseId ( routeValues ) ;
155
+ currentRequest . BasePath = GetBasePath ( resourceContext . ResourceName , options , httpRequest ) ;
156
+ currentRequest . IsRelationshipPath = GetIsRelationshipPath ( routeValues ) ;
157
+ currentRequest . RelationshipId = GetRelationshipId ( currentRequest . IsRelationshipPath , httpRequest . Path . Value , options . Namespace ) ;
165
158
166
- if ( _routeValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
159
+ if ( routeValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
167
160
{
168
- _currentRequest . RequestRelationship = resourceContext . Relationships . SingleOrDefault ( r => r . PublicRelationshipName == ( string ) relationshipName ) ;
161
+ currentRequest . RequestRelationship =
162
+ resourceContext . Relationships . SingleOrDefault ( relationship =>
163
+ relationship . PublicRelationshipName == ( string ) relationshipName ) ;
169
164
}
170
165
}
171
166
172
- private string GetBaseId ( )
167
+ private static string GetBaseId ( RouteValueDictionary routeValues )
173
168
{
174
- return _routeValues . TryGetValue ( "id" , out var id ) ? ( string ) id : null ;
169
+ return routeValues . TryGetValue ( "id" , out var id ) ? ( string ) id : null ;
175
170
}
176
171
177
- private string GetBasePath ( string resourceName )
172
+ private static string GetBasePath ( string resourceName , IJsonApiOptions options , HttpRequest httpRequest )
178
173
{
179
- if ( _options . RelativeLinks )
174
+ if ( options . RelativeLinks )
180
175
{
181
- return _options . Namespace ;
176
+ return options . Namespace ;
182
177
}
183
178
184
- var customRoute = GetCustomRoute ( _httpContext . Request . Path . Value , resourceName ) ;
185
- var toReturn = $ "{ _httpContext . Request . Scheme } ://{ _httpContext . Request . Host } /{ _options . Namespace } ";
179
+ var customRoute = GetCustomRoute ( httpRequest . Path . Value , resourceName , options . Namespace ) ;
180
+ var toReturn = $ "{ httpRequest . Scheme } ://{ httpRequest . Host } /{ options . Namespace } ";
186
181
if ( customRoute != null )
187
182
{
188
183
toReturn += $ "/{ customRoute } ";
189
184
}
190
185
return toReturn ;
191
186
}
192
187
193
- private string GetCustomRoute ( string path , string resourceName )
188
+ private static string GetCustomRoute ( string path , string resourceName , string apiNamespace )
194
189
{
195
190
var trimmedComponents = path . Trim ( '/' ) . Split ( '/' ) . ToList ( ) ;
196
191
var resourceNameIndex = trimmedComponents . FindIndex ( c => c == resourceName ) ;
197
192
var newComponents = trimmedComponents . Take ( resourceNameIndex ) . ToArray ( ) ;
198
193
var customRoute = string . Join ( '/' , newComponents ) ;
199
- return customRoute == _options . Namespace ? null : customRoute ;
194
+ return customRoute == apiNamespace ? null : customRoute ;
200
195
}
201
196
202
- private bool GetIsRelationshipPath ( )
197
+ private static bool GetIsRelationshipPath ( RouteValueDictionary routeValues )
203
198
{
204
- var actionName = ( string ) _routeValues [ "action" ] ;
199
+ var actionName = ( string ) routeValues [ "action" ] ;
205
200
return actionName . ToLowerInvariant ( ) . Contains ( "relationships" ) ;
206
201
}
207
202
208
- private string GetRelationshipId ( )
203
+ private static string GetRelationshipId ( bool currentRequestIsRelationshipPath , string requestPath ,
204
+ string apiNamespace )
209
205
{
210
- if ( ! _currentRequest . IsRelationshipPath )
206
+ if ( ! currentRequestIsRelationshipPath )
211
207
{
212
208
return null ;
213
209
}
214
210
215
- var components = SplitCurrentPath ( ) ;
211
+ var components = SplitCurrentPath ( requestPath , apiNamespace ) ;
216
212
return components . ElementAtOrDefault ( 4 ) ;
217
213
}
218
214
219
- private string [ ] SplitCurrentPath ( )
215
+ private static IEnumerable < string > SplitCurrentPath ( string requestPath , string apiNamespace )
220
216
{
221
- var path = _httpContext . Request . Path . Value ;
222
- var ns = $ "/{ _options . Namespace } ";
223
- var nonNameSpaced = path . Replace ( ns , "" ) ;
217
+ var namespacePrefix = $ "/{ apiNamespace } ";
218
+ var nonNameSpaced = requestPath . Replace ( namespacePrefix , "" ) ;
224
219
nonNameSpaced = nonNameSpaced . Trim ( '/' ) ;
225
220
return nonNameSpaced . Split ( '/' ) ;
226
221
}
0 commit comments