diff --git a/Directory.Build.props b/Directory.Build.props index 5014190440..0b51f53d6d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,12 +2,12 @@ netcoreapp3.0 netstandard2.1 - 3.* - 3.* - 3.* - 3.* - 3.* - 3.* + 3.0 + 3.0.* + 3.0.* + 3.0.* + 3.0.* + 3.0.* 4.1.1 3.0.1 4.5.0 diff --git a/src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs index b47e87d636..68a169ee0d 100644 --- a/src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs @@ -61,20 +61,18 @@ public async Task Invoke(HttpContext httpContext, private string GetBaseId() { - var resource = _currentRequest.GetRequestResource(); - var individualComponents = SplitCurrentPath(); - if (individualComponents.Length < 2) + if (_routeValues.TryGetValue("id", out object stringId)) { - return null; + if ((string)stringId == string.Empty) + { + throw new JsonApiException(400, "No empty string as id please."); + } + return (string)stringId; } - var indexOfResource = individualComponents.ToList().FindIndex(c => c == resource.ResourceName); - var baseId = individualComponents.ElementAtOrDefault(indexOfResource + 1); - if (baseId == null) + else { return null; } - CheckIdType(baseId, resource.IdentityType); - return baseId; } private string GetRelationshipId() { @@ -93,7 +91,6 @@ private string GetRelationshipId() var relType = _currentRequest.RequestRelationship.RightType; var relResource = _resourceGraph.GetResourceContext(relType); var relIdentityType = relResource.IdentityType; - CheckIdType(toReturn, relIdentityType); return toReturn; } private string[] SplitCurrentPath() @@ -106,37 +103,6 @@ private string[] SplitCurrentPath() return individualComponents; } - - private void CheckIdType(string value, Type idType) - { - try - { - var converter = TypeDescriptor.GetConverter(idType); - if (converter != null) - { - if (!converter.IsValid(value)) - { - throw new JsonApiException(500, $"We could not convert the id '{value}'"); - } - else - { - if (idType == typeof(int)) - { - if ((int)converter.ConvertFromString(value) < 0) - { - throw new JsonApiException(500, "The base ID is an integer, and it is negative."); - } - } - } - } - } - catch (NotSupportedException) - { - - } - - } - private string GetBasePath(string resourceName = null) { var r = _httpContext.Request; @@ -147,7 +113,7 @@ private string GetBasePath(string resourceName = null) var ns = GetNameSpace(resourceName); var customRoute = GetCustomRoute(r.Path.Value, resourceName); var toReturn = $"{r.Scheme}://{r.Host}/{ns}"; - if(customRoute != null) + if (customRoute != null) { toReturn += $"/{customRoute}"; } @@ -159,9 +125,9 @@ private object GetCustomRoute(string path, string resourceName) var ns = GetNameSpace(); var trimmedComponents = path.Trim('/').Split('/').ToList(); var resourceNameIndex = trimmedComponents.FindIndex(c => c == resourceName); - var newComponents = trimmedComponents.Take(resourceNameIndex ).ToArray(); + var newComponents = trimmedComponents.Take(resourceNameIndex).ToArray(); var customRoute = string.Join('/', newComponents); - if(customRoute == ns) + if (customRoute == ns) { return null; } diff --git a/test/UnitTests/Middleware/CurrentRequestMiddlewareTests.cs b/test/UnitTests/Middleware/CurrentRequestMiddlewareTests.cs index 01b26a69b1..99238d30ed 100644 --- a/test/UnitTests/Middleware/CurrentRequestMiddlewareTests.cs +++ b/test/UnitTests/Middleware/CurrentRequestMiddlewareTests.cs @@ -23,11 +23,11 @@ namespace UnitTests.Middleware public class CurrentRequestMiddlewareTests { [Fact] - public async Task ParseUrlBase_UrlHasBaseIdSet_ShouldSetCurrentRequestWithSaidId() + public async Task ParseUrlBase_ObfuscatedIdClass_ShouldSetIdCorrectly() { // Arrange - var id = "123"; - var configuration = GetConfiguration($"/users/{id}"); + var id = "ABC123ABC"; + var configuration = GetConfiguration($"/obfuscatedIdModel/{id}", action: "GetAsync", id: id); var currentRequest = configuration.CurrentRequest; // Act @@ -35,66 +35,55 @@ public async Task ParseUrlBase_UrlHasBaseIdSet_ShouldSetCurrentRequestWithSaidId // Assert Assert.Equal(id, currentRequest.BaseId); - } + } [Fact] - public async Task ParseUrlBase_UrlHasNoBaseIdSet_ShouldHaveBaseIdSetToNull() + public async Task ParseUrlBase_UrlHasBaseIdSet_ShouldSetCurrentRequestWithSaidId() { // Arrange - var configuration = GetConfiguration("/users"); + var id = "123"; + var configuration = GetConfiguration($"/users/{id}", id: id); var currentRequest = configuration.CurrentRequest; // Act await RunMiddlewareTask(configuration); // Assert - Assert.Null(currentRequest.BaseId); + Assert.Equal(id, currentRequest.BaseId); } + [Fact] - public async Task ParseUrlRel_UrlHasRelationshipIdSet_ShouldHaveBaseIdAndRelationshipIdSet() + public async Task ParseUrlBase_UrlHasNoBaseIdSet_ShouldHaveBaseIdSetToNull() { // Arrange - var baseId = "5"; - var relId = "23"; - var configuration = GetConfiguration($"/users/{baseId}/relationships/books/{relId}", relType: typeof(TodoItem), relIdType: typeof(int)); + var configuration = GetConfiguration("/users"); var currentRequest = configuration.CurrentRequest; // Act await RunMiddlewareTask(configuration); // Assert - Assert.Equal(baseId, currentRequest.BaseId); - Assert.Equal(relId, currentRequest.RelationshipId); + Assert.Null(currentRequest.BaseId); } [Fact] - public async Task ParseUrlBase_UrlHasNegativeBaseIdAndTypeIsInt_ShouldThrowJAException() + public async Task ParseUrlBase_UrlHasNegativeBaseIdAndTypeIsInt_ShouldNotThrowJAException() { // Arrange var configuration = GetConfiguration("/users/-5/"); - // Act - var task = RunMiddlewareTask(configuration); - - // Assert - var exception = await Assert.ThrowsAsync(async () => - { - await task; - }); - Assert.Equal(500, exception.GetStatusCode()); - Assert.Contains("negative", exception.Message); + // Act / Assert + await RunMiddlewareTask(configuration); } [Theory] - [InlineData("12315K", typeof(int), true)] - [InlineData("12315K", typeof(int), false)] - [InlineData("5", typeof(Guid), true)] - [InlineData("5", typeof(Guid), false)] - public async Task ParseUrlBase_UrlHasIncorrectBaseIdSet_ShouldThrowException(string baseId, Type idType, bool addSlash) + [InlineData("", false)] + [InlineData("", true)] + public async Task ParseUrlBase_UrlHasIncorrectBaseIdSet_ShouldThrowException(string baseId, bool addSlash) { // Arrange var url = addSlash ? $"/users/{baseId}/" : $"/users/{baseId}"; - var configuration = GetConfiguration(url, idType: idType); + var configuration = GetConfiguration(url, id: baseId); // Act var task = RunMiddlewareTask(configuration); @@ -104,7 +93,7 @@ public async Task ParseUrlBase_UrlHasIncorrectBaseIdSet_ShouldThrowException(str { await task; }); - Assert.Equal(500, exception.GetStatusCode()); + Assert.Equal(400, exception.GetStatusCode()); Assert.Contains(baseId, exception.Message); } @@ -126,17 +115,12 @@ private Task RunMiddlewareTask(InvokeConfiguration holder) var resourceGraph = holder.ResourceGraph.Object; return holder.MiddleWare.Invoke(context, controllerResourceMapping, options, currentRequest, resourceGraph); } - private InvokeConfiguration GetConfiguration(string path, string resourceName = "users", Type idType = null, Type relType = null, Type relIdType = null) + private InvokeConfiguration GetConfiguration(string path, string resourceName = "users", string action = "", string id =null, Type relType = null) { - if((relType != null) != (relIdType != null)) - { - throw new ArgumentException("Define both reltype and relidType or dont."); - } if (path.First() != '/') { throw new ArgumentException("Path should start with a '/'"); } - idType ??= typeof(int); var middleware = new CurrentRequestMiddleware((context) => { return Task.Run(() => Console.WriteLine("finished")); @@ -144,16 +128,16 @@ private InvokeConfiguration GetConfiguration(string path, string resourceName = var forcedNamespace = "api/v1"; var mockMapping = new Mock(); Mock mockOptions = CreateMockOptions(forcedNamespace); - var mockGraph = CreateMockResourceGraph(idType, resourceName, relIdType : relIdType); + var mockGraph = CreateMockResourceGraph(resourceName, includeRelationship: relType != null); var currentRequest = new CurrentRequest(); - if (relType != null && relIdType != null) + if (relType != null) { currentRequest.RequestRelationship = new HasManyAttribute { RightType = relType }; } - var context = CreateHttpContext(path, isRelationship: relType != null); + var context = CreateHttpContext(path, isRelationship: relType != null, action: action, id: id); return new InvokeConfiguration { MiddleWare = middleware, @@ -172,33 +156,37 @@ private static Mock CreateMockOptions(string forcedNamespace) return mockOptions; } - private static DefaultHttpContext CreateHttpContext(string path, bool isRelationship = false) + private static DefaultHttpContext CreateHttpContext(string path, bool isRelationship = false, string action = "", string id =null) { var context = new DefaultHttpContext(); context.Request.Path = new PathString(path); context.Response.Body = new MemoryStream(); var feature = new RouteValuesFeature(); feature.RouteValues["controller"] = "fake!"; - feature.RouteValues["action"] = isRelationship ? "relationships" : "noRel"; + feature.RouteValues["action"] = isRelationship ? "GetRelationship" : action; + if(id != null) + { + feature.RouteValues["id"] = id; + } context.Features.Set(feature); return context; } - private Mock CreateMockResourceGraph(Type idType, string resourceName, Type relIdType = null) + private Mock CreateMockResourceGraph( string resourceName, bool includeRelationship = false) { var mockGraph = new Mock(); var resourceContext = new ResourceContext { ResourceName = resourceName, - IdentityType = idType + IdentityType = typeof(string) }; var seq = mockGraph.SetupSequence(d => d.GetResourceContext(It.IsAny())).Returns(resourceContext); - if (relIdType != null) + if (includeRelationship) { var relResourceContext = new ResourceContext { ResourceName = "todoItems", - IdentityType = relIdType + IdentityType = typeof(string) }; seq.Returns(relResourceContext); }