Skip to content

Commit 8b6a94e

Browse files
author
Bart Koelman
committed
Code cleanup
1 parent 7b08441 commit 8b6a94e

File tree

2 files changed

+86
-107
lines changed

2 files changed

+86
-107
lines changed

src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs

Lines changed: 84 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@
1717
namespace JsonApiDotNetCore.Middleware
1818
{
1919
/// <summary>
20-
/// This sets all necessary parameters relating to the HttpContext for JADNC
20+
/// Intercepts HTTP requests to populate injected <see cref="ICurrentRequest"/> instance for json:api requests.
2121
/// </summary>
2222
public sealed class CurrentRequestMiddleware
2323
{
2424
private readonly RequestDelegate _next;
2525
private HttpContext _httpContext;
26+
private IJsonApiOptions _options;
2627
private ICurrentRequest _currentRequest;
2728
private IResourceGraph _resourceGraph;
28-
private IJsonApiOptions _options;
2929
private RouteValueDictionary _routeValues;
30-
private IControllerResourceMapping _controllerResourceMapping;
3130

3231
public CurrentRequestMiddleware(RequestDelegate next)
3332
{
@@ -41,116 +40,50 @@ public async Task Invoke(HttpContext httpContext,
4140
IResourceGraph resourceGraph)
4241
{
4342
_httpContext = httpContext;
43+
_options = options;
4444
_currentRequest = currentRequest;
45-
_controllerResourceMapping = controllerResourceMapping;
4645
_resourceGraph = resourceGraph;
47-
_options = options;
4846
_routeValues = httpContext.GetRouteData().Values;
49-
var requestResource = GetCurrentEntity();
50-
if (requestResource != null)
51-
{
52-
_currentRequest.SetRequestResource(requestResource);
53-
_currentRequest.IsRelationshipPath = PathIsRelationship();
54-
_currentRequest.BasePath = GetBasePath(requestResource.ResourceName);
55-
_currentRequest.BaseId = GetBaseId();
56-
_currentRequest.RelationshipId = GetRelationshipId();
5747

58-
if (await IsValidAsync())
48+
var resourceContext = CreateResourceContext(controllerResourceMapping);
49+
if (resourceContext != null)
50+
{
51+
if (!await ValidateContentTypeHeaderAsync() || !await ValidateAcceptHeaderAsync())
5952
{
60-
_httpContext.SetJsonApiRequest();
61-
await _next(httpContext);
53+
return;
6254
}
6355

64-
return;
56+
SetupCurrentRequest(resourceContext);
57+
58+
_httpContext.SetJsonApiRequest();
6559
}
6660

6761
await _next(httpContext);
6862
}
6963

70-
private string GetBaseId()
71-
{
72-
if (_routeValues.TryGetValue("id", out object stringId))
73-
{
74-
return (string)stringId;
75-
}
76-
77-
return null;
78-
}
79-
private string GetRelationshipId()
64+
private ResourceContext CreateResourceContext(IControllerResourceMapping controllerResourceMapping)
8065
{
81-
if (!_currentRequest.IsRelationshipPath)
66+
var controllerName = (string)_routeValues["controller"];
67+
if (controllerName == null)
8268
{
8369
return null;
8470
}
85-
var components = SplitCurrentPath();
86-
var toReturn = components.ElementAtOrDefault(4);
8771

88-
return toReturn;
89-
}
90-
private string[] SplitCurrentPath()
91-
{
92-
var path = _httpContext.Request.Path.Value;
93-
var ns = $"/{_options.Namespace}";
94-
var nonNameSpaced = path.Replace(ns, "");
95-
nonNameSpaced = nonNameSpaced.Trim('/');
96-
var individualComponents = nonNameSpaced.Split('/');
97-
return individualComponents;
72+
var resourceType = controllerResourceMapping.GetAssociatedResource(controllerName);
73+
var resourceContext = _resourceGraph.GetResourceContext(resourceType);
74+
return resourceContext;
9875
}
9976

100-
private string GetBasePath(string resourceName = null)
77+
private async Task<bool> ValidateContentTypeHeaderAsync()
10178
{
102-
var r = _httpContext.Request;
103-
if (_options.RelativeLinks)
104-
{
105-
return _options.Namespace;
106-
}
107-
108-
var customRoute = GetCustomRoute(r.Path.Value, resourceName);
109-
var toReturn = $"{r.Scheme}://{r.Host}/{_options.Namespace}";
110-
if (customRoute != null)
111-
{
112-
toReturn += $"/{customRoute}";
113-
}
114-
return toReturn;
115-
}
116-
117-
private object GetCustomRoute(string path, string resourceName)
118-
{
119-
var trimmedComponents = path.Trim('/').Split('/').ToList();
120-
var resourceNameIndex = trimmedComponents.FindIndex(c => c == resourceName);
121-
var newComponents = trimmedComponents.Take(resourceNameIndex).ToArray();
122-
var customRoute = string.Join('/', newComponents);
123-
if (customRoute == _options.Namespace)
124-
{
125-
return null;
126-
}
127-
else
128-
{
129-
return customRoute;
130-
}
131-
}
132-
133-
private bool PathIsRelationship()
134-
{
135-
var actionName = (string)_routeValues["action"];
136-
return actionName.ToLowerInvariant().Contains("relationships");
137-
}
138-
139-
private async Task<bool> IsValidAsync()
140-
{
141-
return await IsValidContentTypeHeaderAsync(_httpContext) && await IsValidAcceptHeaderAsync(_httpContext);
142-
}
143-
144-
private async Task<bool> IsValidContentTypeHeaderAsync(HttpContext context)
145-
{
146-
var contentType = context.Request.ContentType;
79+
var contentType = _httpContext.Request.ContentType;
14780
if (contentType != null)
14881
{
14982
if (!MediaTypeHeaderValue.TryParse(contentType, out var headerValue) ||
15083
headerValue.MediaType != HeaderConstants.MediaType || headerValue.CharSet != null ||
15184
headerValue.Parameters.Any(p => p.Name != "ext"))
15285
{
153-
await FlushResponseAsync(context, new Error(HttpStatusCode.UnsupportedMediaType)
86+
await FlushResponseAsync(_httpContext, new Error(HttpStatusCode.UnsupportedMediaType)
15487
{
15588
Title = "The specified Content-Type header value is not supported.",
15689
Detail = $"Please specify '{HeaderConstants.MediaType}' instead of '{contentType}' for the Content-Type header value."
@@ -163,9 +96,9 @@ private async Task<bool> IsValidContentTypeHeaderAsync(HttpContext context)
16396
return true;
16497
}
16598

166-
private async Task<bool> IsValidAcceptHeaderAsync(HttpContext context)
99+
private async Task<bool> ValidateAcceptHeaderAsync()
167100
{
168-
if (context.Request.Headers.TryGetValue("Accept", out StringValues acceptHeaders))
101+
if (_httpContext.Request.Headers.TryGetValue("Accept", out StringValues acceptHeaders))
169102
{
170103
foreach (var acceptHeader in acceptHeaders)
171104
{
@@ -179,7 +112,7 @@ private async Task<bool> IsValidAcceptHeaderAsync(HttpContext context)
179112
}
180113
}
181114

182-
await FlushResponseAsync(context, new Error(HttpStatusCode.NotAcceptable)
115+
await FlushResponseAsync(_httpContext, new Error(HttpStatusCode.NotAcceptable)
183116
{
184117
Title = "The specified Accept header value is not supported.",
185118
Detail = $"Please include '{HeaderConstants.MediaType}' in the Accept header values."
@@ -213,28 +146,74 @@ private async Task FlushResponseAsync(HttpContext context, Error error)
213146
context.Response.Body.Flush();
214147
}
215148

216-
/// <summary>
217-
/// Gets the current entity that we need for serialization and deserialization.
218-
/// </summary>
219-
/// <returns></returns>
220-
private ResourceContext GetCurrentEntity()
149+
private void SetupCurrentRequest(ResourceContext resourceContext)
221150
{
222-
var controllerName = (string)_routeValues["controller"];
223-
if (controllerName == null)
151+
_currentRequest.SetRequestResource(resourceContext);
152+
_currentRequest.BaseId = GetBaseId();
153+
_currentRequest.BasePath = GetBasePath(resourceContext.ResourceName);
154+
_currentRequest.IsRelationshipPath = GetIsRelationshipPath();
155+
_currentRequest.RelationshipId = GetRelationshipId();
156+
157+
if (_routeValues.TryGetValue("relationshipName", out object relationshipName))
224158
{
225-
return null;
159+
_currentRequest.RequestRelationship = resourceContext.Relationships.SingleOrDefault(r => r.PublicRelationshipName == (string) relationshipName);
226160
}
227-
var resourceType = _controllerResourceMapping.GetAssociatedResource(controllerName);
228-
var requestResource = _resourceGraph.GetResourceContext(resourceType);
229-
if (requestResource == null)
161+
}
162+
163+
private string GetBaseId()
164+
{
165+
return _routeValues.TryGetValue("id", out var id) ? (string) id : null;
166+
}
167+
168+
private string GetBasePath(string resourceName)
169+
{
170+
if (_options.RelativeLinks)
230171
{
231-
return null;
172+
return _options.Namespace;
232173
}
233-
if (_routeValues.TryGetValue("relationshipName", out object relationshipName))
174+
175+
var customRoute = GetCustomRoute(_httpContext.Request.Path.Value, resourceName);
176+
var toReturn = $"{_httpContext.Request.Scheme}://{_httpContext.Request.Host}/{_options.Namespace}";
177+
if (customRoute != null)
178+
{
179+
toReturn += $"/{customRoute}";
180+
}
181+
return toReturn;
182+
}
183+
184+
private string GetCustomRoute(string path, string resourceName)
185+
{
186+
var trimmedComponents = path.Trim('/').Split('/').ToList();
187+
var resourceNameIndex = trimmedComponents.FindIndex(c => c == resourceName);
188+
var newComponents = trimmedComponents.Take(resourceNameIndex).ToArray();
189+
var customRoute = string.Join('/', newComponents);
190+
return customRoute == _options.Namespace ? null : customRoute;
191+
}
192+
193+
private bool GetIsRelationshipPath()
194+
{
195+
var actionName = (string)_routeValues["action"];
196+
return actionName.ToLowerInvariant().Contains("relationships");
197+
}
198+
199+
private string GetRelationshipId()
200+
{
201+
if (!_currentRequest.IsRelationshipPath)
234202
{
235-
_currentRequest.RequestRelationship = requestResource.Relationships.SingleOrDefault(r => r.PublicRelationshipName == (string)relationshipName);
203+
return null;
236204
}
237-
return requestResource;
205+
206+
var components = SplitCurrentPath();
207+
return components.ElementAtOrDefault(4);
208+
}
209+
210+
private string[] SplitCurrentPath()
211+
{
212+
var path = _httpContext.Request.Path.Value;
213+
var ns = $"/{_options.Namespace}";
214+
var nonNameSpaced = path.Replace(ns, "");
215+
nonNameSpaced = nonNameSpaced.Trim('/');
216+
return nonNameSpaced.Split('/');
238217
}
239218
}
240219
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiation.cs renamed to test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiationTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec
1515
{
1616
[Collection("WebHostCollection")]
17-
public class ContentNegotiation
17+
public class ContentNegotiationTests
1818
{
1919
private readonly TestFixture<Startup> _fixture;
2020

21-
public ContentNegotiation(TestFixture<Startup> fixture)
21+
public ContentNegotiationTests(TestFixture<Startup> fixture)
2222
{
2323
_fixture = fixture;
2424
}

0 commit comments

Comments
 (0)