@@ -22,100 +22,94 @@ namespace JsonApiDotNetCore.Middleware
2222 public sealed class CurrentRequestMiddleware
2323 {
2424 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 ;
3125
3226 public CurrentRequestMiddleware ( RequestDelegate next )
3327 {
3428 _next = next ;
3529 }
3630
3731 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 )
4236 {
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 ) ;
5042 if ( requestResource != null )
5143 {
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 ) ;
5749 }
5850
59- if ( await IsValidAsync ( ) )
51+ if ( await IsValidAsync ( requestContext ) )
6052 {
61- await _next ( httpContext ) ;
53+ await _next ( requestContext . HttpContext ) ;
6254 }
6355 }
6456
65- private string GetBaseId ( )
57+ private static string GetBaseId ( RouteValueDictionary routeValues )
6658 {
67- if ( _routeValues . TryGetValue ( "id" , out object stringId ) )
59+ if ( routeValues . TryGetValue ( "id" , out object stringId ) )
6860 {
6961 return ( string ) stringId ;
7062 }
7163
7264 return null ;
7365 }
74- private string GetRelationshipId ( )
66+
67+ private static string GetRelationshipId ( RequestContext requestContext )
7568 {
76- if ( ! _currentRequest . IsRelationshipPath )
69+ if ( ! requestContext . CurrentRequest . IsRelationshipPath )
7770 {
7871 return null ;
7972 }
80- var components = SplitCurrentPath ( ) ;
73+ var components = SplitCurrentPath ( requestContext ) ;
8174 var toReturn = components . ElementAtOrDefault ( 4 ) ;
8275
8376 return toReturn ;
8477 }
85- private string [ ] SplitCurrentPath ( )
78+
79+ private static string [ ] SplitCurrentPath ( RequestContext requestContext )
8680 {
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 } ";
8983 var nonNameSpaced = path . Replace ( ns , "" ) ;
9084 nonNameSpaced = nonNameSpaced . Trim ( '/' ) ;
9185 var individualComponents = nonNameSpaced . Split ( '/' ) ;
9286 return individualComponents ;
9387 }
9488
95- private string GetBasePath ( string resourceName = null )
89+ private static string GetBasePath ( RequestContext requestContext , string resourceName = null )
9690 {
97- var r = _httpContext . Request ;
98- if ( _options . RelativeLinks )
91+ var r = requestContext . HttpContext . Request ;
92+ if ( requestContext . Options . RelativeLinks )
9993 {
100- return _options . Namespace ;
94+ return requestContext . Options . Namespace ;
10195 }
10296
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 } ";
10599 if ( customRoute != null )
106100 {
107101 toReturn += $ "/{ customRoute } ";
108102 }
109103 return toReturn ;
110104 }
111105
112- private object GetCustomRoute ( string path , string resourceName )
106+ private static object GetCustomRoute ( IJsonApiOptions options , string path , string resourceName )
113107 {
114108 var trimmedComponents = path . Trim ( '/' ) . Split ( '/' ) . ToList ( ) ;
115109 var resourceNameIndex = trimmedComponents . FindIndex ( c => c == resourceName ) ;
116110 var newComponents = trimmedComponents . Take ( resourceNameIndex ) . ToArray ( ) ;
117111 var customRoute = string . Join ( '/' , newComponents ) ;
118- if ( customRoute == _options . Namespace )
112+ if ( customRoute == options . Namespace )
119113 {
120114 return null ;
121115 }
@@ -125,23 +119,23 @@ private object GetCustomRoute(string path, string resourceName)
125119 }
126120 }
127121
128- private bool PathIsRelationship ( )
122+ private static bool PathIsRelationship ( RouteValueDictionary routeValues )
129123 {
130- var actionName = ( string ) _routeValues [ "action" ] ;
124+ var actionName = ( string ) routeValues [ "action" ] ;
131125 return actionName . ToLowerInvariant ( ) . Contains ( "relationships" ) ;
132126 }
133127
134- private async Task < bool > IsValidAsync ( )
128+ private static async Task < bool > IsValidAsync ( RequestContext requestContext )
135129 {
136- return await IsValidContentTypeHeaderAsync ( _httpContext ) && await IsValidAcceptHeaderAsync ( _httpContext ) ;
130+ return await IsValidContentTypeHeaderAsync ( requestContext ) && await IsValidAcceptHeaderAsync ( requestContext ) ;
137131 }
138132
139- private async Task < bool > IsValidContentTypeHeaderAsync ( HttpContext context )
133+ private static async Task < bool > IsValidContentTypeHeaderAsync ( RequestContext requestContext )
140134 {
141- var contentType = context . Request . ContentType ;
135+ var contentType = requestContext . HttpContext . Request . ContentType ;
142136 if ( contentType != null && ContainsMediaTypeParameters ( contentType ) )
143137 {
144- await FlushResponseAsync ( context , new Error ( HttpStatusCode . UnsupportedMediaType )
138+ await FlushResponseAsync ( requestContext , new Error ( HttpStatusCode . UnsupportedMediaType )
145139 {
146140 Title = "The specified Content-Type header value is not supported." ,
147141 Detail = $ "Please specify '{ HeaderConstants . ContentType } ' for the Content-Type header value."
@@ -152,9 +146,9 @@ private async Task<bool> IsValidContentTypeHeaderAsync(HttpContext context)
152146 return true ;
153147 }
154148
155- private async Task < bool > IsValidAcceptHeaderAsync ( HttpContext context )
149+ private static async Task < bool > IsValidAcceptHeaderAsync ( RequestContext requestContext )
156150 {
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 )
158152 return true ;
159153
160154 foreach ( var acceptHeader in acceptHeaders )
@@ -164,7 +158,7 @@ private async Task<bool> IsValidAcceptHeaderAsync(HttpContext context)
164158 continue ;
165159 }
166160
167- await FlushResponseAsync ( context , new Error ( HttpStatusCode . NotAcceptable )
161+ await FlushResponseAsync ( requestContext , new Error ( HttpStatusCode . NotAcceptable )
168162 {
169163 Title = "The specified Accept header value is not supported." ,
170164 Detail = $ "Please specify '{ HeaderConstants . ContentType } ' for the Accept header value."
@@ -195,11 +189,11 @@ private static bool ContainsMediaTypeParameters(string mediaType)
195189 ) ;
196190 }
197191
198- private async Task FlushResponseAsync ( HttpContext context , Error error )
192+ private static async Task FlushResponseAsync ( RequestContext requestContext , Error error )
199193 {
200- context . Response . StatusCode = ( int ) error . StatusCode ;
194+ requestContext . HttpContext . Response . StatusCode = ( int ) error . StatusCode ;
201195
202- JsonSerializer serializer = JsonSerializer . CreateDefault ( _options . SerializerSettings ) ;
196+ JsonSerializer serializer = JsonSerializer . CreateDefault ( requestContext . Options . SerializerSettings ) ;
203197 serializer . ApplyErrorSettings ( ) ;
204198
205199 // https://github.com/JamesNK/Newtonsoft.Json/issues/1193
@@ -212,34 +206,59 @@ private async Task FlushResponseAsync(HttpContext context, Error error)
212206 }
213207
214208 stream . Seek ( 0 , SeekOrigin . Begin ) ;
215- await stream . CopyToAsync ( context . Response . Body ) ;
209+ await stream . CopyToAsync ( requestContext . HttpContext . Response . Body ) ;
216210 }
217211
218- context . Response . Body . Flush ( ) ;
212+ requestContext . HttpContext . Response . Body . Flush ( ) ;
219213 }
220214
221215 /// <summary>
222216 /// Gets the current entity that we need for serialization and deserialization.
223217 /// </summary>
224218 /// <returns></returns>
225- private ResourceContext GetCurrentEntity ( )
219+ private static ResourceContext GetCurrentEntity ( RequestContext requestContext )
226220 {
227- var controllerName = ( string ) _routeValues [ "controller" ] ;
221+ var controllerName = ( string ) requestContext . RouteValues [ "controller" ] ;
228222 if ( controllerName == null )
229223 {
230224 return null ;
231225 }
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 ) ;
234228 if ( requestResource == null )
235229 {
236230 return null ;
237231 }
238- if ( _routeValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
232+ if ( requestContext . RouteValues . TryGetValue ( "relationshipName" , out object relationshipName ) )
239233 {
240- _currentRequest . RequestRelationship = requestResource . Relationships . SingleOrDefault ( r => r . PublicRelationshipName == ( string ) relationshipName ) ;
234+ requestContext . CurrentRequest . RequestRelationship = requestResource . Relationships . SingleOrDefault ( r => r . PublicRelationshipName == ( string ) relationshipName ) ;
241235 }
242236 return requestResource ;
243237 }
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+ }
244263 }
245264}
0 commit comments