From 26fb294ca163df075c2bcce410eff0fec28cf342 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Thu, 9 Nov 2017 09:18:37 -0600 Subject: [PATCH 001/227] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 85e8992f80..46d6118fe6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ A framework for building [json:api](http://jsonapi.org/) compliant web APIs. The ultimate goal of this library is to eliminate as much boilerplate as possible by offering out-of-the-box features such as sorting, filtering and pagination. You just need to focus on defining the resources and implementing your custom business logic. This library has been designed around dependency injection making extensibility incredibly easy. +## Examples + +See the [examples](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/src/Examples) directory for up-to-date sample applications. There is also a [Todo List App](https://github.com/json-api-dotnet/TodoListExample) that includes a JADNC API and an EmberJs client. + ## Installation And Usage See [the documentation](https://json-api-dotnet.github.io/JsonApiDotNetCore/) for detailed usage. From 8a6b6bdd69aacbf4d0a650d8cd5cc08369d5cf60 Mon Sep 17 00:00:00 2001 From: David Perfors Date: Sat, 11 Nov 2017 17:52:34 +0100 Subject: [PATCH 002/227] feat(JsonApiOptions): Add SerializerSettings to JsonApiOptions * Add SerializerSettings to JsonApiOptions * Fixed spacing, and added obsolete attribute to JsonContractResolver * Correctly fix spacing. --- .../Configuration/JsonApiOptions.cs | 15 +++++++- .../Serialization/JsonApiDeSerializer.cs | 9 +---- .../Serialization/JsonApiSerializer.cs | 13 +++---- .../Serialization/JsonApiDeSerializerTests.cs | 37 +++++++++---------- .../Serialization/JsonApiSerializerTests.cs | 10 ++--- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 3d169998a3..58d1a33376 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Serialization; using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; using Newtonsoft.Json.Serialization; namespace JsonApiDotNetCore.Configuration @@ -21,10 +22,20 @@ public class JsonApiOptions /// of the v1 spec. However, we have decided that this is a real /// requirement for users of this library and a gap in the specification. /// It will likely be removed when the spec is updated to support this - /// requirement. + /// requirement. /// public bool AllowCustomQueryParameters { get; set; } - public IContractResolver JsonContractResolver { get; set; } = new DasherizedResolver(); + [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] + public IContractResolver JsonContractResolver + { + get => SerializerSettings.ContractResolver; + set => SerializerSettings.ContractResolver = value; + } + public JsonSerializerSettings SerializerSettings { get; } = new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new DasherizedResolver() + }; internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); public void BuildContextGraph(Action builder) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 608a23b66e..d8cbf245bf 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -135,12 +135,7 @@ private object ConvertAttrValue(object newValue, Type targetType) private object DeserializeComplexType(JContainer obj, Type targetType) { - var serializerSettings = new JsonSerializerSettings - { - ContractResolver = _jsonApiContext.Options.JsonContractResolver - }; - - return obj.ToObject(targetType, JsonSerializer.Create(serializerSettings)); + return obj.ToObject(targetType, JsonSerializer.Create(_jsonApiContext.Options.SerializerSettings)); } private object SetRelationships( @@ -223,4 +218,4 @@ private object SetHasManyRelationship(object entity, return entity; } } -} +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs index a7e14341b0..8e94835266 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs @@ -19,12 +19,12 @@ public JsonApiSerializer( IDocumentBuilder documentBuilder) { _jsonApiContext = jsonApiContext; - _documentBuilder = documentBuilder; + _documentBuilder = documentBuilder; } public JsonApiSerializer( IJsonApiContext jsonApiContext, - IDocumentBuilder documentBuilder, + IDocumentBuilder documentBuilder, ILoggerFactory loggerFactory) { _jsonApiContext = jsonApiContext; @@ -43,7 +43,7 @@ public string Serialize(object entity) if (entity is IEnumerable) return SerializeDocuments(entity); - return SerializeDocument(entity); + return SerializeDocument(entity); } private string GetNullDataResponse() @@ -83,10 +83,7 @@ private string SerializeDocument(object entity) private string _serialize(object obj) { - return JsonConvert.SerializeObject(obj, new JsonSerializerSettings { - NullValueHandling = NullValueHandling.Ignore, - ContractResolver = _jsonApiContext.Options.JsonContractResolver - }); + return JsonConvert.SerializeObject(obj, _jsonApiContext.Options.SerializerSettings); } } -} +} \ No newline at end of file diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index 53edc9faad..3e54c7b393 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -26,10 +26,10 @@ public void Can_Deserialize_Complex_Types() jsonApiContextMock.SetupAllProperties(); jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); - jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions - { - JsonContractResolver = new CamelCasePropertyNamesContractResolver() - }); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); var genericProcessorFactoryMock = new Mock(); @@ -69,10 +69,9 @@ public void Can_Deserialize_Complex_List_Types() jsonApiContextMock.SetupAllProperties(); jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); - jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions - { - JsonContractResolver = new CamelCasePropertyNamesContractResolver() - }); + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); var genericProcessorFactoryMock = new Mock(); @@ -116,10 +115,9 @@ public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); - jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions - { - JsonContractResolver = new DasherizedResolver() // <--- - }); + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new DasherizedResolver(); // <-- + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); var genericProcessorFactoryMock = new Mock(); @@ -162,10 +160,9 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(attributesToUpdate); - jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions - { - JsonContractResolver = new DasherizedResolver() - }); + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new DasherizedResolver(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); var genericProcessorFactoryMock = new Mock(); @@ -178,8 +175,8 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() Type = "test-resource", Id = "1", Attributes = new Dictionary { - { "complex-member", new Dictionary { - { "compound-name", "testName" } } + { "complex-member", new Dictionary { + { "compound-name", "testName" } } }, { "immutable", "value"} } @@ -194,8 +191,8 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() // assert Assert.NotNull(result.ComplexMember); Assert.Equal(1, attributesToUpdate.Count); - - foreach(var attr in attributesToUpdate) + + foreach (var attr in attributesToUpdate) Assert.False(attr.Key.IsImmutable); } diff --git a/test/UnitTests/Serialization/JsonApiSerializerTests.cs b/test/UnitTests/Serialization/JsonApiSerializerTests.cs index e671f3fc0c..3630cd6452 100644 --- a/test/UnitTests/Serialization/JsonApiSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiSerializerTests.cs @@ -26,9 +26,7 @@ public void Can_Serialize_Complex_Types() var jsonApiContextMock = new Mock(); jsonApiContextMock.SetupAllProperties(); jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); - jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions { - JsonContractResolver = new DasherizedResolver() - }); + jsonApiContextMock.Setup(m => m.Options).Returns(new JsonApiOptions()); jsonApiContextMock.Setup(m => m.RequestEntity) .Returns(contextGraph.GetContextEntity("test-resource")); jsonApiContextMock.Setup(m => m.MetaBuilder).Returns(new MetaBuilder()); @@ -36,8 +34,10 @@ public void Can_Serialize_Complex_Types() var documentBuilder = new DocumentBuilder(jsonApiContextMock.Object); var serializer = new JsonApiSerializer(jsonApiContextMock.Object, documentBuilder); - var resource = new TestResource { - ComplexMember = new ComplexType { + var resource = new TestResource + { + ComplexMember = new ComplexType + { CompoundName = "testname" } }; From e6e4cce270cf071f22a5b4d02f76ff0605bac653 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 12 Nov 2017 20:32:45 -0600 Subject: [PATCH 003/227] refactor(query-set): move logic into IQueryParser to improve extensibility * chore(csproj): bump package version * refactor(query-set): move logic into IQueryParser to improve extensibility closes #186 --- .../Configuration/JsonApiOptions.cs | 12 +- .../IServiceCollectionExtensions.cs | 2 + .../Internal/Query/QuerySet.cs | 180 ---------------- .../JsonApiDotNetCore.csproj | 2 +- .../Services/ControllerContext.cs | 25 +++ .../Services/JsonApiContext.cs | 27 +-- src/JsonApiDotNetCore/Services/QueryParser.cs | 198 ++++++++++++++++++ test/UnitTests/Services/QueryAccessorTests.cs | 50 ++--- .../QueryParser_Tests.cs} | 94 ++++----- 9 files changed, 310 insertions(+), 280 deletions(-) create mode 100644 src/JsonApiDotNetCore/Services/ControllerContext.cs create mode 100644 src/JsonApiDotNetCore/Services/QueryParser.cs rename test/UnitTests/{Internal/QuerySet_Tests.cs => Services/QueryParser_Tests.cs} (72%) diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 58d1a33376..26e16b0741 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -16,15 +16,8 @@ public class JsonApiOptions public bool AllowClientGeneratedIds { get; set; } public IContextGraph ContextGraph { get; set; } public bool RelativeLinks { get; set; } - - /// - /// This flag is experimental and could be perceived as a violation - /// of the v1 spec. However, we have decided that this is a real - /// requirement for users of this library and a gap in the specification. - /// It will likely be removed when the spec is updated to support this - /// requirement. - /// public bool AllowCustomQueryParameters { get; set; } + [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] public IContractResolver JsonContractResolver { @@ -38,8 +31,7 @@ public IContractResolver JsonContractResolver }; internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); - public void BuildContextGraph(Action builder) - where TContext : DbContext + public void BuildContextGraph(Action builder) where TContext : DbContext { BuildContextGraph(builder); diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 3d2b14704a..afcc11ee8d 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -110,6 +110,8 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(typeof(GenericProcessor<>)); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions jsonApiOptions) diff --git a/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs b/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs index 628e6187a3..88aac1e67b 100644 --- a/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs +++ b/src/JsonApiDotNetCore/Internal/Query/QuerySet.cs @@ -1,193 +1,13 @@ -using System; using System.Collections.Generic; -using System.Linq; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Services; -using Microsoft.AspNetCore.Http; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Controllers; namespace JsonApiDotNetCore.Internal.Query { public class QuerySet { - private readonly IJsonApiContext _jsonApiContext; - - public QuerySet( - IJsonApiContext jsonApiContext, - IQueryCollection query) - { - _jsonApiContext = jsonApiContext; - BuildQuerySet(query); - } - public List Filters { get; set; } = new List(); public PageQuery PageQuery { get; set; } = new PageQuery(); public List SortParameters { get; set; } = new List(); public List IncludedRelationships { get; set; } = new List(); public List Fields { get; set; } = new List(); - - private void BuildQuerySet(IQueryCollection query) - { - var disabledQueries = _jsonApiContext.GetControllerAttribute()?.QueryParams ?? QueryParams.None; - - foreach (var pair in query) - { - if (pair.Key.StartsWith("filter")) - { - if (disabledQueries.HasFlag(QueryParams.Filter) == false) - Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); - continue; - } - - if (pair.Key.StartsWith("sort")) - { - if (disabledQueries.HasFlag(QueryParams.Sort) == false) - SortParameters = ParseSortParameters(pair.Value); - continue; - } - - if (pair.Key.StartsWith("include")) - { - if (disabledQueries.HasFlag(QueryParams.Include) == false) - IncludedRelationships = ParseIncludedRelationships(pair.Value); - continue; - } - - if (pair.Key.StartsWith("page")) - { - if (disabledQueries.HasFlag(QueryParams.Page) == false) - PageQuery = ParsePageQuery(pair.Key, pair.Value); - continue; - } - - if (pair.Key.StartsWith("fields")) - { - if (disabledQueries.HasFlag(QueryParams.Fields) == false) - Fields = ParseFieldsQuery(pair.Key, pair.Value); - continue; - } - - if (_jsonApiContext.Options.AllowCustomQueryParameters == false) - throw new JsonApiException(400, $"{pair} is not a valid query."); - } - } - - private List ParseFilterQuery(string key, string value) - { - // expected input = filter[id]=1 - // expected input = filter[id]=eq:1 - var queries = new List(); - - var propertyName = key.Split('[', ']')[1].ToProperCase(); - - var values = value.Split(','); - foreach (var val in values) - { - (var operation, var filterValue) = ParseFilterOperation(val); - queries.Add(new FilterQuery(propertyName, filterValue, operation)); - } - - return queries; - } - - private (string operation, string value) ParseFilterOperation(string value) - { - if (value.Length < 3) - return (string.Empty, value); - - var operation = value.Split(':'); - - if (operation.Length == 1) - return (string.Empty, value); - - // remove prefix from value - if (Enum.TryParse(operation[0], out FilterOperations op) == false) - return (string.Empty, value); - - var prefix = operation[0]; - value = string.Join(":", operation.Skip(1)); - - return (prefix, value); - } - - private PageQuery ParsePageQuery(string key, string value) - { - // expected input = page[size]=10 - // page[number]=1 - PageQuery = PageQuery ?? new PageQuery(); - - var propertyName = key.Split('[', ']')[1]; - - if (propertyName == "size") - PageQuery.PageSize = Convert.ToInt32(value); - else if (propertyName == "number") - PageQuery.PageOffset = Convert.ToInt32(value); - - return PageQuery; - } - - // sort=id,name - // sort=-id - private List ParseSortParameters(string value) - { - var sortParameters = new List(); - value.Split(',').ToList().ForEach(p => - { - var direction = SortDirection.Ascending; - if (p[0] == '-') - { - direction = SortDirection.Descending; - p = p.Substring(1); - } - - var attribute = GetAttribute(p.ToProperCase()); - - sortParameters.Add(new SortQuery(direction, attribute)); - }); - - return sortParameters; - } - - private List ParseIncludedRelationships(string value) - { - if (value.Contains(".")) - throw new JsonApiException(400, "Deeply nested relationships are not supported"); - - return value - .Split(',') - .ToList(); - } - - private List ParseFieldsQuery(string key, string value) - { - // expected: fields[TYPE]=prop1,prop2 - var typeName = key.Split('[', ']')[1]; - - var includedFields = new List { "Id" }; - - if (typeName != _jsonApiContext.RequestEntity.EntityName) - return includedFields; - - var fields = value.Split(','); - foreach (var field in fields) - { - var internalAttrName = _jsonApiContext.RequestEntity - .Attributes - .SingleOrDefault(attr => attr.PublicAttributeName == field) - .InternalAttributeName; - includedFields.Add(internalAttrName); - } - - return includedFields; - } - - private AttrAttribute GetAttribute(string propertyName) - { - return _jsonApiContext.RequestEntity.Attributes - .FirstOrDefault(attr => - attr.InternalAttributeName.ToLower() == propertyName.ToLower() - ); - } } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 03628876b9..c3c987f32a 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.1.8 + 2.1.9 netstandard1.6 JsonApiDotNetCore JsonApiDotNetCore diff --git a/src/JsonApiDotNetCore/Services/ControllerContext.cs b/src/JsonApiDotNetCore/Services/ControllerContext.cs new file mode 100644 index 0000000000..1984262b15 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/ControllerContext.cs @@ -0,0 +1,25 @@ +using System; +using System.Reflection; +using JsonApiDotNetCore.Internal; + +namespace JsonApiDotNetCore.Services +{ + public interface IControllerContext + { + Type ControllerType { get; set; } + ContextEntity RequestEntity { get; set; } + TAttribute GetControllerAttribute() where TAttribute : Attribute; + } + + public class ControllerContext : IControllerContext + { + public Type ControllerType { get; set; } + public ContextEntity RequestEntity { get; set; } + + public TAttribute GetControllerAttribute() where TAttribute : Attribute + { + var attribute = ControllerType.GetTypeInfo().GetCustomAttribute(typeof(TAttribute)); + return attribute == null ? null : (TAttribute)attribute; + } + } +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index e634938087..a93d76acdc 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Data; @@ -17,6 +16,8 @@ public class JsonApiContext : IJsonApiContext { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IDbContextResolver _contextResolver; + private readonly IQueryParser _queryParser; + private readonly IControllerContext _controllerContext; public JsonApiContext( IDbContextResolver contextResolver, @@ -24,7 +25,9 @@ public JsonApiContext( IHttpContextAccessor httpContextAccessor, JsonApiOptions options, IMetaBuilder metaBuilder, - IGenericProcessorFactory genericProcessorFactory) + IGenericProcessorFactory genericProcessorFactory, + IQueryParser queryParser, + IControllerContext controllerContext) { _contextResolver = contextResolver; ContextGraph = contextGraph; @@ -32,11 +35,14 @@ public JsonApiContext( Options = options; MetaBuilder = metaBuilder; GenericProcessorFactory = genericProcessorFactory; + _queryParser = queryParser; + _controllerContext = controllerContext; } public JsonApiOptions Options { get; set; } public IContextGraph ContextGraph { get; set; } - public ContextEntity RequestEntity { get; set; } + [Obsolete("Use the proxied member IControllerContext.RequestEntity instead.")] + public ContextEntity RequestEntity { get => _controllerContext.RequestEntity; set => _controllerContext.RequestEntity = value; } public string BasePath { get; set; } public QuerySet QuerySet { get; set; } public bool IsRelationshipData { get; set; } @@ -54,21 +60,20 @@ public IJsonApiContext ApplyContext(object controller) if (controller == null) throw new JsonApiException(500, $"Cannot ApplyContext from null controller for type {typeof(T)}"); - ControllerType = controller.GetType(); + _controllerContext.ControllerType = controller.GetType(); + _controllerContext.RequestEntity = ContextGraph.GetContextEntity(typeof(T)); var context = _httpContextAccessor.HttpContext; var path = context.Request.Path.Value.Split('/'); - RequestEntity = ContextGraph.GetContextEntity(typeof(T)); - if (context.Request.Query.Any()) { - QuerySet = new QuerySet(this, context.Request.Query); + QuerySet = _queryParser.Parse(context.Request.Query); IncludedRelationships = QuerySet.IncludedRelationships; } var linkBuilder = new LinkBuilder(this); - BasePath = linkBuilder.GetBasePath(context, RequestEntity.EntityName); + BasePath = linkBuilder.GetBasePath(context, _controllerContext.RequestEntity.EntityName); PageManager = GetPageManager(); IsRelationshipPath = path[path.Length - 2] == "relationships"; return this; @@ -91,10 +96,8 @@ private PageManager GetPageManager() }; } + [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] public TAttribute GetControllerAttribute() where TAttribute : Attribute - { - var attribute = ControllerType.GetTypeInfo().GetCustomAttribute(typeof(TAttribute)); - return attribute == null ? null : (TAttribute)attribute; - } + => _controllerContext.GetControllerAttribute(); } } diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs new file mode 100644 index 0000000000..26c735e30c --- /dev/null +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Query; +using JsonApiDotNetCore.Models; +using Microsoft.AspNetCore.Http; + +namespace JsonApiDotNetCore.Services +{ + public interface IQueryParser + { + QuerySet Parse(IQueryCollection query); + } + + public class QueryParser : IQueryParser + { + private readonly IControllerContext _controllerContext; + private readonly JsonApiOptions _options; + + public QueryParser( + IControllerContext controllerContext, + JsonApiOptions options) + { + _controllerContext = controllerContext; + _options = options; + } + + public QuerySet Parse(IQueryCollection query) + { + var querySet = new QuerySet(); + var disabledQueries = _controllerContext.GetControllerAttribute()?.QueryParams ?? QueryParams.None; + + foreach (var pair in query) + { + if (pair.Key.StartsWith("filter")) + { + if (disabledQueries.HasFlag(QueryParams.Filter) == false) + querySet.Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); + continue; + } + + if (pair.Key.StartsWith("sort")) + { + if (disabledQueries.HasFlag(QueryParams.Sort) == false) + querySet.SortParameters = ParseSortParameters(pair.Value); + continue; + } + + if (pair.Key.StartsWith("include")) + { + if (disabledQueries.HasFlag(QueryParams.Include) == false) + querySet.IncludedRelationships = ParseIncludedRelationships(pair.Value); + continue; + } + + if (pair.Key.StartsWith("page")) + { + if (disabledQueries.HasFlag(QueryParams.Page) == false) + querySet.PageQuery = ParsePageQuery(querySet.PageQuery, pair.Key, pair.Value); + continue; + } + + if (pair.Key.StartsWith("fields")) + { + if (disabledQueries.HasFlag(QueryParams.Fields) == false) + querySet.Fields = ParseFieldsQuery(pair.Key, pair.Value); + continue; + } + + if (_options.AllowCustomQueryParameters == false) + throw new JsonApiException(400, $"{pair} is not a valid query."); + } + + return querySet; + } + + private List ParseFilterQuery(string key, string value) + { + // expected input = filter[id]=1 + // expected input = filter[id]=eq:1 + var queries = new List(); + + var propertyName = key.Split('[', ']')[1].ToProperCase(); + + var values = value.Split(','); + foreach (var val in values) + { + (var operation, var filterValue) = ParseFilterOperation(val); + queries.Add(new FilterQuery(propertyName, filterValue, operation)); + } + + return queries; + } + + private (string operation, string value) ParseFilterOperation(string value) + { + if (value.Length < 3) + return (string.Empty, value); + + var operation = value.Split(':'); + + if (operation.Length == 1) + return (string.Empty, value); + + // remove prefix from value + if (Enum.TryParse(operation[0], out FilterOperations op) == false) + return (string.Empty, value); + + var prefix = operation[0]; + value = string.Join(":", operation.Skip(1)); + + return (prefix, value); + } + + private PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) + { + // expected input = page[size]=10 + // page[number]=1 + pageQuery = pageQuery ?? new PageQuery(); + + var propertyName = key.Split('[', ']')[1]; + + if (propertyName == "size") + pageQuery.PageSize = Convert.ToInt32(value); + else if (propertyName == "number") + pageQuery.PageOffset = Convert.ToInt32(value); + + return pageQuery; + } + + // sort=id,name + // sort=-id + private List ParseSortParameters(string value) + { + var sortParameters = new List(); + value.Split(',').ToList().ForEach(p => + { + var direction = SortDirection.Ascending; + if (p[0] == '-') + { + direction = SortDirection.Descending; + p = p.Substring(1); + } + + var attribute = GetAttribute(p.ToProperCase()); + + sortParameters.Add(new SortQuery(direction, attribute)); + }); + + return sortParameters; + } + + private List ParseIncludedRelationships(string value) + { + if (value.Contains(".")) + throw new JsonApiException(400, "Deeply nested relationships are not supported"); + + return value + .Split(',') + .ToList(); + } + + private List ParseFieldsQuery(string key, string value) + { + // expected: fields[TYPE]=prop1,prop2 + var typeName = key.Split('[', ']')[1]; + + var includedFields = new List { "Id" }; + + if (typeName != _controllerContext.RequestEntity.EntityName) + return includedFields; + + var fields = value.Split(','); + foreach (var field in fields) + { + var internalAttrName = _controllerContext.RequestEntity + .Attributes + .SingleOrDefault(attr => attr.PublicAttributeName == field) + .InternalAttributeName; + includedFields.Add(internalAttrName); + } + + return includedFields; + } + + private AttrAttribute GetAttribute(string propertyName) + => _controllerContext + .RequestEntity + .Attributes + .FirstOrDefault(attr => + string.Equals(attr.InternalAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) + ); + } +} \ No newline at end of file diff --git a/test/UnitTests/Services/QueryAccessorTests.cs b/test/UnitTests/Services/QueryAccessorTests.cs index 45538fde66..aa8bc6ae7e 100644 --- a/test/UnitTests/Services/QueryAccessorTests.cs +++ b/test/UnitTests/Services/QueryAccessorTests.cs @@ -5,7 +5,6 @@ using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; using Moq; using Xunit; @@ -28,19 +27,16 @@ public QueryAccessorTests() public void Can_Get_Guid_QueryValue() { // arrange - const string key = "some-id"; - var filterQuery = $"filter[{key}]"; + const string key = "SomeId"; var value = Guid.NewGuid(); - - var query = new Dictionary { - { filterQuery, value.ToString() } + var querySet = new QuerySet + { + Filters = new List { + new FilterQuery(key, value.ToString(), "eq") + } }; - _queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator()); - - var querySet = new QuerySet(_contextMock.Object, _queryMock.Object); - _contextMock.Setup(c => c.QuerySet) - .Returns(querySet); + _contextMock.Setup(c => c.QuerySet).Returns(querySet); var service = new QueryAccessor(_contextMock.Object, _loggerMock.Object); @@ -56,19 +52,17 @@ public void Can_Get_Guid_QueryValue() public void GetRequired_Throws_If_Not_Present() { // arrange - const string key = "some-id"; - var filterQuery = $"filter[{key}]"; + const string key = "SomeId"; var value = Guid.NewGuid(); - var query = new Dictionary { - { filterQuery, value.ToString() } + var querySet = new QuerySet + { + Filters = new List { + new FilterQuery(key, value.ToString(), "eq") + } }; - _queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator()); - - var querySet = new QuerySet(_contextMock.Object, _queryMock.Object); - _contextMock.Setup(c => c.QuerySet) - .Returns(querySet); + _contextMock.Setup(c => c.QuerySet).Returns(querySet); var service = new QueryAccessor(_contextMock.Object, _loggerMock.Object); @@ -83,19 +77,17 @@ public void GetRequired_Throws_If_Not_Present() public void GetRequired_Does_Not_Throw_If_Present() { // arrange - const string key = "some-id"; - var filterQuery = $"filter[{key}]"; + const string key = "SomeId"; var value = Guid.NewGuid(); - var query = new Dictionary { - { filterQuery, value.ToString() } + var querySet = new QuerySet + { + Filters = new List { + new FilterQuery(key, value.ToString(), "eq") + } }; - _queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator()); - - var querySet = new QuerySet(_contextMock.Object, _queryMock.Object); - _contextMock.Setup(c => c.QuerySet) - .Returns(querySet); + _contextMock.Setup(c => c.QuerySet).Returns(querySet); var service = new QueryAccessor(_contextMock.Object, _loggerMock.Object); diff --git a/test/UnitTests/Internal/QuerySet_Tests.cs b/test/UnitTests/Services/QueryParser_Tests.cs similarity index 72% rename from test/UnitTests/Internal/QuerySet_Tests.cs rename to test/UnitTests/Services/QueryParser_Tests.cs index 2a433e63af..a64c5b3692 100644 --- a/test/UnitTests/Internal/QuerySet_Tests.cs +++ b/test/UnitTests/Services/QueryParser_Tests.cs @@ -1,25 +1,23 @@ -using System; using System.Collections.Generic; using System.Linq; +using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Moq; using Xunit; -namespace UnitTests.Internal +namespace UnitTests.Services { - public class QuerySet_Tests + public class QueryParser_Tests { - private readonly Mock _jsonApiContextMock; + private readonly Mock _controllerContextMock; private readonly Mock _queryCollectionMock; - public QuerySet_Tests() + public QueryParser_Tests() { - _jsonApiContextMock = new Mock(); + _controllerContextMock = new Mock(); _queryCollectionMock = new Mock(); } @@ -35,14 +33,14 @@ public void Can_Build_Filters() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.None)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Equal("value", querySet.Filters.Single(f => f.Key == "Key").Value); @@ -61,14 +59,14 @@ public void Filters_Properly_Parses_DateTime_With_Operation() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.None)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Equal(dt, querySet.Filters.Single(f => f.Key == "Key").Value); @@ -88,14 +86,14 @@ public void Filters_Properly_Parses_DateTime_Without_Operation() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.None)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Equal(dt, querySet.Filters.Single(f => f.Key == "Key").Value); @@ -114,14 +112,14 @@ public void Can_Disable_Filters() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.Filter)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Empty(querySet.Filters); @@ -139,14 +137,14 @@ public void Can_Disable_Sort() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.Sort)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Empty(querySet.SortParameters); @@ -164,14 +162,14 @@ public void Can_Disable_Include() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.Include)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Empty(querySet.IncludedRelationships); @@ -189,14 +187,14 @@ public void Can_Disable_Page() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.Page)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Equal(0, querySet.PageQuery.PageSize); @@ -214,14 +212,14 @@ public void Can_Disable_Fields() .Setup(m => m.GetEnumerator()) .Returns(query.GetEnumerator()); - _jsonApiContextMock + _controllerContextMock .Setup(m => m.GetControllerAttribute()) .Returns(new DisableQueryAttribute(QueryParams.Fields)); - // act -- ctor calls BuildQuerySet() - var querySet = new QuerySet( - _jsonApiContextMock.Object, - _queryCollectionMock.Object); + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert Assert.Empty(querySet.Fields); From fc161d2708fbfcd6256c74b218c99c5a28506700 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 9 Aug 2017 22:16:01 -0500 Subject: [PATCH 004/227] feat(models): initial operation models --- .../Controllers/QueryParams.cs | 2 - .../Models/Operations/Operation.cs | 53 +++++++++++++++++++ .../Models/Operations/OperationCode.cs | 10 ++++ .../Models/Operations/ResourceReference.cs | 16 ++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/JsonApiDotNetCore/Models/Operations/Operation.cs create mode 100644 src/JsonApiDotNetCore/Models/Operations/OperationCode.cs create mode 100644 src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs diff --git a/src/JsonApiDotNetCore/Controllers/QueryParams.cs b/src/JsonApiDotNetCore/Controllers/QueryParams.cs index 7e59f976c5..4c963098ad 100644 --- a/src/JsonApiDotNetCore/Controllers/QueryParams.cs +++ b/src/JsonApiDotNetCore/Controllers/QueryParams.cs @@ -1,5 +1,3 @@ -using System; - namespace JsonApiDotNetCore.Controllers { public enum QueryParams diff --git a/src/JsonApiDotNetCore/Models/Operations/Operation.cs b/src/JsonApiDotNetCore/Models/Operations/Operation.cs new file mode 100644 index 0000000000..533af2e109 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Operations/Operation.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Collections.Generic; +using JsonApiDotNetCore.Controllers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace JsonApiDotNetCore.Models.Operations +{ + public class Operation : DocumentBase + { + [JsonProperty("op")] + public OperationCode Op { get; set; } + + [JsonProperty("ref")] + public ResourceReference Ref { get; set; } + + [JsonProperty("params")] + public QueryParams Params { get; set; } + + [JsonProperty("data")] + public object Data + { + get + { + if (DataIsList) return DataList; + return DataObject; + } + set => SetData(value); + } + + private void SetData(object data) + { + if (data is JArray jArray) { + DataIsList = true; + DataList = jArray.ToObject>(); + } + else if (data is List dataList) { + DataIsList = true; + DataList = dataList; + } + else if (data is JObject jObject) { + DataObject = jObject.ToObject(); + } + else if (data is DocumentData dataObject) { + DataObject = dataObject; + } + } + + public bool DataIsList { get; private set; } + public List DataList { get; private set; } + public DocumentData DataObject { get; private set; } + } +} diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs b/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs new file mode 100644 index 0000000000..ffe3310985 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs @@ -0,0 +1,10 @@ +namespace JsonApiDotNetCore.Models.Operations +{ + public enum OperationCode + { + get = 1, + add = 2, + replace = 3, + remove = 4 + } +} diff --git a/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs b/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs new file mode 100644 index 0000000000..a8caa7ca05 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace JsonApiDotNetCore.Models.Operations +{ + public class ResourceReference + { + [JsonProperty("type")] + public object Type { get; set; } + + [JsonProperty("id")] + public object Id { get; set; } + + [JsonProperty("relationship")] + public string Relationship { get; set; } + } +} From c504ef17496e0fa3de1b6f7f8b032cf7b2cc53a5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 9 Aug 2017 22:16:33 -0500 Subject: [PATCH 005/227] feat(pointers): first pass at OperationsPointer --- .../JsonApiDotNetCore.csproj | 3 +- .../Models/Pointers/OperationsPointer.cs | 84 +++++++++++++++++++ .../Models/Pointers/Pointer.cs | 22 +++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs create mode 100644 src/JsonApiDotNetCore/Models/Pointers/Pointer.cs diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index c3c987f32a..a67648a417 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -19,6 +19,7 @@ + - + \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs new file mode 100644 index 0000000000..61b9b9b166 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models.Operations; + +namespace JsonApiDotNetCore.Models.Pointers +{ + public class OperationsPointer : Pointer + { + /// + /// + /// + /// + public override object GetValue(object root) + { + if (root == null) throw new ArgumentNullException(nameof(root)); + if (PointerAddress == null) throw new InvalidOperationException("Cannot get pointer value from null PointerAddress"); + + if (root is List operations) + return GetValueFromRoot(operations); + + throw new ArgumentException(nameof(root)); + } + + private object GetValueFromRoot(List operations) + { + var pathSegments = PointerAddress.Split('/'); + + if(pathSegments.Length < 4) + throw BadRequestException("number of segments", pathSegments.Length); + + if (pathSegments[0] != "operations") + throw BadRequestException("prefix", pathSegments[0]); + + // /operations/{operationIndex} → operations = [...] + if(int.TryParse(pathSegments[1], out int operationIndex)) + return GetValueFromOperation(operations[operationIndex], pathSegments); + else + throw BadRequestException("operation index", operationIndex); + } + + private object GetValueFromOperation(Operation operation, string[] pathSegments) + { + var operationPropertyName = pathSegments[2]; + if(operationPropertyName != "data") + throw BadRequestException("operation property name", operationPropertyName); + + // /operations/0/data → data = {...} + if(operation.DataIsList == false) + return GetValueFromData(operation.DataObject, pathSegments, segementStartIndex: 3); + + // /operations/0/data/{dataIndex} → data = [...] + if(int.TryParse(pathSegments[3], out int dataIndex)) { + if(operation.DataList.Count >= dataIndex - 1) + return GetValueFromData(operation.DataList[dataIndex], pathSegments, segementStartIndex: 4); + throw BadRequestException("data index", dataIndex, "Pointer references an index in the data array that cannot be found at the specified position."); + } + else { + throw BadRequestException("data index", dataIndex, "Pointer segement should provide array index but could not be parsed to an integer."); + } + } + + private object GetValueFromData(DocumentData data, string[] pathSegments, int segementStartIndex) + { + // /operations/0/data/{dataPropertyName} + if(pathSegments.Length <= segementStartIndex) + throw BadRequestException("length", pathSegments.Length, "Pointer does not contain enough segments to locate data property."); + + var dataPropertyName = pathSegments[segementStartIndex]; + switch(dataPropertyName) + { + case "id": + return data.Id; + case "type": + return data.Type; + default: + throw BadRequestException("data property name", dataPropertyName, "Only 'id' and 'type' pointers are supported."); + } + } + + private JsonApiException BadRequestException(string condition, object value, string extraDetail = null) + => new JsonApiException(400, $"Operations pointer has invalid {condition} '{value}' in pointer '{PointerAddress}'. {extraDetail}"); + } +} diff --git a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs new file mode 100644 index 0000000000..ecb25f314c --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Schema; + +namespace JsonApiDotNetCore.Models.Pointers +{ + public abstract class Pointer + { + private static JSchema JsonSchema { get; } = JSchema.Parse("{ 'pointer': {'type': 'string'} }"); + + /// + /// Location represented by the pointer + /// + /// /operations/0/data/id + [JsonProperty("pointer")] + public string PointerAddress { get; set; } + + /// + /// Get the value located at the PointerAddress in the supplied object + /// + public abstract object GetValue(object root); + } +} From be26e89849b6319a4ab3d3209053dfe9689db089 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 10 Aug 2017 22:56:48 -0500 Subject: [PATCH 006/227] feat(pointers): wrap up OperationsPointers and tests --- .../Builders/DocumentBuilder.cs | 10 +- .../Models/Pointers/OperationsPointer.cs | 2 +- .../Models/RelationshipData.cs | 12 +- .../Serialization/JsonApiDeSerializer.cs | 6 +- .../Models/Pointers/OperationsPointerTests.cs | 145 ++++++++++++++++++ 5 files changed, 160 insertions(+), 15 deletions(-) create mode 100644 test/UnitTests/Models/Pointers/OperationsPointerTests.cs diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index d8d38390d8..ae102111c3 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -227,29 +227,29 @@ private bool RelationshipIsIncluded(string relationshipName) _jsonApiContext.IncludedRelationships.Contains(relationshipName); } - private List> GetRelationships(IEnumerable entities) + private List> GetRelationships(IEnumerable entities) { var objType = entities.GetType().GenericTypeArguments[0]; var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); - var relationships = new List>(); + var relationships = new List>(); foreach (var entity in entities) { - relationships.Add(new Dictionary { + relationships.Add(new Dictionary { {"type", typeName.EntityName }, {"id", ((IIdentifiable)entity).StringId } }); } return relationships; } - private Dictionary GetRelationship(object entity) + private Dictionary GetRelationship(object entity) { var objType = entity.GetType(); var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); - return new Dictionary { + return new Dictionary { {"type", typeName.EntityName }, {"id", ((IIdentifiable)entity).StringId } }; diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs index 61b9b9b166..5c5d852b25 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs @@ -24,7 +24,7 @@ public override object GetValue(object root) private object GetValueFromRoot(List operations) { - var pathSegments = PointerAddress.Split('/'); + var pathSegments = PointerAddress.Split(new [] { '/' } , StringSplitOptions.RemoveEmptyEntries); if(pathSegments.Length < 4) throw BadRequestException("number of segments", pathSegments.Length); diff --git a/src/JsonApiDotNetCore/Models/RelationshipData.cs b/src/JsonApiDotNetCore/Models/RelationshipData.cs index 21efa7409c..f74651318e 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipData.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipData.cs @@ -20,20 +20,20 @@ public object ExposedData { set { if(value is IEnumerable) if(value is JObject jObject) - SingleData = jObject.ToObject>(); + SingleData = jObject.ToObject>(); else if(value is JArray jArray) - ManyData = jArray.ToObject>>(); + ManyData = jArray.ToObject>>(); else - ManyData = (List>)value; + ManyData = (List>)value; else - SingleData = (Dictionary)value; + SingleData = (Dictionary)value; } } [JsonIgnore] - public List> ManyData { get; set; } + public List> ManyData { get; set; } [JsonIgnore] - public Dictionary SingleData { get; set; } + public Dictionary SingleData { get; set; } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index d8cbf245bf..021adbe538 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -176,7 +176,7 @@ private object SetHasOneRelationship(object entity, var relationshipAttr = _jsonApiContext.RequestEntity.Relationships .SingleOrDefault(r => r.PublicRelationshipName == relationshipName); - var data = (Dictionary)relationshipData.ExposedData; + var data = (Dictionary)relationshipData.ExposedData; if (data == null) return entity; @@ -206,12 +206,12 @@ private object SetHasManyRelationship(object entity, if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) { - var data = (List>)relationshipData.ExposedData; + var data = (List>)relationshipData.ExposedData; if (data == null) return entity; var genericProcessor = _genericProcessorFactory.GetProcessor(attr.Type); - var ids = relationshipData.ManyData.Select(r => r["id"]); + var ids = relationshipData.ManyData.Select(r => r["id"].ToString()); genericProcessor.SetRelationships(entity, attr, ids); } diff --git a/test/UnitTests/Models/Pointers/OperationsPointerTests.cs b/test/UnitTests/Models/Pointers/OperationsPointerTests.cs new file mode 100644 index 0000000000..4a82e1a164 --- /dev/null +++ b/test/UnitTests/Models/Pointers/OperationsPointerTests.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Models.Pointers; +using Newtonsoft.Json; +using Xunit; + +namespace UnitTests.Models.Pointers +{ + public class OperationsPointerTests + { + [Fact] + public void GetValue_Can_Get_Value_From_Data_Id() + { + // arrange + var json = @"[ + { + ""op"": ""add"", + ""data"": { + ""id"": ""1"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/0/data/id"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("1", value.ToString()); + } + + [Fact] + public void GetValue_Can_Get_Value_From_Data_Type() + { + // arrange + var json = @"[ + { + ""op"": ""add"", + ""data"": { + ""id"": ""1"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/0/data/type"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("authors", value.ToString()); + } + + [Fact] + public void GetValue_Can_Get_Value_From_ListData_Id() + { + // arrange + var json = @"[ + { + ""op"": ""get"", + ""data"": [{ + ""id"": ""1"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + }, { + ""id"": ""2"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""jaredcnance"" + } + }] + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/0/data/1/id"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("2", value.ToString()); + } + + [Fact] + public void GetValue_Can_Get_Value_From_Second_Operations_Data_Id() + { + // arrange + var json = @"[ + { + ""op"": ""get"", + ""data"": { + ""id"": ""1"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + },{ + ""op"": ""get"", + ""data"": { + ""id"": ""2"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""jaredcnance"" + } + } + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/1/data/id"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("2", value.ToString()); + } + + [Fact] + public void GetValue_Can_Get_Value_From_Second_Operations_Data_Type() + { + // arrange + var json = @"[ + { + ""op"": ""get"", + ""data"": { + ""id"": ""1"", + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + },{ + ""op"": ""get"", + ""data"": { + ""id"": ""1"", + ""type"": ""articles"", + ""attributes"": { + ""name"": ""JSON API paints my bikeshed!"" + } + } + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/1/data/type"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("articles", value.ToString()); + } + } +} \ No newline at end of file From 4f354a0b2673e47e0d55c8954503708e38b211df Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 24 Aug 2017 21:06:13 -0500 Subject: [PATCH 007/227] feat(pointers): finish pointer modeling and eval --- src/JsonApiDotNetCore/Models/DocumentData.cs | 2 +- .../Models/Operations/Operation.cs | 4 +- .../Models/Operations/Params.cs | 13 +++++ .../Models/Pointers/OperationsPointer.cs | 52 ++++++++++++++----- .../Models/Pointers/OperationsPointerTests.cs | 19 +++++++ 5 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 src/JsonApiDotNetCore/Models/Operations/Params.cs diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index 32ca6f3f51..8c736f2922 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -13,7 +13,7 @@ public class DocumentData [JsonProperty("attributes")] public Dictionary Attributes { get; set; } - + [JsonProperty("relationships")] public Dictionary Relationships { get; set; } } diff --git a/src/JsonApiDotNetCore/Models/Operations/Operation.cs b/src/JsonApiDotNetCore/Models/Operations/Operation.cs index 533af2e109..558d224d04 100644 --- a/src/JsonApiDotNetCore/Models/Operations/Operation.cs +++ b/src/JsonApiDotNetCore/Models/Operations/Operation.cs @@ -1,6 +1,4 @@ -using System.Collections; using System.Collections.Generic; -using JsonApiDotNetCore.Controllers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -15,7 +13,7 @@ public class Operation : DocumentBase public ResourceReference Ref { get; set; } [JsonProperty("params")] - public QueryParams Params { get; set; } + public Params Params { get; set; } [JsonProperty("data")] public object Data diff --git a/src/JsonApiDotNetCore/Models/Operations/Params.cs b/src/JsonApiDotNetCore/Models/Operations/Params.cs new file mode 100644 index 0000000000..470e8f4aa3 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Operations/Params.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace JsonApiDotNetCore.Models.Operations +{ + public class Params + { + public List Include { get; set; } + public List Sort { get; set; } + public Dictionary Filter { get; set; } + public string Page { get; set; } + public Dictionary Fields { get; set; } + } +} diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs index 5c5d852b25..f245ea4414 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs @@ -15,8 +15,8 @@ public override object GetValue(object root) { if (root == null) throw new ArgumentNullException(nameof(root)); if (PointerAddress == null) throw new InvalidOperationException("Cannot get pointer value from null PointerAddress"); - - if (root is List operations) + + if (root is List operations) return GetValueFromRoot(operations); throw new ArgumentException(nameof(root)); @@ -24,16 +24,16 @@ public override object GetValue(object root) private object GetValueFromRoot(List operations) { - var pathSegments = PointerAddress.Split(new [] { '/' } , StringSplitOptions.RemoveEmptyEntries); + var pathSegments = PointerAddress.ToLower().Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - if(pathSegments.Length < 4) + if (pathSegments.Length < 4) throw BadRequestException("number of segments", pathSegments.Length); if (pathSegments[0] != "operations") throw BadRequestException("prefix", pathSegments[0]); // /operations/{operationIndex} → operations = [...] - if(int.TryParse(pathSegments[1], out int operationIndex)) + if (int.TryParse(pathSegments[1], out int operationIndex)) return GetValueFromOperation(operations[operationIndex], pathSegments); else throw BadRequestException("operation index", operationIndex); @@ -42,32 +42,56 @@ private object GetValueFromRoot(List operations) private object GetValueFromOperation(Operation operation, string[] pathSegments) { var operationPropertyName = pathSegments[2]; - if(operationPropertyName != "data") - throw BadRequestException("operation property name", operationPropertyName); - + + // /operations/0/ref → ref = {...} + if (operationPropertyName == "ref") + return GetValueFromRef(operation.Ref, pathSegments); + // /operations/0/data → data = {...} - if(operation.DataIsList == false) + if (operation.DataIsList == false) return GetValueFromData(operation.DataObject, pathSegments, segementStartIndex: 3); // /operations/0/data/{dataIndex} → data = [...] - if(int.TryParse(pathSegments[3], out int dataIndex)) { - if(operation.DataList.Count >= dataIndex - 1) + if (int.TryParse(pathSegments[3], out int dataIndex)) + { + if (operation.DataList.Count >= dataIndex - 1) return GetValueFromData(operation.DataList[dataIndex], pathSegments, segementStartIndex: 4); throw BadRequestException("data index", dataIndex, "Pointer references an index in the data array that cannot be found at the specified position."); } - else { + else + { throw BadRequestException("data index", dataIndex, "Pointer segement should provide array index but could not be parsed to an integer."); } } + private object GetValueFromRef(ResourceReference reference, string[] pathSegments) + { + const int segementStartIndex = 3; + + // /operations/0/ref/{dataPropertyName} + if (pathSegments.Length <= segementStartIndex) + throw BadRequestException("length", pathSegments.Length, "Pointer does not contain enough segments to locate ref property."); + + var dataPropertyName = pathSegments[segementStartIndex]; + switch (dataPropertyName) + { + case "id": + return reference.Id; + case "type": + return reference.Type; + default: + throw BadRequestException("ref property name", dataPropertyName, "Only 'id' and 'type' pointers are supported."); + } + } + private object GetValueFromData(DocumentData data, string[] pathSegments, int segementStartIndex) { // /operations/0/data/{dataPropertyName} - if(pathSegments.Length <= segementStartIndex) + if (pathSegments.Length <= segementStartIndex) throw BadRequestException("length", pathSegments.Length, "Pointer does not contain enough segments to locate data property."); var dataPropertyName = pathSegments[segementStartIndex]; - switch(dataPropertyName) + switch (dataPropertyName) { case "id": return data.Id; diff --git a/test/UnitTests/Models/Pointers/OperationsPointerTests.cs b/test/UnitTests/Models/Pointers/OperationsPointerTests.cs index 4a82e1a164..9aafc284dc 100644 --- a/test/UnitTests/Models/Pointers/OperationsPointerTests.cs +++ b/test/UnitTests/Models/Pointers/OperationsPointerTests.cs @@ -8,6 +8,25 @@ namespace UnitTests.Models.Pointers { public class OperationsPointerTests { + [Fact] + public void GetValue_Can_Get_Value_From_Ref_Id() + { + // arrange + var json = @"[ + { + ""op"": ""add"", + ""ref"": { + ""type"": ""articles"", + ""id"": ""1"" + } + }]"; + var operations = JsonConvert.DeserializeObject>(json); + var pointerJson = @"{ ""pointer"": ""/operations/0/ref/id"" }"; + var pointer = JsonConvert.DeserializeObject(pointerJson); + var value = pointer.GetValue(operations); + Assert.Equal("1", value.ToString()); + } + [Fact] public void GetValue_Can_Get_Value_From_Data_Id() { From 0d9589090fbf3b1c8334a6714bdf1da5a79b882f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 24 Aug 2017 23:14:38 -0500 Subject: [PATCH 008/227] first pass at pointer replacement and service location --- .../Builders/ContextGraphBuilder.cs | 6 ++- .../Builders/IContextGraphBuilder.cs | 3 +- .../Data/DefaultEntityRepository.cs | 2 +- .../Internal/ContextEntity.cs | 1 + .../Generics/GenericProcessorFactory.cs | 12 ++--- .../Generics/IGenericProcessorFactory.cs | 4 +- src/JsonApiDotNetCore/Models/DocumentData.cs | 47 ++++++++++++++++++- .../Models/Operations/Operation.cs | 11 +++++ .../Models/Pointers/OperationsPointer.cs | 2 +- .../Models/Pointers/Pointer.cs | 4 +- .../Serialization/IJsonApiDeSerializer.cs | 2 + .../Serialization/JsonApiDeSerializer.cs | 8 ++-- .../Services/Contract/ICreateService.cs | 1 - .../Services/Contract/IDeleteService.cs | 1 - .../Services/Contract/IGetByIdService.cs | 1 - .../Contract/IGetRelationshipService.cs | 1 - .../Contract/IGetRelationshipsService.cs | 1 - .../Services/Contract/IUpdateService.cs | 1 - .../Services/EntityResourceService.cs | 2 +- .../Services/Operations/CreateOpProcessor.cs | 41 ++++++++++++++++ .../Services/Operations/IOpProcessor.cs | 16 +++++++ .../Operations/IOperationsProcessor.cs | 45 ++++++++++++++++++ .../Operations/OperationProcessorResolver.cs | 44 +++++++++++++++++ 23 files changed, 228 insertions(+), 28 deletions(-) create mode 100644 src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs create mode 100644 src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs create mode 100644 src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs create mode 100644 src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index e47dec2065..c5099bf298 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -28,7 +28,10 @@ public IContextGraph Build() return graph; } - public void AddResource(string pluralizedTypeName) where TResource : class + public void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable + => AddResource(pluralizedTypeName); + + public void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable { var entityType = typeof(TResource); @@ -38,6 +41,7 @@ public void AddResource(string pluralizedTypeName) where TResource : { EntityName = pluralizedTypeName, EntityType = entityType, + IdentityType = typeof(TId), Attributes = GetAttributes(entityType), Relationships = GetRelationships(entityType) }); diff --git a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs index bab62cca64..5844166c18 100644 --- a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs @@ -8,7 +8,8 @@ public interface IContextGraphBuilder { Link DocumentLinks { get; set; } IContextGraph Build(); - void AddResource(string pluralizedTypeName) where TResource : class; + void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; + void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; void AddDbContext() where T : DbContext; } } diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 1199389c60..66804abee5 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -137,7 +137,7 @@ public virtual async Task UpdateAsync(TId id, TEntity entity) public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds) { - var genericProcessor = _genericProcessorFactory.GetProcessor(relationship.Type); + var genericProcessor = _genericProcessorFactory.GetProcessor(relationship.Type); await genericProcessor.UpdateRelationshipsAsync(parent, relationship, relationshipIds); } diff --git a/src/JsonApiDotNetCore/Internal/ContextEntity.cs b/src/JsonApiDotNetCore/Internal/ContextEntity.cs index 4843d245c1..ff539b79ea 100644 --- a/src/JsonApiDotNetCore/Internal/ContextEntity.cs +++ b/src/JsonApiDotNetCore/Internal/ContextEntity.cs @@ -8,6 +8,7 @@ public class ContextEntity { public string EntityName { get; set; } public Type EntityType { get; set; } + public Type IdentityType { get; set; } public List Attributes { get; set; } public List Relationships { get; set; } public Link Links { get; set; } = Link.All; diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index a238e4ef9f..0918da40d1 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,24 +1,20 @@ using System; -using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Internal.Generics { public class GenericProcessorFactory : IGenericProcessorFactory { - private readonly DbContext _dbContext; private readonly IServiceProvider _serviceProvider; - public GenericProcessorFactory(DbContext dbContext, - IServiceProvider serviceProvider) + public GenericProcessorFactory(IServiceProvider serviceProvider) { - _dbContext = dbContext; _serviceProvider = serviceProvider; } - public IGenericProcessor GetProcessor(Type type) + public TInterface GetProcessor(Type[] types) { - var processorType = typeof(GenericProcessor<>).MakeGenericType(type); - return (IGenericProcessor)_serviceProvider.GetService(processorType); + var processorType = typeof(GenericProcessor<>).MakeGenericType(types); + return (TInterface)_serviceProvider.GetService(processorType); } } } diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs index 83e794a12b..ecd2c7cdc4 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs @@ -5,10 +5,12 @@ namespace JsonApiDotNetCore.Internal.Generics /// /// Used to generate a generic operations processor when the types /// are not know until runtime. The typical use case would be for + /// accessing relationship data.be for /// accessing relationship data. /// public interface IGenericProcessorFactory { - IGenericProcessor GetProcessor(Type type); + + TInterface GetProcessor(params Type[] types); } } diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index 8c736f2922..d87958f37c 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -1,15 +1,18 @@ using System.Collections.Generic; +using JsonApiDotNetCore.Models.Pointers; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; namespace JsonApiDotNetCore.Models { public class DocumentData { [JsonProperty("type")] - public string Type { get; set; } + public object Type { get; set; } [JsonProperty("id")] - public string Id { get; set; } + public object Id { get; set; } [JsonProperty("attributes")] public Dictionary Attributes { get; set; } @@ -17,4 +20,44 @@ public class DocumentData [JsonProperty("relationships")] public Dictionary Relationships { get; set; } } + + public class DocumentDataPointerReplacement + where TPointer : Pointer, new() + { + private readonly DocumentData _data; + + public DocumentDataPointerReplacement(DocumentData data) + { + _data = data; + } + + public void ReplacePointers(List parentDoc) + { + ReplacePointer(_data.Id, parentDoc); + ReplacePointer(_data.Type, parentDoc); + } + + private void ReplacePointer(object reference, List parentDoc) + { + if (reference is JObject jObj) + if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) + reference = pointer.GetValue(parentDoc); + } + } } + +public static class JObjectExtensions +{ + public static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) + where TPointer : Pointer, new() + { + if (obj.IsValid(schema)) + { + pointer = obj.ToObject(); + return true; + } + + pointer = null; + return false; + } +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Models/Operations/Operation.cs b/src/JsonApiDotNetCore/Models/Operations/Operation.cs index 558d224d04..1493142b9f 100644 --- a/src/JsonApiDotNetCore/Models/Operations/Operation.cs +++ b/src/JsonApiDotNetCore/Models/Operations/Operation.cs @@ -47,5 +47,16 @@ private void SetData(object data) public bool DataIsList { get; private set; } public List DataList { get; private set; } public DocumentData DataObject { get; private set; } + + public string GetResourceTypeName() + { + if(Ref != null) + return Ref.Type?.ToString(); + + if(DataIsList) + return DataList[0].Type?.ToString(); + + return DataObject.Type?.ToString(); + } } } diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs index f245ea4414..0df8f64e72 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs @@ -5,7 +5,7 @@ namespace JsonApiDotNetCore.Models.Pointers { - public class OperationsPointer : Pointer + public class OperationsPointer : Pointer { /// /// diff --git a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs index ecb25f314c..27f0083904 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs @@ -3,9 +3,9 @@ namespace JsonApiDotNetCore.Models.Pointers { - public abstract class Pointer + public abstract class Pointer { - private static JSchema JsonSchema { get; } = JSchema.Parse("{ 'pointer': {'type': 'string'} }"); + public static JSchema JsonSchema { get; } = JSchema.Parse("{ 'pointer': {'type': 'string'} }"); /// /// Location represented by the pointer diff --git a/src/JsonApiDotNetCore/Serialization/IJsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/IJsonApiDeSerializer.cs index 5fb91dae36..0355c962ed 100644 --- a/src/JsonApiDotNetCore/Serialization/IJsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/IJsonApiDeSerializer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Serialization { @@ -8,5 +9,6 @@ public interface IJsonApiDeSerializer TEntity Deserialize(string requestBody); object DeserializeRelationship(string requestBody); List DeserializeList(string requestBody); + object DocumentToObject(DocumentData data); } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 021adbe538..a5168f6185 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -78,9 +78,9 @@ public List DeserializeList(string requestBody) } } - private object DocumentToObject(DocumentData data) + public object DocumentToObject(DocumentData data) { - var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(data.Type); + var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(data.Type?.ToString()); _jsonApiContext.RequestEntity = contextEntity; var entity = Activator.CreateInstance(contextEntity.EntityType); @@ -91,7 +91,7 @@ private object DocumentToObject(DocumentData data) var identifiableEntity = (IIdentifiable)entity; if (data.Id != null) - identifiableEntity.StringId = data.Id; + identifiableEntity.StringId = data.Id?.ToString(); return identifiableEntity; } @@ -210,7 +210,7 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var genericProcessor = _genericProcessorFactory.GetProcessor(attr.Type); + var genericProcessor = _genericProcessorFactory.GetProcessor(attr.Type); var ids = relationshipData.ManyData.Select(r => r["id"].ToString()); genericProcessor.SetRelationships(entity, attr, ids); } diff --git a/src/JsonApiDotNetCore/Services/Contract/ICreateService.cs b/src/JsonApiDotNetCore/Services/Contract/ICreateService.cs index a4c0cd6cbb..df4916856d 100644 --- a/src/JsonApiDotNetCore/Services/Contract/ICreateService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/ICreateService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Contract/IDeleteService.cs b/src/JsonApiDotNetCore/Services/Contract/IDeleteService.cs index 4ba09fdf40..52e4ca17f4 100644 --- a/src/JsonApiDotNetCore/Services/Contract/IDeleteService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/IDeleteService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Contract/IGetByIdService.cs b/src/JsonApiDotNetCore/Services/Contract/IGetByIdService.cs index 27761abd5d..c01c6a1391 100644 --- a/src/JsonApiDotNetCore/Services/Contract/IGetByIdService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/IGetByIdService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipService.cs b/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipService.cs index bd9c0b2be0..de32b77547 100644 --- a/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipsService.cs b/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipsService.cs index a61cf8f7ac..e519d0b4d1 100644 --- a/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipsService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/IGetRelationshipsService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Contract/IUpdateService.cs b/src/JsonApiDotNetCore/Services/Contract/IUpdateService.cs index ca2e171090..bd5f13dd60 100644 --- a/src/JsonApiDotNetCore/Services/Contract/IUpdateService.cs +++ b/src/JsonApiDotNetCore/Services/Contract/IUpdateService.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 7db499fd5e..c8c150a108 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -133,7 +133,7 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa .Relationships .FirstOrDefault(r => r.InternalRelationshipName == relationshipName); - var relationshipIds = relationships.Select(r => r.Id); + var relationshipIds = relationships.Select(r => r.Id?.ToString()); await _entities.UpdateRelationshipsAsync(entity, relationship, relationshipIds); } diff --git a/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs new file mode 100644 index 0000000000..53a91c2fa6 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Serialization; + +namespace JsonApiDotNetCore.Services.Operations +{ + public class CreateOpProcessor : IOpProcessor + where T : class, IIdentifiable + { + private readonly ICreateService _service; + private readonly IJsonApiDeSerializer _deSerializer; + private readonly IDocumentBuilder _documentBuilder; + + public CreateOpProcessor( + ICreateService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder) + { + _service = service; + _deSerializer = deSerializer; + _documentBuilder = documentBuilder; + } + + public async Task ProcessAsync(Operation operation) + { + var model = (T)_deSerializer.DocumentToObject(operation.DataObject); + var result = await _service.CreateAsync(model); + + var operationResult = new Operation { + Op = OperationCode.add + }; + + operationResult.Data = _documentBuilder.Build(result); + + return operationResult; + } + } +} diff --git a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs new file mode 100644 index 0000000000..fe36dd8a9a --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; + +namespace JsonApiDotNetCore.Services.Operations +{ + public interface IOpProcessor + { + Task ProcessAsync(Operation operation); + } + + public interface IOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } +} diff --git a/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs new file mode 100644 index 0000000000..8230730d69 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Models.Pointers; + +namespace JsonApiDotNetCore.Services.Operations +{ + public interface IOperationsProcessor + { + Task> ProcessAsync(List inputOps); + } + + public class OperationsProcessor : IOperationsProcessor + { + private readonly IOperationProcessorResolver _processorResolver; + + public OperationsProcessor(IOperationProcessorResolver processorResolver) + { + _processorResolver = processorResolver; + } + public async Task> ProcessAsync(List inputOps) + { + var outputOps = new List(); + + foreach(var op in inputOps) + { + // TODO: parse pointers: + // locate all objects within the document and replace them + var operationsPointer = new OperationsPointer(); + var replacer = new DocumentDataPointerReplacement(op.DataObject); + replacer.ReplacePointers(outputOps); + + /// + var processor = _processorResolver.LocateCreateService(op); + var resultOp = await processor.ProcessAsync(op); + outputOps.Add(resultOp); + } + for(var i=0; i < inputOps.Count; i++) + { + + } + } + } +} diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs new file mode 100644 index 0000000000..98cf03a892 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -0,0 +1,44 @@ +using System.Collections.Concurrent; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Internal.Generics; +using JsonApiDotNetCore.Models.Operations; + +namespace JsonApiDotNetCore.Services.Operations +{ + public interface IOperationProcessorResolver + { + IOpProcessor LocateCreateService(Operation operation); + } + + public class OperationProcessorResolver : IOperationProcessorResolver + { + private readonly IGenericProcessorFactory _processorFactory; + private readonly IJsonApiContext _context; + private ConcurrentDictionary _cachedProcessors = new ConcurrentDictionary(); + + public OperationProcessorResolver( + IGenericProcessorFactory processorFactory, + IJsonApiContext context) + { + _processorFactory = processorFactory; + _context = context; + } + + // TODO: there may be some optimizations here around the cache such as not caching processors + // if the request only contains a single op + public IOpProcessor LocateCreateService(Operation operation) + { + var resource = operation.GetResourceTypeName(); + + if (_cachedProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + return cachedProcessor; + + var contextEntity = _context.ContextGraph.GetContextEntity(); + var processor = _processorFactory.GetProcessor(contextEntity.EntityType, contextEntity.IdentityType); + + _cachedProcessors[resource] = processor; + + return processor; + } + } +} From 4eb77ec6ed81e1e93a99df55cf6a44b390d04558 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 25 Aug 2017 23:44:00 -0500 Subject: [PATCH 009/227] chore(pointers): move classes into separate files --- .../Extensions/JObjectExtensions.cs | 23 +++++++ .../Generics/IGenericProcessorFactory.cs | 1 - src/JsonApiDotNetCore/Models/DocumentData.cs | 43 +------------ .../Operations/OperationsPointerExchanger.cs | 62 +++++++++++++++++++ 4 files changed, 86 insertions(+), 43 deletions(-) create mode 100644 src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs create mode 100644 src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs diff --git a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs new file mode 100644 index 0000000000..ec997042fb --- /dev/null +++ b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using JsonApiDotNetCore.Models.Pointers; + +namespace JsonApiDotNetCore.Extensions +{ + public static class JObjectExtensions + { + public static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) + where TPointer : Pointer, new() + { + if (obj.IsValid(schema)) + { + pointer = obj.ToObject(); + return true; + } + + pointer = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs index ecd2c7cdc4..39df292e14 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs @@ -10,7 +10,6 @@ namespace JsonApiDotNetCore.Internal.Generics /// public interface IGenericProcessorFactory { - TInterface GetProcessor(params Type[] types); } } diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index d87958f37c..afd9c717cf 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -1,8 +1,7 @@ +using System; using System.Collections.Generic; using JsonApiDotNetCore.Models.Pointers; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; namespace JsonApiDotNetCore.Models { @@ -20,44 +19,4 @@ public class DocumentData [JsonProperty("relationships")] public Dictionary Relationships { get; set; } } - - public class DocumentDataPointerReplacement - where TPointer : Pointer, new() - { - private readonly DocumentData _data; - - public DocumentDataPointerReplacement(DocumentData data) - { - _data = data; - } - - public void ReplacePointers(List parentDoc) - { - ReplacePointer(_data.Id, parentDoc); - ReplacePointer(_data.Type, parentDoc); - } - - private void ReplacePointer(object reference, List parentDoc) - { - if (reference is JObject jObj) - if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) - reference = pointer.GetValue(parentDoc); - } - } -} - -public static class JObjectExtensions -{ - public static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) - where TPointer : Pointer, new() - { - if (obj.IsValid(schema)) - { - pointer = obj.ToObject(); - return true; - } - - pointer = null; - return false; - } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs new file mode 100644 index 0000000000..87a7dbdc25 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using JsonApiDotNetCore.Models.Pointers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Extensions; + +namespace JsonApiDotNetCore.Services.Operations +{ + public class DocumentDataPointerReplacement + where TPointer : Pointer, new() + { + private readonly DocumentData _data; + + public DocumentDataPointerReplacement(DocumentData data) + { + _data = data; + } + + public void ReplacePointers(List parentDoc) + { + _data.Id = GetPointerValue(_data.Id, parentDoc); + _data.Type = GetPointerValue(_data.Type, parentDoc); + + if (_data.Relationships != null) + { + foreach (var relationshipDictionary in _data.Relationships) + { + if (relationshipDictionary.Value.IsHasMany) + { + foreach (var relationship in relationshipDictionary.Value.ManyData) + ReplaceDictionaryPointers(relationship, parentDoc); + } + else + { + ReplaceDictionaryPointers(relationshipDictionary.Value.SingleData, parentDoc); + } + } + } + } + + private void ReplaceDictionaryPointers(Dictionary relationship, List parentDoc) + { + if (relationship.ContainsKey("id")) + relationship["id"] = GetPointerValue(relationship["id"], parentDoc); + + if (relationship.ContainsKey("type")) + relationship["type"] = GetPointerValue(relationship["type"], parentDoc); + } + + private object GetPointerValue(object reference, List parentDoc) + { + if (reference is JObject jObj) + if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) + return pointer.GetValue(parentDoc); + + return reference; + } + } +} \ No newline at end of file From 63827cd3f77db64c39777dac8698011291de1330 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 25 Aug 2017 23:44:27 -0500 Subject: [PATCH 010/227] feat(RelationshipData): expose IsHasMany property --- .../Models/RelationshipData.cs | 40 ++++++--- .../UnitTests/Models/RelationshipDataTests.cs | 90 +++++++++++++++++++ 2 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 test/UnitTests/Models/RelationshipDataTests.cs diff --git a/src/JsonApiDotNetCore/Models/RelationshipData.cs b/src/JsonApiDotNetCore/Models/RelationshipData.cs index f74651318e..d81b2fe75a 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipData.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipData.cs @@ -11,29 +11,41 @@ public class RelationshipData public Links Links { get; set; } [JsonProperty("data")] - public object ExposedData { - get { - if(ManyData != null) + public object ExposedData + { + get + { + if (ManyData != null) return ManyData; return SingleData; } - set { - if(value is IEnumerable) - if(value is JObject jObject) - SingleData = jObject.ToObject>(); - else if(value is JArray jArray) - ManyData = jArray.ToObject>>(); - else - ManyData = (List>)value; - else + set + { + if (value is JObject jObject) + SingleData = jObject.ToObject>(); + else if (value is Dictionary dict) SingleData = (Dictionary)value; + else + SetManyData(value); } - } + } + + private void SetManyData(object value) + { + IsHasMany = true; + if (value is JArray jArray) + ManyData = jArray.ToObject>>(); + else + ManyData = (List>)value; + } [JsonIgnore] public List> ManyData { get; set; } - + [JsonIgnore] public Dictionary SingleData { get; set; } + + [JsonIgnore] + public bool IsHasMany { get; private set; } } } diff --git a/test/UnitTests/Models/RelationshipDataTests.cs b/test/UnitTests/Models/RelationshipDataTests.cs new file mode 100644 index 0000000000..780a5faa0b --- /dev/null +++ b/test/UnitTests/Models/RelationshipDataTests.cs @@ -0,0 +1,90 @@ +using JsonApiDotNetCore.Models; +using System.Collections.Generic; +using Xunit; +using Newtonsoft.Json.Linq; + +namespace UnitTests.Models +{ + public class RelationshipDataTests + { + [Fact] + public void Setting_ExposedData_To_List_Sets_ManyData() + { + // arrange + var relationshipData = new RelationshipData(); + var relationships = new List> { + new Dictionary { + { "authors", new { } } + } + }; + + // act + relationshipData.ExposedData = relationships; + + // assert + Assert.NotEmpty(relationshipData.ManyData); + Assert.True(relationshipData.ManyData[0].ContainsKey("authors")); + Assert.True(relationshipData.IsHasMany); + } + + [Fact] + public void Setting_ExposedData_To_JArray_Sets_ManyData() + { + // arrange + var relationshipData = new RelationshipData(); + var relationshipsJson = @"[ + { + ""authors"": {} + } + ]"; + + var relationships = JArray.Parse(relationshipsJson); + + // act + relationshipData.ExposedData = relationships; + + // assert + Assert.NotEmpty(relationshipData.ManyData); + Assert.True(relationshipData.ManyData[0].ContainsKey("authors")); + Assert.True(relationshipData.IsHasMany); + } + + [Fact] + public void Setting_ExposedData_To_Dictionary_Sets_SingleData() + { + // arrange + var relationshipData = new RelationshipData(); + var relationship = new Dictionary { + { "authors", new { } } + }; + + // act + relationshipData.ExposedData = relationship; + + // assert + Assert.NotNull(relationshipData.SingleData); + Assert.True(relationshipData.SingleData.ContainsKey("authors")); + Assert.False(relationshipData.IsHasMany); + } + + [Fact] + public void Setting_ExposedData_To_JObject_Sets_SingleData() + { + // arrange + var relationshipData = new RelationshipData(); + var relationshipJson = @"{ + ""authors"": {} + }"; + + var relationship = JObject.Parse(relationshipJson); + + // act + relationshipData.ExposedData = relationship; + + // assert + Assert.NotNull(relationshipData.SingleData); + Assert.True(relationshipData.SingleData.ContainsKey("authors")); + Assert.False(relationshipData.IsHasMany); + } + } +} From 8f8d76ff2caaa9bc59e1dfe772dabac85ead5fc1 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 25 Aug 2017 23:45:23 -0500 Subject: [PATCH 011/227] test(OperationsProcessor): performs pointer substitution --- .../Operations/IOperationsProcessor.cs | 10 +- .../Operations/OperationProcessorResolver.cs | 3 +- .../Operations/OperationsProcessorTests.cs | 94 +++++++++++++++++++ 3 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 test/UnitTests/Services/Operations/OperationsProcessorTests.cs diff --git a/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs index 8230730d69..0158caa081 100644 --- a/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs @@ -19,6 +19,7 @@ public OperationsProcessor(IOperationProcessorResolver processorResolver) { _processorResolver = processorResolver; } + public async Task> ProcessAsync(List inputOps) { var outputOps = new List(); @@ -31,15 +32,14 @@ public async Task> ProcessAsync(List inputOps) var replacer = new DocumentDataPointerReplacement(op.DataObject); replacer.ReplacePointers(outputOps); - /// var processor = _processorResolver.LocateCreateService(op); var resultOp = await processor.ProcessAsync(op); - outputOps.Add(resultOp); - } - for(var i=0; i < inputOps.Count; i++) - { + if(resultOp != null) + outputOps.Add(resultOp); } + + return outputOps; } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 98cf03a892..b56eb11bd6 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -1,5 +1,4 @@ using System.Collections.Concurrent; -using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models.Operations; @@ -33,7 +32,7 @@ public IOpProcessor LocateCreateService(Operation operation) if (_cachedProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) return cachedProcessor; - var contextEntity = _context.ContextGraph.GetContextEntity(); + var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor(contextEntity.EntityType, contextEntity.IdentityType); _cachedProcessors[resource] = processor; diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs new file mode 100644 index 0000000000..fadcd3be78 --- /dev/null +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Services.Operations; +using Moq; +using Newtonsoft.Json; +using Xunit; + +namespace UnitTests.Services +{ + public class OperationsProcessorTests + { + private readonly Mock _resolverMock; + + public OperationsProcessorTests() + { + _resolverMock = new Mock(); + } + + [Fact] + public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() + { + // arrange + var request = @"[ + { + ""op"": ""add"", + ""data"": { + ""type"": ""authors"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + }, { + ""op"": ""add"", + ""data"": { + ""type"": ""articles"", + ""attributes"": { + ""title"": ""JSON API paints my bikeshed!"" + }, + ""relationships"": { + ""author"": { + ""data"": { + ""type"": ""authors"", + ""id"": { ""pointer"": ""/operations/0/data/id"" } + } + } + } + } + } + ]"; + + var op1Result = @"{ + ""links"": { + ""self"": ""http://example.com/authors/9"" + }, + ""data"": { + ""type"": ""authors"", + ""id"": ""9"", + ""attributes"": { + ""name"": ""dgeb"" + } + } + }"; + + var operations = JsonConvert.DeserializeObject>(request); + var addOperationResult = JsonConvert.DeserializeObject(op1Result); + + var opProcessorMock = new Mock(); + opProcessorMock.Setup(m => m.ProcessAsync(It.Is(op => op.DataObject.Type.ToString() == "authors"))) + .ReturnsAsync(addOperationResult); + + _resolverMock.Setup(m => m.LocateCreateService(It.IsAny())) + .Returns(opProcessorMock.Object); + + _resolverMock.Setup(m => m.LocateCreateService((It.IsAny()))) + .Returns(opProcessorMock.Object); + + var operationsProcessor = new OperationsProcessor(_resolverMock.Object); + + // act + var results = await operationsProcessor.ProcessAsync(operations); + + // assert + opProcessorMock.Verify( + m => m.ProcessAsync( + It.Is(o => + o.DataObject.Type.ToString() == "articles" + && o.DataObject.Relationships["author"].SingleData["id"].ToString() == "9" + ) + ) + ); + } + } +} From 97c27e056cc3c06cf79c06f646831ddbb041f2d4 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 25 Aug 2017 23:48:06 -0500 Subject: [PATCH 012/227] style(*): naming conventions and namespacr cleanup --- src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs | 1 - src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs | 1 - src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs | 1 - .../Services/Operations/OperationsPointerExchanger.cs | 3 --- .../{IOperationsProcessor.cs => OperationsProcessor.cs} | 1 - 5 files changed, 7 deletions(-) rename src/JsonApiDotNetCore/Services/Operations/{IOperationsProcessor.cs => OperationsProcessor.cs} (97%) diff --git a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs index ec997042fb..70aa070fc6 100644 --- a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs @@ -1,4 +1,3 @@ -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; using JsonApiDotNetCore.Models.Pointers; diff --git a/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs index 53a91c2fa6..1c8fb50603 100644 --- a/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Models; diff --git a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs index fe36dd8a9a..67cd0896ec 100644 --- a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading.Tasks; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs index 87a7dbdc25..7301353c3e 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs @@ -1,9 +1,6 @@ -using System; using System.Collections.Generic; using JsonApiDotNetCore.Models.Pointers; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Extensions; diff --git a/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs similarity index 97% rename from src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs rename to src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 0158caa081..9449564f22 100644 --- a/src/JsonApiDotNetCore/Services/Operations/IOperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Threading.Tasks; -using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Models.Pointers; From 5cda230eba1e1d8b08ce30e7053d06f92d55dc1d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 25 Aug 2017 23:48:59 -0500 Subject: [PATCH 013/227] style(processors): create namespace for individual processors --- .../Services/Operations/{ => Processors}/CreateOpProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/JsonApiDotNetCore/Services/Operations/{ => Processors}/CreateOpProcessor.cs (95%) diff --git a/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs similarity index 95% rename from src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs rename to src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs index 1c8fb50603..3004ba15ef 100644 --- a/src/JsonApiDotNetCore/Services/Operations/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs @@ -4,7 +4,7 @@ using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Serialization; -namespace JsonApiDotNetCore.Services.Operations +namespace JsonApiDotNetCore.Services.Operations.Processors { public class CreateOpProcessor : IOpProcessor where T : class, IIdentifiable From fbb698d5f5249c32687de027baf3036e57c641fa Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 26 Aug 2017 20:50:51 -0500 Subject: [PATCH 014/227] test(CreateOpProcessor): test and implement the create op processor --- .../Builders/ContextGraphBuilder.cs | 10 ++- .../Builders/DocumentBuilder.cs | 2 +- .../Builders/IContextGraphBuilder.cs | 6 +- .../Builders/IDocumentBuilder.cs | 2 + src/JsonApiDotNetCore/Models/DocumentData.cs | 2 - .../Processors/CreateOpProcessor.cs | 22 ++++- .../Processors/CreateOpProcessorTests.cs | 80 +++++++++++++++++++ 7 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 test/UnitTests/Services/Operations/Processors/CreateOpProcessorTests.cs diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index c5099bf298..efbc0535e1 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -28,10 +28,10 @@ public IContextGraph Build() return graph; } - public void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable + public IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable => AddResource(pluralizedTypeName); - public void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable + public IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable { var entityType = typeof(TResource); @@ -45,6 +45,8 @@ public void AddResource(string pluralizedTypeName) where TResour Attributes = GetAttributes(entityType), Relationships = GetRelationships(entityType) }); + + return this; } private Link GetLinkFlags(Type entityType) @@ -97,7 +99,7 @@ protected virtual Type GetRelationshipType(RelationshipAttribute relation, Prope return prop.PropertyType; } - public void AddDbContext() where T : DbContext + public IContextGraphBuilder AddDbContext() where T : DbContext { _usesDbContext = true; @@ -125,6 +127,8 @@ public void AddDbContext() where T : DbContext }); } } + + return this; } private string GetResourceName(PropertyInfo property) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index ae102111c3..c6439efbc8 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -104,7 +104,7 @@ private List AppendIncludedObject(List includedObjec return includedObject; } - private DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) + public DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) { var data = new DocumentData { diff --git a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs index 5844166c18..9f3c7bd1a8 100644 --- a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs @@ -8,8 +8,8 @@ public interface IContextGraphBuilder { Link DocumentLinks { get; set; } IContextGraph Build(); - void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; - void AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; - void AddDbContext() where T : DbContext; + IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; + IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; + IContextGraphBuilder AddDbContext() where T : DbContext; } } diff --git a/src/JsonApiDotNetCore/Builders/IDocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/IDocumentBuilder.cs index 8fe5c65ae9..4fbc8df01b 100644 --- a/src/JsonApiDotNetCore/Builders/IDocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/IDocumentBuilder.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Builders @@ -7,5 +8,6 @@ public interface IDocumentBuilder { Document Build(IIdentifiable entity); Documents Build(IEnumerable entities); + DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity); } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index afd9c717cf..f4a3c137ae 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -1,6 +1,4 @@ -using System; using System.Collections.Generic; -using JsonApiDotNetCore.Models.Pointers; using Newtonsoft.Json; namespace JsonApiDotNetCore.Models diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs index 3004ba15ef..8ef9298027 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs @@ -1,26 +1,42 @@ using System.Threading.Tasks; using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Serialization; namespace JsonApiDotNetCore.Services.Operations.Processors { + public class CreateOpProcessor : CreateOpProcessor + where T : class, IIdentifiable + { + public CreateOpProcessor( + ICreateService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph + ) : base(service, deSerializer, documentBuilder, contextGraph) + { } + } + public class CreateOpProcessor : IOpProcessor where T : class, IIdentifiable { private readonly ICreateService _service; private readonly IJsonApiDeSerializer _deSerializer; private readonly IDocumentBuilder _documentBuilder; + private readonly IContextGraph _contextGraph; public CreateOpProcessor( ICreateService service, IJsonApiDeSerializer deSerializer, - IDocumentBuilder documentBuilder) + IDocumentBuilder documentBuilder, + IContextGraph contextGraph) { _service = service; _deSerializer = deSerializer; _documentBuilder = documentBuilder; + _contextGraph = contextGraph; } public async Task ProcessAsync(Operation operation) @@ -32,7 +48,9 @@ public async Task ProcessAsync(Operation operation) Op = OperationCode.add }; - operationResult.Data = _documentBuilder.Build(result); + operationResult.Data = _documentBuilder.GetData( + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + result); return operationResult; } diff --git a/test/UnitTests/Services/Operations/Processors/CreateOpProcessorTests.cs b/test/UnitTests/Services/Operations/Processors/CreateOpProcessorTests.cs new file mode 100644 index 0000000000..9e33af63c2 --- /dev/null +++ b/test/UnitTests/Services/Operations/Processors/CreateOpProcessorTests.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Serialization; +using JsonApiDotNetCore.Services; +using JsonApiDotNetCore.Services.Operations.Processors; +using Moq; +using Xunit; + +namespace UnitTests.Services +{ + public class CreateOpProcessorTests + { + private readonly Mock> _createServiceMock; + private readonly Mock _deserializerMock; + private readonly Mock _documentBuilderMock; + + public CreateOpProcessorTests() + { + _createServiceMock = new Mock>(); + _deserializerMock = new Mock(); + _documentBuilderMock = new Mock(); + } + + [Fact] + public async Task ProcessAsync_Deserializes_And_Creates() + { + // arrange + var testResource = new TestResource { + Name = "some-name" + }; + + var data = new DocumentData { + Type = "test-resources", + Attributes = new Dictionary { + { "name", testResource.Name } + } + }; + + var operation = new Operation { + Data = data, + }; + + var contextGraph = new ContextGraphBuilder() + .AddResource("test-resources") + .Build(); + + _deserializerMock.Setup(m => m.DocumentToObject(It.IsAny())) + .Returns(testResource); + + var opProcessor = new CreateOpProcessor( + _createServiceMock.Object, + _deserializerMock.Object, + _documentBuilderMock.Object, + contextGraph + ); + + _documentBuilderMock.Setup(m => m.GetData(It.IsAny(), It.IsAny())) + .Returns(data); + + // act + var result = await opProcessor.ProcessAsync(operation); + + // assert + Assert.Equal(OperationCode.add, result.Op); + Assert.NotNull(result.Data); + Assert.Equal(testResource.Name, result.DataObject.Attributes["name"]); + _createServiceMock.Verify(m => m.CreateAsync(It.IsAny())); + } + + public class TestResource : Identifiable + { + [Attr("name")] + public string Name { get; set; } + } + } +} From 030599316cd0d29eeb93e4bf953cb3e603bd70a5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 26 Aug 2017 21:11:58 -0500 Subject: [PATCH 015/227] feat(content-negotiation): wire up reader and input formatter --- .../JsonApiOperationsInputFormatter.cs | 33 ++++++++++++++ .../Formatters/JsonApiOperationsReader.cs | 44 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs create mode 100644 src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs new file mode 100644 index 0000000000..61ae97ffbb --- /dev/null +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; + +namespace JsonApiDotNetCore.Formatters +{ + public class JsonApiOperationsInputFormatter : IInputFormatter + { + const string PROFILE_EXTENSION = "; rel=\"profile\""; + + public bool CanRead(InputFormatterContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var contentTypeString = context.HttpContext.Request.ContentType; + + return ( + contentTypeString == "application/vnd.api+json" && + context.HttpContext.Request.Headers.TryGetValue("Link", out StringValues profileExtension) && + profileExtension == PROFILE_EXTENSION + ); + } + + public async Task ReadAsync(InputFormatterContext context) + { + var reader = context.HttpContext.RequestServices.GetService(); + return await reader.ReadAsync(context); + } + } +} diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs new file mode 100644 index 0000000000..f586d2e7e9 --- /dev/null +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Serialization; +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace JsonApiDotNetCore.Formatters +{ + public interface IJsonApiOperationsReader + { + Task ReadAsync(InputFormatterContext context); + } + + public class JsonApiOperationsReader : IJsonApiOperationsReader + { + public JsonApiOperationsReader() + { + } + + public Task ReadAsync(InputFormatterContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var request = context.HttpContext.Request; + if (request.ContentLength == 0) + return InputFormatterResult.FailureAsync(); + + return InputFormatterResult.SuccessAsync(null); + } + + private string GetRequestBody(Stream body) + { + using (var reader = new StreamReader(body)) + { + return reader.ReadToEnd(); + } + } + } +} \ No newline at end of file From 4055b4102385bc460ca00764200993b4d6dbe6c4 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 27 Aug 2017 18:09:00 -0500 Subject: [PATCH 016/227] feat(reader): deserialize operations document --- .../Formatters/JsonApiOperationsReader.cs | 17 ++++++----------- .../Models/Operations/OperationsDocument.cs | 9 +++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs index f586d2e7e9..3fc4524b9b 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs @@ -1,11 +1,8 @@ using System; using System.IO; using System.Threading.Tasks; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Services; +using JsonApiDotNetCore.Models.Operations; using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace JsonApiDotNetCore.Formatters @@ -17,28 +14,26 @@ public interface IJsonApiOperationsReader public class JsonApiOperationsReader : IJsonApiOperationsReader { - public JsonApiOperationsReader() - { - } - public Task ReadAsync(InputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var request = context.HttpContext.Request; - if (request.ContentLength == 0) + if (request.ContentLength == null || request.ContentLength == 0) return InputFormatterResult.FailureAsync(); + var body = GetRequestBody(request.Body); + + var operations = JsonConvert.DeserializeObject(body); + return InputFormatterResult.SuccessAsync(null); } private string GetRequestBody(Stream body) { using (var reader = new StreamReader(body)) - { return reader.ReadToEnd(); - } } } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs b/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs new file mode 100644 index 0000000000..987f9abc20 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace JsonApiDotNetCore.Models.Operations +{ + public class OperationsDocument + { + public List Operations { get; set; } + } +} From 2b59bdff4da9c131bdb637bbae95404a6c783679 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Mon, 28 Aug 2017 20:01:23 -0500 Subject: [PATCH 017/227] feat(*): add controller, input formatter, and services --- JsonApiDotnetCore.sln | 15 ++++++++++++ .../Configuration/JsonApiOptions.cs | 8 +++++++ .../Controllers/BaseJsonApiController.cs | 1 - .../JsonApiOperationsController.cs | 24 +++++++++++++++++++ .../IServiceCollectionExtensions.cs | 15 ++++++++++++ .../Formatters/JsonApiInputFormatter.cs | 9 +++++-- .../JsonApiOperationsInputFormatter.cs | 22 +++++++++++++---- .../Formatters/JsonApiOperationsReader.cs | 6 ++++- .../Models/JsonApiExtension.cs | 7 ++++++ 9 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs create mode 100644 src/JsonApiDotNetCore/Models/JsonApiExtension.cs diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index b4ff89b0aa..74ea28c41a 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -28,6 +28,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{02 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportsExample", "src\Examples\ReportsExample\ReportsExample.csproj", "{FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExample", "src\Examples\OperationsExample\OperationsExample.csproj", "{CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -110,6 +112,18 @@ Global {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|x64 {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|x86 {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|x86 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.ActiveCfg = Debug|x64 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.Build.0 = Debug|x64 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.ActiveCfg = Debug|x86 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.Build.0 = Debug|x86 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.Build.0 = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.ActiveCfg = Release|x64 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.Build.0 = Release|x64 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.ActiveCfg = Release|x86 + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -123,5 +137,6 @@ Global {6D4BD85A-A262-44C6-8572-FE3A30410BF3} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {026FBC6C-AF76-4568-9B87-EC73457899FD} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} EndGlobalSection EndGlobal diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 26e16b0741..be22f8af07 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; @@ -30,6 +32,7 @@ public IContractResolver JsonContractResolver ContractResolver = new DasherizedResolver() }; internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); + internal List EnabledExtensions { get; set; } = new List(); public void BuildContextGraph(Action builder) where TContext : DbContext { @@ -48,5 +51,10 @@ public void BuildContextGraph(Action builder) ContextGraph = ContextGraphBuilder.Build(); } + + public void EnableExtension(JsonApiExtension extension) + { + EnabledExtensions.Add(extension); + } } } diff --git a/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs b/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs index a10ea381de..8785eb2266 100644 --- a/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs +++ b/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs @@ -4,7 +4,6 @@ using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Controllers { diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs new file mode 100644 index 0000000000..40ac76fea3 --- /dev/null +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Services.Operations; +using Microsoft.AspNetCore.Mvc; + +namespace JsonApiDotNetCore.Controllers +{ + public class JsonApiOperationsController : Controller + { + private readonly IOperationsProcessor _operationsProcessor; + + public JsonApiOperationsController(IOperationsProcessor operationsProcessor) + { + _operationsProcessor = operationsProcessor; + } + + [HttpPost("bulk")] + public async Task PatchAsync(OperationsDocument doc) + { + var results = await _operationsProcessor.ProcessAsync(doc.Operations); + return Ok(results); + } + } +} diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index afcc11ee8d..6cd84d397c 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -6,8 +6,10 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Middleware; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; +using JsonApiDotNetCore.Services.Operations; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -91,6 +93,9 @@ public static void AddJsonApiInternals( services.AddSingleton(new DbContextOptionsBuilder().Options); } + if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) + AddOperationServices(services); + services.AddScoped(); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); @@ -114,8 +119,18 @@ public static void AddJsonApiInternals( services.AddScoped(); } + private static void AddOperationServices(IServiceCollection services) + { + services.AddScoped(); + services.AddSingleton(); + services.AddSingleton(); + } + public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions jsonApiOptions) { + if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) + options.InputFormatters.Insert(0, new JsonApiOperationsInputFormatter()); + options.InputFormatters.Insert(0, new JsonApiInputFormatter()); options.OutputFormatters.Insert(0, new JsonApiOutputFormatter()); diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs index 12e57deadf..f5b822fd62 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs @@ -8,17 +8,22 @@ namespace JsonApiDotNetCore.Formatters public class JsonApiInputFormatter : IInputFormatter { public bool CanRead(InputFormatterContext context) - { + { if (context == null) throw new ArgumentNullException(nameof(context)); var contentTypeString = context.HttpContext.Request.ContentType; - return contentTypeString == "application/vnd.api+json"; + var canRead = contentTypeString == "application/vnd.api+json"; + + Console.WriteLine($">>> JsonApiInputFormatter Can Read {canRead}"); + + return canRead; } public async Task ReadAsync(InputFormatterContext context) { + Console.WriteLine($">>> JsonApiInputFormatter ReadAsync"); var reader = context.HttpContext.RequestServices.GetService(); return await reader.ReadAsync(context); } diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs index 61ae97ffbb..0f83c1f031 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs @@ -1,31 +1,43 @@ using System; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace JsonApiDotNetCore.Formatters { - public class JsonApiOperationsInputFormatter : IInputFormatter + public class JsonApiOperationsInputFormatter : TextInputFormatter { const string PROFILE_EXTENSION = "; rel=\"profile\""; - public bool CanRead(InputFormatterContext context) + public JsonApiOperationsInputFormatter() + { + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/vnd.api+json")); + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + } + + public override bool CanRead(InputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var contentTypeString = context.HttpContext.Request.ContentType; - return ( - contentTypeString == "application/vnd.api+json" && + var canRead = ( + contentTypeString == "application/vnd.api+json" && context.HttpContext.Request.Headers.TryGetValue("Link", out StringValues profileExtension) && profileExtension == PROFILE_EXTENSION ); + Console.WriteLine($">>> JsonApiOperationsInputFormatter Can Read {canRead}"); + return canRead; } - public async Task ReadAsync(InputFormatterContext context) + public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) { + Console.WriteLine($">>> JsonApiOperationsInputFormatter ReadAsync"); var reader = context.HttpContext.RequestServices.GetService(); return await reader.ReadAsync(context); } diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs index 3fc4524b9b..9cfc4c177b 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models.Operations; using Microsoft.AspNetCore.Mvc.Formatters; using Newtonsoft.Json; @@ -27,7 +28,10 @@ public Task ReadAsync(InputFormatterContext context) var operations = JsonConvert.DeserializeObject(body); - return InputFormatterResult.SuccessAsync(null); + if(operations == null) + throw new JsonApiException(400, "Failed to deserialize operations request."); + + return InputFormatterResult.SuccessAsync(operations); } private string GetRequestBody(Stream body) diff --git a/src/JsonApiDotNetCore/Models/JsonApiExtension.cs b/src/JsonApiDotNetCore/Models/JsonApiExtension.cs new file mode 100644 index 0000000000..7d3b0c87ea --- /dev/null +++ b/src/JsonApiDotNetCore/Models/JsonApiExtension.cs @@ -0,0 +1,7 @@ +namespace JsonApiDotNetCore.Models +{ + public enum JsonApiExtension + { + Operations = 0 + } +} From 3c8e3620a55d2418812a1c126bcd9d3f87db8583 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Mon, 28 Aug 2017 20:01:39 -0500 Subject: [PATCH 018/227] feat(examples): add operations example --- src/Examples/OperationsExample/.gitignore | 236 ++++++++++++++++++ .../Controllers/OperationsController.cs | 14 ++ .../OperationsExample/Data/AppDbContext.cs | 14 ++ .../20170827234334_AddArticles.Designer.cs | 33 +++ .../Migrations/20170827234334_AddArticles.cs | 32 +++ .../Migrations/AppDbContextModelSnapshot.cs | 32 +++ .../OperationsExample/Models/Article.cs | 10 + .../OperationsExample.csproj | 33 +++ src/Examples/OperationsExample/Program.cs | 26 ++ src/Examples/OperationsExample/Startup.cs | 66 +++++ .../OperationsExample/appsettings.json | 13 + 11 files changed, 509 insertions(+) create mode 100644 src/Examples/OperationsExample/.gitignore create mode 100644 src/Examples/OperationsExample/Controllers/OperationsController.cs create mode 100644 src/Examples/OperationsExample/Data/AppDbContext.cs create mode 100755 src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs create mode 100755 src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs create mode 100755 src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs create mode 100644 src/Examples/OperationsExample/Models/Article.cs create mode 100644 src/Examples/OperationsExample/OperationsExample.csproj create mode 100644 src/Examples/OperationsExample/Program.cs create mode 100644 src/Examples/OperationsExample/Startup.cs create mode 100644 src/Examples/OperationsExample/appsettings.json diff --git a/src/Examples/OperationsExample/.gitignore b/src/Examples/OperationsExample/.gitignore new file mode 100644 index 0000000000..0f552f400b --- /dev/null +++ b/src/Examples/OperationsExample/.gitignore @@ -0,0 +1,236 @@ +_data/ + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/src/Examples/OperationsExample/Controllers/OperationsController.cs b/src/Examples/OperationsExample/Controllers/OperationsController.cs new file mode 100644 index 0000000000..d0ceaab71e --- /dev/null +++ b/src/Examples/OperationsExample/Controllers/OperationsController.cs @@ -0,0 +1,14 @@ +using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Services.Operations; +using Microsoft.AspNetCore.Mvc; + +namespace OperationsExample.Controllers +{ + [Route("api/[controller]")] + public class OperationsController : JsonApiOperationsController + { + public OperationsController(IOperationsProcessor processor) + : base(processor) + { } + } +} diff --git a/src/Examples/OperationsExample/Data/AppDbContext.cs b/src/Examples/OperationsExample/Data/AppDbContext.cs new file mode 100644 index 0000000000..d00bfe4765 --- /dev/null +++ b/src/Examples/OperationsExample/Data/AppDbContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; +using OperationsExample.Models; + +namespace OperationsExample.Data +{ + public class AppDbContext : DbContext + { + public AppDbContext(DbContextOptions options) + : base(options) + { } + + public DbSet
Articles { get; set; } + } +} diff --git a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs new file mode 100755 index 0000000000..10f16d49cd --- /dev/null +++ b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using OperationsExample.Data; + +namespace OperationsExample.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20170827234334_AddArticles")] + partial class AddArticles + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "1.1.2"); + + modelBuilder.Entity("OperationsExample.Models.Article", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Articles"); + }); + } + } +} diff --git a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs new file mode 100755 index 0000000000..308e6f78f5 --- /dev/null +++ b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace OperationsExample.Migrations +{ + public partial class AddArticles : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Articles", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Articles", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Articles"); + } + } +} diff --git a/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs new file mode 100755 index 0000000000..547bbbf2cf --- /dev/null +++ b/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using OperationsExample.Data; + +namespace OperationsExample.Migrations +{ + [DbContext(typeof(AppDbContext))] + partial class AppDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "1.1.2"); + + modelBuilder.Entity("OperationsExample.Models.Article", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Articles"); + }); + } + } +} diff --git a/src/Examples/OperationsExample/Models/Article.cs b/src/Examples/OperationsExample/Models/Article.cs new file mode 100644 index 0000000000..fc4b5d6647 --- /dev/null +++ b/src/Examples/OperationsExample/Models/Article.cs @@ -0,0 +1,10 @@ +using JsonApiDotNetCore.Models; + +namespace OperationsExample.Models +{ + public class Article : Identifiable + { + [Attr("name")] + public string Name { get; set; } + } +} diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj new file mode 100644 index 0000000000..e033989925 --- /dev/null +++ b/src/Examples/OperationsExample/OperationsExample.csproj @@ -0,0 +1,33 @@ + + + + netcoreapp1.0 + true + OperationsExample + Exe + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Examples/OperationsExample/Program.cs b/src/Examples/OperationsExample/Program.cs new file mode 100644 index 0000000000..b528f47d15 --- /dev/null +++ b/src/Examples/OperationsExample/Program.cs @@ -0,0 +1,26 @@ +using System.IO; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; + +namespace OperationsExample +{ + public class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .AddCommandLine(args) + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + + var host = new WebHostBuilder() + .UseConfiguration(config) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs new file mode 100644 index 0000000000..40e9f5295a --- /dev/null +++ b/src/Examples/OperationsExample/Startup.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using JsonApiDotNetCore.Extensions; +using System; +using OperationsExample.Data; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Formatters; + +namespace OperationsExample +{ + public class Startup + { + public readonly IConfiguration Config; + + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables(); + + Config = builder.Build(); + } + + public virtual IServiceProvider ConfigureServices(IServiceCollection services) + { + var loggerFactory = new LoggerFactory(); + loggerFactory + .AddConsole(LogLevel.Trace); + services.AddSingleton(loggerFactory); + + services.AddDbContext(options => + { + options.UseNpgsql(GetDbConnectionString()); + }, ServiceLifetime .Transient); + + services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); + + services.AddMvc().AddMvcOptions(options => { + options.InputFormatters.Clear(); + options.InputFormatters.Insert(0, new JsonApiOperationsInputFormatter()); + }); + + return services.BuildServiceProvider(); + } + + public virtual void Configure( + IApplicationBuilder app, + IHostingEnvironment env, + ILoggerFactory loggerFactory, + AppDbContext context) + { + context.Database.EnsureCreated(); + + loggerFactory.AddConsole(Config.GetSection("Logging")); + loggerFactory.AddDebug(); + app.UseJsonApi(); + } + + public string GetDbConnectionString() => Config["Data:DefaultConnection"]; + } +} \ No newline at end of file diff --git a/src/Examples/OperationsExample/appsettings.json b/src/Examples/OperationsExample/appsettings.json new file mode 100644 index 0000000000..c1061281cc --- /dev/null +++ b/src/Examples/OperationsExample/appsettings.json @@ -0,0 +1,13 @@ +{ + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=password" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "System": "Trace", + "Microsoft": "Trace" + } + } +} From 34e68297ab5bbf831d41ca74ed2a2a3969df6dc2 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 12 Sep 2017 06:30:16 -0500 Subject: [PATCH 019/227] fix(controller): use HTTP PATCH --- .vscode/launch.json | 10 ++++++++++ .../Controllers/OperationsController.cs | 2 +- .../Controllers/JsonApiOperationsController.cs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b26b008078..1da452f8e1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,16 @@ { "version": "0.2.0", "configurations": [ + { + "name": "OperationsExample", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/src/Examples/OperationsExample/bin/Debug/netcoreapp1.0/OperationsExample.dll", + "args": [], + "cwd": "${workspaceRoot}/src/Examples/OperationsExample", + "stopAtEntry": false + }, { "name": ".NET Core Attach", "type": "coreclr", diff --git a/src/Examples/OperationsExample/Controllers/OperationsController.cs b/src/Examples/OperationsExample/Controllers/OperationsController.cs index d0ceaab71e..6e56791f9c 100644 --- a/src/Examples/OperationsExample/Controllers/OperationsController.cs +++ b/src/Examples/OperationsExample/Controllers/OperationsController.cs @@ -4,7 +4,7 @@ namespace OperationsExample.Controllers { - [Route("api/[controller]")] + [Route("api/bulk")] public class OperationsController : JsonApiOperationsController { public OperationsController(IOperationsProcessor processor) diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index 40ac76fea3..639468450d 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -14,7 +14,7 @@ public JsonApiOperationsController(IOperationsProcessor operationsProcessor) _operationsProcessor = operationsProcessor; } - [HttpPost("bulk")] + [HttpPatch] public async Task PatchAsync(OperationsDocument doc) { var results = await _operationsProcessor.ProcessAsync(doc.Operations); From e476e25b7e19d09f66f8f7f26dc6684de82bf303 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 13 Sep 2017 07:25:04 -0500 Subject: [PATCH 020/227] fix(inputFormatters): needed FromBody param attribute --- .vscode/tasks.json | 38 +++++++++---------- src/Examples/OperationsExample/Startup.cs | 8 +--- .../JsonApiOperationsController.cs | 2 +- .../IServiceCollectionExtensions.cs | 5 ++- .../Formatters/JsonApiInputFormatter.cs | 5 +-- .../JsonApiOperationsInputFormatter.cs | 18 ++------- 6 files changed, 29 insertions(+), 47 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 725d8335be..3906009211 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,20 +1,20 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "options": { - "cwd": "${workspaceRoot}/src/Examples/JsonApiDotNetCoreExample" - }, - "tasks": [ - { - "taskName": "build", - "args": [ ], - "isBuildCommand": true, - "showOutput": "silent", - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "dotnet", + "isShellCommand": true, + "args": [], + "options": { + "cwd": "${workspaceRoot}" + }, + "tasks": [ + { + "taskName": "build", + "args": [], + "isBuildCommand": true, + "showOutput": "silent", + "problemMatcher": "$msCompile" + } + ] +} diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs index 40e9f5295a..1ffedf9116 100644 --- a/src/Examples/OperationsExample/Startup.cs +++ b/src/Examples/OperationsExample/Startup.cs @@ -8,7 +8,6 @@ using System; using OperationsExample.Data; using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Formatters; namespace OperationsExample { @@ -36,15 +35,10 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services) services.AddDbContext(options => { options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime .Transient); + }, ServiceLifetime.Transient); services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); - services.AddMvc().AddMvcOptions(options => { - options.InputFormatters.Clear(); - options.InputFormatters.Insert(0, new JsonApiOperationsInputFormatter()); - }); - return services.BuildServiceProvider(); } diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index 639468450d..3990f7b85d 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -15,7 +15,7 @@ public JsonApiOperationsController(IOperationsProcessor operationsProcessor) } [HttpPatch] - public async Task PatchAsync(OperationsDocument doc) + public async Task PatchAsync([FromBody] OperationsDocument doc) { var results = await _operationsProcessor.ProcessAsync(doc.Operations); return Ok(results); diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 6cd84d397c..12e86d09ea 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -112,6 +112,7 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(typeof(GenericProcessor<>)); services.AddScoped(); @@ -128,11 +129,11 @@ private static void AddOperationServices(IServiceCollection services) public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions jsonApiOptions) { + options.InputFormatters.Insert(0, new JsonApiInputFormatter()); + if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) options.InputFormatters.Insert(0, new JsonApiOperationsInputFormatter()); - options.InputFormatters.Insert(0, new JsonApiInputFormatter()); - options.OutputFormatters.Insert(0, new JsonApiOutputFormatter()); options.Conventions.Insert(0, new DasherizedRoutingConvention(jsonApiOptions.Namespace)); diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs index f5b822fd62..b7f5ae7f76 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs @@ -8,7 +8,7 @@ namespace JsonApiDotNetCore.Formatters public class JsonApiInputFormatter : IInputFormatter { public bool CanRead(InputFormatterContext context) - { + { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -16,14 +16,11 @@ public bool CanRead(InputFormatterContext context) var canRead = contentTypeString == "application/vnd.api+json"; - Console.WriteLine($">>> JsonApiInputFormatter Can Read {canRead}"); - return canRead; } public async Task ReadAsync(InputFormatterContext context) { - Console.WriteLine($">>> JsonApiInputFormatter ReadAsync"); var reader = context.HttpContext.RequestServices.GetService(); return await reader.ReadAsync(context); } diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs index 0f83c1f031..de5ed86bf1 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs @@ -1,25 +1,16 @@ using System; -using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace JsonApiDotNetCore.Formatters { - public class JsonApiOperationsInputFormatter : TextInputFormatter + public class JsonApiOperationsInputFormatter : IInputFormatter { const string PROFILE_EXTENSION = "; rel=\"profile\""; - public JsonApiOperationsInputFormatter() - { - SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/vnd.api+json")); - SupportedEncodings.Add(Encoding.UTF8); - SupportedEncodings.Add(Encoding.Unicode); - } - - public override bool CanRead(InputFormatterContext context) + public bool CanRead(InputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -31,13 +22,12 @@ public override bool CanRead(InputFormatterContext context) context.HttpContext.Request.Headers.TryGetValue("Link", out StringValues profileExtension) && profileExtension == PROFILE_EXTENSION ); - Console.WriteLine($">>> JsonApiOperationsInputFormatter Can Read {canRead}"); + return canRead; } - public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) + public async Task ReadAsync(InputFormatterContext context) { - Console.WriteLine($">>> JsonApiOperationsInputFormatter ReadAsync"); var reader = context.HttpContext.RequestServices.GetService(); return await reader.ReadAsync(context); } From bc18fe92511e696beaa4f34fc969392ccffcc46b Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 14 Sep 2017 21:54:11 -0500 Subject: [PATCH 021/227] chore(*): replace Any with Count --- docs/Usage.md | 2 +- src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs | 2 +- .../Extensions/IQueryableExtensions.cs | 10 +++++----- src/JsonApiDotNetCore/Services/JsonApiContext.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/Usage.md b/docs/Usage.md index 33db2d787f..07ac168a21 100644 --- a/docs/Usage.md +++ b/docs/Usage.md @@ -117,7 +117,7 @@ public void Configure( AppDbContext context) { context.Database.EnsureCreated(); - if(context.People.Any() == false) + if(context.People.Count == 0) { context.People.Add(new Person { Name = "John Doe" diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 66804abee5..742a32e305 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -62,7 +62,7 @@ public DefaultEntityRepository( public virtual IQueryable Get() { - if (_jsonApiContext.QuerySet?.Fields != null && _jsonApiContext.QuerySet.Fields.Any()) + if (_jsonApiContext.QuerySet?.Fields != null && _jsonApiContext.QuerySet.Fields.Count > 0) return _dbSet.Select(_jsonApiContext.QuerySet?.Fields); return _dbSet; diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index c40d61b517..9713b6ddbf 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -13,15 +13,15 @@ public static class IQueryableExtensions { public static IOrderedQueryable Sort(this IQueryable source, SortQuery sortQuery) { - return sortQuery.Direction == SortDirection.Descending - ? source.OrderByDescending(sortQuery.SortedAttribute.InternalAttributeName) + return sortQuery.Direction == SortDirection.Descending + ? source.OrderByDescending(sortQuery.SortedAttribute.InternalAttributeName) : source.OrderBy(sortQuery.SortedAttribute.InternalAttributeName); } public static IOrderedQueryable Sort(this IOrderedQueryable source, SortQuery sortQuery) { - return sortQuery.Direction == SortDirection.Descending - ? source.ThenByDescending(sortQuery.SortedAttribute.InternalAttributeName) + return sortQuery.Direction == SortDirection.Descending + ? source.ThenByDescending(sortQuery.SortedAttribute.InternalAttributeName) : source.ThenBy(sortQuery.SortedAttribute.InternalAttributeName); } @@ -179,7 +179,7 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression public static IQueryable Select(this IQueryable source, List columns) { - if (columns == null || columns.Any() == false) + if (columns == null || columns.Count == 0) return source; var sourceType = source.ElementType; diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index a93d76acdc..85978c66f6 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -66,7 +66,7 @@ public IJsonApiContext ApplyContext(object controller) var context = _httpContextAccessor.HttpContext; var path = context.Request.Path.Value.Split('/'); - if (context.Request.Query.Any()) + if (context.Request.Query.Count > 0) { QuerySet = _queryParser.Parse(context.Request.Query); IncludedRelationships = QuerySet.IncludedRelationships; From 6c1937f9d658d2e51987e1013771a57b6da69e1d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 14 Sep 2017 23:47:49 -0500 Subject: [PATCH 022/227] fix(CreateOpProcessor): issues around service location also cleans up some styling --- .../Builders/ContextGraphBuilder.cs | 44 +++++++++++-------- .../Data/DefaultEntityRepository.cs | 2 +- .../IServiceCollectionExtensions.cs | 6 +++ .../Internal/Generics/GenericProcessor.cs | 13 +++++- .../Generics/GenericProcessorFactory.cs | 37 ++++++++++++++-- .../Internal/Generics/IGenericProcessor.cs | 12 ----- .../Generics/IGenericProcessorFactory.cs | 15 ------- src/JsonApiDotNetCore/Models/DocumentBase.cs | 22 ++-------- src/JsonApiDotNetCore/Models/DocumentData.cs | 2 +- .../Models/Operations/Operation.cs | 28 ++++++++---- .../Serialization/JsonApiDeSerializer.cs | 2 +- .../Services/Operations/IOpProcessor.cs | 5 --- .../Operations/OperationProcessorResolver.cs | 9 ++-- .../Operations/OperationsProcessor.cs | 8 ++-- .../Processors/CreateOpProcessor.cs | 17 +++++-- 15 files changed, 126 insertions(+), 96 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index efbc0535e1..e35cc916d2 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -35,20 +35,22 @@ public IContextGraphBuilder AddResource(string pluralizedTypeNam { var entityType = typeof(TResource); - VerifyEntityIsNotAlreadyDefined(entityType); + AssertEntityIsNotAlreadyDefined(entityType); - _entities.Add(new ContextEntity - { - EntityName = pluralizedTypeName, - EntityType = entityType, - IdentityType = typeof(TId), - Attributes = GetAttributes(entityType), - Relationships = GetRelationships(entityType) - }); + _entities.Add(GetEntity(pluralizedTypeName, entityType, typeof(TId))); return this; } + private ContextEntity GetEntity(string pluralizedTypeName, Type entityType, Type idType) => new ContextEntity + { + EntityName = pluralizedTypeName, + EntityType = entityType, + IdentityType = idType, + Attributes = GetAttributes(entityType), + Relationships = GetRelationships(entityType) + }; + private Link GetLinkFlags(Type entityType) { var attribute = (LinksAttribute)entityType.GetTypeInfo().GetCustomAttribute(typeof(LinksAttribute)); @@ -116,15 +118,9 @@ public IContextGraphBuilder AddDbContext() where T : DbContext { var entityType = dbSetType.GetGenericArguments()[0]; - VerifyEntityIsNotAlreadyDefined(entityType); + AssertEntityIsNotAlreadyDefined(entityType); - _entities.Add(new ContextEntity - { - EntityName = GetResourceName(property), - EntityType = entityType, - Attributes = GetAttributes(entityType), - Relationships = GetRelationships(entityType) - }); + _entities.Add(GetEntity(GetResourceName(property), entityType, GetIdType(entityType))); } } @@ -140,7 +136,19 @@ private string GetResourceName(PropertyInfo property) return ((ResourceAttribute)resourceAttribute).ResourceName; } - private void VerifyEntityIsNotAlreadyDefined(Type entityType) + private Type GetIdType(Type resourceType) + { + var interfaces = resourceType.GetInterfaces(); + foreach (var type in interfaces) + { + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IIdentifiable<>)) + return type.GetGenericArguments()[0]; + } + + throw new ArgumentException("Type does not implement 'IIdentifiable'", nameof(resourceType)); + } + + private void AssertEntityIsNotAlreadyDefined(Type entityType) { if (_entities.Any(e => e.EntityType == entityType)) throw new InvalidOperationException($"Cannot add entity type {entityType} to context graph, there is already an entity of that type configured."); diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 742a32e305..e8aefb5ca9 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -137,7 +137,7 @@ public virtual async Task UpdateAsync(TId id, TEntity entity) public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds) { - var genericProcessor = _genericProcessorFactory.GetProcessor(relationship.Type); + var genericProcessor = _genericProcessorFactory.GetProcessor(typeof(GenericProcessor<>), relationship.Type); await genericProcessor.UpdateRelationshipsAsync(parent, relationship, relationshipIds); } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 12e86d09ea..ab297252f9 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -10,6 +10,7 @@ using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCore.Services.Operations; +using JsonApiDotNetCore.Services.Operations.Processors; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -99,6 +100,8 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); + services.AddScoped(typeof(ICreateService<>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(ICreateService<,>), typeof(EntityResourceService<,>)); services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); services.AddSingleton(jsonApiOptions); @@ -115,6 +118,7 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(); services.AddScoped(typeof(GenericProcessor<>)); + services.AddScoped(typeof(GenericProcessor<,>)); services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -123,6 +127,8 @@ public static void AddJsonApiInternals( private static void AddOperationServices(IServiceCollection services) { services.AddScoped(); + services.AddScoped(typeof(ICreateOpProcessor<>), typeof(CreateOpProcessor<>)); + services.AddScoped(typeof(ICreateOpProcessor<,>), typeof(CreateOpProcessor<,>)); services.AddSingleton(); services.AddSingleton(); } diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs index ce76b47dae..74bc551ece 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs @@ -7,7 +7,18 @@ namespace JsonApiDotNetCore.Internal.Generics { - public class GenericProcessor : IGenericProcessor where T : class, IIdentifiable + public interface IGenericProcessor + { + Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds); + void SetRelationships(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds); + } + + public class GenericProcessor : GenericProcessor where T : class, IIdentifiable + { + public GenericProcessor(DbContext context) : base(context) { } + } + + public class GenericProcessor : IGenericProcessor where T : class, IIdentifiable { private readonly DbContext _context; public GenericProcessor(DbContext context) diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 0918da40d1..3f88010e0a 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -2,6 +2,30 @@ namespace JsonApiDotNetCore.Internal.Generics { + /// + /// Used to generate a generic operations processor when the types + /// are not known until runtime. The typical use case would be for + /// accessing relationship data or resolving operations processors. + /// + public interface IGenericProcessorFactory + { + /// + /// Constructs the generic type and locates the service, then casts to TInterface + /// + /// + /// GetProcessor<IGenericProcessor>(typeof(GenericProcessor<>), typeof(TResource)); + /// + TInterface GetProcessor(Type openGenericType, Type resourceType); + + /// + /// Constructs the generic type and locates the service, then casts to TInterface + /// + /// + /// GetProcessor<IGenericProcessor>(typeof(GenericProcessor<,>), typeof(TResource), typeof(TId)); + /// + TInterface GetProcessor(Type openGenericType, Type resourceType, Type keyType); + } + public class GenericProcessorFactory : IGenericProcessorFactory { private readonly IServiceProvider _serviceProvider; @@ -11,10 +35,17 @@ public GenericProcessorFactory(IServiceProvider serviceProvider) _serviceProvider = serviceProvider; } - public TInterface GetProcessor(Type[] types) + public TInterface GetProcessor(Type openGenericType, Type resourceType) + => _getProcessor(openGenericType, resourceType); + + public TInterface GetProcessor(Type openGenericType, Type resourceType, Type keyType) + => _getProcessor(openGenericType, resourceType, keyType); + + private TInterface _getProcessor(Type openGenericType, params Type[] types) { - var processorType = typeof(GenericProcessor<>).MakeGenericType(types); - return (TInterface)_serviceProvider.GetService(processorType); + var concreteType = openGenericType.MakeGenericType(types); + + return (TInterface)_serviceProvider.GetService(concreteType); } } } diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs deleted file mode 100644 index d05e47cb6c..0000000000 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessor.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using JsonApiDotNetCore.Models; - -namespace JsonApiDotNetCore.Internal.Generics -{ - public interface IGenericProcessor - { - Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds); - void SetRelationships(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds); - } -} diff --git a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs deleted file mode 100644 index 39df292e14..0000000000 --- a/src/JsonApiDotNetCore/Internal/Generics/IGenericProcessorFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace JsonApiDotNetCore.Internal.Generics -{ - /// - /// Used to generate a generic operations processor when the types - /// are not know until runtime. The typical use case would be for - /// accessing relationship data.be for - /// accessing relationship data. - /// - public interface IGenericProcessorFactory - { - TInterface GetProcessor(params Type[] types); - } -} diff --git a/src/JsonApiDotNetCore/Models/DocumentBase.cs b/src/JsonApiDotNetCore/Models/DocumentBase.cs index 1cb31595ec..eb38f9582d 100644 --- a/src/JsonApiDotNetCore/Models/DocumentBase.cs +++ b/src/JsonApiDotNetCore/Models/DocumentBase.cs @@ -5,29 +5,13 @@ namespace JsonApiDotNetCore.Models { public class DocumentBase { - [JsonProperty("links")] + [JsonProperty("links", NullValueHandling = NullValueHandling.Ignore)] public RootLinks Links { get; set; } - [JsonProperty("included")] + [JsonProperty("included", NullValueHandling = NullValueHandling.Ignore)] public List Included { get; set; } - [JsonProperty("meta")] + [JsonProperty("meta", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Meta { get; set; } - - // http://www.newtonsoft.com/json/help/html/ConditionalProperties.htm - public bool ShouldSerializeIncluded() - { - return (Included != null); - } - - public bool ShouldSerializeMeta() - { - return (Meta != null); - } - - public bool ShouldSerializeLinks() - { - return (Links != null); - } } } diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index f4a3c137ae..7b5bdadd5b 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -14,7 +14,7 @@ public class DocumentData [JsonProperty("attributes")] public Dictionary Attributes { get; set; } - [JsonProperty("relationships")] + [JsonProperty("relationships", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Relationships { get; set; } } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Models/Operations/Operation.cs b/src/JsonApiDotNetCore/Models/Operations/Operation.cs index 1493142b9f..38c544eabc 100644 --- a/src/JsonApiDotNetCore/Models/Operations/Operation.cs +++ b/src/JsonApiDotNetCore/Models/Operations/Operation.cs @@ -1,18 +1,19 @@ using System.Collections.Generic; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; namespace JsonApiDotNetCore.Models.Operations { public class Operation : DocumentBase { - [JsonProperty("op")] + [JsonProperty("op"), JsonConverter(typeof(StringEnumConverter))] public OperationCode Op { get; set; } - [JsonProperty("ref")] + [JsonProperty("ref", NullValueHandling = NullValueHandling.Ignore)] public ResourceReference Ref { get; set; } - [JsonProperty("params")] + [JsonProperty("params", NullValueHandling = NullValueHandling.Ignore)] public Params Params { get; set; } [JsonProperty("data")] @@ -28,32 +29,41 @@ public object Data private void SetData(object data) { - if (data is JArray jArray) { + if (data is JArray jArray) + { DataIsList = true; DataList = jArray.ToObject>(); } - else if (data is List dataList) { + else if (data is List dataList) + { DataIsList = true; DataList = dataList; } - else if (data is JObject jObject) { + else if (data is JObject jObject) + { DataObject = jObject.ToObject(); } - else if (data is DocumentData dataObject) { + else if (data is DocumentData dataObject) + { DataObject = dataObject; } } + [JsonIgnore] public bool DataIsList { get; private set; } + + [JsonIgnore] public List DataList { get; private set; } + + [JsonIgnore] public DocumentData DataObject { get; private set; } public string GetResourceTypeName() { - if(Ref != null) + if (Ref != null) return Ref.Type?.ToString(); - if(DataIsList) + if (DataIsList) return DataList[0].Type?.ToString(); return DataObject.Type?.ToString(); diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index a5168f6185..05394fe551 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -210,7 +210,7 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var genericProcessor = _genericProcessorFactory.GetProcessor(attr.Type); + var genericProcessor = _genericProcessorFactory.GetProcessor(typeof(GenericProcessor<>), attr.Type); var ids = relationshipData.ManyData.Select(r => r["id"].ToString()); genericProcessor.SetRelationships(entity, attr, ids); } diff --git a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs index 67cd0896ec..0a2d30397c 100644 --- a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; namespace JsonApiDotNetCore.Services.Operations @@ -8,8 +7,4 @@ public interface IOpProcessor { Task ProcessAsync(Operation operation); } - - public interface IOpProcessor : IOpProcessor - where T : class, IIdentifiable - { } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index b56eb11bd6..64261af1c7 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -1,6 +1,7 @@ using System.Collections.Concurrent; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Services.Operations.Processors; namespace JsonApiDotNetCore.Services.Operations { @@ -33,10 +34,12 @@ public IOpProcessor LocateCreateService(Operation operation) return cachedProcessor; var contextEntity = _context.ContextGraph.GetContextEntity(resource); - var processor = _processorFactory.GetProcessor(contextEntity.EntityType, contextEntity.IdentityType); - + var processor = _processorFactory.GetProcessor( + typeof(ICreateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + ); + _cachedProcessors[resource] = processor; - + return processor; } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 9449564f22..75e013c8c8 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -18,12 +18,12 @@ public OperationsProcessor(IOperationProcessorResolver processorResolver) { _processorResolver = processorResolver; } - + public async Task> ProcessAsync(List inputOps) { var outputOps = new List(); - foreach(var op in inputOps) + foreach (var op in inputOps) { // TODO: parse pointers: // locate all objects within the document and replace them @@ -33,8 +33,8 @@ public async Task> ProcessAsync(List inputOps) var processor = _processorResolver.LocateCreateService(op); var resultOp = await processor.ProcessAsync(op); - - if(resultOp != null) + + if (resultOp != null) outputOps.Add(resultOp); } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs index 8ef9298027..251b81a5d6 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs @@ -7,6 +7,14 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { + public interface ICreateOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public interface ICreateOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + public class CreateOpProcessor : CreateOpProcessor where T : class, IIdentifiable { @@ -19,7 +27,7 @@ IContextGraph contextGraph { } } - public class CreateOpProcessor : IOpProcessor + public class CreateOpProcessor : ICreateOpProcessor where T : class, IIdentifiable { private readonly ICreateService _service; @@ -44,12 +52,13 @@ public async Task ProcessAsync(Operation operation) var model = (T)_deSerializer.DocumentToObject(operation.DataObject); var result = await _service.CreateAsync(model); - var operationResult = new Operation { + var operationResult = new Operation + { Op = OperationCode.add }; - + operationResult.Data = _documentBuilder.GetData( - _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), result); return operationResult; From 8723bbe3c95279a0a4f7d699faf4b0f99753bdac Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 14 Sep 2017 23:48:44 -0500 Subject: [PATCH 023/227] fix(DocumentBuilder): duplicate included entities use string.Equals over reference equality check --- .../Builders/DocumentBuilder.cs | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index c6439efbc8..775800434f 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -36,7 +36,7 @@ public Document Build(IIdentifiable entity) Meta = GetMeta(entity) }; - if(ShouldIncludePageLinks(contextEntity)) + if (ShouldIncludePageLinks(contextEntity)) document.Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext)); document.Included = AppendIncludedObject(document.Included, contextEntity, entity); @@ -59,7 +59,7 @@ public Documents Build(IEnumerable entities) Meta = GetMeta(enumeratedEntities.FirstOrDefault()) }; - if(ShouldIncludePageLinks(contextEntity)) + if (ShouldIncludePageLinks(contextEntity)) documents.Links = _jsonApiContext.PageManager.GetPageLinks(new LinkBuilder(_jsonApiContext)); foreach (var entity in enumeratedEntities) @@ -74,20 +74,20 @@ public Documents Build(IEnumerable entities) private Dictionary GetMeta(IIdentifiable entity) { if (entity == null) return null; - + var builder = _jsonApiContext.MetaBuilder; - if(entity is IHasMeta metaEntity) + if (entity is IHasMeta metaEntity) builder.Add(metaEntity.GetMeta(_jsonApiContext)); - if(_jsonApiContext.Options.IncludeTotalRecordCount) + if (_jsonApiContext.Options.IncludeTotalRecordCount) builder.Add("total-records", _jsonApiContext.PageManager.TotalRecords); - - if(_requestMeta != null) + + if (_requestMeta != null) builder.Add(_requestMeta.GetMeta()); var meta = builder.Build(); - if(meta.Count > 0) return meta; + if (meta.Count > 0) return meta; return null; } @@ -119,7 +119,7 @@ public DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) contextEntity.Attributes.ForEach(attr => { - if(ShouldIncludeAttribute(attr)) + if (ShouldIncludeAttribute(attr)) data.Attributes.Add(attr.PublicAttributeName, attr.GetValue(entity)); }); @@ -131,8 +131,8 @@ public DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) private bool ShouldIncludeAttribute(AttrAttribute attr) { - return (_jsonApiContext.QuerySet == null - || _jsonApiContext.QuerySet.Fields.Count == 0 + return (_jsonApiContext.QuerySet == null + || _jsonApiContext.QuerySet.Fields.Count == 0 || _jsonApiContext.QuerySet.Fields.Contains(attr.InternalAttributeName)); } @@ -145,13 +145,13 @@ private void AddRelationships(DocumentData data, ContextEntity contextEntity, II { var relationshipData = new RelationshipData(); - if(r.DocumentLinks.HasFlag(Link.None) == false) + if (r.DocumentLinks.HasFlag(Link.None) == false) { relationshipData.Links = new Links(); - if(r.DocumentLinks.HasFlag(Link.Self)) + if (r.DocumentLinks.HasFlag(Link.Self)) relationshipData.Links.Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.StringId, r.PublicRelationshipName); - - if(r.DocumentLinks.HasFlag(Link.Related)) + + if (r.DocumentLinks.HasFlag(Link.Related)) relationshipData.Links.Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, r.PublicRelationshipName); } @@ -160,7 +160,7 @@ private void AddRelationships(DocumentData data, ContextEntity contextEntity, II var navigationEntity = _jsonApiContext.ContextGraph .GetRelationship(entity, r.InternalRelationshipName); - if(navigationEntity == null) + if (navigationEntity == null) relationshipData.SingleData = null; else if (navigationEntity is IEnumerable) relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); @@ -194,19 +194,22 @@ private List AddIncludedEntity(List entities, IIdent { var includedEntity = GetIncludedEntity(entity); - if(entities == null) + if (entities == null) entities = new List(); - if(includedEntity != null && !entities.Any(doc => doc.Id == includedEntity.Id && doc.Type == includedEntity.Type)) + if (includedEntity != null && entities.Any(doc => + string.Equals(doc.Id, includedEntity.Id) && string.Equals(doc.Type, includedEntity.Type)) == false) + { entities.Add(includedEntity); + } return entities; } private DocumentData GetIncludedEntity(IIdentifiable entity) { - if(entity == null) return null; - + if (entity == null) return null; + var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(entity.GetType()); var data = GetData(contextEntity, entity); From 017d37569a698bc5b918bd263b206a865b20e608 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 26 Sep 2017 21:48:24 -0500 Subject: [PATCH 024/227] test(add): integration tests add articles --- JsonApiDotnetCore.sln | 15 ++ src/JsonApiDotNetCore/AssemblyInfo.cs | 3 + .../JsonApiOperationsInputFormatter.cs | 2 +- .../Formatters/JsonApiOperationsReader.cs | 4 +- .../Serialization/JsonApiDeSerializer.cs | 2 + test/OperationsExampleTests/.gitignore | 234 ++++++++++++++++++ test/OperationsExampleTests/Add/AddTests.cs | 102 ++++++++ .../Factories/ArticleFactory.cs | 25 ++ .../OperationsExampleTests.csproj | 23 ++ .../WebHostCollection.cs | 42 ++++ test/OperationsExampleTests/appsettings.json | 13 + 11 files changed, 462 insertions(+), 3 deletions(-) create mode 100644 src/JsonApiDotNetCore/AssemblyInfo.cs create mode 100644 test/OperationsExampleTests/.gitignore create mode 100644 test/OperationsExampleTests/Add/AddTests.cs create mode 100644 test/OperationsExampleTests/Factories/ArticleFactory.cs create mode 100644 test/OperationsExampleTests/OperationsExampleTests.csproj create mode 100644 test/OperationsExampleTests/WebHostCollection.cs create mode 100644 test/OperationsExampleTests/appsettings.json diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index 74ea28c41a..86ee801e58 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportsExample", "src\Examp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExample", "src\Examples\OperationsExample\OperationsExample.csproj", "{CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExampleTests", "test\OperationsExampleTests\OperationsExampleTests.csproj", "{9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -124,6 +126,18 @@ Global {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.Build.0 = Release|x64 {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.ActiveCfg = Release|x86 {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.Build.0 = Release|x86 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.ActiveCfg = Debug|x64 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.Build.0 = Debug|x64 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.ActiveCfg = Debug|x86 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.Build.0 = Debug|x86 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.Build.0 = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.ActiveCfg = Release|x64 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.Build.0 = Release|x64 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.ActiveCfg = Release|x86 + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -138,5 +152,6 @@ Global {026FBC6C-AF76-4568-9B87-EC73457899FD} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} EndGlobalSection EndGlobal diff --git a/src/JsonApiDotNetCore/AssemblyInfo.cs b/src/JsonApiDotNetCore/AssemblyInfo.cs new file mode 100644 index 0000000000..9aa4855d37 --- /dev/null +++ b/src/JsonApiDotNetCore/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("OperationsExampleTests")] diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs index de5ed86bf1..6f114aff33 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs @@ -8,7 +8,7 @@ namespace JsonApiDotNetCore.Formatters { public class JsonApiOperationsInputFormatter : IInputFormatter { - const string PROFILE_EXTENSION = "; rel=\"profile\""; + internal const string PROFILE_EXTENSION = "; rel=\"profile\""; public bool CanRead(InputFormatterContext context) { diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs index 9cfc4c177b..912cac2fff 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs @@ -22,13 +22,13 @@ public Task ReadAsync(InputFormatterContext context) var request = context.HttpContext.Request; if (request.ContentLength == null || request.ContentLength == 0) - return InputFormatterResult.FailureAsync(); + throw new JsonApiException(400, "Content-Length cannot be empty."); var body = GetRequestBody(request.Body); var operations = JsonConvert.DeserializeObject(body); - if(operations == null) + if (operations == null) throw new JsonApiException(400, "Failed to deserialize operations request."); return InputFormatterResult.SuccessAsync(operations); diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 05394fe551..07732a2910 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -80,6 +80,8 @@ public List DeserializeList(string requestBody) public object DocumentToObject(DocumentData data) { + if (data == null) throw new JsonApiException(422, "Failed to deserialize document as json:api."); + var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(data.Type?.ToString()); _jsonApiContext.RequestEntity = contextEntity; diff --git a/test/OperationsExampleTests/.gitignore b/test/OperationsExampleTests/.gitignore new file mode 100644 index 0000000000..0ca27f04e1 --- /dev/null +++ b/test/OperationsExampleTests/.gitignore @@ -0,0 +1,234 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs new file mode 100644 index 0000000000..b42dc342f1 --- /dev/null +++ b/test/OperationsExampleTests/Add/AddTests.cs @@ -0,0 +1,102 @@ +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using JsonApiDotNetCore.Extensions; +using Microsoft.EntityFrameworkCore; +using OperationsExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + [Collection("WebHostCollection")] + public class AddTests + { + private readonly Fixture _fixture; + + public AddTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Can_Create_Article() + { + // arrange + var context = _fixture.GetService(); + var article = ArticleFactory.Get(); + var content = new + { + operations = new[] { + new { + op = "add", + data = new { + type = "articles", + attributes = new { + name = article.Name + } + } + } + } + }; + + // act + var response = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var lastArticle = await context.Articles.LastAsync(); + Assert.Equal(article.Name, lastArticle.Name); + } + + [Fact] + public async Task Can_Create_Articles() + { + // arrange + var context = _fixture.GetService(); + var articles = ArticleFactory.Get(2); + var content = new + { + operations = new[] { + new { + op = "add", + data = new { + type = "articles", + attributes = new { + name = articles[0].Name + } + } + }, + new { + op = "add", + data = new { + type = "articles", + attributes = new { + name = articles[1].Name + } + } + } + } + }; + + // act + var response = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var lastArticles = (await context.Articles + .OrderByDescending(d => d.Id) + .Take(2) + .ToListAsync()) + .OrderBy(l => l.Id) + .ToList(); + + Assert.Equal(articles[0].Name, lastArticles[0].Name); + Assert.Equal(articles[1].Name, lastArticles[1].Name); + } + } +} diff --git a/test/OperationsExampleTests/Factories/ArticleFactory.cs b/test/OperationsExampleTests/Factories/ArticleFactory.cs new file mode 100644 index 0000000000..1907e2de24 --- /dev/null +++ b/test/OperationsExampleTests/Factories/ArticleFactory.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Bogus; +using OperationsExample.Models; + +namespace OperationsExampleTests.Factories +{ + public static class ArticleFactory + { + public static Article Get() + { + var faker = new Faker
(); + faker.RuleFor(m => m.Name, f => f.Lorem.Sentence()); + return faker.Generate(); + } + + public static List
Get(int count) + { + var articles = new List
(); + for (int i = 0; i < count; i++) + articles.Add(Get()); + + return articles; + } + } +} \ No newline at end of file diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj new file mode 100644 index 0000000000..18e795cb9e --- /dev/null +++ b/test/OperationsExampleTests/OperationsExampleTests.csproj @@ -0,0 +1,23 @@ + + + netcoreapp1.1 + false + OperationsExampleTests + + + + + + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/test/OperationsExampleTests/WebHostCollection.cs b/test/OperationsExampleTests/WebHostCollection.cs new file mode 100644 index 0000000000..a92285aff0 --- /dev/null +++ b/test/OperationsExampleTests/WebHostCollection.cs @@ -0,0 +1,42 @@ +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using OperationsExample; +using Xunit; +using Microsoft.AspNetCore.TestHost; +using Newtonsoft.Json; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using JsonApiDotNetCore.Formatters; + +namespace OperationsExampleTests +{ + [CollectionDefinition("WebHostCollection")] + public class WebHostCollection + : ICollectionFixture + { } + + public class Fixture + { + public Fixture() + { + var builder = new WebHostBuilder().UseStartup(); + Server = new TestServer(builder); + Client = Server.CreateClient(); + } + + public TestServer Server { get; private set; } + public HttpClient Client { get; } + public T GetService() => (T)Server.Host.Services.GetService(typeof(T)); + + public async Task PatchAsync(string route, object data) + { + var httpMethod = new HttpMethod("PATCH"); + var request = new HttpRequestMessage(httpMethod, route); + request.Content = new StringContent(JsonConvert.SerializeObject(data)); + request.Content.Headers.ContentLength = 1; + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + request.Content.Headers.Add("Link", JsonApiOperationsInputFormatter.PROFILE_EXTENSION); + return await Client.SendAsync(request); + } + } +} \ No newline at end of file diff --git a/test/OperationsExampleTests/appsettings.json b/test/OperationsExampleTests/appsettings.json new file mode 100644 index 0000000000..c1061281cc --- /dev/null +++ b/test/OperationsExampleTests/appsettings.json @@ -0,0 +1,13 @@ +{ + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=password" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "System": "Trace", + "Microsoft": "Trace" + } + } +} From ed7659bb2a36dd6f02741617746fadc40c77c3d5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 26 Sep 2017 23:28:22 -0500 Subject: [PATCH 025/227] feat(fetch): add get all operation --- .../JsonApiOperationsController.cs | 6 +- .../IServiceCollectionExtensions.cs | 10 +++ .../Models/Operations/OperationsDocument.cs | 8 ++ .../Services/IJsonApiContext.cs | 1 - ...r.cs => DocumentDataPointerReplacement.cs} | 0 .../Operations/OperationProcessorResolver.cs | 25 +++++- .../Operations/OperationsProcessor.cs | 39 ++++++++- .../Operations/Processors/GetOpProcessor.cs | 79 +++++++++++++++++++ .../ResourceRefPointerReplacement.cs | 34 ++++++++ test/OperationsExampleTests/Get/GetTests.cs | 49 ++++++++++++ .../WebHostCollection.cs | 9 +++ 11 files changed, 251 insertions(+), 9 deletions(-) rename src/JsonApiDotNetCore/Services/Operations/{OperationsPointerExchanger.cs => DocumentDataPointerReplacement.cs} (100%) create mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs create mode 100644 src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs create mode 100644 test/OperationsExampleTests/Get/GetTests.cs diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index 3990f7b85d..f3d0b6651d 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -9,7 +9,8 @@ public class JsonApiOperationsController : Controller { private readonly IOperationsProcessor _operationsProcessor; - public JsonApiOperationsController(IOperationsProcessor operationsProcessor) + public JsonApiOperationsController( + IOperationsProcessor operationsProcessor) { _operationsProcessor = operationsProcessor; } @@ -18,7 +19,8 @@ public JsonApiOperationsController(IOperationsProcessor operationsProcessor) public async Task PatchAsync([FromBody] OperationsDocument doc) { var results = await _operationsProcessor.ProcessAsync(doc.Operations); - return Ok(results); + + return Ok(new OperationsDocument(results)); } } } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index ab297252f9..dc9bd56cef 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -100,8 +100,13 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); + services.AddScoped(typeof(ICreateService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(ICreateService<,>), typeof(EntityResourceService<,>)); + + services.AddScoped(typeof(IGetAllService<>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(IGetAllService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); services.AddSingleton(jsonApiOptions); @@ -127,8 +132,13 @@ public static void AddJsonApiInternals( private static void AddOperationServices(IServiceCollection services) { services.AddScoped(); + services.AddScoped(typeof(ICreateOpProcessor<>), typeof(CreateOpProcessor<>)); services.AddScoped(typeof(ICreateOpProcessor<,>), typeof(CreateOpProcessor<,>)); + + services.AddScoped(typeof(IGetOpProcessor<>), typeof(GetOpProcessor<>)); + services.AddScoped(typeof(IGetOpProcessor<,>), typeof(GetOpProcessor<,>)); + services.AddSingleton(); services.AddSingleton(); } diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs b/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs index 987f9abc20..3228e9ca88 100644 --- a/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs +++ b/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs @@ -1,9 +1,17 @@ using System.Collections.Generic; +using Newtonsoft.Json; namespace JsonApiDotNetCore.Models.Operations { public class OperationsDocument { + public OperationsDocument() { } + public OperationsDocument(List operations) + { + Operations = operations; + } + + [JsonProperty("operations")] public List Operations { get; set; } } } diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 7b1b9e67a8..2a201e2691 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Data; diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs b/src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs similarity index 100% rename from src/JsonApiDotNetCore/Services/Operations/OperationsPointerExchanger.cs rename to src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 64261af1c7..1fbe130d0d 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -8,13 +8,15 @@ namespace JsonApiDotNetCore.Services.Operations public interface IOperationProcessorResolver { IOpProcessor LocateCreateService(Operation operation); + IOpProcessor LocateGeteService(Operation operation); } public class OperationProcessorResolver : IOperationProcessorResolver { private readonly IGenericProcessorFactory _processorFactory; private readonly IJsonApiContext _context; - private ConcurrentDictionary _cachedProcessors = new ConcurrentDictionary(); + private ConcurrentDictionary _createOpProcessors = new ConcurrentDictionary(); + private ConcurrentDictionary _getOpProcessors = new ConcurrentDictionary(); public OperationProcessorResolver( IGenericProcessorFactory processorFactory, @@ -30,7 +32,7 @@ public IOpProcessor LocateCreateService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_cachedProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + if (_createOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) return cachedProcessor; var contextEntity = _context.ContextGraph.GetContextEntity(resource); @@ -38,7 +40,24 @@ public IOpProcessor LocateCreateService(Operation operation) typeof(ICreateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _cachedProcessors[resource] = processor; + _createOpProcessors[resource] = processor; + + return processor; + } + + public IOpProcessor LocateGeteService(Operation operation) + { + var resource = operation.GetResourceTypeName(); + + if (_getOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + return cachedProcessor; + + var contextEntity = _context.ContextGraph.GetContextEntity(resource); + var processor = _processorFactory.GetProcessor( + typeof(IGetOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + ); + + _getOpProcessors[resource] = processor; return processor; } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 75e013c8c8..bc241e72ad 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -1,5 +1,8 @@ +using System; using System.Collections.Generic; using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Models.Pointers; @@ -28,10 +31,11 @@ public async Task> ProcessAsync(List inputOps) // TODO: parse pointers: // locate all objects within the document and replace them var operationsPointer = new OperationsPointer(); - var replacer = new DocumentDataPointerReplacement(op.DataObject); - replacer.ReplacePointers(outputOps); - var processor = _processorResolver.LocateCreateService(op); + ReplaceDataPointers(op.DataObject, outputOps); + ReplaceRefPointers(op.Ref, outputOps); + + var processor = GetOperationsProcessor(op); var resultOp = await processor.ProcessAsync(op); if (resultOp != null) @@ -40,5 +44,34 @@ public async Task> ProcessAsync(List inputOps) return outputOps; } + + private void ReplaceDataPointers(DocumentData dataObject, List outputOps) + { + if (dataObject == null) return; + + var replacer = new DocumentDataPointerReplacement(dataObject); + replacer.ReplacePointers(outputOps); + } + + private void ReplaceRefPointers(ResourceReference resourceRef, List outputOps) + { + if (resourceRef == null) return; + + var replacer = new ResourceRefPointerReplacement(resourceRef); + replacer.ReplacePointers(outputOps); + } + + private IOpProcessor GetOperationsProcessor(Operation op) + { + switch (op.Op) + { + case OperationCode.add: + return _processorResolver.LocateCreateService(op); + case OperationCode.get: + return _processorResolver.LocateGeteService(op); + default: + throw new JsonApiException(400, $"'{op.Op}' is not a valid operation code"); + } + } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs new file mode 100644 index 0000000000..cc6f864516 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Serialization; +using JsonApiDotNetCore.Services; + +namespace JsonApiDotNetCore.Services.Operations.Processors +{ + public interface IGetOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public interface IGetOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public class GetOpProcessor : GetOpProcessor + where T : class, IIdentifiable + { + public GetOpProcessor( + IGetAllService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph, + IJsonApiContext jsonApiContext + ) : base(service, deSerializer, documentBuilder, contextGraph, jsonApiContext) + { } + } + + public class GetOpProcessor : IGetOpProcessor + where T : class, IIdentifiable + { + private readonly IGetAllService _service; + private readonly IJsonApiDeSerializer _deSerializer; + private readonly IDocumentBuilder _documentBuilder; + private readonly IContextGraph _contextGraph; + private readonly IJsonApiContext _jsonApiContext; + + public GetOpProcessor( + IGetAllService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph, + IJsonApiContext jsonApiContext) + { + _service = service; + _deSerializer = deSerializer; + _documentBuilder = documentBuilder; + _contextGraph = contextGraph; + _jsonApiContext = jsonApiContext.ApplyContext(this); + } + + public async Task ProcessAsync(Operation operation) + { + var result = await _service.GetAsync(); + + var operationResult = new Operation + { + Op = OperationCode.add + }; + + var operations = new List(); + foreach (var resource in result) + { + var doc = _documentBuilder.GetData( + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + resource); + operations.Add(doc); + } + + operationResult.Data = operations; + + return operationResult; + } + } +} diff --git a/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs b/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs new file mode 100644 index 0000000000..d24d7e879a --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Models.Pointers; +using Newtonsoft.Json.Linq; +using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Models.Operations; + +namespace JsonApiDotNetCore.Services.Operations +{ + public class ResourceRefPointerReplacement + where TPointer : Pointer, new() + { + private readonly ResourceReference _ref; + + public ResourceRefPointerReplacement(ResourceReference data) + { + _ref = data; + } + + public void ReplacePointers(List parentDoc) + { + _ref.Id = GetPointerValue(_ref.Id, parentDoc); + _ref.Type = GetPointerValue(_ref.Type, parentDoc); + } + + private object GetPointerValue(object reference, List parentDoc) + { + if (reference is JObject jObj) + if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) + return pointer.GetValue(parentDoc); + + return reference; + } + } +} \ No newline at end of file diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs new file mode 100644 index 0000000000..1b04df8089 --- /dev/null +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using JsonApiDotNetCore.Models.Operations; +using Microsoft.EntityFrameworkCore; +using OperationsExample.Data; +using Xunit; + +namespace OperationsExampleTests +{ + [Collection("WebHostCollection")] + public class GetTests + { + private readonly Fixture _fixture; + + public GetTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Can_Get_Articles() + { + // arrange + var context = _fixture.GetService(); + var articles = await context.Articles.ToListAsync(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "get"}, + { "ref", new { type = "articles" } } + } + } + }; + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + Assert.Equal(articles.Count, result.data.Operations[0].DataList.Count); + } + } +} diff --git a/test/OperationsExampleTests/WebHostCollection.cs b/test/OperationsExampleTests/WebHostCollection.cs index a92285aff0..6ddbebd433 100644 --- a/test/OperationsExampleTests/WebHostCollection.cs +++ b/test/OperationsExampleTests/WebHostCollection.cs @@ -1,3 +1,4 @@ +using System; using System.Net.Http; using Microsoft.AspNetCore.Hosting; using OperationsExample; @@ -38,5 +39,13 @@ public async Task PatchAsync(string route, object data) request.Content.Headers.Add("Link", JsonApiOperationsInputFormatter.PROFILE_EXTENSION); return await Client.SendAsync(request); } + + public async Task<(HttpResponseMessage response, T data)> PatchAsync(string route, object data) + { + var response = await PatchAsync(route, data); + var json = await response.Content.ReadAsStringAsync(); + var obj = JsonConvert.DeserializeObject(json); + return (response, obj); + } } } \ No newline at end of file From dfd5266455de4f29c48456979c97d9d1daf95738 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 26 Sep 2017 23:42:03 -0500 Subject: [PATCH 026/227] feat(fetch): get by id operation --- .../IServiceCollectionExtensions.cs | 5 +- .../Operations/Processors/GetOpProcessor.cs | 47 ++++++++++++++----- test/OperationsExampleTests/Get/GetTests.cs | 31 +++++++++++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index dc9bd56cef..9985f957bc 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -100,13 +100,16 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); - + services.AddScoped(typeof(ICreateService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(ICreateService<,>), typeof(EntityResourceService<,>)); services.AddScoped(typeof(IGetAllService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IGetAllService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IGetByIdService<>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(IGetByIdService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); services.AddSingleton(jsonApiOptions); diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs index cc6f864516..8bd5b2b0f4 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs @@ -5,7 +5,6 @@ using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Services; namespace JsonApiDotNetCore.Services.Operations.Processors { @@ -21,32 +20,36 @@ public class GetOpProcessor : GetOpProcessor where T : class, IIdentifiable { public GetOpProcessor( - IGetAllService service, + IGetAllService getAll, + IGetByIdService getById, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, IContextGraph contextGraph, IJsonApiContext jsonApiContext - ) : base(service, deSerializer, documentBuilder, contextGraph, jsonApiContext) + ) : base(getAll, getById, deSerializer, documentBuilder, contextGraph, jsonApiContext) { } } public class GetOpProcessor : IGetOpProcessor where T : class, IIdentifiable { - private readonly IGetAllService _service; + private readonly IGetAllService _getAll; + private readonly IGetByIdService _getById; private readonly IJsonApiDeSerializer _deSerializer; private readonly IDocumentBuilder _documentBuilder; private readonly IContextGraph _contextGraph; private readonly IJsonApiContext _jsonApiContext; public GetOpProcessor( - IGetAllService service, + IGetAllService getAll, + IGetByIdService getById, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, IContextGraph contextGraph, IJsonApiContext jsonApiContext) { - _service = service; + _getAll = getAll; + _getById = getById; _deSerializer = deSerializer; _documentBuilder = documentBuilder; _contextGraph = contextGraph; @@ -55,25 +58,43 @@ public GetOpProcessor( public async Task ProcessAsync(Operation operation) { - var result = await _service.GetAsync(); - var operationResult = new Operation { - Op = OperationCode.add + Op = OperationCode.get }; + operationResult.Data = string.IsNullOrWhiteSpace(operation.Ref.Id?.ToString()) + ? await GetAllAsync(operation) + : await GetByIdAsync(operation); + + return operationResult; + } + + private async Task GetAllAsync(Operation operation) + { + var result = await _getAll.GetAsync(); + var operations = new List(); foreach (var resource in result) { var doc = _documentBuilder.GetData( - _contextGraph.GetContextEntity(operation.GetResourceTypeName()), - resource); + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + resource); operations.Add(doc); } - operationResult.Data = operations; + return operations; + } - return operationResult; + private async Task GetByIdAsync(Operation operation) + { + var id = TypeHelper.ConvertType(operation.Ref.Id); + var result = await _getById.GetAsync(id); + var doc = _documentBuilder.GetData( + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + result); + + return doc; } } } diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs index 1b04df8089..82233a4fc8 100644 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Net; using System.Threading.Tasks; using JsonApiDotNetCore.Models.Operations; @@ -43,7 +44,35 @@ public async Task Can_Get_Articles() Assert.NotNull(result.data); Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); Assert.Equal(1, result.data.Operations.Count); - Assert.Equal(articles.Count, result.data.Operations[0].DataList.Count); + Assert.Equal(articles.Count, result.data.Operations.Single().DataList.Count); + } + + [Fact] + public async Task Can_Get_Article_By_Id() + { + // arrange + var context = _fixture.GetService(); + var article = await context.Articles.LastAsync(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "get"}, + { "ref", new { type = "articles", id = article.StringId } } + } + } + }; + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + Assert.Equal(article.Id.ToString(), result.data.Operations.Single().DataObject.Id); } } } From cb1b2e4d7564ba4a669e6d192cb954d9598710ce Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 22 Oct 2017 21:14:42 -0500 Subject: [PATCH 027/227] replace operations --- .../IServiceCollectionExtensions.cs | 6 + .../Operations/OperationProcessorResolver.cs | 23 +++- .../Operations/OperationsProcessor.cs | 4 +- .../Processors/ReplaceOpProcessor.cs | 75 ++++++++++++ test/OperationsExampleTests/Get/GetTests.cs | 16 ++- .../Replace/ReplaceTests.cs | 112 ++++++++++++++++++ .../WebHostCollection.cs | 3 +- 7 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs create mode 100644 test/OperationsExampleTests/Replace/ReplaceTests.cs diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 9985f957bc..3788f62c19 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -110,6 +110,9 @@ public static void AddJsonApiInternals( services.AddScoped(typeof(IGetByIdService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IGetByIdService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IUpdateService<>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(IUpdateService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); services.AddSingleton(jsonApiOptions); @@ -142,6 +145,9 @@ private static void AddOperationServices(IServiceCollection services) services.AddScoped(typeof(IGetOpProcessor<>), typeof(GetOpProcessor<>)); services.AddScoped(typeof(IGetOpProcessor<,>), typeof(GetOpProcessor<,>)); + services.AddScoped(typeof(IReplaceOpProcessor<>), typeof(ReplaceOpProcessor<>)); + services.AddScoped(typeof(IReplaceOpProcessor<,>), typeof(ReplaceOpProcessor<,>)); + services.AddSingleton(); services.AddSingleton(); } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 1fbe130d0d..544cbe9fa0 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -8,7 +8,8 @@ namespace JsonApiDotNetCore.Services.Operations public interface IOperationProcessorResolver { IOpProcessor LocateCreateService(Operation operation); - IOpProcessor LocateGeteService(Operation operation); + IOpProcessor LocateGetService(Operation operation); + IOpProcessor LocateReplaceService(Operation operation); } public class OperationProcessorResolver : IOperationProcessorResolver @@ -17,6 +18,7 @@ public class OperationProcessorResolver : IOperationProcessorResolver private readonly IJsonApiContext _context; private ConcurrentDictionary _createOpProcessors = new ConcurrentDictionary(); private ConcurrentDictionary _getOpProcessors = new ConcurrentDictionary(); + private ConcurrentDictionary _replaceOpProcessors = new ConcurrentDictionary(); public OperationProcessorResolver( IGenericProcessorFactory processorFactory, @@ -45,7 +47,7 @@ public IOpProcessor LocateCreateService(Operation operation) return processor; } - public IOpProcessor LocateGeteService(Operation operation) + public IOpProcessor LocateGetService(Operation operation) { var resource = operation.GetResourceTypeName(); @@ -61,5 +63,22 @@ public IOpProcessor LocateGeteService(Operation operation) return processor; } + + public IOpProcessor LocateReplaceService(Operation operation) + { + var resource = operation.GetResourceTypeName(); + + if (_replaceOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + return cachedProcessor; + + var contextEntity = _context.ContextGraph.GetContextEntity(resource); + var processor = _processorFactory.GetProcessor( + typeof(IReplaceOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + ); + + _replaceOpProcessors[resource] = processor; + + return processor; + } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index bc241e72ad..9a66245f67 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -68,7 +68,9 @@ private IOpProcessor GetOperationsProcessor(Operation op) case OperationCode.add: return _processorResolver.LocateCreateService(op); case OperationCode.get: - return _processorResolver.LocateGeteService(op); + return _processorResolver.LocateGetService(op); + case OperationCode.replace: + return _processorResolver.LocateReplaceService(op); default: throw new JsonApiException(400, $"'{op.Op}' is not a valid operation code"); } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs new file mode 100644 index 0000000000..a426be7236 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading.Tasks; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Serialization; +using Newtonsoft.Json; + +namespace JsonApiDotNetCore.Services.Operations.Processors +{ + public interface IReplaceOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public interface IReplaceOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public class ReplaceOpProcessor : ReplaceOpProcessor + where T : class, IIdentifiable + { + public ReplaceOpProcessor( + IUpdateService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph + ) : base(service, deSerializer, documentBuilder, contextGraph) + { } + } + + public class ReplaceOpProcessor : IReplaceOpProcessor + where T : class, IIdentifiable + { + private readonly IUpdateService _service; + private readonly IJsonApiDeSerializer _deSerializer; + private readonly IDocumentBuilder _documentBuilder; + private readonly IContextGraph _contextGraph; + + public ReplaceOpProcessor( + IUpdateService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph) + { + _service = service; + _deSerializer = deSerializer; + _documentBuilder = documentBuilder; + _contextGraph = contextGraph; + } + + public async Task ProcessAsync(Operation operation) + { + Console.WriteLine(JsonConvert.SerializeObject(operation)); + var model = (T)_deSerializer.DocumentToObject(operation.DataObject); + + if (string.IsNullOrWhiteSpace(operation?.DataObject?.Id?.ToString())) + throw new JsonApiException(400, "The data.id parameter is required for replace operations"); + + var id = TypeHelper.ConvertType(operation.DataObject.Id); + var result = await _service.UpdateAsync(id, model); + + var operationResult = new Operation + { + Op = OperationCode.replace + }; + + operationResult.Data = _documentBuilder.GetData( + _contextGraph.GetContextEntity(operation.GetResourceTypeName()), + result); + + return operationResult; + } + } +} diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs index 82233a4fc8..17c868cebd 100644 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -2,9 +2,10 @@ using System.Linq; using System.Net; using System.Threading.Tasks; +using Bogus; using JsonApiDotNetCore.Models.Operations; -using Microsoft.EntityFrameworkCore; using OperationsExample.Data; +using OperationsExampleTests.Factories; using Xunit; namespace OperationsExampleTests @@ -13,6 +14,7 @@ namespace OperationsExampleTests public class GetTests { private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); public GetTests(Fixture fixture) { @@ -23,8 +25,12 @@ public GetTests(Fixture fixture) public async Task Can_Get_Articles() { // arrange + var expectedCount = _faker.Random.Int(1, 10); var context = _fixture.GetService(); - var articles = await context.Articles.ToListAsync(); + context.Articles.RemoveRange(context.Articles); + var articles = ArticleFactory.Get(expectedCount); + context.AddRange(articles); + context.SaveChanges(); var content = new { @@ -44,7 +50,7 @@ public async Task Can_Get_Articles() Assert.NotNull(result.data); Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); Assert.Equal(1, result.data.Operations.Count); - Assert.Equal(articles.Count, result.data.Operations.Single().DataList.Count); + Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count); } [Fact] @@ -52,7 +58,9 @@ public async Task Can_Get_Article_By_Id() { // arrange var context = _fixture.GetService(); - var article = await context.Articles.LastAsync(); + var article = ArticleFactory.Get(); + context.Articles.Add(article); + context.SaveChanges(); var content = new { diff --git a/test/OperationsExampleTests/Replace/ReplaceTests.cs b/test/OperationsExampleTests/Replace/ReplaceTests.cs new file mode 100644 index 0000000000..521dcd979b --- /dev/null +++ b/test/OperationsExampleTests/Replace/ReplaceTests.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Bogus; +using JsonApiDotNetCore.Models.Operations; +using OperationsExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + [Collection("WebHostCollection")] + public class ReplaceTests + { + private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); + + public ReplaceTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Can_Update_Article() + { + // arrange + var context = _fixture.GetService(); + var article = ArticleFactory.Get(); + var updates = ArticleFactory.Get(); + context.Articles.Add(article); + context.SaveChanges(); + + var content = new + { + operations = new[] { + new { + op = "replace", + data = new { + type = "articles", + id = article.Id, + attributes = new { + name = updates.Name + } + } + }, + } + }; + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + + var attrs = result.data.Operations.Single().DataObject.Attributes; + Assert.Equal(updates.Name, attrs["name"]); + } + + [Fact] + public async Task Can_Update_Articles() + { + // arrange + var count = _faker.Random.Int(1, 10); + var context = _fixture.GetService(); + + var articles = ArticleFactory.Get(count); + var updates = ArticleFactory.Get(count); + + context.Articles.AddRange(articles); + context.SaveChanges(); + + var content = new + { + operations = new List() + }; + + for (int i = 0; i < count; i++) + content.operations.Add(new + { + op = "replace", + data = new + { + type = "articles", + id = articles[i].Id, + attributes = new + { + name = updates[i].Name + } + } + }); + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(count, result.data.Operations.Count); + + for (int i = 0; i < count; i++) + { + var attrs = result.data.Operations[i].DataObject.Attributes; + Assert.Equal(updates[i].Name, attrs["name"]); + } + } + } +} diff --git a/test/OperationsExampleTests/WebHostCollection.cs b/test/OperationsExampleTests/WebHostCollection.cs index 6ddbebd433..dc4f02a58c 100644 --- a/test/OperationsExampleTests/WebHostCollection.cs +++ b/test/OperationsExampleTests/WebHostCollection.cs @@ -12,8 +12,7 @@ namespace OperationsExampleTests { [CollectionDefinition("WebHostCollection")] - public class WebHostCollection - : ICollectionFixture + public class WebHostCollection : ICollectionFixture { } public class Fixture From f9761477af37f9dda783c91c04ba59b7c861cf2a Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 22 Oct 2017 21:41:08 -0500 Subject: [PATCH 028/227] remove operations --- .../IServiceCollectionExtensions.cs | 6 ++ .../Operations/OperationProcessorResolver.cs | 22 +++++ .../Operations/OperationsProcessor.cs | 2 + .../Processors/RemoveOpProcessor.cs | 65 +++++++++++++ .../Processors/ReplaceOpProcessor.cs | 3 - .../Remove/RemoveTests.cs | 92 +++++++++++++++++++ 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs create mode 100644 test/OperationsExampleTests/Remove/RemoveTests.cs diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 3788f62c19..173544c2ce 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -113,6 +113,9 @@ public static void AddJsonApiInternals( services.AddScoped(typeof(IUpdateService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IUpdateService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IDeleteService<>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(IDeleteService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>)); services.AddSingleton(jsonApiOptions); @@ -148,6 +151,9 @@ private static void AddOperationServices(IServiceCollection services) services.AddScoped(typeof(IReplaceOpProcessor<>), typeof(ReplaceOpProcessor<>)); services.AddScoped(typeof(IReplaceOpProcessor<,>), typeof(ReplaceOpProcessor<,>)); + services.AddScoped(typeof(IRemoveOpProcessor<>), typeof(RemoveOpProcessor<>)); + services.AddScoped(typeof(IRemoveOpProcessor<,>), typeof(RemoveOpProcessor<,>)); + services.AddSingleton(); services.AddSingleton(); } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 544cbe9fa0..eeadc38e22 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -10,15 +10,20 @@ public interface IOperationProcessorResolver IOpProcessor LocateCreateService(Operation operation); IOpProcessor LocateGetService(Operation operation); IOpProcessor LocateReplaceService(Operation operation); + IOpProcessor LocateRemoveService(Operation operation); } public class OperationProcessorResolver : IOperationProcessorResolver { private readonly IGenericProcessorFactory _processorFactory; private readonly IJsonApiContext _context; + + // processor caches -- since there is some associated cost with creating the processors, we store them in memory + // to reduce the cost of subsequent requests. in the future, this may be moved into setup code run at startup private ConcurrentDictionary _createOpProcessors = new ConcurrentDictionary(); private ConcurrentDictionary _getOpProcessors = new ConcurrentDictionary(); private ConcurrentDictionary _replaceOpProcessors = new ConcurrentDictionary(); + private ConcurrentDictionary _removeOpProcessors = new ConcurrentDictionary(); public OperationProcessorResolver( IGenericProcessorFactory processorFactory, @@ -80,5 +85,22 @@ public IOpProcessor LocateReplaceService(Operation operation) return processor; } + + public IOpProcessor LocateRemoveService(Operation operation) + { + var resource = operation.GetResourceTypeName(); + + if (_removeOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + return cachedProcessor; + + var contextEntity = _context.ContextGraph.GetContextEntity(resource); + var processor = _processorFactory.GetProcessor( + typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + ); + + _removeOpProcessors[resource] = processor; + + return processor; + } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 9a66245f67..05c87dd0f7 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -71,6 +71,8 @@ private IOpProcessor GetOperationsProcessor(Operation op) return _processorResolver.LocateGetService(op); case OperationCode.replace: return _processorResolver.LocateReplaceService(op); + case OperationCode.remove: + return _processorResolver.LocateRemoveService(op); default: throw new JsonApiException(400, $"'{op.Op}' is not a valid operation code"); } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs new file mode 100644 index 0000000000..c96af5bb37 --- /dev/null +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading.Tasks; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCore.Serialization; + +namespace JsonApiDotNetCore.Services.Operations.Processors +{ + public interface IRemoveOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public interface IRemoveOpProcessor : IOpProcessor + where T : class, IIdentifiable + { } + + public class RemoveOpProcessor : RemoveOpProcessor + where T : class, IIdentifiable + { + public RemoveOpProcessor( + IDeleteService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph + ) : base(service, deSerializer, documentBuilder, contextGraph) + { } + } + + public class RemoveOpProcessor : IRemoveOpProcessor + where T : class, IIdentifiable + { + private readonly IDeleteService _service; + private readonly IJsonApiDeSerializer _deSerializer; + private readonly IDocumentBuilder _documentBuilder; + private readonly IContextGraph _contextGraph; + + public RemoveOpProcessor( + IDeleteService service, + IJsonApiDeSerializer deSerializer, + IDocumentBuilder documentBuilder, + IContextGraph contextGraph) + { + _service = service; + _deSerializer = deSerializer; + _documentBuilder = documentBuilder; + _contextGraph = contextGraph; + } + + public async Task ProcessAsync(Operation operation) + { + var stringId = operation.Ref?.Id?.ToString(); + if (string.IsNullOrWhiteSpace(stringId)) + throw new JsonApiException(400, "The data.id parameter is required for delete operations"); + + var id = TypeHelper.ConvertType(stringId); + var result = await _service.DeleteAsync(id); + + var operationResult = new Operation { }; + + return operationResult; + } + } +} diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs index a426be7236..27cf348397 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs @@ -1,11 +1,9 @@ -using System; using System.Threading.Tasks; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Serialization; -using Newtonsoft.Json; namespace JsonApiDotNetCore.Services.Operations.Processors { @@ -51,7 +49,6 @@ public ReplaceOpProcessor( public async Task ProcessAsync(Operation operation) { - Console.WriteLine(JsonConvert.SerializeObject(operation)); var model = (T)_deSerializer.DocumentToObject(operation.DataObject); if (string.IsNullOrWhiteSpace(operation?.DataObject?.Id?.ToString())) diff --git a/test/OperationsExampleTests/Remove/RemoveTests.cs b/test/OperationsExampleTests/Remove/RemoveTests.cs new file mode 100644 index 0000000000..f5229ebbd5 --- /dev/null +++ b/test/OperationsExampleTests/Remove/RemoveTests.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Bogus; +using JsonApiDotNetCore.Models.Operations; +using OperationsExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + [Collection("WebHostCollection")] + public class RemoveTests + { + private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); + + public RemoveTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Can_Remove_Article() + { + // arrange + var context = _fixture.GetService(); + var article = ArticleFactory.Get(); + context.Articles.Add(article); + context.SaveChanges(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "remove"}, + { "ref", new { type = "articles", id = article.StringId } } + } + } + }; + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + Assert.Null(context.Articles.SingleOrDefault(a => a.Id == article.Id)); + } + + [Fact] + public async Task Can_Remove_Articles() + { + // arrange + var count = _faker.Random.Int(1, 10); + var context = _fixture.GetService(); + + var articles = ArticleFactory.Get(count); + + context.Articles.AddRange(articles); + context.SaveChanges(); + + var content = new + { + operations = new List() + }; + + for (int i = 0; i < count; i++) + content.operations.Add( + new Dictionary { + { "op", "remove"}, + { "ref", new { type = "articles", id = articles[i].StringId } } + } + ); + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(count, result.data.Operations.Count); + + for (int i = 0; i < count; i++) + Assert.Null(context.Articles.SingleOrDefault(a => a.Id == articles[i].Id)); + } + } +} From 05056a9e9cc952695ff93dd43757efbb3848c806 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 22 Oct 2017 22:11:00 -0500 Subject: [PATCH 029/227] wrap operations in EF transaction --- .../Internal/JsonApiException.cs | 12 +-- .../Operations/OperationsProcessor.cs | 54 +++++++++---- test/OperationsExampleTests/Add/AddTests.cs | 77 ++++++++++--------- 3 files changed, 86 insertions(+), 57 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/JsonApiException.cs b/src/JsonApiDotNetCore/Internal/JsonApiException.cs index 9ce12fe428..aa5faf3f73 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiException.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiException.cs @@ -8,7 +8,7 @@ public class JsonApiException : Exception private readonly ErrorCollection _errors = new ErrorCollection(); public JsonApiException(ErrorCollection errorCollection) - { + { _errors = errorCollection; } @@ -42,15 +42,15 @@ public JsonApiException(int statusCode, string message, Exception innerException public int GetStatusCode() { - if(_errors.Errors.Count == 1) + if (_errors.Errors.Count == 1) return _errors.Errors[0].StatusCode; - if(_errors.Errors.FirstOrDefault(e => e.StatusCode >= 500) != null) + if (_errors.Errors.FirstOrDefault(e => e.StatusCode >= 500) != null) return 500; - - if(_errors.Errors.FirstOrDefault(e => e.StatusCode >= 400) != null) + + if (_errors.Errors.FirstOrDefault(e => e.StatusCode >= 400) != null) return 400; - + return 500; } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 05c87dd0f7..2873d243b1 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -5,6 +5,7 @@ using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Models.Pointers; +using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Services.Operations { @@ -16,35 +17,60 @@ public interface IOperationsProcessor public class OperationsProcessor : IOperationsProcessor { private readonly IOperationProcessorResolver _processorResolver; + private readonly DbContext _dbContext; - public OperationsProcessor(IOperationProcessorResolver processorResolver) + public OperationsProcessor( + IOperationProcessorResolver processorResolver, + DbContext dbContext) { _processorResolver = processorResolver; + _dbContext = dbContext; } public async Task> ProcessAsync(List inputOps) { var outputOps = new List(); - - foreach (var op in inputOps) + var opIndex = 0; + using (var transaction = await _dbContext.Database.BeginTransactionAsync()) { - // TODO: parse pointers: - // locate all objects within the document and replace them - var operationsPointer = new OperationsPointer(); - - ReplaceDataPointers(op.DataObject, outputOps); - ReplaceRefPointers(op.Ref, outputOps); - - var processor = GetOperationsProcessor(op); - var resultOp = await processor.ProcessAsync(op); + try + { + foreach (var op in inputOps) + { + await ProcessOperation(op, outputOps); + opIndex++; + } - if (resultOp != null) - outputOps.Add(resultOp); + transaction.Commit(); + } + catch (JsonApiException e) + { + outputOps = new List(); + throw new JsonApiException(e.GetStatusCode(), $"Transaction failed on operation[{opIndex}].", e); + } + catch (Exception e) + { + throw new JsonApiException(500, $"Transaction failed on operation[{opIndex}] for an unexpected reason.", e); + } } return outputOps; } + private async Task ProcessOperation(Operation op, List outputOps) + { + var operationsPointer = new OperationsPointer(); + + ReplaceDataPointers(op.DataObject, outputOps); + ReplaceRefPointers(op.Ref, outputOps); + + var processor = GetOperationsProcessor(op); + var resultOp = await processor.ProcessAsync(op); + + if (resultOp != null) + outputOps.Add(resultOp); + } + private void ReplaceDataPointers(DocumentData dataObject, List outputOps) { if (dataObject == null) return; diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs index b42dc342f1..2d765e1633 100644 --- a/test/OperationsExampleTests/Add/AddTests.cs +++ b/test/OperationsExampleTests/Add/AddTests.cs @@ -1,7 +1,10 @@ +using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Bogus; using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Models.Operations; using Microsoft.EntityFrameworkCore; using OperationsExample.Data; using OperationsExampleTests.Factories; @@ -13,6 +16,7 @@ namespace OperationsExampleTests public class AddTests { private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); public AddTests(Fixture fixture) { @@ -41,13 +45,14 @@ public async Task Can_Create_Article() }; // act - var response = await _fixture.PatchAsync("api/bulk", content); + var result = await _fixture.PatchAsync("api/bulk", content); // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(result); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - var lastArticle = await context.Articles.LastAsync(); + var id = (string)result.data.Operations.Single().DataObject.Id; + var lastArticle = await context.Articles.SingleAsync(a => a.StringId == id); Assert.Equal(article.Name, lastArticle.Name); } @@ -55,48 +60,46 @@ public async Task Can_Create_Article() public async Task Can_Create_Articles() { // arrange + var expectedCount = _faker.Random.Int(1, 10); var context = _fixture.GetService(); - var articles = ArticleFactory.Get(2); + var articles = ArticleFactory.Get(expectedCount); var content = new { - operations = new[] { - new { - op = "add", - data = new { - type = "articles", - attributes = new { - name = articles[0].Name - } - } - }, - new { - op = "add", - data = new { - type = "articles", - attributes = new { - name = articles[1].Name - } - } - } - } + operations = new List() }; + for (int i = 0; i < expectedCount; i++) + { + content.operations.Add( + new + { + op = "add", + data = new + { + type = "articles", + attributes = new + { + name = articles[i].Name + } + } + } + ); + } + // act - var response = await _fixture.PatchAsync("api/bulk", content); + var result = await _fixture.PatchAsync("api/bulk", content); // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(result); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(expectedCount, result.data.Operations.Count); - var lastArticles = (await context.Articles - .OrderByDescending(d => d.Id) - .Take(2) - .ToListAsync()) - .OrderBy(l => l.Id) - .ToList(); - - Assert.Equal(articles[0].Name, lastArticles[0].Name); - Assert.Equal(articles[1].Name, lastArticles[1].Name); + for (int i = 0; i < expectedCount; i++) + { + var data = result.data.Operations[i].DataObject; + var article = context.Articles.Single(a => a.StringId == data.Id.ToString()); + Assert.Equal(articles[i].Name, article.Name); + } } } } From 8ada5c03e4259eb7abba64ab104c1b50be4a6204 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 24 Oct 2017 06:18:41 -0500 Subject: [PATCH 030/227] chore(*): bump project version and document usage --- couscous.yml | 8 +++++++- docs/Operations.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 docs/Operations.md diff --git a/couscous.yml b/couscous.yml index 87b795a1c3..2a038cf45b 100644 --- a/couscous.yml +++ b/couscous.yml @@ -110,4 +110,10 @@ menu: relativeUrl: entityrepositories.html middleware: text: Middleware - relativeUrl: middleware.html \ No newline at end of file + relativeUrl: middleware.html + extensions: + name: Spec Extensions + items: + operations: + text: Operations + relativeUrl: operations.html \ No newline at end of file diff --git a/docs/Operations.md b/docs/Operations.md new file mode 100644 index 0000000000..697f9171b2 --- /dev/null +++ b/docs/Operations.md @@ -0,0 +1,33 @@ +--- +currentMenu: operations +--- + +# Operations + +Operations is currently an unofficial proposal. It allows you to perform bulk operations in a single transaction. + +### Enabling + +To enable the operations extension, modify you `Startup.ConfigureServices` method: + +```csharp +services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); +``` + +### Controllers + +To create a bulk operations controller, inherit `JsonApiOperationsController`: + +```csharp +[Route("api/bulk")] +public class OperationsController : JsonApiOperationsController +{ + public OperationsController(IOperationsProcessor processor) + : base(processor) + { } +} +``` + +### Example + +There is a working example in the `/src/examples/OperationsExample` directory of the repository. \ No newline at end of file From 5832ea3674830bf1986092ec8a959c96ee86afd5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 24 Oct 2017 06:46:55 -0500 Subject: [PATCH 031/227] fix tests --- .../Operations/OperationsProcessorTests.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index fadcd3be78..74298f0cca 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -1,7 +1,11 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Services.Operations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; using Moq; using Newtonsoft.Json; using Xunit; @@ -12,9 +16,12 @@ public class OperationsProcessorTests { private readonly Mock _resolverMock; + public readonly Mock _dbContextMock; + public OperationsProcessorTests() { _resolverMock = new Mock(); + _dbContextMock = new Mock(); } [Fact] @@ -61,21 +68,27 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() } } }"; - + var operations = JsonConvert.DeserializeObject>(request); var addOperationResult = JsonConvert.DeserializeObject(op1Result); + var databaseMock = new Mock(_dbContextMock.Object); + var transactionMock = new Mock(); + databaseMock.Setup(m => m.BeginTransactionAsync(It.IsAny())) + .ReturnsAsync(transactionMock.Object); + _dbContextMock.Setup(m => m.Database).Returns(databaseMock.Object); + var opProcessorMock = new Mock(); opProcessorMock.Setup(m => m.ProcessAsync(It.Is(op => op.DataObject.Type.ToString() == "authors"))) .ReturnsAsync(addOperationResult); - + _resolverMock.Setup(m => m.LocateCreateService(It.IsAny())) .Returns(opProcessorMock.Object); - + _resolverMock.Setup(m => m.LocateCreateService((It.IsAny()))) .Returns(opProcessorMock.Object); - var operationsProcessor = new OperationsProcessor(_resolverMock.Object); + var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextMock.Object); // act var results = await operationsProcessor.ProcessAsync(operations); @@ -83,7 +96,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() // assert opProcessorMock.Verify( m => m.ProcessAsync( - It.Is(o => + It.Is(o => o.DataObject.Type.ToString() == "articles" && o.DataObject.Relationships["author"].SingleData["id"].ToString() == "9" ) From e4c3968eb1e6c8635c95a4e52f57792283808951 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 12 Nov 2017 20:31:58 -0600 Subject: [PATCH 032/227] chore(csproj): bump package version --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index a67648a417..e6429a1364 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.1.9 + 2.2.0 netstandard1.6 JsonApiDotNetCore JsonApiDotNetCore From bb90f9ed60ccc2f06a42a36d4dfc657708559578 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 12 Nov 2017 20:50:15 -0600 Subject: [PATCH 033/227] feat(query-parser): allow inheritance and method overrides (#191) --- src/JsonApiDotNetCore/Services/QueryParser.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 26c735e30c..297eb246a0 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -29,7 +29,7 @@ public QueryParser( _options = options; } - public QuerySet Parse(IQueryCollection query) + public virtual QuerySet Parse(IQueryCollection query) { var querySet = new QuerySet(); var disabledQueries = _controllerContext.GetControllerAttribute()?.QueryParams ?? QueryParams.None; @@ -78,7 +78,7 @@ public QuerySet Parse(IQueryCollection query) return querySet; } - private List ParseFilterQuery(string key, string value) + protected virtual List ParseFilterQuery(string key, string value) { // expected input = filter[id]=1 // expected input = filter[id]=eq:1 @@ -96,7 +96,7 @@ private List ParseFilterQuery(string key, string value) return queries; } - private (string operation, string value) ParseFilterOperation(string value) + protected virtual (string operation, string value) ParseFilterOperation(string value) { if (value.Length < 3) return (string.Empty, value); @@ -116,7 +116,7 @@ private List ParseFilterQuery(string key, string value) return (prefix, value); } - private PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) + protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) { // expected input = page[size]=10 // page[number]=1 @@ -134,7 +134,7 @@ private PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) // sort=id,name // sort=-id - private List ParseSortParameters(string value) + protected virtual List ParseSortParameters(string value) { var sortParameters = new List(); value.Split(',').ToList().ForEach(p => @@ -154,7 +154,7 @@ private List ParseSortParameters(string value) return sortParameters; } - private List ParseIncludedRelationships(string value) + protected virtual List ParseIncludedRelationships(string value) { if (value.Contains(".")) throw new JsonApiException(400, "Deeply nested relationships are not supported"); @@ -164,7 +164,7 @@ private List ParseIncludedRelationships(string value) .ToList(); } - private List ParseFieldsQuery(string key, string value) + protected virtual List ParseFieldsQuery(string key, string value) { // expected: fields[TYPE]=prop1,prop2 var typeName = key.Split('[', ']')[1]; @@ -187,7 +187,7 @@ private List ParseFieldsQuery(string key, string value) return includedFields; } - private AttrAttribute GetAttribute(string propertyName) + protected virtual AttrAttribute GetAttribute(string propertyName) => _controllerContext .RequestEntity .Attributes From c81a7accb9735b99c156e93e360f706c980b04fa Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 12 Nov 2017 21:28:47 -0600 Subject: [PATCH 034/227] document options --- couscous.yml | 5 +- docs/CustomQueryFormat.md | 13 ++ docs/Options.md | 28 +++ docs/QueryingData.md | 185 ------------------ .../HttpMethodRestrictionFilter.cs | 9 +- 5 files changed, 48 insertions(+), 192 deletions(-) create mode 100644 docs/CustomQueryFormat.md delete mode 100644 docs/QueryingData.md diff --git a/couscous.yml b/couscous.yml index 87b795a1c3..2acaad12d7 100644 --- a/couscous.yml +++ b/couscous.yml @@ -110,4 +110,7 @@ menu: relativeUrl: entityrepositories.html middleware: text: Middleware - relativeUrl: middleware.html \ No newline at end of file + relativeUrl: middleware.html + customqueryformat: + text: Custom Query Formats + relativeUrl: customqueryformat.html \ No newline at end of file diff --git a/docs/CustomQueryFormat.md b/docs/CustomQueryFormat.md new file mode 100644 index 0000000000..b23993d333 --- /dev/null +++ b/docs/CustomQueryFormat.md @@ -0,0 +1,13 @@ +--- +currentMenu: customqueryformat +--- + +# Custom Query Formats + +For information on the default query parameter formats, see the documentation for each query method. + +In order to customize the query formats, you need to implement the `IQueryParser` interface and inject it like so: + +```csharp +services.AddScoped(); +``` \ No newline at end of file diff --git a/docs/Options.md b/docs/Options.md index 681c502557..3f94f4031e 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -80,4 +80,32 @@ Accept: application/vnd.api+json } } } +``` + +## Custom Query Parameters + +If you would like to use custom query params (parameters not reserved by the json:api specification), you can set `AllowCustomQueryParameters = true`. The default behavior is to return an `HTTP 400 Bad Request` for unknown query parameters. + +```csharp +public IServiceProvider ConfigureServices(IServiceCollection services) { + services.AddJsonApi( + opt => opt.AllowCustomQueryParameters = true); + // ... +} +``` + +## Custom Serializer Settings + +We use Json.Net for all serialization needs. If you want to change the default serializer settings, you can: + +```csharp +public IServiceProvider ConfigureServices(IServiceCollection services) { + services.AddJsonApi( + opt => opt.SerializerSettings = new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new DasherizedResolver() + }); + // ... +} ``` \ No newline at end of file diff --git a/docs/QueryingData.md b/docs/QueryingData.md deleted file mode 100644 index d6de50111a..0000000000 --- a/docs/QueryingData.md +++ /dev/null @@ -1,185 +0,0 @@ -# Querying Data -### Pagination - -Resources can be paginated. -The following query would set the page size to 10 and get page 2. - -``` -?page[size]=10&page[number]=2 -``` - -If you would like pagination implemented by default, you can specify the page size -when setting up the services: - -```csharp - services.AddJsonApi( - opt => opt.DefaultPageSize = 10); -``` - -**Total Record Count** - -The total number of records can be added to the document meta by setting it in the options: - -```csharp -services.AddJsonApi(opt => -{ - opt.DefaultPageSize = 5; - opt.IncludeTotalRecordCount = true; -}); -``` - -### Filtering - -You can filter resources by attributes using the `filter` query parameter. -By default, all attributes are filterable. -The filtering strategy we have selected, uses the following form: - -``` -?filter[attribute]=value -``` - -For operations other than equality, the query can be prefixed with an operation -identifier): - -``` -?filter[attribute]=eq:value -?filter[attribute]=lt:value -?filter[attribute]=gt:value -?filter[attribute]=le:value -?filter[attribute]=ge:value -?filter[attribute]=like:value -``` - -#### Custom Filters - -You can customize the filter implementation by overriding the method in the `DefaultEntityRepository` like so: - -```csharp -public class MyEntityRepository : DefaultEntityRepository -{ - public MyEntityRepository( - AppDbContext context, - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) - : base(context, loggerFactory, jsonApiContext) - { } - - public override IQueryable Filter(IQueryable entities, FilterQuery filterQuery) - { - // use the base filtering method - entities = base.Filter(entities, filterQuery); - - // implement custom method - return ApplyMyCustomFilter(entities, filterQuery); - } -} -``` - -### Sorting - -Resources can be sorted by an attribute: - -``` -?sort=attribute // ascending -?sort=-attribute // descending -``` - -### Meta - -Meta objects can be assigned in two ways: - - Resource meta - - Request Meta - -Resource meta can be defined by implementing `IHasMeta` on the model class: - -```csharp -public class Person : Identifiable, IHasMeta -{ - // ... - - public Dictionary GetMeta(IJsonApiContext context) - { - return new Dictionary { - { "copyright", "Copyright 2015 Example Corp." }, - { "authors", new string[] { "Jared Nance" } } - }; - } -} -``` - -Request Meta can be added by injecting a service that implements `IRequestMeta`. -In the event of a key collision, the Request Meta will take precendence. - -### Client Generated Ids - -By default, the server will respond with a `403 Forbidden` HTTP Status Code if a `POST` request is -received with a client generated id. However, this can be allowed by setting the `AllowClientGeneratedIds` -flag in the options: - -```csharp -services.AddJsonApi(opt => -{ - opt.AllowClientGeneratedIds = true; - // .. -}); -``` - -### Custom Errors - -By default, errors will only contain the properties defined by the internal [Error](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Internal/Error.cs) class. However, you can create your own by inheriting from `Error` and either throwing it in a `JsonApiException` or returning the error from your controller. - -```csharp -// custom error definition -public class CustomError : Error { - public CustomError(string status, string title, string detail, string myProp) - : base(status, title, detail) - { - MyCustomProperty = myProp; - } - public string MyCustomProperty { get; set; } -} - -// throwing a custom error -public void MyMethod() { - var error = new CustomError("507", "title", "detail", "custom"); - throw new JsonApiException(error); -} - -// returning from controller -[HttpPost] -public override async Task PostAsync([FromBody] MyEntity entity) -{ - if(_db.IsFull) - return new ObjectResult(new CustomError("507", "Database is full.", "Theres no more room.", "Sorry.")); - - // ... -} -``` - -### Sparse Fieldsets - -We currently support top-level field selection. -What this means is you can restrict which fields are returned by a query using the `fields` query parameter, but this does not yet apply to included relationships. - -- Currently valid: -```http -GET /articles?fields[articles]=title,body HTTP/1.1 -Accept: application/vnd.api+json -``` - -- Not yet supported: -```http -GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1 -Accept: application/vnd.api+json -``` - -## Tests - -I am using DotNetCoreDocs to generate sample requests and documentation. - -1. To run the tests, start a postgres server and verify the connection properties define in `/test/JsonApiDotNetCoreExampleTests/appsettings.json` -2. `cd ./test/JsonApiDotNetCoreExampleTests` -3. `dotnet test` -4. `cd ./src/JsonApiDotNetCoreExample` -5. `dotnet run` -6. `open http://localhost:5000/docs` diff --git a/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs b/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs index 9bf533502a..ca9a2ff138 100644 --- a/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs +++ b/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs @@ -1,8 +1,5 @@ -using System; using System.Linq; -using System.Reflection; using System.Threading.Tasks; -using JsonApiDotNetCore.Controllers; using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Mvc.Filters; @@ -17,15 +14,15 @@ public override async Task OnActionExecutionAsync( ActionExecutionDelegate next) { var method = context.HttpContext.Request.Method; - - if(CanExecuteAction(method) == false) + + if (CanExecuteAction(method) == false) throw new JsonApiException(405, $"This resource does not support {method} requests."); await next(); } private bool CanExecuteAction(string requestMethod) - { + { return Methods.Contains(requestMethod) == false; } } From 7a42f74eb2ffdc12be35be435970d8d49385e66d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 21:04:46 -0600 Subject: [PATCH 035/227] chore(JsonApiContext): improve error handling if resource not defined on context graph --- .../Internal/ContextGraph.cs | 24 ++++++------------- .../Services/JsonApiContext.cs | 2 ++ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs index aae5c2179b..fd29794194 100644 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ContextGraph.cs @@ -8,21 +8,13 @@ namespace JsonApiDotNetCore.Internal public class ContextGraph : IContextGraph { public List Entities { get; set; } - public bool UsesDbContext { get; set; } + public bool UsesDbContext { get; set; } public ContextEntity GetContextEntity(string entityName) - { - return Entities - .FirstOrDefault(e => - e.EntityName.ToLower() == entityName.ToLower()); - } + => Entities.SingleOrDefault(e => string.Equals(e.EntityName, entityName, StringComparison.OrdinalIgnoreCase)); public ContextEntity GetContextEntity(Type entityType) - { - return Entities - .FirstOrDefault(e => - e.EntityType == entityType); - } + => Entities.SingleOrDefault(e => e.EntityType == entityType); public object GetRelationship(TParent entity, string relationshipName) { @@ -30,9 +22,9 @@ public object GetRelationship(TParent entity, string relationshipName) var navigationProperty = parentEntityType .GetProperties() - .FirstOrDefault(p => p.Name.ToLower() == relationshipName.ToLower()); + .SingleOrDefault(p => string.Equals(p.Name, relationshipName, StringComparison.OrdinalIgnoreCase)); - if(navigationProperty == null) + if (navigationProperty == null) throw new JsonApiException(400, $"{parentEntityType} does not contain a relationship named {relationshipName}"); return navigationProperty.GetValue(entity); @@ -42,11 +34,9 @@ public string GetRelationshipName(string relationshipName) { var entityType = typeof(TParent); return Entities - .FirstOrDefault(e => - e.EntityType == entityType) + .SingleOrDefault(e => e.EntityType == entityType) .Relationships - .FirstOrDefault(r => - r.PublicRelationshipName.ToLower() == relationshipName.ToLower()) + .SingleOrDefault(r => string.Equals(r.PublicRelationshipName, relationshipName, StringComparison.OrdinalIgnoreCase)) ?.InternalRelationshipName; } } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index a93d76acdc..b223e47bf5 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -62,6 +62,8 @@ public IJsonApiContext ApplyContext(object controller) _controllerContext.ControllerType = controller.GetType(); _controllerContext.RequestEntity = ContextGraph.GetContextEntity(typeof(T)); + if (_controllerContext.RequestEntity == null) + throw new JsonApiException(500, $"A resource has not been properly defined for type '{typeof(T)}'. Ensure it has been registered on the ContextGraph."); var context = _httpContextAccessor.HttpContext; var path = context.Request.Path.Value.Split('/'); From a28b17f51876263c876dc45e63a898d27ed62428 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 20:51:41 -0600 Subject: [PATCH 036/227] fix(deserializer): skip foreign key if data not in relationship also, improve the error message --- .../Serialization/JsonApiDeSerializer.cs | 11 +- .../Serialization/JsonApiDeSerializerTests.cs | 107 +++++++++++++++++- 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index d8cbf245bf..25021c441e 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -164,11 +164,6 @@ private object SetHasOneRelationship(object entity, ContextEntity contextEntity, Dictionary relationships) { - var entityProperty = entityProperties.FirstOrDefault(p => p.Name == $"{attr.InternalRelationshipName}Id"); - - if (entityProperty == null) - throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain an relationsip named {attr.InternalRelationshipName}"); - var relationshipName = attr.PublicRelationshipName; if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) @@ -181,6 +176,12 @@ private object SetHasOneRelationship(object entity, if (data == null) return entity; var newValue = data["id"]; + + var foreignKey = attr.InternalRelationshipName + "Id"; + var entityProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); + if (entityProperty == null) + throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a foreign key property '{foreignKey}' for has one relationship '{attr.InternalRelationshipName}'"); + var convertedValue = TypeHelper.ConvertType(newValue, entityProperty.PropertyType); _jsonApiContext.RelationshipsToUpdate[relationshipAttr] = convertedValue; diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index 3e54c7b393..eeefa4d857 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal.Generics; @@ -196,6 +197,98 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() Assert.False(attr.Key.IsImmutable); } + [Fact] + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource("independents"); + contextGraphBuilder.AddResource("dependents"); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var genericProcessorFactoryMock = new Mock(); + + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + + var property = Guid.NewGuid().ToString(); + var content = new Document + { + Data = new DocumentData + { + Type = "independents", + Id = "1", + Attributes = new Dictionary { + { "property", property } + } + } + }; + + var contentString = JsonConvert.SerializeObject(content); + + // act + var result = deserializer.Deserialize(contentString); + + // assert + Assert.NotNull(result); + Assert.Equal(property, result.Property); + } + + [Fact] + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Relationship_Body() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource("independents"); + contextGraphBuilder.AddResource("dependents"); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var genericProcessorFactoryMock = new Mock(); + + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + + var property = Guid.NewGuid().ToString(); + var content = new Document + { + Data = new DocumentData + { + Type = "independents", + Id = "1", + Attributes = new Dictionary { + { "property", property } + }, + // a common case for this is deserialization in unit tests + Relationships = new Dictionary { + { "dependent", new RelationshipData { } } + } + } + }; + + var contentString = JsonConvert.SerializeObject(content); + + // act + var result = deserializer.Deserialize(contentString); + + // assert + Assert.NotNull(result); + Assert.Equal(property, result.Property); + } + private class TestResource : Identifiable { [Attr("complex-member")] @@ -215,5 +308,17 @@ private class ComplexType { public string CompoundName { get; set; } } + + private class Independent : Identifiable + { + [Attr("property")] public string Property { get; set; } + [HasOne("dependent")] public Dependent Dependent { get; set; } + } + + private class Dependent : Identifiable + { + [HasOne("independent")] public Independent Independent { get; set; } + public int IndependentId { get; set; } + } } } From 818de068d9231265bafc4242ac34d13a846d75e2 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 20:56:23 -0600 Subject: [PATCH 037/227] chore(csproj): bump package version --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index c3c987f32a..c2a21cb7f1 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.1.9 + 2.1.10 netstandard1.6 JsonApiDotNetCore JsonApiDotNetCore From 4be705ac66328e12d1ccdb5c115bbccbd8b1e339 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Dec 2017 06:56:15 -0600 Subject: [PATCH 038/227] test(*): fix tests broken after aspnet and ef core 2.0 upgrades --- .../Acceptance/Spec/CreatingDataTests.cs | 2 + .../Acceptance/Spec/DocumentTests/Included.cs | 22 +++++--- .../Spec/FetchingRelationshipsTests.cs | 6 ++- .../Acceptance/Spec/PagingTests.cs | 29 +++-------- .../Spec/UpdatingRelationshipsTests.cs | 1 + .../Acceptance/TestFixture.cs | 23 ++++++++- .../Extensions/IQueryableExtensions.cs | 9 ++-- .../TestFixture.cs | 51 ------------------- .../WebHostCollection.cs | 1 + .../appsettings.json | 2 +- 10 files changed, 61 insertions(+), 85 deletions(-) delete mode 100644 test/JsonApiDotNetCoreExampleTests/TestFixture.cs diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs index e011cb8679..2f461c4f74 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs @@ -272,6 +272,8 @@ public async Task Can_Create_And_Set_HasMany_Relationships() var body = await response.Content.ReadAsStringAsync(); var deserializedBody = (TodoItemCollection)_fixture.GetService().Deserialize(body); var newId = deserializedBody.Id; + + context = _fixture.GetService(); var contextCollection = context.TodoItemCollections .Include(c => c.Owner) .Include(c => c.TodoItems) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs index 6ca456d680..5d4a4aa4e2 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -45,8 +46,14 @@ public Included(TestFixture fixture) public async Task GET_Included_Contains_SideloadedData_ForManyToOne() { // arrange - var builder = new WebHostBuilder() - .UseStartup(); + var person = _personFaker.Generate(); + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = person; + _context.TodoItems.RemoveRange(_context.TodoItems); + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var builder = new WebHostBuilder().UseStartup(); var httpMethod = new HttpMethod("GET"); var route = $"/api/v1/todo-items?include=owner"; @@ -57,13 +64,16 @@ public async Task GET_Included_Contains_SideloadedData_ForManyToOne() // act var response = await client.SendAsync(request); - var documents = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - var data = documents.Data[0]; // assert + var json = await response.Content.ReadAsStringAsync(); + var documents = JsonConvert.DeserializeObject(json); + // we only care about counting the todo-items that have owners + var expectedCount = documents.Data.Count(d => d.Relationships["owner"].SingleData != null); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotEmpty(documents.Included); - Assert.Equal(documents.Data.Count, documents.Included.Count); + Assert.Equal(expectedCount, documents.Included.Count); } [Fact] diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs index 51356222ba..ea805c515f 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs @@ -66,7 +66,11 @@ public async Task Request_ForRelationshipLink_ThatDoesNotExist_Returns_404() { // arrange var context = _fixture.GetService(); - var todoItem = context.TodoItems.First(); + + var todoItem = _todoItemFaker.Generate(); + context.TodoItems.Add(todoItem); + await context.SaveChangesAsync(); + var todoItemId = todoItem.Id; context.TodoItems.Remove(todoItem); await context.SaveChangesAsync(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs index ea99cb7d59..02dbd019e0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs @@ -1,33 +1,22 @@ -using System.Collections.Generic; -using System; using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Tasks; using Bogus; -using DotNetCoreDocs; -using DotNetCoreDocs.Models; -using DotNetCoreDocs.Writers; using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample; -using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; -namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec -{ - public class PagingTests : TestFixture - { +namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec { + public class PagingTests : TestFixture { private readonly Faker _todoItemFaker = new Faker() - .RuleFor(t => t.Description, f => f.Lorem.Sentence()) - .RuleFor(t => t.Ordinal, f => f.Random.Number()) - .RuleFor(t => t.CreatedDate, f => f.Date.Past()); + .RuleFor(t => t.Description, f => f.Lorem.Sentence()) + .RuleFor(t => t.Ordinal, f => f.Random.Number()) + .RuleFor(t => t.CreatedDate, f => f.Date.Past()); [Fact] - public async Task Can_Paginate_TodoItems() - { + public async Task Can_Paginate_TodoItems() { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; @@ -56,8 +45,7 @@ public async Task Can_Paginate_TodoItems() } [Fact] - public async Task Can_Paginate_TodoItems_From_Start() - { + public async Task Can_Paginate_TodoItems_From_Start() { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; @@ -91,8 +79,7 @@ public async Task Can_Paginate_TodoItems_From_Start() } [Fact] - public async Task Can_Paginate_TodoItems_From_End() - { + public async Task Can_Paginate_TodoItems_From_End() { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs index d17a10c1d7..5cc3772497 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs @@ -77,6 +77,7 @@ public async Task Can_Update_ToMany_Relationship_ThroughLink() // Act var response = await client.SendAsync(request); + _context = _fixture.GetService(); var personsTodoItems = _context.People.Include(p => p.TodoItems).Single(p => p.Id == person.Id).TodoItems; // Assert diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs index 0379eae91d..d7ec6868b9 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs @@ -5,11 +5,10 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using JsonApiDotNetCore.Services; -using Newtonsoft.Json; namespace JsonApiDotNetCoreExampleTests.Acceptance { - public class TestFixture where TStartup : class + public class TestFixture : IDisposable where TStartup : class { private readonly TestServer _server; private IServiceProvider _services; @@ -33,5 +32,25 @@ public TestFixture() public IJsonApiDeSerializer DeSerializer { get; private set; } public IJsonApiContext JsonApiContext { get; private set; } public T GetService() => (T)_services.GetService(typeof(T)); + + private bool disposedValue = false; + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Client.Dispose(); + _server.Dispose(); + } + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } } } \ No newline at end of file diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/IQueryableExtensions.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/IQueryableExtensions.cs index a40dfb4a5a..c774478227 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/IQueryableExtensions.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/IQueryableExtensions.cs @@ -4,12 +4,12 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Internal; +using Microsoft.EntityFrameworkCore.Storage; using Remotion.Linq.Parsing.Structure; using Database = Microsoft.EntityFrameworkCore.Storage.Database; namespace JsonApiDotNetCoreExampleTests.Helpers.Extensions { - public static class IQueryableExtensions { private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo(); @@ -22,19 +22,22 @@ public static class IQueryableExtensions private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database"); - private static readonly FieldInfo QueryCompilationContextFactoryField = typeof(Database).GetTypeInfo().DeclaredFields.Single(x => x.Name == "_queryCompilationContextFactory"); + private static readonly PropertyInfo DatabaseDependenciesField + = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies"); public static string ToSql(this IQueryable query) where TEntity : class { if (!(query is EntityQueryable) && !(query is InternalDbSet)) + { throw new ArgumentException("Invalid query"); + } var queryCompiler = (IQueryCompiler)QueryCompilerField.GetValue(query.Provider); var nodeTypeProvider = (INodeTypeProvider)NodeTypeProviderField.GetValue(queryCompiler); var parser = (IQueryParser)CreateQueryParserMethod.Invoke(queryCompiler, new object[] { nodeTypeProvider }); var queryModel = parser.GetParsedQuery(query.Expression); var database = DataBaseField.GetValue(queryCompiler); - var queryCompilationContextFactory = (IQueryCompilationContextFactory)QueryCompilationContextFactoryField.GetValue(database); + var queryCompilationContextFactory = ((DatabaseDependencies)DatabaseDependenciesField.GetValue(database)).QueryCompilationContextFactory; var queryCompilationContext = queryCompilationContextFactory.Create(false); var modelVisitor = (RelationalQueryModelVisitor)queryCompilationContext.CreateQueryModelVisitor(); modelVisitor.CreateQueryExecutor(queryModel); diff --git a/test/JsonApiDotNetCoreExampleTests/TestFixture.cs b/test/JsonApiDotNetCoreExampleTests/TestFixture.cs deleted file mode 100644 index 424163f956..0000000000 --- a/test/JsonApiDotNetCoreExampleTests/TestFixture.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; - -namespace JsonApiDotNetCoreExampleTests -{ - public class TestFixture : IDisposable - where TStartup : class - { - private readonly TestServer _server; - private IServiceProvider _services; - - public TestFixture() - { - var builder = new WebHostBuilder() - .UseStartup(); - - _server = new TestServer(builder); - _services = _server.Host.Services; - Client = _server.CreateClient(); - } - - public HttpClient Client { get; set; } - - public T GetService() - { - return (T)_services.GetService(typeof(T)); - } - - private bool disposedValue = false; - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - Client.Dispose(); - _server.Dispose(); - } - - disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } - } -} \ No newline at end of file diff --git a/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs b/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs index 01b3ace217..43a89616df 100644 --- a/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs +++ b/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs @@ -1,4 +1,5 @@ using JsonApiDotNetCoreExample; +using JsonApiDotNetCoreExampleTests.Acceptance; using Xunit; namespace JsonApiDotNetCoreExampleTests diff --git a/test/JsonApiDotNetCoreExampleTests/appsettings.json b/test/JsonApiDotNetCoreExampleTests/appsettings.json index 7067b2bee0..7af3457293 100644 --- a/test/JsonApiDotNetCoreExampleTests/appsettings.json +++ b/test/JsonApiDotNetCoreExampleTests/appsettings.json @@ -6,7 +6,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Debug", + "Default": "Error", "System": "Information", "Microsoft": "Information" } From 1280195139713f5670ac0d60719d7fbf0429cd0a Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Dec 2017 07:10:22 -0600 Subject: [PATCH 039/227] ci(travis): target 2.0.0 sdk --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 234e836e7e..b8a1d74643 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ services: before_script: - psql -c 'create database JsonApiDotNetCoreExample;' -U postgres mono: none -dotnet: 1.0.4 # https://www.microsoft.com/net/download/linux +dotnet: 2.0.3 # https://www.microsoft.com/net/download/linux branches: only: - master From 1e932d3954aeb6f6957e0d91065e0fabf98c3577 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Dec 2017 07:25:04 -0600 Subject: [PATCH 040/227] ci: remove file watching on startup classes System.IO.IOException : The configured user limit (128) on the number of inotify instances has been reached. --- src/Examples/JsonApiDotNetCoreExample/Startup.cs | 2 +- src/Examples/NoEntityFrameworkExample/Startup.cs | 2 +- src/Examples/ReportsExample/Startup.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs index 9683eb033d..1388004a55 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -18,7 +18,7 @@ public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); diff --git a/src/Examples/NoEntityFrameworkExample/Startup.cs b/src/Examples/NoEntityFrameworkExample/Startup.cs index fdea4fc582..81f743aa5f 100755 --- a/src/Examples/NoEntityFrameworkExample/Startup.cs +++ b/src/Examples/NoEntityFrameworkExample/Startup.cs @@ -18,7 +18,7 @@ public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); diff --git a/src/Examples/ReportsExample/Startup.cs b/src/Examples/ReportsExample/Startup.cs index 39d740da84..fed3707789 100644 --- a/src/Examples/ReportsExample/Startup.cs +++ b/src/Examples/ReportsExample/Startup.cs @@ -21,7 +21,7 @@ public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); From bf357fbf2209bf9f819948defb1f550c9ba7455f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Dec 2017 17:25:27 -0600 Subject: [PATCH 041/227] chore(*): fix build warnings and use new Program.cs format --- .../JsonApiDotNetCoreExample.csproj | 4 ++-- .../JsonApiDotNetCoreExample/Program.cs | 18 +++++------------- .../NoEntityFrameworkExample/Program.cs | 14 ++++++-------- src/Examples/ReportsExample/Program.cs | 14 ++++++-------- .../CamelCasedModelsControllerTests.cs | 1 - .../Acceptance/TodoItemsControllerTests.cs | 10 +++++----- 6 files changed, 24 insertions(+), 37 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index e9971a1113..dcbf2a2841 100755 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -1,7 +1,7 @@ - netcoreapp2.0 + $(NetCoreAppVersion) true JsonApiDotNetCoreExample Exe @@ -13,7 +13,7 @@ - + diff --git a/src/Examples/JsonApiDotNetCoreExample/Program.cs b/src/Examples/JsonApiDotNetCoreExample/Program.cs index 16f0ad10a1..e4e3fe355e 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Program.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Program.cs @@ -1,6 +1,5 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; namespace JsonApiDotNetCoreExample { @@ -8,19 +7,12 @@ public class Program { public static void Main(string[] args) { - var config = new ConfigurationBuilder() - .AddCommandLine(args) - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .Build(); + BuildWebHost(args).Run(); + } - var host = new WebHostBuilder() - .UseConfiguration(config) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); - - host.Run(); - } } } diff --git a/src/Examples/NoEntityFrameworkExample/Program.cs b/src/Examples/NoEntityFrameworkExample/Program.cs index 5606e8e9f4..76f3020c52 100755 --- a/src/Examples/NoEntityFrameworkExample/Program.cs +++ b/src/Examples/NoEntityFrameworkExample/Program.cs @@ -1,4 +1,4 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace NoEntityFrameworkExample @@ -7,14 +7,12 @@ public class Program { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); - - host.Run(); - } } } diff --git a/src/Examples/ReportsExample/Program.cs b/src/Examples/ReportsExample/Program.cs index 41d4c37780..f3ce6c81b0 100644 --- a/src/Examples/ReportsExample/Program.cs +++ b/src/Examples/ReportsExample/Program.cs @@ -1,4 +1,4 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace ReportsExample @@ -7,14 +7,12 @@ public class Program { public static void Main(string[] args) { - var host = new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); - - host.Run(); - } } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs index 3cc920544f..b76293adba 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs @@ -35,7 +35,6 @@ public CamelCasedModelsControllerTests(TestFixture fixture) [Fact] public async Task Can_Get_CamelCasedModels() - { // Arrange var model = _faker.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs index 3c4e748966..657e282cb8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs @@ -219,7 +219,7 @@ public async Task Can_Get_TodoItem_ById() Assert.Equal(todoItem.Description, deserializedBody.Description); Assert.Equal(todoItem.Ordinal, deserializedBody.Ordinal); Assert.Equal(todoItem.CreatedDate.ToString("G"), deserializedBody.CreatedDate.ToString("G")); - Assert.Equal(null, deserializedBody.AchievedDate); + Assert.Null(deserializedBody.AchievedDate); } [Fact] @@ -248,7 +248,7 @@ public async Task Can_Get_TodoItem_WithOwner() Assert.Equal(todoItem.Description, deserializedBody.Description); Assert.Equal(todoItem.Ordinal, deserializedBody.Ordinal); Assert.Equal(todoItem.CreatedDate.ToString("G"), deserializedBody.CreatedDate.ToString("G")); - Assert.Equal(null, deserializedBody.AchievedDate); + Assert.Null(deserializedBody.AchievedDate); } [Fact] @@ -301,7 +301,7 @@ public async Task Can_Post_TodoItem() Assert.Equal(HttpStatusCode.Created, response.StatusCode); Assert.Equal(todoItem.Description, deserializedBody.Description); Assert.Equal(todoItem.CreatedDate.ToString("G"), deserializedBody.CreatedDate.ToString("G")); - Assert.Equal(null, deserializedBody.AchievedDate); + Assert.Null(deserializedBody.AchievedDate); } [Fact] @@ -350,7 +350,7 @@ public async Task Can_Patch_TodoItem() Assert.Equal(newTodoItem.Description, deserializedBody.Description); Assert.Equal(newTodoItem.Ordinal, deserializedBody.Ordinal); Assert.Equal(newTodoItem.CreatedDate.ToString("G"), deserializedBody.CreatedDate.ToString("G")); - Assert.Equal(null, deserializedBody.AchievedDate); + Assert.Null(deserializedBody.AchievedDate); } [Fact] @@ -453,7 +453,7 @@ public async Task Can_Patch_TodoItemWithNullValue() Assert.Equal(newTodoItem.Description, deserializedBody.Description); Assert.Equal(newTodoItem.Ordinal, deserializedBody.Ordinal); Assert.Equal(newTodoItem.CreatedDate.ToString("G"), deserializedBody.CreatedDate.ToString("G")); - Assert.Equal(null, deserializedBody.AchievedDate); + Assert.Null(deserializedBody.AchievedDate); } [Fact] From 71a55d4613b36f5333822c0b05d0eee632a08a95 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Thu, 7 Dec 2017 05:32:31 -0600 Subject: [PATCH 042/227] docs(readme): update priorities --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 46d6118fe6..360e13275d 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,8 @@ public class Startup The current priorities for future development (in order): 1. Operations Support ([#150](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/150)) -2. ASP.Net Core 2.0 Support ([#161](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/161)) -3. Minor features ([#105](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/105), [#144](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/144), [#162](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/162)) -4. Resource to Entity Mapping ([#112](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/112)) +2. Minor features ([#105](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/105), [#144](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/144), [#162](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/162)) +3. Resource to Entity Mapping ([#112](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/112)) If you're interested in working on any of the above features, take a look at the [Contributing Guide](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/CONTRIBUTING.MD) or hop on the project Gitter for more direct communication. From 3e2cd155f3495c3ef1be8295bcb6769d2c584c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Thu, 7 Dec 2017 15:10:19 +0100 Subject: [PATCH 043/227] 200: fixed check of element type for IEnumerable --- .../Builders/DocumentBuilder.cs | 7 ++- .../Extensions/TypeExtensions.cs | 35 +++++++++++++++ .../Builders/DocumentBuilder_Tests.cs | 43 +++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/JsonApiDotNetCore/Extensions/TypeExtensions.cs diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index d8d38390d8..ac7e1b3ade 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; @@ -46,9 +47,7 @@ public Document Build(IIdentifiable entity) public Documents Build(IEnumerable entities) { - var entityType = entities - .GetType() - .GenericTypeArguments[0]; + var entityType = entities.GetElementType(); var contextEntity = _contextGraph.GetContextEntity(entityType); @@ -229,7 +228,7 @@ private bool RelationshipIsIncluded(string relationshipName) private List> GetRelationships(IEnumerable entities) { - var objType = entities.GetType().GenericTypeArguments[0]; + var objType = entities.GetElementType(); var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs new file mode 100644 index 0000000000..ccc4619966 --- /dev/null +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace JsonApiDotNetCore.Extensions +{ + internal static class TypeExtensions + { + public static Type GetElementType(this IEnumerable enumerable) + { + var enumerableTypes = enumerable.GetType() + .GetInterfaces() + .Where(t => t.IsGenericType == true && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + .ToList(); + + var numberOfEnumerableTypes = enumerableTypes.Count; + + if (numberOfEnumerableTypes == 0) + { + throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} does not implement a generic variant of {nameof(IEnumerable)}"); + } + + if (numberOfEnumerableTypes > 1) + { + throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} implements more than one generic variant of {nameof(IEnumerable)}:\n" + + $"{string.Join("\n", enumerableTypes.Select(t => t.FullName))}"); + } + + var elementType = enumerableTypes[0].GenericTypeArguments[0]; + + return elementType; + } + } +} diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index cd1227ef52..2cc4e7f7a3 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; @@ -118,6 +119,28 @@ public void Related_Links_Can_Be_Disabled() Assert.Null(document.Data.Relationships["related-model"].Links); } + [Fact] + public void Build_Can_Build_Arrays() + { + var entities = new[] { new Model() }; + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + + var documents = documentBuilder.Build(entities); + + Assert.Equal(1, documents.Data.Count); + } + + [Fact] + public void Build_Can_Build_CustomIEnumerables() + { + var entities = new Models(new[] { new Model() }); + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + + var documents = documentBuilder.Build(entities); + + Assert.Equal(1, documents.Data.Count); + } + private class Model : Identifiable { [HasOne("related-model", Link.None)] @@ -130,5 +153,25 @@ private class RelatedModel : Identifiable [HasMany("models")] public List Models { get; set; } } + + private class Models : IEnumerable + { + private readonly IEnumerable models; + + public Models(IEnumerable models) + { + this.models = models; + } + + public IEnumerator GetEnumerator() + { + return models.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return models.GetEnumerator(); + } + } } } From 52fc5f4bcb39478d656834b93e4babd852f5d7dd Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Mon, 11 Dec 2017 18:02:34 -0600 Subject: [PATCH 044/227] feat(JsonApiController: Expose CQRS constructor Closes #205 --- .../Controllers/JsonApiController.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiController.cs index bea2105482..97350127ba 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiController.cs @@ -16,6 +16,18 @@ public JsonApiController( ILoggerFactory loggerFactory) : base(jsonApiContext, resourceService, loggerFactory) { } + + public JsonApiController( + IJsonApiContext jsonApiContext, + IGetAllService getAll = null, + IGetByIdService getById = null, + IGetRelationshipService getRelationship = null, + IGetRelationshipsService getRelationships = null, + ICreateService create = null, + IUpdateService update = null, + IUpdateRelationshipService updateRelationships = null, + IDeleteService delete = null + ) : base(jsonApiContext, getAll, getById, getRelationship, getRelationships, create, update, updateRelationships, delete) { } } public class JsonApiController @@ -34,6 +46,18 @@ public JsonApiController( : base(jsonApiContext, resourceService) { } + public JsonApiController( + IJsonApiContext jsonApiContext, + IGetAllService getAll = null, + IGetByIdService getById = null, + IGetRelationshipService getRelationship = null, + IGetRelationshipsService getRelationships = null, + ICreateService create = null, + IUpdateService update = null, + IUpdateRelationshipService updateRelationships = null, + IDeleteService delete = null + ) : base(jsonApiContext, getAll, getById, getRelationship, getRelationships, create, update, updateRelationships, delete) { } + [HttpGet] public override async Task GetAsync() => await base.GetAsync(); From ad0ca38a120237c8b2142180c62768a57c78b3a4 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Mon, 11 Dec 2017 18:18:31 -0600 Subject: [PATCH 045/227] docs(readme): fix appveyor link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 360e13275d..1acbbbf799 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # JSON API .Net Core -[![Build status](https://ci.appveyor.com/api/projects/status/9fvgeoxdikwkom10?svg=true)](https://ci.appveyor.com/project/jaredcnance/json-api-dotnet-core) +[![Build status](https://ci.appveyor.com/api/projects/status/9fvgeoxdikwkom10?svg=true)](https://ci.appveyor.com/project/jaredcnance/jsonapidotnetcore) [![Travis](https://travis-ci.org/json-api-dotnet/JsonApiDotNetCore.svg?branch=master)](https://travis-ci.org/json-api-dotnet/JsonApiDotNetCore) [![NuGet](https://img.shields.io/nuget/v/JsonApiDotNetCore.svg)](https://www.nuget.org/packages/JsonApiDotNetCore/) [![MyGet CI](https://img.shields.io/myget/research-institute/vpre/JsonApiDotNetCore.svg)](https://www.myget.org/feed/research-institute/package/nuget/JsonApiDotNetCore) From 192513edc38468a2ecc173e63d86520338d50497 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 21:53:30 -0600 Subject: [PATCH 046/227] feat(*): add benchmarks project and dependencies.props --- .editorconfig | 14 ++ JsonApiDotnetCore.sln | 25 +- benchmarks/Benchmarks/.gitignore | 236 ++++++++++++++++++ ...piDeserializer_Benchmarks-report-github.md | 13 + ....JsonApiDeserializer_Benchmarks-report.csv | 2 + ...JsonApiDeserializer_Benchmarks-report.html | 30 +++ benchmarks/Benchmarks/Benchmarks.csproj | 15 ++ benchmarks/Benchmarks/Program.cs | 10 + .../JsonApiDeserializer_Benchmarks.cs | 59 +++++ build/dependencies.props | 11 + .../JsonApiDotNetCoreExample.csproj | 2 +- .../NoEntityFrameworkExample.csproj | 2 +- .../ReportsExample/ReportsExample.csproj | 48 ++-- .../JsonApiDotNetCore.csproj | 2 + .../JsonApiDotNetCoreExampleTests.csproj | 2 +- .../NoEntityFrameworkTests.csproj | 2 +- .../Serialization/JsonApiDeSerializerTests.cs | 161 +++++------- test/UnitTests/UnitTests.csproj | 3 +- 18 files changed, 512 insertions(+), 125 deletions(-) create mode 100644 .editorconfig create mode 100644 benchmarks/Benchmarks/.gitignore create mode 100755 benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md create mode 100755 benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv create mode 100755 benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html create mode 100644 benchmarks/Benchmarks/Benchmarks.csproj create mode 100644 benchmarks/Benchmarks/Program.cs create mode 100644 benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs create mode 100644 build/dependencies.props diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..134066baff --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8 + +[*.{csproj,props}] +indent_size = 2 diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index a144223671..ef4c03dc49 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -28,6 +28,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{02 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportsExample", "src\Examples\ReportsExample\ReportsExample.csproj", "{FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{076E1AE4-FD25-4684-B826-CAAE37FEA0AA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "benchmarks\Benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,10 +110,22 @@ Global {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Debug|x86.Build.0 = Debug|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.Build.0 = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|x64 + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|x64 + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|x86 + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.ActiveCfg = Debug|x64 + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.Build.0 = Debug|x64 + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.ActiveCfg = Debug|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.Build.0 = Debug|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|Any CPU.Build.0 = Release|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.ActiveCfg = Release|x64 + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.Build.0 = Release|x64 + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.ActiveCfg = Release|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -123,6 +139,7 @@ Global {6D4BD85A-A262-44C6-8572-FE3A30410BF3} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {026FBC6C-AF76-4568-9B87-EC73457899FD} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} + {1F604666-BB0F-413E-922D-9D37C6073285} = {076E1AE4-FD25-4684-B826-CAAE37FEA0AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2421882-8F0A-4905-928F-B550B192F9A4} diff --git a/benchmarks/Benchmarks/.gitignore b/benchmarks/Benchmarks/.gitignore new file mode 100644 index 0000000000..0f552f400b --- /dev/null +++ b/benchmarks/Benchmarks/.gitignore @@ -0,0 +1,236 @@ +_data/ + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md new file mode 100755 index 0000000000..1eacea495f --- /dev/null +++ b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md @@ -0,0 +1,13 @@ +``` ini + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.0.0 + [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + + +``` +| Method | Mean | Error | StdDev | +|------------------------ |---------:|----------:|----------:| +| DeserializeSimpleObject | 27.29 us | 0.5275 us | 0.5863 us | diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv new file mode 100755 index 0000000000..1a8fbe9734 --- /dev/null +++ b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv @@ -0,0 +1,2 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev +DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.29 us,0.5275 us,0.5863 us diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html new file mode 100755 index 0000000000..c7e5ed02a4 --- /dev/null +++ b/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html @@ -0,0 +1,30 @@ + + + + +JsonApiDeserializer_Benchmarks + + + + +

+BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12
+Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4
+.NET Core SDK=2.0.0
+  [Host]     : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
+  DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
+
+
+ + + + + +
MethodMeanErrorStdDev
DeserializeSimpleObject27.29 us0.5275 us0.5863 us
+ + diff --git a/benchmarks/Benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks/Benchmarks.csproj new file mode 100644 index 0000000000..a7a1593823 --- /dev/null +++ b/benchmarks/Benchmarks/Benchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + $(NetCoreAppVersion) + + + + + + + + + + diff --git a/benchmarks/Benchmarks/Program.cs b/benchmarks/Benchmarks/Program.cs new file mode 100644 index 0000000000..be5115f62c --- /dev/null +++ b/benchmarks/Benchmarks/Program.cs @@ -0,0 +1,10 @@ +using BenchmarkDotNet.Running; +using Benchmarks.Serialization; + +namespace Benchmarks { + class Program { + static void Main(string[] args) { + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs b/benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs new file mode 100644 index 0000000000..9303b4d4c1 --- /dev/null +++ b/benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Internal.Generics; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Serialization; +using JsonApiDotNetCore.Services; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Benchmarks.Serialization { + public class JsonApiDeserializer_Benchmarks { + private const string TYPE_NAME = "simple-types"; + private static readonly string Content = JsonConvert.SerializeObject(new Document { + Data = new DocumentData { + Type = TYPE_NAME, + Id = "1", + Attributes = new Dictionary { + { + "name", + Guid.NewGuid().ToString() + } + } + } + }); + + private readonly JsonApiDeSerializer _jsonApiDeSerializer; + + public JsonApiDeserializer_Benchmarks() { + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource(TYPE_NAME); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var genericProcessorFactoryMock = new Mock(); + + _jsonApiDeSerializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + } + + [Benchmark] + public object DeserializeSimpleObject() => _jsonApiDeSerializer.Deserialize(Content); + + private class SimpleType : Identifiable { + [Attr("name")] + public string Name { get; set; } + } + } +} diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..d4686bba2e --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,11 @@ + + + netcoreapp1.1 + netstandard1.6 + + + 4.7.10 + 2.2.0 + 8.0.1-beta-1 + + diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index dcbf2a2841..a2981cffd1 100755 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -1,5 +1,5 @@ - + $(NetCoreAppVersion) true diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj index afaf0e7cff..32506808fe 100755 --- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj +++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj @@ -1,5 +1,5 @@  - + $(NetCoreAppVersion) diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj index 2131c545a4..f8f83e454c 100644 --- a/src/Examples/ReportsExample/ReportsExample.csproj +++ b/src/Examples/ReportsExample/ReportsExample.csproj @@ -1,24 +1,24 @@ - - - - $(NetCoreAppVersion) - - - - - - - - - - - - - - - - - - - - + + + + $(NetCoreAppVersion) + + + + + + + + + + + + + + + + + + + + diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 9ebddb4512..53c81b2ec1 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,4 +1,5 @@  + 2.2.0 $(NetStandardVersion) @@ -20,4 +21,5 @@ + diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj index b22953dc23..1b40e2dd73 100755 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -1,5 +1,5 @@  - + $(NetCoreAppVersion) true diff --git a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj index 8daa7dc9af..5553a7c1eb 100644 --- a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +++ b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj @@ -1,5 +1,5 @@  - + $(NetCoreAppVersion) true diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index eeefa4d857..5096cbac31 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -11,13 +11,10 @@ using Newtonsoft.Json.Serialization; using Xunit; -namespace UnitTests.Serialization -{ - public class JsonApiDeSerializerTests - { +namespace UnitTests.Serialization { + public class JsonApiDeSerializerTests { [Fact] - public void Can_Deserialize_Complex_Types() - { + public void Can_Deserialize_Complex_Types() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -36,17 +33,16 @@ public void Can_Deserialize_Complex_Types() var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - var content = new Document - { - Data = new DocumentData + var content = new Document { + Data = new DocumentData { + Type = "test-resource", + Id = "1", + Attributes = new Dictionary { { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { - { - "complex-member", new { compoundName = "testName" } - } - } + "complex-member", + new { compoundName = "testName" } + } + } } }; @@ -59,8 +55,7 @@ public void Can_Deserialize_Complex_Types() } [Fact] - public void Can_Deserialize_Complex_List_Types() - { + public void Can_Deserialize_Complex_List_Types() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -78,19 +73,18 @@ public void Can_Deserialize_Complex_List_Types() var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - var content = new Document - { - Data = new DocumentData + var content = new Document { + Data = new DocumentData { + Type = "test-resource", + Id = "1", + Attributes = new Dictionary { { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { - { - "complex-members", new [] { - new { compoundName = "testName" } - } - } - } + "complex-members", + new [] { + new { compoundName = "testName" } + } + } + } } }; @@ -104,8 +98,7 @@ public void Can_Deserialize_Complex_List_Types() } [Fact] - public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() - { + public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -124,17 +117,16 @@ public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - var content = new Document - { - Data = new DocumentData + var content = new Document { + Data = new DocumentData { + Type = "test-resource", + Id = "1", + Attributes = new Dictionary { { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { - { - "complex-member", new Dictionary { { "compound-name", "testName" } } - } - } + "complex-member", + new Dictionary { { "compound-name", "testName" } } + } + } } }; @@ -147,8 +139,7 @@ public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() } [Fact] - public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() - { + public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -169,18 +160,18 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - var content = new Document - { - Data = new DocumentData + var content = new Document { + Data = new DocumentData { + Type = "test-resource", + Id = "1", + Attributes = new Dictionary { { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { - { "complex-member", new Dictionary { - { "compound-name", "testName" } } - }, - { "immutable", "value"} - } + "complex-member", + new Dictionary { { "compound-name", "testName" } + } + }, + { "immutable", "value" } + } } }; @@ -198,8 +189,7 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() } [Fact] - public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() - { + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("independents"); @@ -219,15 +209,12 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); var property = Guid.NewGuid().ToString(); - var content = new Document - { - Data = new DocumentData - { - Type = "independents", - Id = "1", - Attributes = new Dictionary { - { "property", property } - } + var content = new Document { + Data = new DocumentData { + Type = "independents", + Id = "1", + Attributes = new Dictionary { { "property", property } + } } }; @@ -242,8 +229,7 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() } [Fact] - public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Relationship_Body() - { + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Relationship_Body() { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("independents"); @@ -263,19 +249,15 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Rel var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); var property = Guid.NewGuid().ToString(); - var content = new Document - { - Data = new DocumentData - { - Type = "independents", - Id = "1", - Attributes = new Dictionary { - { "property", property } - }, - // a common case for this is deserialization in unit tests - Relationships = new Dictionary { - { "dependent", new RelationshipData { } } - } + var content = new Document { + Data = new DocumentData { + Type = "independents", + Id = "1", + Attributes = new Dictionary { { "property", property } + }, + // a common case for this is deserialization in unit tests + Relationships = new Dictionary { { "dependent", new RelationshipData { } } + } } }; @@ -289,34 +271,29 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Rel Assert.Equal(property, result.Property); } - private class TestResource : Identifiable - { + private class TestResource : Identifiable { [Attr("complex-member")] public ComplexType ComplexMember { get; set; } - [Attr("immutable", isImmutable: true)] + [Attr("immutable", isImmutable : true)] public string Immutable { get; set; } } - private class TestResourceWithList : Identifiable - { + private class TestResourceWithList : Identifiable { [Attr("complex-members")] public List ComplexMembers { get; set; } } - private class ComplexType - { + private class ComplexType { public string CompoundName { get; set; } } - private class Independent : Identifiable - { + private class Independent : Identifiable { [Attr("property")] public string Property { get; set; } [HasOne("dependent")] public Dependent Dependent { get; set; } } - private class Dependent : Identifiable - { + private class Dependent : Identifiable { [HasOne("independent")] public Independent Independent { get; set; } public int IndependentId { get; set; } } diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index dcd659d2df..4848455eac 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -1,4 +1,5 @@ + $(NetCoreAppVersion) false @@ -13,4 +14,4 @@ - \ No newline at end of file + From c9b6c11d3dad6aa3e3bc2abc6f87bd4ebd43c30f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 21:58:07 -0600 Subject: [PATCH 047/227] chore(benchmarks): remove parent dir --- JsonApiDotnetCore.sln | 2 +- benchmarks/{Benchmarks => }/.gitignore | 0 ...ialization.JsonApiDeserializer_Benchmarks-report-github.md | 0 ...ks.Serialization.JsonApiDeserializer_Benchmarks-report.csv | 0 ...s.Serialization.JsonApiDeserializer_Benchmarks-report.html | 0 benchmarks/{Benchmarks => }/Benchmarks.csproj | 4 ++-- benchmarks/{Benchmarks => }/Program.cs | 0 .../Serialization/JsonApiDeserializer_Benchmarks.cs | 0 8 files changed, 3 insertions(+), 3 deletions(-) rename benchmarks/{Benchmarks => }/.gitignore (100%) rename benchmarks/{Benchmarks => }/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md (100%) rename benchmarks/{Benchmarks => }/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv (100%) rename benchmarks/{Benchmarks => }/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html (100%) rename benchmarks/{Benchmarks => }/Benchmarks.csproj (75%) rename benchmarks/{Benchmarks => }/Program.cs (100%) rename benchmarks/{Benchmarks => }/Serialization/JsonApiDeserializer_Benchmarks.cs (100%) diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index ef4c03dc49..385fa4d6ad 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -30,7 +30,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportsExample", "src\Examp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{076E1AE4-FD25-4684-B826-CAAE37FEA0AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "benchmarks\Benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/benchmarks/Benchmarks/.gitignore b/benchmarks/.gitignore similarity index 100% rename from benchmarks/Benchmarks/.gitignore rename to benchmarks/.gitignore diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md similarity index 100% rename from benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md rename to benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv similarity index 100% rename from benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv rename to benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv diff --git a/benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html similarity index 100% rename from benchmarks/Benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html rename to benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html diff --git a/benchmarks/Benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj similarity index 75% rename from benchmarks/Benchmarks/Benchmarks.csproj rename to benchmarks/Benchmarks.csproj index a7a1593823..107fd008c2 100644 --- a/benchmarks/Benchmarks/Benchmarks.csproj +++ b/benchmarks/Benchmarks.csproj @@ -1,5 +1,5 @@ - + Exe $(NetCoreAppVersion) @@ -10,6 +10,6 @@ - + diff --git a/benchmarks/Benchmarks/Program.cs b/benchmarks/Program.cs similarity index 100% rename from benchmarks/Benchmarks/Program.cs rename to benchmarks/Program.cs diff --git a/benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs similarity index 100% rename from benchmarks/Benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs rename to benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs From 53ad46f4b1e998124aefaa921076f77b816f0aec Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 22:07:25 -0600 Subject: [PATCH 048/227] bench(serializer): test simple object serialization --- ...piDeserializer_Benchmarks-report-github.md | 2 +- ....JsonApiDeserializer_Benchmarks-report.csv | 2 +- ...JsonApiDeserializer_Benchmarks-report.html | 2 +- ...nApiSerializer_Benchmarks-report-github.md | 13 +++++ ...on.JsonApiSerializer_Benchmarks-report.csv | 2 + ...n.JsonApiSerializer_Benchmarks-report.html | 30 ++++++++++++ benchmarks/Program.cs | 3 +- .../JsonApiSerializer_Benchmarks.cs | 49 +++++++++++++++++++ 8 files changed, 99 insertions(+), 4 deletions(-) create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html create mode 100644 benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md index 1eacea495f..2004bb0243 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 27.29 us | 0.5275 us | 0.5863 us | +| DeserializeSimpleObject | 27.34 us | 0.5458 us | 0.7472 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv index 1a8fbe9734..230be6418f 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv @@ -1,2 +1,2 @@ Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev -DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.29 us,0.5275 us,0.5863 us +DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.34 us,0.5458 us,0.7472 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html index c7e5ed02a4..e1906ca4e0 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html @@ -24,7 +24,7 @@ - +
MethodMeanErrorStdDev
DeserializeSimpleObject27.29 us0.5275 us0.5863 us
DeserializeSimpleObject27.34 us0.5458 us0.7472 us
diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md new file mode 100755 index 0000000000..66104fb0a2 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md @@ -0,0 +1,13 @@ +``` ini + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.0.0 + [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + + +``` +| Method | Mean | Error | StdDev | +|------------------------ |---------:|----------:|----------:| +| DeserializeSimpleObject | 6.940 us | 0.1364 us | 0.1675 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv new file mode 100755 index 0000000000..d49d1e3e51 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv @@ -0,0 +1,2 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev +DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,6.940 us,0.1364 us,0.1675 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html new file mode 100755 index 0000000000..0f84d09546 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html @@ -0,0 +1,30 @@ + + + + +JsonApiSerializer_Benchmarks + + + + +

+BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12
+Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4
+.NET Core SDK=2.0.0
+  [Host]     : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
+  DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
+
+
+ + + + + +
MethodMeanErrorStdDev
DeserializeSimpleObject6.940 us0.1364 us0.1675 us
+ + diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index be5115f62c..2e552496c9 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -4,7 +4,8 @@ namespace Benchmarks { class Program { static void Main(string[] args) { - var summary = BenchmarkRunner.Run(); + BenchmarkRunner.Run(); + BenchmarkRunner.Run(); } } } diff --git a/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs new file mode 100644 index 0000000000..0c87a3edfb --- /dev/null +++ b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Internal.Generics; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Serialization; +using JsonApiDotNetCore.Services; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Benchmarks.Serialization { + public class JsonApiSerializer_Benchmarks { + private const string TYPE_NAME = "simple-types"; + private static readonly SimpleType Content = new SimpleType(); + + private readonly JsonApiSerializer _jsonApiSerializer; + + public JsonApiSerializer_Benchmarks() { + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource(TYPE_NAME); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var genericProcessorFactoryMock = new Mock(); + + var documentBuilder = new DocumentBuilder(jsonApiContextMock.Object); + _jsonApiSerializer = new JsonApiSerializer(jsonApiContextMock.Object, documentBuilder); + } + + [Benchmark] + public object DeserializeSimpleObject() => _jsonApiSerializer.Serialize(Content); + + private class SimpleType : Identifiable { + [Attr("name")] + public string Name { get; set; } + } + } +} From 45dcb1258761f210d1fd14c8c0b623373319b3c4 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 14 Nov 2017 22:16:50 -0600 Subject: [PATCH 049/227] perf(*): only keep markdown benchmarks --- ...n.JsonApiDeserializer_Benchmarks-report-default.md | 11 +++++++++++ ...on.JsonApiDeserializer_Benchmarks-report-github.md | 2 +- ...lization.JsonApiDeserializer_Benchmarks-report.csv | 2 +- ...ization.JsonApiDeserializer_Benchmarks-report.html | 2 +- ...ion.JsonApiSerializer_Benchmarks-report-default.md | 11 +++++++++++ ...tion.JsonApiSerializer_Benchmarks-report-github.md | 2 +- ...ialization.JsonApiSerializer_Benchmarks-report.csv | 2 +- ...alization.JsonApiSerializer_Benchmarks-report.html | 2 +- .../Serialization/JsonApiDeserializer_Benchmarks.cs | 2 ++ .../Serialization/JsonApiSerializer_Benchmarks.cs | 4 ++-- 10 files changed, 32 insertions(+), 8 deletions(-) create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md new file mode 100755 index 0000000000..489c6588bf --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md @@ -0,0 +1,11 @@ + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.0.0 + [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + + + Method | Mean | Error | StdDev | +------------------------ |---------:|----------:|----------:| + DeserializeSimpleObject | 27.79 us | 0.5299 us | 0.4956 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md index 2004bb0243..e87cadc3a7 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 27.34 us | 0.5458 us | 0.7472 us | +| DeserializeSimpleObject | 27.79 us | 0.5299 us | 0.4956 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv index 230be6418f..80fffa3d41 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv @@ -1,2 +1,2 @@ Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev -DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.34 us,0.5458 us,0.7472 us +DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.79 us,0.5299 us,0.4956 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html index e1906ca4e0..deb436dab9 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html @@ -24,7 +24,7 @@ - +
MethodMeanErrorStdDev
DeserializeSimpleObject27.34 us0.5458 us0.7472 us
DeserializeSimpleObject27.79 us0.5299 us0.4956 us
diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md new file mode 100755 index 0000000000..6e486a91d3 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md @@ -0,0 +1,11 @@ + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.0.0 + [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + + + Method | Mean | Error | StdDev | +------------------------ |---------:|----------:|----------:| + DeserializeSimpleObject | 7.032 us | 0.1101 us | 0.1030 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md index 66104fb0a2..e63c564dca 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 6.940 us | 0.1364 us | 0.1675 us | +| DeserializeSimpleObject | 7.032 us | 0.1101 us | 0.1030 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv index d49d1e3e51..3279dabd04 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv @@ -1,2 +1,2 @@ Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev -DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,6.940 us,0.1364 us,0.1675 us +DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,7.032 us,0.1101 us,0.1030 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html index 0f84d09546..642ee73032 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html @@ -24,7 +24,7 @@ - +
MethodMeanErrorStdDev
DeserializeSimpleObject6.940 us0.1364 us0.1675 us
DeserializeSimpleObject7.032 us0.1101 us0.1030 us
diff --git a/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs index 9303b4d4c1..c490bee362 100644 --- a/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs +++ b/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal.Generics; @@ -12,6 +13,7 @@ using Newtonsoft.Json.Serialization; namespace Benchmarks.Serialization { + [MarkdownExporter] public class JsonApiDeserializer_Benchmarks { private const string TYPE_NAME = "simple-types"; private static readonly string Content = JsonConvert.SerializeObject(new Document { diff --git a/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs index 0c87a3edfb..e5de3cae79 100644 --- a/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs +++ b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs @@ -1,6 +1,6 @@ -using System; using System.Collections.Generic; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal.Generics; @@ -8,10 +8,10 @@ using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using Moq; -using Newtonsoft.Json; using Newtonsoft.Json.Serialization; namespace Benchmarks.Serialization { + [MarkdownExporter] public class JsonApiSerializer_Benchmarks { private const string TYPE_NAME = "simple-types"; private static readonly SimpleType Content = new SimpleType(); From 4748e1620a9b59824e6638988d7ed3653ba577f5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 11:13:32 -0600 Subject: [PATCH 050/227] bench(QueryParser): add sort benchmarks --- benchmarks/.gitignore | 3 ++ ...ry.QueryParser_Benchmarks-report-github.md | 15 ++++++ benchmarks/Benchmarks.csproj | 1 + benchmarks/Program.cs | 2 + benchmarks/Query/QueryParser_Benchmarks.cs | 48 +++++++++++++++++++ 5 files changed, 69 insertions(+) create mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md create mode 100644 benchmarks/Query/QueryParser_Benchmarks.cs diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore index 0f552f400b..5a3c72cbbb 100644 --- a/benchmarks/.gitignore +++ b/benchmarks/.gitignore @@ -1,4 +1,7 @@ _data/ +*-report-default.md +*-report.csv +*-report.html ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md new file mode 100755 index 0000000000..97fea375d6 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md @@ -0,0 +1,15 @@ +``` ini + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.0.0 + [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + Job-HURVUO : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + +LaunchCount=3 TargetCount=20 WarmupCount=10 + +``` +| Method | Mean | Error | StdDev | +|--------------- |---------:|----------:|----------:| +| AscendingSort | 3.146 us | 0.0326 us | 0.0709 us | +| DescendingSort | 3.372 us | 0.1228 us | 0.2618 us | diff --git a/benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj index 107fd008c2..b5ff121826 100644 --- a/benchmarks/Benchmarks.csproj +++ b/benchmarks/Benchmarks.csproj @@ -3,6 +3,7 @@ Exe $(NetCoreAppVersion) + Benchmarks diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index 2e552496c9..da4eaa2b50 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Running; +using Benchmarks.Query; using Benchmarks.Serialization; namespace Benchmarks { @@ -6,6 +7,7 @@ class Program { static void Main(string[] args) { BenchmarkRunner.Run(); BenchmarkRunner.Run(); + BenchmarkRunner.Run(); } } } diff --git a/benchmarks/Query/QueryParser_Benchmarks.cs b/benchmarks/Query/QueryParser_Benchmarks.cs new file mode 100644 index 0000000000..0edaee6cb5 --- /dev/null +++ b/benchmarks/Query/QueryParser_Benchmarks.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; +using BenchmarkDotNet.Attributes.Jobs; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Services; +using Moq; + +namespace Benchmarks.Query { + [MarkdownExporter, SimpleJob(launchCount : 3, warmupCount : 10, targetCount : 20)] + public class QueryParser_Benchmarks { + private readonly BenchmarkFacade _queryParser; + + private const string ATTRIBUTE = "Attribute"; + private const string ASCENDING_SORT = ATTRIBUTE; + private const string DESCENDING_SORT = "-" + ATTRIBUTE; + + public QueryParser_Benchmarks() { + var controllerContextMock = new Mock(); + controllerContextMock.Setup(m => m.RequestEntity).Returns(new ContextEntity { + Attributes = new List { + new AttrAttribute(ATTRIBUTE) { + InternalAttributeName = ATTRIBUTE + } + } + }); + var options = new JsonApiOptions(); + _queryParser = new BenchmarkFacade(controllerContextMock.Object, options); + } + + [Benchmark] + public void AscendingSort() => _queryParser._ParseSortParameters(ASCENDING_SORT); + + [Benchmark] + public void DescendingSort() => _queryParser._ParseSortParameters(DESCENDING_SORT); + + // this facade allows us to expose and micro-benchmark protected methods + private class BenchmarkFacade : QueryParser { + public BenchmarkFacade( + IControllerContext controllerContext, + JsonApiOptions options) : base(controllerContext, options) { } + + public void _ParseSortParameters(string value) => base.ParseSortParameters(value); + } + } +} From 78274c3c21b117f9c59b34ac659c2d2ecc1e04e6 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 11:16:57 -0600 Subject: [PATCH 051/227] perf(QueryParser): improve sort parsing perf AscendingSort: 30.9% improvement DescendingSort: 20% improvement BEFORE Method | Mean | Error | StdDev| --------------- |---------:|----------:|----------:| AscendingSort | 4.558 us | 0.2451 us | 0.6832 us | DescendingSort | 4.218 us | 0.1780 us | 0.4990 us | AFTER Method | Mean | Error | StdDev | --------------- |---------:|----------:|----------:| AscendingSort | 3.146 us | 0.0326 us | 0.0709 us | DescendingSort | 3.372 us | 0.1228 us | 0.2618 us | --- src/JsonApiDotNetCore/Services/QueryParser.cs | 102 ++++++++---------- 1 file changed, 44 insertions(+), 58 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 297eb246a0..46f7a4e68a 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -9,63 +9,52 @@ using JsonApiDotNetCore.Models; using Microsoft.AspNetCore.Http; -namespace JsonApiDotNetCore.Services -{ - public interface IQueryParser - { +namespace JsonApiDotNetCore.Services { + public interface IQueryParser { QuerySet Parse(IQueryCollection query); } - public class QueryParser : IQueryParser - { + public class QueryParser : IQueryParser { private readonly IControllerContext _controllerContext; private readonly JsonApiOptions _options; public QueryParser( IControllerContext controllerContext, - JsonApiOptions options) - { + JsonApiOptions options) { _controllerContext = controllerContext; _options = options; } - public virtual QuerySet Parse(IQueryCollection query) - { + public virtual QuerySet Parse(IQueryCollection query) { var querySet = new QuerySet(); - var disabledQueries = _controllerContext.GetControllerAttribute()?.QueryParams ?? QueryParams.None; + var disabledQueries = _controllerContext.GetControllerAttribute() ? .QueryParams ?? QueryParams.None; - foreach (var pair in query) - { - if (pair.Key.StartsWith("filter")) - { + foreach (var pair in query) { + if (pair.Key.StartsWith("filter")) { if (disabledQueries.HasFlag(QueryParams.Filter) == false) querySet.Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); continue; } - if (pair.Key.StartsWith("sort")) - { + if (pair.Key.StartsWith("sort")) { if (disabledQueries.HasFlag(QueryParams.Sort) == false) querySet.SortParameters = ParseSortParameters(pair.Value); continue; } - if (pair.Key.StartsWith("include")) - { + if (pair.Key.StartsWith("include")) { if (disabledQueries.HasFlag(QueryParams.Include) == false) querySet.IncludedRelationships = ParseIncludedRelationships(pair.Value); continue; } - if (pair.Key.StartsWith("page")) - { + if (pair.Key.StartsWith("page")) { if (disabledQueries.HasFlag(QueryParams.Page) == false) querySet.PageQuery = ParsePageQuery(querySet.PageQuery, pair.Key, pair.Value); continue; } - if (pair.Key.StartsWith("fields")) - { + if (pair.Key.StartsWith("fields")) { if (disabledQueries.HasFlag(QueryParams.Fields) == false) querySet.Fields = ParseFieldsQuery(pair.Key, pair.Value); continue; @@ -78,26 +67,24 @@ public virtual QuerySet Parse(IQueryCollection query) return querySet; } - protected virtual List ParseFilterQuery(string key, string value) - { + protected virtual List ParseFilterQuery(string key, string value) { // expected input = filter[id]=1 // expected input = filter[id]=eq:1 var queries = new List(); - var propertyName = key.Split('[', ']')[1].ToProperCase(); + var propertyName = key.Split('[', ']') [1].ToProperCase(); var values = value.Split(','); - foreach (var val in values) - { - (var operation, var filterValue) = ParseFilterOperation(val); + foreach (var val in values) { + (var operation, + var filterValue) = ParseFilterOperation(val); queries.Add(new FilterQuery(propertyName, filterValue, operation)); } return queries; } - protected virtual (string operation, string value) ParseFilterOperation(string value) - { + protected virtual(string operation, string value) ParseFilterOperation(string value) { if (value.Length < 3) return (string.Empty, value); @@ -116,13 +103,12 @@ protected virtual (string operation, string value) ParseFilterOperation(string v return (prefix, value); } - protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) - { + protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) { // expected input = page[size]=10 // page[number]=1 pageQuery = pageQuery ?? new PageQuery(); - var propertyName = key.Split('[', ']')[1]; + var propertyName = key.Split('[', ']') [1]; if (propertyName == "size") pageQuery.PageSize = Convert.ToInt32(value); @@ -134,28 +120,31 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri // sort=id,name // sort=-id - protected virtual List ParseSortParameters(string value) - { + protected virtual List ParseSortParameters(string value) { + const char SORT_DELIMITER = ','; + const char DESCENDING_SORT_OPERATOR = '-'; + var sortParameters = new List(); - value.Split(',').ToList().ForEach(p => - { + var sortSegments = value.Split(SORT_DELIMITER); + foreach (var sortSegment in sortSegments) { + + var propertyName = sortSegment; var direction = SortDirection.Ascending; - if (p[0] == '-') - { + + if (sortSegment[0] == DESCENDING_SORT_OPERATOR) { direction = SortDirection.Descending; - p = p.Substring(1); + propertyName = propertyName.Substring(1); } - var attribute = GetAttribute(p.ToProperCase()); + var attribute = GetAttribute(propertyName); sortParameters.Add(new SortQuery(direction, attribute)); - }); + }; return sortParameters; } - protected virtual List ParseIncludedRelationships(string value) - { + protected virtual List ParseIncludedRelationships(string value) { if (value.Contains(".")) throw new JsonApiException(400, "Deeply nested relationships are not supported"); @@ -164,10 +153,9 @@ protected virtual List ParseIncludedRelationships(string value) .ToList(); } - protected virtual List ParseFieldsQuery(string key, string value) - { + protected virtual List ParseFieldsQuery(string key, string value) { // expected: fields[TYPE]=prop1,prop2 - var typeName = key.Split('[', ']')[1]; + var typeName = key.Split('[', ']') [1]; var includedFields = new List { "Id" }; @@ -175,8 +163,7 @@ protected virtual List ParseFieldsQuery(string key, string value) return includedFields; var fields = value.Split(','); - foreach (var field in fields) - { + foreach (var field in fields) { var internalAttrName = _controllerContext.RequestEntity .Attributes .SingleOrDefault(attr => attr.PublicAttributeName == field) @@ -187,12 +174,11 @@ protected virtual List ParseFieldsQuery(string key, string value) return includedFields; } - protected virtual AttrAttribute GetAttribute(string propertyName) - => _controllerContext - .RequestEntity - .Attributes - .FirstOrDefault(attr => - string.Equals(attr.InternalAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) - ); + protected virtual AttrAttribute GetAttribute(string propertyName) => _controllerContext + .RequestEntity + .Attributes + .FirstOrDefault(attr => + string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) + ); } -} \ No newline at end of file +} From 8d29d7e1467860a94bc9c3b1758e7060bf0336d0 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 11:30:47 -0600 Subject: [PATCH 052/227] chore(benchmark-results): cleanup results --- ...ry.QueryParser_Benchmarks-report-github.md | 6 ++-- ...iDeserializer_Benchmarks-report-default.md | 11 ------- ...piDeserializer_Benchmarks-report-github.md | 2 +- ....JsonApiDeserializer_Benchmarks-report.csv | 2 -- ...JsonApiDeserializer_Benchmarks-report.html | 30 ------------------- ...ApiSerializer_Benchmarks-report-default.md | 11 ------- ...nApiSerializer_Benchmarks-report-github.md | 2 +- ...on.JsonApiSerializer_Benchmarks-report.csv | 2 -- ...n.JsonApiSerializer_Benchmarks-report.html | 30 ------------------- .../JsonApiSerializer_Benchmarks.cs | 2 +- 10 files changed, 6 insertions(+), 92 deletions(-) delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv delete mode 100755 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md index 97fea375d6..324281fa40 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md @@ -4,12 +4,12 @@ BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 .NET Core SDK=2.0.0 [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - Job-HURVUO : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + Job-ROPOBW : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT LaunchCount=3 TargetCount=20 WarmupCount=10 ``` | Method | Mean | Error | StdDev | |--------------- |---------:|----------:|----------:| -| AscendingSort | 3.146 us | 0.0326 us | 0.0709 us | -| DescendingSort | 3.372 us | 0.1228 us | 0.2618 us | +| AscendingSort | 3.101 us | 0.0298 us | 0.0636 us | +| DescendingSort | 3.195 us | 0.0297 us | 0.0632 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md deleted file mode 100755 index 489c6588bf..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-default.md +++ /dev/null @@ -1,11 +0,0 @@ - -BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 -Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 -.NET Core SDK=2.0.0 - [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - - - Method | Mean | Error | StdDev | ------------------------- |---------:|----------:|----------:| - DeserializeSimpleObject | 27.79 us | 0.5299 us | 0.4956 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md index e87cadc3a7..d8571f9644 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 27.79 us | 0.5299 us | 0.4956 us | +| DeserializeSimpleObject | 26.37 us | 0.4458 us | 0.4170 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv deleted file mode 100755 index 80fffa3d41..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.csv +++ /dev/null @@ -1,2 +0,0 @@ -Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev -DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,27.79 us,0.5299 us,0.4956 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html deleted file mode 100755 index deb436dab9..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - -JsonApiDeserializer_Benchmarks - - - - -

-BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12
-Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4
-.NET Core SDK=2.0.0
-  [Host]     : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
-  DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
-
-
- - - - - -
MethodMeanErrorStdDev
DeserializeSimpleObject27.79 us0.5299 us0.4956 us
- - diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md deleted file mode 100755 index 6e486a91d3..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-default.md +++ /dev/null @@ -1,11 +0,0 @@ - -BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 -Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 -.NET Core SDK=2.0.0 - [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - - - Method | Mean | Error | StdDev | ------------------------- |---------:|----------:|----------:| - DeserializeSimpleObject | 7.032 us | 0.1101 us | 0.1030 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md index e63c564dca..4671d6b3af 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 7.032 us | 0.1101 us | 0.1030 us | +| DeserializeSimpleObject | 7.135 us | 0.1401 us | 0.1439 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv deleted file mode 100755 index 3279dabd04..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.csv +++ /dev/null @@ -1,2 +0,0 @@ -Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,RemoveOutliers,Affinity,Jit,Platform,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,EnvironmentVariables,Toolchain,InvocationCount,IterationTime,LaunchCount,RunStrategy,TargetCount,UnrollFactor,WarmupCount,Mean,Error,StdDev -DeserializeSimpleObject,Default,False,Default,Default,Default,Default,Default,Default,0,RyuJit,X64,Core,False,True,False,True,False,False,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,16,Default,7.032 us,0.1101 us,0.1030 us diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html deleted file mode 100755 index 642ee73032..0000000000 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - -JsonApiSerializer_Benchmarks - - - - -

-BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12
-Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4
-.NET Core SDK=2.0.0
-  [Host]     : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
-  DefaultJob : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT
-
-
- - - - - -
MethodMeanErrorStdDev
DeserializeSimpleObject7.032 us0.1101 us0.1030 us
- - diff --git a/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs index e5de3cae79..3d5ef7c001 100644 --- a/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs +++ b/benchmarks/Serialization/JsonApiSerializer_Benchmarks.cs @@ -39,7 +39,7 @@ public JsonApiSerializer_Benchmarks() { } [Benchmark] - public object DeserializeSimpleObject() => _jsonApiSerializer.Serialize(Content); + public object SerializeSimpleObject() => _jsonApiSerializer.Serialize(Content); private class SimpleType : Identifiable { [Attr("name")] From 15a9830f9e0cc9ea51b0051441457bc8a77047e5 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 15:40:04 -0600 Subject: [PATCH 053/227] feat(FilterQuery / QueryAccessor): use public attribute names for keys Closes #197 --- .../Internal/Query/AttrFilterQuery.cs | 20 ++++++++-------- .../Internal/Query/FilterQuery.cs | 14 +++++++---- .../Services/QueryAccessor.cs | 23 +++++++++++++++---- src/JsonApiDotNetCore/Services/QueryParser.cs | 4 +++- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index 8af2fe95e1..74db2b342e 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; @@ -9,14 +10,14 @@ public class AttrFilterQuery : BaseFilterQuery private readonly IJsonApiContext _jsonApiContext; public AttrFilterQuery( - IJsonApiContext jsonApiCopntext, + IJsonApiContext jsonApiContext, FilterQuery filterQuery) { - _jsonApiContext = jsonApiCopntext; + _jsonApiContext = jsonApiContext; - var attribute = GetAttribute(filterQuery.Key); + var attribute = GetAttribute(filterQuery.Attribute); - FilteredAttribute = attribute ?? throw new JsonApiException(400, $"{filterQuery.Key} is not a valid property."); + FilteredAttribute = attribute ?? throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); PropertyValue = filterQuery.Value; FilterOperation = GetFilterOperation(filterQuery.Operation); } @@ -25,12 +26,9 @@ public AttrFilterQuery( public string PropertyValue { get; set; } public FilterOperations FilterOperation { get; set; } - private AttrAttribute GetAttribute(string propertyName) - { - return _jsonApiContext.RequestEntity.Attributes - .FirstOrDefault(attr => - attr.InternalAttributeName.ToLower() == propertyName.ToLower() + private AttrAttribute GetAttribute(string attribute) => + _jsonApiContext.RequestEntity.Attributes.FirstOrDefault( + attr => string.Equals(attr.PublicAttributeName, attribute, StringComparison.OrdinalIgnoreCase) ); - } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs index 7f4f1a40c6..dd72e827ff 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs @@ -1,17 +1,23 @@ +using System; +using JsonApiDotNetCore.Extensions; + namespace JsonApiDotNetCore.Internal.Query { public class FilterQuery { - public FilterQuery(string key, string value, string operation) + public FilterQuery(string attribute, string value, string operation) { - Key = key; + Attribute = attribute; + Key = attribute.ToProperCase(); Value = value; Operation = operation; } + [Obsolete("Key has been replaced by '" + nameof(Attribute) + "'. Members should be located by their public name, not by coercing the provided value to the internal name.")] public string Key { get; set; } + public string Attribute { get; } public string Value { get; set; } public string Operation { get; set; } - public bool IsAttributeOfRelationship => Key.Contains("."); + public bool IsAttributeOfRelationship => Attribute.Contains("."); } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Services/QueryAccessor.cs b/src/JsonApiDotNetCore/Services/QueryAccessor.cs index 09942d4031..63b91ed239 100644 --- a/src/JsonApiDotNetCore/Services/QueryAccessor.cs +++ b/src/JsonApiDotNetCore/Services/QueryAccessor.cs @@ -61,9 +61,22 @@ public bool TryGetValue(string key, out T value) } } - private string GetFilterValue(string key) => _jsonApiContext.QuerySet - .Filters - .FirstOrDefault(f => string.Equals(f.Key, key, StringComparison.OrdinalIgnoreCase)) - ?.Value; + private string GetFilterValue(string key) { + var publicValue = _jsonApiContext.QuerySet.Filters + .FirstOrDefault(f => string.Equals(f.Attribute, key, StringComparison.OrdinalIgnoreCase))?.Value; + + if(publicValue != null) + return publicValue; + + var internalValue = _jsonApiContext.QuerySet.Filters + .FirstOrDefault(f => string.Equals(f.Key, key, StringComparison.OrdinalIgnoreCase))?.Value; + + if(internalValue != null) { + _logger.LogWarning("Locating filters by the internal propterty name is deprecated. You should use the public attribute name instead."); + return publicValue; + } + + return null; + } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 46f7a4e68a..1e956d64f4 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -18,6 +18,8 @@ public class QueryParser : IQueryParser { private readonly IControllerContext _controllerContext; private readonly JsonApiOptions _options; + private const char OPEN_BRACKET = '['; + private const char CLOSE_BRACKET = ']'; public QueryParser( IControllerContext controllerContext, JsonApiOptions options) { @@ -72,7 +74,7 @@ protected virtual List ParseFilterQuery(string key, string value) { // expected input = filter[id]=eq:1 var queries = new List(); - var propertyName = key.Split('[', ']') [1].ToProperCase(); + var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; var values = value.Split(','); foreach (var val in values) { From cb20ff405cf24a835e3c99bee690895455c82ba9 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 15:56:23 -0600 Subject: [PATCH 054/227] perf(QueryParser): constants instead of inline strings --- src/JsonApiDotNetCore/Services/QueryParser.cs | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 1e956d64f4..8f721aef62 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -3,7 +3,6 @@ using System.Linq; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; @@ -18,8 +17,17 @@ public class QueryParser : IQueryParser { private readonly IControllerContext _controllerContext; private readonly JsonApiOptions _options; + private const string FILTER = "filter"; + private const string SORT = "sort"; + private const string INCLUDE = "include"; + private const string PAGE = "page"; + private const string FIELDS = "fields"; private const char OPEN_BRACKET = '['; private const char CLOSE_BRACKET = ']'; + private const char COMMA = ','; + private const char COLON = ':'; + private const string COLON_STR = ":"; + public QueryParser( IControllerContext controllerContext, JsonApiOptions options) { @@ -32,31 +40,31 @@ public virtual QuerySet Parse(IQueryCollection query) { var disabledQueries = _controllerContext.GetControllerAttribute() ? .QueryParams ?? QueryParams.None; foreach (var pair in query) { - if (pair.Key.StartsWith("filter")) { + if (pair.Key.StartsWith(FILTER)) { if (disabledQueries.HasFlag(QueryParams.Filter) == false) querySet.Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); continue; } - if (pair.Key.StartsWith("sort")) { + if (pair.Key.StartsWith(SORT)) { if (disabledQueries.HasFlag(QueryParams.Sort) == false) querySet.SortParameters = ParseSortParameters(pair.Value); continue; } - if (pair.Key.StartsWith("include")) { + if (pair.Key.StartsWith(INCLUDE)) { if (disabledQueries.HasFlag(QueryParams.Include) == false) querySet.IncludedRelationships = ParseIncludedRelationships(pair.Value); continue; } - if (pair.Key.StartsWith("page")) { + if (pair.Key.StartsWith(PAGE)) { if (disabledQueries.HasFlag(QueryParams.Page) == false) querySet.PageQuery = ParsePageQuery(querySet.PageQuery, pair.Key, pair.Value); continue; } - if (pair.Key.StartsWith("fields")) { + if (pair.Key.StartsWith(FIELDS)) { if (disabledQueries.HasFlag(QueryParams.Fields) == false) querySet.Fields = ParseFieldsQuery(pair.Key, pair.Value); continue; @@ -76,10 +84,9 @@ protected virtual List ParseFilterQuery(string key, string value) { var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; - var values = value.Split(','); + var values = value.Split(COMMA); foreach (var val in values) { - (var operation, - var filterValue) = ParseFilterOperation(val); + (var operation, var filterValue) = ParseFilterOperation(val); queries.Add(new FilterQuery(propertyName, filterValue, operation)); } @@ -90,7 +97,7 @@ protected virtual(string operation, string value) ParseFilterOperation(string va if (value.Length < 3) return (string.Empty, value); - var operation = value.Split(':'); + var operation = value.Split(COLON); if (operation.Length == 1) return (string.Empty, value); @@ -100,7 +107,7 @@ protected virtual(string operation, string value) ParseFilterOperation(string va return (string.Empty, value); var prefix = operation[0]; - value = string.Join(":", operation.Skip(1)); + value = string.Join(COLON_STR, operation.Skip(1)); return (prefix, value); } @@ -110,11 +117,14 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri // page[number]=1 pageQuery = pageQuery ?? new PageQuery(); - var propertyName = key.Split('[', ']') [1]; + var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; + + const string SIZE = "size"; + const string NUMBER = "number"; - if (propertyName == "size") + if (propertyName == SIZE) pageQuery.PageSize = Convert.ToInt32(value); - else if (propertyName == "number") + else if (propertyName == NUMBER) pageQuery.PageOffset = Convert.ToInt32(value); return pageQuery; @@ -123,11 +133,11 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri // sort=id,name // sort=-id protected virtual List ParseSortParameters(string value) { - const char SORT_DELIMITER = ','; + var sortParameters = new List(); + const char DESCENDING_SORT_OPERATOR = '-'; + var sortSegments = value.Split(COMMA); - var sortParameters = new List(); - var sortSegments = value.Split(SORT_DELIMITER); foreach (var sortSegment in sortSegments) { var propertyName = sortSegment; @@ -147,24 +157,26 @@ protected virtual List ParseSortParameters(string value) { } protected virtual List ParseIncludedRelationships(string value) { - if (value.Contains(".")) + const string NESTED_DELIMITER = "."; + if (value.Contains(NESTED_DELIMITER)) throw new JsonApiException(400, "Deeply nested relationships are not supported"); return value - .Split(',') + .Split(COMMA) .ToList(); } protected virtual List ParseFieldsQuery(string key, string value) { // expected: fields[TYPE]=prop1,prop2 - var typeName = key.Split('[', ']') [1]; + var typeName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; - var includedFields = new List { "Id" }; + const string ID = "Id"; + var includedFields = new List { ID }; if (typeName != _controllerContext.RequestEntity.EntityName) return includedFields; - var fields = value.Split(','); + var fields = value.Split(COMMA); foreach (var field in fields) { var internalAttrName = _controllerContext.RequestEntity .Attributes @@ -176,11 +188,17 @@ protected virtual List ParseFieldsQuery(string key, string value) { return includedFields; } - protected virtual AttrAttribute GetAttribute(string propertyName) => _controllerContext - .RequestEntity - .Attributes - .FirstOrDefault(attr => - string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) - ); + protected virtual AttrAttribute GetAttribute(string propertyName) { + try { + return _controllerContext + .RequestEntity + .Attributes + .Single(attr => + string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) + ); + } catch (InvalidOperationException e) { + throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'"); + } + } } } From a8831b2ef0d1453195cc0a19f9b875316b071b4d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 26 Nov 2017 15:56:34 -0600 Subject: [PATCH 055/227] bench(*): run new benchmarks --- ...ry.QueryParser_Benchmarks-report-github.md | 11 +++++----- ...piDeserializer_Benchmarks-report-github.md | 2 +- ...nApiSerializer_Benchmarks-report-github.md | 6 +++--- benchmarks/Query/QueryParser_Benchmarks.cs | 21 +++++++++++++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md index 324281fa40..4678b3141e 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md @@ -4,12 +4,13 @@ BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 .NET Core SDK=2.0.0 [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - Job-ROPOBW : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + Job-OWXJBF : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT LaunchCount=3 TargetCount=20 WarmupCount=10 ``` -| Method | Mean | Error | StdDev | -|--------------- |---------:|----------:|----------:| -| AscendingSort | 3.101 us | 0.0298 us | 0.0636 us | -| DescendingSort | 3.195 us | 0.0297 us | 0.0632 us | +| Method | Mean | Error | StdDev | Median | +|--------------- |-------------:|-----------:|------------:|-------------:| +| AscendingSort | 4.451 us | 1.5230 us | 3.2457 us | 3.305 us | +| DescendingSort | 3.287 us | 0.0307 us | 0.0673 us | 3.263 us | +| ComplexQuery | 1,973.029 us | 67.5600 us | 143.9759 us | 1,952.663 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md index d8571f9644..6c8c3f2905 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiDeserializer_Benchmarks-report-github.md @@ -10,4 +10,4 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` | Method | Mean | Error | StdDev | |------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 26.37 us | 0.4458 us | 0.4170 us | +| DeserializeSimpleObject | 27.05 us | 0.5353 us | 0.5950 us | diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md index 4671d6b3af..f86bf0faa9 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Serialization.JsonApiSerializer_Benchmarks-report-github.md @@ -8,6 +8,6 @@ Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 ``` -| Method | Mean | Error | StdDev | -|------------------------ |---------:|----------:|----------:| -| DeserializeSimpleObject | 7.135 us | 0.1401 us | 0.1439 us | +| Method | Mean | Error | StdDev | +|---------------------- |---------:|----------:|----------:| +| SerializeSimpleObject | 7.195 us | 0.1436 us | 0.1816 us | diff --git a/benchmarks/Query/QueryParser_Benchmarks.cs b/benchmarks/Query/QueryParser_Benchmarks.cs index 0edaee6cb5..8a077de2bf 100644 --- a/benchmarks/Query/QueryParser_Benchmarks.cs +++ b/benchmarks/Query/QueryParser_Benchmarks.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes.Exporters; @@ -6,6 +7,8 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.Extensions.Primitives; using Moq; namespace Benchmarks.Query { @@ -36,6 +39,24 @@ public QueryParser_Benchmarks() { [Benchmark] public void DescendingSort() => _queryParser._ParseSortParameters(DESCENDING_SORT); + [Benchmark] + public void ComplexQuery() => Run(100, () => _queryParser.Parse( + new QueryCollection( + new Dictionary { + { $"filter[{ATTRIBUTE}]", new StringValues(new [] { "abc", "eq:abc" }) }, + { $"sort", $"-{ATTRIBUTE}" }, + { $"include", "relationship" }, + { $"page[size]", "1" }, + { $"fields[resource]", ATTRIBUTE }, + } + ) + )); + + private void Run(int iterations, Action action) { + for (int i = 0; i < iterations; i++) + action(); + } + // this facade allows us to expose and micro-benchmark protected methods private class BenchmarkFacade : QueryParser { public BenchmarkFacade( From 0e6778fa1aa6f208350530db3994ebd4390330f7 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 3 Dec 2017 15:14:23 -0600 Subject: [PATCH 056/227] feat(*): add constants for Content-Type --- ...uery.QueryParser_Benchmarks-report-github.md | 12 ++++++------ benchmarks/Program.cs | 9 ++++++--- benchmarks/Query/QueryParser_Benchmarks.cs | 2 +- .../Formatters/JsonApiInputFormatter.cs | 3 ++- .../Formatters/JsonApiOutputFormatter.cs | 3 ++- .../Formatters/JsonApiWriter.cs | 7 ++++--- src/JsonApiDotNetCore/Internal/Constants.cs | 8 ++++++++ .../Internal/JsonApiExceptionFactory.cs | 7 +++++-- .../Internal/Query/BaseFilterQuery.cs | 4 ++-- .../Internal/Query/RelatedAttrFilterQuery.cs | 9 +++++---- .../Middleware/RequestMiddleware.cs | 5 +++-- src/JsonApiDotNetCore/Models/DocumentBase.cs | 17 +++-------------- 12 files changed, 47 insertions(+), 39 deletions(-) create mode 100644 src/JsonApiDotNetCore/Internal/Constants.cs diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md index 4678b3141e..b3ebd8a29c 100755 --- a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.Query.QueryParser_Benchmarks-report-github.md @@ -4,13 +4,13 @@ BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 .NET Core SDK=2.0.0 [Host] : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT - Job-OWXJBF : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT + Job-WKDOLS : .NET Core 1.1.4 (Framework 4.6.25714.03), 64bit RyuJIT LaunchCount=3 TargetCount=20 WarmupCount=10 ``` -| Method | Mean | Error | StdDev | Median | -|--------------- |-------------:|-----------:|------------:|-------------:| -| AscendingSort | 4.451 us | 1.5230 us | 3.2457 us | 3.305 us | -| DescendingSort | 3.287 us | 0.0307 us | 0.0673 us | 3.263 us | -| ComplexQuery | 1,973.029 us | 67.5600 us | 143.9759 us | 1,952.663 us | +| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Allocated | +|--------------- |-------------:|-----------:|-----------:|---------:|--------:|----------:| +| AscendingSort | 4.316 us | 1.3773 us | 3.0232 us | 0.5066 | 0.1303 | 1.08 KB | +| DescendingSort | 3.300 us | 0.0314 us | 0.0682 us | 0.5123 | 0.1318 | 1.13 KB | +| ComplexQuery | 2,041.642 us | 41.5631 us | 92.1010 us | 312.5000 | 80.2734 | 648.99 KB | diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index da4eaa2b50..7665d5fb97 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -5,9 +5,12 @@ namespace Benchmarks { class Program { static void Main(string[] args) { - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); + var switcher = new BenchmarkSwitcher(new[] { + typeof(JsonApiDeserializer_Benchmarks), + typeof(JsonApiSerializer_Benchmarks), + typeof(QueryParser_Benchmarks) + }); + switcher.Run(args); } } } diff --git a/benchmarks/Query/QueryParser_Benchmarks.cs b/benchmarks/Query/QueryParser_Benchmarks.cs index 8a077de2bf..61fe3b1bc2 100644 --- a/benchmarks/Query/QueryParser_Benchmarks.cs +++ b/benchmarks/Query/QueryParser_Benchmarks.cs @@ -12,7 +12,7 @@ using Moq; namespace Benchmarks.Query { - [MarkdownExporter, SimpleJob(launchCount : 3, warmupCount : 10, targetCount : 20)] + [MarkdownExporter, SimpleJob(launchCount : 3, warmupCount : 10, targetCount : 20), MemoryDiagnoser] public class QueryParser_Benchmarks { private readonly BenchmarkFacade _queryParser; diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs index 12e57deadf..f556b7433d 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.DependencyInjection; @@ -14,7 +15,7 @@ public bool CanRead(InputFormatterContext context) var contentTypeString = context.HttpContext.Request.ContentType; - return contentTypeString == "application/vnd.api+json"; + return contentTypeString == Constants.ContentType; } public async Task ReadAsync(InputFormatterContext context) diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOutputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOutputFormatter.cs index 2431055d1d..b456932fc5 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOutputFormatter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiOutputFormatter.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.DependencyInjection; @@ -14,7 +15,7 @@ public bool CanWriteResult(OutputFormatterCanWriteContext context) var contentTypeString = context.HttpContext.Request.ContentType; - return string.IsNullOrEmpty(contentTypeString) || contentTypeString == "application/vnd.api+json"; + return string.IsNullOrEmpty(contentTypeString) || contentTypeString == Constants.ContentType; } public async Task WriteAsync(OutputFormatterWriteContext context) diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs index 730a88f13e..d644def66d 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs @@ -13,7 +13,8 @@ public class JsonApiWriter : IJsonApiWriter private readonly ILogger _logger; private readonly IJsonApiSerializer _serializer; - public JsonApiWriter(IJsonApiSerializer serializer, + public JsonApiWriter( + IJsonApiSerializer serializer, ILoggerFactory loggerFactory) { _serializer = serializer; @@ -30,7 +31,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context) var response = context.HttpContext.Response; using (var writer = context.WriterFactory(response.Body, Encoding.UTF8)) { - response.ContentType = "application/vnd.api+json"; + response.ContentType = Constants.ContentType; string responseContent; try { @@ -55,4 +56,4 @@ private string GetResponseBody(object responseObject) return _serializer.Serialize(responseObject); } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Internal/Constants.cs b/src/JsonApiDotNetCore/Internal/Constants.cs new file mode 100644 index 0000000000..750d94ba07 --- /dev/null +++ b/src/JsonApiDotNetCore/Internal/Constants.cs @@ -0,0 +1,8 @@ +namespace JsonApiDotNetCore.Internal +{ + public static class Constants + { + public const string AcceptHeader = "Accept"; + public const string ContentType = "application/vnd.api+json"; + } +} diff --git a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs index 42f3037f89..36b4969b1d 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs @@ -5,14 +5,17 @@ namespace JsonApiDotNetCore.Internal { public static class JsonApiExceptionFactory { + private const string JsonApiException = nameof(JsonApiException); + private const string InvalidCastException = nameof(InvalidCastException); + public static JsonApiException GetException(Exception exception) { var exceptionType = exception.GetType().ToString().Split('.').Last(); switch(exceptionType) { - case "JsonApiException": + case JsonApiException: return (JsonApiException)exception; - case "InvalidCastException": + case InvalidCastException: return new JsonApiException(409, exception.Message); default: return new JsonApiException(500, exception.Message, GetExceptionDetail(exception.InnerException)); diff --git a/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs index 527b842ca8..1c43d84254 100644 --- a/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs @@ -8,10 +8,10 @@ protected FilterOperations GetFilterOperation(string prefix) { if (prefix.Length == 0) return FilterOperations.eq; - if (!Enum.TryParse(prefix, out FilterOperations opertion)) + if (Enum.TryParse(prefix, out FilterOperations opertion) == false) throw new JsonApiException(400, $"Invalid filter prefix '{prefix}'"); return opertion; } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index dc633c5302..3b249c176c 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; @@ -14,7 +15,7 @@ public RelatedAttrFilterQuery( { _jsonApiContext = jsonApiCopntext; - var relationshipArray = filterQuery.Key.Split('.'); + var relationshipArray = filterQuery.Attribute.Split('.'); var relationship = GetRelationship(relationshipArray[0]); if (relationship == null) @@ -36,14 +37,14 @@ public RelatedAttrFilterQuery( private RelationshipAttribute GetRelationship(string propertyName) { return _jsonApiContext.RequestEntity.Relationships - .FirstOrDefault(r => r.InternalRelationshipName.ToLower() == propertyName.ToLower()); + .FirstOrDefault(r => string.Equals(r.PublicRelationshipName, propertyName, StringComparison.OrdinalIgnoreCase)); } private AttrAttribute GetAttribute(RelationshipAttribute relationship, string attribute) { var relatedContextExntity = _jsonApiContext.ContextGraph.GetContextEntity(relationship.Type); return relatedContextExntity.Attributes - .FirstOrDefault(a => a.InternalAttributeName.ToLower() == attribute.ToLower()); + .FirstOrDefault(a => string.Equals(a.PublicAttributeName, attribute, StringComparison.OrdinalIgnoreCase)); } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 670def21d6..6e2612c9a6 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -37,7 +38,7 @@ private static bool IsValidContentTypeHeader(HttpContext context) private static bool IsValidAcceptHeader(HttpContext context) { - if (context.Request.Headers.TryGetValue("Accept", out StringValues acceptHeaders) == false) + if (context.Request.Headers.TryGetValue(Constants.AcceptHeader, out StringValues acceptHeaders) == false) return true; foreach (var acceptHeader in acceptHeaders) @@ -54,7 +55,7 @@ private static bool IsValidAcceptHeader(HttpContext context) private static bool ContainsMediaTypeParameters(string mediaType) { var mediaTypeArr = mediaType.Split(';'); - return (mediaTypeArr[0] == "application/vnd.api+json" && mediaTypeArr.Length == 2); + return (mediaTypeArr[0] == Constants.ContentType && mediaTypeArr.Length == 2); } private static void FlushResponse(HttpContext context, int statusCode) diff --git a/src/JsonApiDotNetCore/Models/DocumentBase.cs b/src/JsonApiDotNetCore/Models/DocumentBase.cs index 1cb31595ec..df51301c20 100644 --- a/src/JsonApiDotNetCore/Models/DocumentBase.cs +++ b/src/JsonApiDotNetCore/Models/DocumentBase.cs @@ -15,19 +15,8 @@ public class DocumentBase public Dictionary Meta { get; set; } // http://www.newtonsoft.com/json/help/html/ConditionalProperties.htm - public bool ShouldSerializeIncluded() - { - return (Included != null); - } - - public bool ShouldSerializeMeta() - { - return (Meta != null); - } - - public bool ShouldSerializeLinks() - { - return (Links != null); - } + public bool ShouldSerializeIncluded() => (Included != null); + public bool ShouldSerializeMeta() => (Meta != null); + public bool ShouldSerializeLinks() => (Links != null); } } From a26990235d897fde7cc6a9fdee047334405eaad1 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 3 Dec 2017 15:18:10 -0600 Subject: [PATCH 057/227] fix(queryParser): remove access to obsolete key --- src/JsonApiDotNetCore/Services/QueryAccessor.cs | 2 +- src/JsonApiDotNetCore/Services/QueryParser.cs | 2 +- test/UnitTests/Services/QueryParser_Tests.cs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryAccessor.cs b/src/JsonApiDotNetCore/Services/QueryAccessor.cs index 63b91ed239..41bc64151b 100644 --- a/src/JsonApiDotNetCore/Services/QueryAccessor.cs +++ b/src/JsonApiDotNetCore/Services/QueryAccessor.cs @@ -69,7 +69,7 @@ private string GetFilterValue(string key) { return publicValue; var internalValue = _jsonApiContext.QuerySet.Filters - .FirstOrDefault(f => string.Equals(f.Key, key, StringComparison.OrdinalIgnoreCase))?.Value; + .FirstOrDefault(f => string.Equals(f.Attribute, key, StringComparison.OrdinalIgnoreCase))?.Value; if(internalValue != null) { _logger.LogWarning("Locating filters by the internal propterty name is deprecated. You should use the public attribute name instead."); diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 8f721aef62..47f9efa631 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -197,7 +197,7 @@ protected virtual AttrAttribute GetAttribute(string propertyName) { string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) ); } catch (InvalidOperationException e) { - throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'"); + throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'", e); } } } diff --git a/test/UnitTests/Services/QueryParser_Tests.cs b/test/UnitTests/Services/QueryParser_Tests.cs index a64c5b3692..abe5d75568 100644 --- a/test/UnitTests/Services/QueryParser_Tests.cs +++ b/test/UnitTests/Services/QueryParser_Tests.cs @@ -43,7 +43,7 @@ public void Can_Build_Filters() var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert - Assert.Equal("value", querySet.Filters.Single(f => f.Key == "Key").Value); + Assert.Equal("value", querySet.Filters.Single(f => f.Attribute == "key").Value); } [Fact] @@ -69,8 +69,8 @@ public void Filters_Properly_Parses_DateTime_With_Operation() var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert - Assert.Equal(dt, querySet.Filters.Single(f => f.Key == "Key").Value); - Assert.Equal("le", querySet.Filters.Single(f => f.Key == "Key").Operation); + Assert.Equal(dt, querySet.Filters.Single(f => f.Attribute == "key").Value); + Assert.Equal("le", querySet.Filters.Single(f => f.Attribute == "key").Operation); } [Fact] @@ -96,8 +96,8 @@ public void Filters_Properly_Parses_DateTime_Without_Operation() var querySet = queryParser.Parse(_queryCollectionMock.Object); // assert - Assert.Equal(dt, querySet.Filters.Single(f => f.Key == "Key").Value); - Assert.Equal(string.Empty, querySet.Filters.Single(f => f.Key == "Key").Operation); + Assert.Equal(dt, querySet.Filters.Single(f => f.Attribute == "key").Value); + Assert.Equal(string.Empty, querySet.Filters.Single(f => f.Attribute == "key").Operation); } [Fact] From ae452d28b70abdd243f45fd09ad6fc87473cc4c2 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 16 Dec 2017 07:31:24 -0600 Subject: [PATCH 058/227] fix(JsonApiDeSerializer): throw on possible null exception --- src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 25021c441e..1c0c5014f7 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -169,9 +169,12 @@ private object SetHasOneRelationship(object entity, if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) { var relationshipAttr = _jsonApiContext.RequestEntity.Relationships - .SingleOrDefault(r => r.PublicRelationshipName == relationshipName); + .SingleOrDefault(r => r.PublicRelationshipName == relationshipName); - var data = (Dictionary)relationshipData.ExposedData; + if (relationshipAttr == null) + throw new JsonApiException(400, $"{_jsonApiContext.RequestEntity.EntityName} does not contain a relationship '{relationshipName}'"); + + var data = (Dictionary) relationshipData.ExposedData; if (data == null) return entity; From a54a211a5e64f4d969d58afa827bde52600e29a3 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 16 Dec 2017 07:35:48 -0600 Subject: [PATCH 059/227] test(queryParser): add test coverage and handle exception --- src/JsonApiDotNetCore/Services/QueryParser.cs | 53 ++++--- test/UnitTests/Services/QueryParser_Tests.cs | 130 +++++++++++++++++- 2 files changed, 165 insertions(+), 18 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 47f9efa631..2a97723347 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -112,38 +112,47 @@ protected virtual(string operation, string value) ParseFilterOperation(string va return (prefix, value); } - protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) { + protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) + { // expected input = page[size]=10 // page[number]=1 pageQuery = pageQuery ?? new PageQuery(); - var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; + var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; const string SIZE = "size"; const string NUMBER = "number"; if (propertyName == SIZE) - pageQuery.PageSize = Convert.ToInt32(value); + pageQuery.PageSize = int.TryParse(value, out var pageSize) ? + pageSize : + throw new JsonApiException(400, $"Invalid page size '{value}'"); + else if (propertyName == NUMBER) - pageQuery.PageOffset = Convert.ToInt32(value); + pageQuery.PageOffset = int.TryParse(value, out var pageOffset) ? + pageOffset : + throw new JsonApiException(400, $"Invalid page size '{value}'"); return pageQuery; } // sort=id,name // sort=-id - protected virtual List ParseSortParameters(string value) { + protected virtual List ParseSortParameters(string value) + { var sortParameters = new List(); const char DESCENDING_SORT_OPERATOR = '-'; var sortSegments = value.Split(COMMA); - foreach (var sortSegment in sortSegments) { + foreach (var sortSegment in sortSegments) + { var propertyName = sortSegment; var direction = SortDirection.Ascending; - if (sortSegment[0] == DESCENDING_SORT_OPERATOR) { + if (sortSegment[0] == DESCENDING_SORT_OPERATOR) + { direction = SortDirection.Descending; propertyName = propertyName.Substring(1); } @@ -166,37 +175,47 @@ protected virtual List ParseIncludedRelationships(string value) { .ToList(); } - protected virtual List ParseFieldsQuery(string key, string value) { + protected virtual List ParseFieldsQuery(string key, string value) + { // expected: fields[TYPE]=prop1,prop2 - var typeName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; + var typeName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; const string ID = "Id"; var includedFields = new List { ID }; - if (typeName != _controllerContext.RequestEntity.EntityName) + // this will not support nested inclusions, it requires that the typeName is the current request type + if (string.Equals(typeName, _controllerContext.RequestEntity.EntityName, StringComparison.OrdinalIgnoreCase) == false) return includedFields; var fields = value.Split(COMMA); - foreach (var field in fields) { - var internalAttrName = _controllerContext.RequestEntity + foreach (var field in fields) + { + var attr = _controllerContext.RequestEntity .Attributes - .SingleOrDefault(attr => attr.PublicAttributeName == field) - .InternalAttributeName; + .SingleOrDefault(a => string.Equals(a.PublicAttributeName, field, StringComparison.OrdinalIgnoreCase)); + + if (attr == null) throw new JsonApiException(400, $"'{_controllerContext.RequestEntity.EntityName}' does not contain '{field}'."); + + var internalAttrName = attr.InternalAttributeName; includedFields.Add(internalAttrName); } return includedFields; } - protected virtual AttrAttribute GetAttribute(string propertyName) { - try { + protected virtual AttrAttribute GetAttribute(string propertyName) + { + try + { return _controllerContext .RequestEntity .Attributes .Single(attr => string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) ); - } catch (InvalidOperationException e) { + } + catch (InvalidOperationException e) + { throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'", e); } } diff --git a/test/UnitTests/Services/QueryParser_Tests.cs b/test/UnitTests/Services/QueryParser_Tests.cs index abe5d75568..ed7808d1f4 100644 --- a/test/UnitTests/Services/QueryParser_Tests.cs +++ b/test/UnitTests/Services/QueryParser_Tests.cs @@ -224,5 +224,133 @@ public void Can_Disable_Fields() // assert Assert.Empty(querySet.Fields); } + + [Fact] + public void Can_Parse_Fields_Query() + { + // arrange + const string type = "articles"; + const string attrName = "some-field"; + const string internalAttrName = "SomeField"; + + var query = new Dictionary { { $"fields[{type}]", new StringValues(attrName) } }; + + _queryCollectionMock + .Setup(m => m.GetEnumerator()) + .Returns(query.GetEnumerator()); + + _controllerContextMock + .Setup(m => m.RequestEntity) + .Returns(new ContextEntity + { + EntityName = type, + Attributes = new List + { + new AttrAttribute(attrName) + { + InternalAttributeName = internalAttrName + } + } + }); + + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + var querySet = queryParser.Parse(_queryCollectionMock.Object); + + // assert + Assert.NotEmpty(querySet.Fields); + Assert.Equal(2, querySet.Fields.Count); + Assert.Equal("Id", querySet.Fields[0]); + Assert.Equal(internalAttrName, querySet.Fields[1]); + } + + [Fact] + public void Throws_JsonApiException_If_Field_DoesNotExist() + { + // arrange + const string type = "articles"; + const string attrName = "dne"; + + var query = new Dictionary { { $"fields[{type}]", new StringValues(attrName) } }; + + _queryCollectionMock + .Setup(m => m.GetEnumerator()) + .Returns(query.GetEnumerator()); + + _controllerContextMock + .Setup(m => m.RequestEntity) + .Returns(new ContextEntity + { + EntityName = type, + Attributes = new List() + }); + + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act , assert + var ex = Assert.Throws(() => queryParser.Parse(_queryCollectionMock.Object)); + Assert.Equal(400, ex.GetStatusCode()); + } + + [Theory] + [InlineData("1", 1, false)] + [InlineData("abcde", 0, true)] + [InlineData("", 0, true)] + public void Can_Parse_Page_Size_Query(string value, int expectedValue, bool shouldThrow) + { + // arrange + var query = new Dictionary + { { "page[size]", new StringValues(value) } + }; + + _queryCollectionMock + .Setup(m => m.GetEnumerator()) + .Returns(query.GetEnumerator()); + + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + if (shouldThrow) + { + var ex = Assert.Throws(() => queryParser.Parse(_queryCollectionMock.Object)); + Assert.Equal(400, ex.GetStatusCode()); + } + else + { + var querySet = queryParser.Parse(_queryCollectionMock.Object); + Assert.Equal(expectedValue, querySet.PageQuery.PageSize); + } + } + + [Theory] + [InlineData("1", 1, false)] + [InlineData("abcde", 0, true)] + [InlineData("", 0, true)] + public void Can_Parse_Page_Number_Query(string value, int expectedValue, bool shouldThrow) + { + // arrange + var query = new Dictionary + { { "page[number]", new StringValues(value) } + }; + + _queryCollectionMock + .Setup(m => m.GetEnumerator()) + .Returns(query.GetEnumerator()); + + var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions()); + + // act + if (shouldThrow) + { + var ex = Assert.Throws(() => queryParser.Parse(_queryCollectionMock.Object)); + Assert.Equal(400, ex.GetStatusCode()); + } + else + { + var querySet = queryParser.Parse(_queryCollectionMock.Object); + Assert.Equal(expectedValue, querySet.PageQuery.PageOffset); + } + } } -} +} \ No newline at end of file From 2b1cbcc52b626c59cda82d788d6c96123ed6c693 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 16 Dec 2017 07:37:08 -0600 Subject: [PATCH 060/227] fix(ContextGraph): return null instead of throwing null exception --- src/JsonApiDotNetCore/Internal/ContextGraph.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs index fd29794194..163196341b 100644 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ContextGraph.cs @@ -1,7 +1,7 @@ -using System.Reflection; +using System; using System.Collections.Generic; using System.Linq; -using System; +using System.Reflection; namespace JsonApiDotNetCore.Internal { @@ -34,9 +34,9 @@ public string GetRelationshipName(string relationshipName) { var entityType = typeof(TParent); return Entities - .SingleOrDefault(e => e.EntityType == entityType) - .Relationships - .SingleOrDefault(r => string.Equals(r.PublicRelationshipName, relationshipName, StringComparison.OrdinalIgnoreCase)) + .SingleOrDefault(e => e.EntityType == entityType) + ?.Relationships + .SingleOrDefault(r => string.Equals(r.PublicRelationshipName, relationshipName, StringComparison.OrdinalIgnoreCase)) ?.InternalRelationshipName; } } From 5eb948f3c46227393de82f71a87618891e8c686c Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 16 Dec 2017 07:38:28 -0600 Subject: [PATCH 061/227] fix(queryParser): add missing usings --- test/UnitTests/Services/QueryParser_Tests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/UnitTests/Services/QueryParser_Tests.cs b/test/UnitTests/Services/QueryParser_Tests.cs index ed7808d1f4..64c9830f2b 100644 --- a/test/UnitTests/Services/QueryParser_Tests.cs +++ b/test/UnitTests/Services/QueryParser_Tests.cs @@ -2,6 +2,8 @@ using System.Linq; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; From 6d52888ca7a3146d76c201beee208661b39e72a9 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 16 Dec 2017 07:49:48 -0600 Subject: [PATCH 062/227] fix(props): bump to netstandard2.0 fixing rebase --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d4686bba2e..13b9ba4ecb 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,7 +1,7 @@ - netcoreapp1.1 - netstandard1.6 + netcoreapp2.0 + netstandard2.0 4.7.10 From f2ae1127e303d0f3a335b81706ce192384c2fde6 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 06:43:50 -0600 Subject: [PATCH 063/227] feat(AttrAttribute): add isSortable and isFilterable --- src/JsonApiDotNetCore/AssemblyInfo.cs | 4 ++++ .../Internal/Query/AttrFilterQuery.cs | 14 ++++++++++---- .../Internal/Query/RelatedAttrFilterQuery.cs | 10 ++++++++-- src/JsonApiDotNetCore/Models/AttrAttribute.cs | 15 +++++++++------ .../Models/RelationshipAttribute.cs | 8 ++++---- src/JsonApiDotNetCore/Services/QueryParser.cs | 3 +++ 6 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 src/JsonApiDotNetCore/AssemblyInfo.cs diff --git a/src/JsonApiDotNetCore/AssemblyInfo.cs b/src/JsonApiDotNetCore/AssemblyInfo.cs new file mode 100644 index 0000000000..f03399b449 --- /dev/null +++ b/src/JsonApiDotNetCore/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; +[assembly:InternalsVisibleTo("UnitTests")] +[assembly:InternalsVisibleTo("JsonApiDotNetCoreExampleTests")] +[assembly:InternalsVisibleTo("NoEntityFrameworkTests")] diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index 74db2b342e..e94f872b54 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -17,14 +17,20 @@ public AttrFilterQuery( var attribute = GetAttribute(filterQuery.Attribute); - FilteredAttribute = attribute ?? throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); + if(attribute == null) + throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); + + if(attribute.IsFilterable == false) + throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); + + FilteredAttribute = attribute; PropertyValue = filterQuery.Value; FilterOperation = GetFilterOperation(filterQuery.Operation); } - public AttrAttribute FilteredAttribute { get; set; } - public string PropertyValue { get; set; } - public FilterOperations FilterOperation { get; set; } + public AttrAttribute FilteredAttribute { get; } + public string PropertyValue { get; } + public FilterOperations FilterOperation { get; } private AttrAttribute GetAttribute(string attribute) => _jsonApiContext.RequestEntity.Attributes.FirstOrDefault( diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 3b249c176c..52d7c66f41 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -19,12 +19,18 @@ public RelatedAttrFilterQuery( var relationship = GetRelationship(relationshipArray[0]); if (relationship == null) - throw new JsonApiException(400, $"{relationshipArray[0]} is not a valid relationship."); + throw new JsonApiException(400, $"{relationshipArray[1]} is not a valid relationship on {relationshipArray[0]}."); var attribute = GetAttribute(relationship, relationshipArray[1]); + + if(attribute == null) + throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); + + if(attribute.IsFilterable == false) + throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); FilteredRelationship = relationship; - FilteredAttribute = attribute ?? throw new JsonApiException(400, $"{relationshipArray[1]} is not a valid attribute on {relationshipArray[0]}."); + FilteredAttribute = attribute; PropertyValue = filterQuery.Value; FilterOperation = GetFilterOperation(filterQuery.Operation); } diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs index f84fd229ef..9fa869aeb0 100644 --- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs +++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs @@ -1,27 +1,30 @@ using System; -using System.Reflection; using JsonApiDotNetCore.Internal; namespace JsonApiDotNetCore.Models { public class AttrAttribute : Attribute { - public AttrAttribute(string publicName, bool isImmutable = false) + public AttrAttribute(string publicName, bool isImmutable = false, bool isFilterable = true, bool isSortable = true) { PublicAttributeName = publicName; IsImmutable = isImmutable; + IsFilterable = isFilterable; + IsSortable = isSortable; } - public AttrAttribute(string publicName, string internalName, bool isImmutable = false) + internal AttrAttribute(string publicName, string internalName, bool isImmutable = false) { PublicAttributeName = publicName; InternalAttributeName = internalName; IsImmutable = isImmutable; } - public string PublicAttributeName { get; set; } - public string InternalAttributeName { get; set; } - public bool IsImmutable { get; set; } + public string PublicAttributeName { get; } + public string InternalAttributeName { get; } + public bool IsImmutable { get; } + public bool IsFilterable { get; } + public bool IsSortable { get; } public object GetValue(object entity) { diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 93662032a5..4f6d42f47e 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -10,12 +10,12 @@ protected RelationshipAttribute(string publicName, Link documentLinks) DocumentLinks = documentLinks; } - public string PublicRelationshipName { get; set; } - public string InternalRelationshipName { get; set; } - public Type Type { get; set; } + public string PublicRelationshipName { get; } + public string InternalRelationshipName { get; } + public Type Type { get; } public bool IsHasMany => GetType() == typeof(HasManyAttribute); public bool IsHasOne => GetType() == typeof(HasOneAttribute); - public Link DocumentLinks { get; set; } = Link.All; + public Link DocumentLinks { get; } = Link.All; public abstract void SetValue(object entity, object newValue); diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 2a97723347..d9dfab532d 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -159,6 +159,9 @@ protected virtual List ParseSortParameters(string value) var attribute = GetAttribute(propertyName); + if(attribute.IsSortable == false) + throw new JsonApiException(400, $"Sort is not allowed for attribute '{attribute.PublicAttributeName}'."); + sortParameters.Add(new SortQuery(direction, attribute)); }; From 6cdd04bb53dbae932ab66503e430a971fc92c9be Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 19:57:34 -0600 Subject: [PATCH 064/227] fix(Attr/RelationshipAttibute): make setters internal --- benchmarks/Query/QueryParser_Benchmarks.cs | 4 +--- src/JsonApiDotNetCore/AssemblyInfo.cs | 1 + src/JsonApiDotNetCore/Models/AttrAttribute.cs | 2 +- src/JsonApiDotNetCore/Models/HasManyAttribute.cs | 6 +----- src/JsonApiDotNetCore/Models/HasOneAttribute.cs | 6 +----- src/JsonApiDotNetCore/Models/RelationshipAttribute.cs | 4 ++-- 6 files changed, 7 insertions(+), 16 deletions(-) diff --git a/benchmarks/Query/QueryParser_Benchmarks.cs b/benchmarks/Query/QueryParser_Benchmarks.cs index 61fe3b1bc2..de82baa60f 100644 --- a/benchmarks/Query/QueryParser_Benchmarks.cs +++ b/benchmarks/Query/QueryParser_Benchmarks.cs @@ -24,9 +24,7 @@ public QueryParser_Benchmarks() { var controllerContextMock = new Mock(); controllerContextMock.Setup(m => m.RequestEntity).Returns(new ContextEntity { Attributes = new List { - new AttrAttribute(ATTRIBUTE) { - InternalAttributeName = ATTRIBUTE - } + new AttrAttribute(ATTRIBUTE, ATTRIBUTE) } }); var options = new JsonApiOptions(); diff --git a/src/JsonApiDotNetCore/AssemblyInfo.cs b/src/JsonApiDotNetCore/AssemblyInfo.cs index f03399b449..f11bb5d594 100644 --- a/src/JsonApiDotNetCore/AssemblyInfo.cs +++ b/src/JsonApiDotNetCore/AssemblyInfo.cs @@ -2,3 +2,4 @@ [assembly:InternalsVisibleTo("UnitTests")] [assembly:InternalsVisibleTo("JsonApiDotNetCoreExampleTests")] [assembly:InternalsVisibleTo("NoEntityFrameworkTests")] +[assembly:InternalsVisibleTo("Benchmarks")] diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs index 9fa869aeb0..5be036636d 100644 --- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs +++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs @@ -21,7 +21,7 @@ internal AttrAttribute(string publicName, string internalName, bool isImmutable } public string PublicAttributeName { get; } - public string InternalAttributeName { get; } + public string InternalAttributeName { get; internal set; } public bool IsImmutable { get; } public bool IsFilterable { get; } public bool IsSortable { get; } diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs index 379458014b..b4fd1b42ec 100644 --- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs @@ -1,14 +1,10 @@ -using System.Reflection; - namespace JsonApiDotNetCore.Models { public class HasManyAttribute : RelationshipAttribute { public HasManyAttribute(string publicName, Link documentLinks = Link.All) : base(publicName, documentLinks) - { - PublicRelationshipName = publicName; - } + { } public override void SetValue(object entity, object newValue) { diff --git a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs index 296b71369e..0dd20e73e7 100644 --- a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs @@ -1,14 +1,10 @@ -using System.Reflection; - namespace JsonApiDotNetCore.Models { public class HasOneAttribute : RelationshipAttribute { public HasOneAttribute(string publicName, Link documentLinks = Link.All) : base(publicName, documentLinks) - { - PublicRelationshipName = publicName; - } + { } public override void SetValue(object entity, object newValue) { diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 4f6d42f47e..852b602bea 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -11,8 +11,8 @@ protected RelationshipAttribute(string publicName, Link documentLinks) } public string PublicRelationshipName { get; } - public string InternalRelationshipName { get; } - public Type Type { get; } + public string InternalRelationshipName { get; internal set; } + public Type Type { get; internal set; } public bool IsHasMany => GetType() == typeof(HasManyAttribute); public bool IsHasOne => GetType() == typeof(HasOneAttribute); public Link DocumentLinks { get; } = Link.All; From cb0780f48f64a4bd5802ee44ebaa9f19f7008a55 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 3 Jan 2018 06:00:41 -0600 Subject: [PATCH 065/227] test(acceptance): verify filter/sort limitations --- .../Models/TodoItem.cs | 2 +- .../Acceptance/Spec/AttributeFilterTests.cs | 37 +++++++++++-------- .../Acceptance/Spec/AttributeSortTests.cs | 34 +++++++++++++++++ 3 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs b/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs index 7257835791..fecd16319d 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs @@ -22,7 +22,7 @@ public TodoItem() [Attr("created-date")] public DateTime CreatedDate { get; set; } - [Attr("achieved-date")] + [Attr("achieved-date", isFilterable: false, isSortable: false)] public DateTime? AchievedDate { get; set; } public int? OwnerId { get; set; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index 740a61193c..dd7c673b4c 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -8,8 +9,6 @@ using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; using Newtonsoft.Json; using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; @@ -44,17 +43,13 @@ public async Task Can_Filter_On_Guid_Properties() var todoItem = _todoItemFaker.Generate(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); - - var builder = new WebHostBuilder() - .UseStartup(); + var httpMethod = new HttpMethod("GET"); var route = $"/api/v1/todo-items?filter[guid-property]={todoItem.GuidProperty}"; - var server = new TestServer(builder); - var client = server.CreateClient(); var request = new HttpRequestMessage(httpMethod, route); // act - var response = await client.SendAsync(request); + var response = await _fixture.Client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); var deserializedBody = _fixture .GetService() @@ -68,7 +63,6 @@ public async Task Can_Filter_On_Guid_Properties() Assert.Equal(todoItem.GuidProperty, todoItemResponse.GuidProperty); } - [Fact] public async Task Can_Filter_On_Related_Attrs() { @@ -79,17 +73,13 @@ public async Task Can_Filter_On_Related_Attrs() todoItem.Owner = person; context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); - - var builder = new WebHostBuilder() - .UseStartup(); + var httpMethod = new HttpMethod("GET"); var route = $"/api/v1/todo-items?include=owner&filter[owner.first-name]={person.FirstName}"; - var server = new TestServer(builder); - var client = server.CreateClient(); var request = new HttpRequestMessage(httpMethod, route); // act - var response = await client.SendAsync(request); + var response = await _fixture.Client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); var documents = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); var included = documents.Included; @@ -101,5 +91,20 @@ public async Task Can_Filter_On_Related_Attrs() foreach(var item in included) Assert.Equal(person.FirstName, item.Attributes["first-name"]); } + + [Fact] + public async Task Cannot_Filter_If_Explicitly_Forbidden() + { + // arrange + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?include=owner&filter[achieved-date]={DateTime.UtcNow.Date}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + + // assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs new file mode 100644 index 0000000000..8525f251d1 --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs @@ -0,0 +1,34 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using JsonApiDotNetCoreExample; +using Xunit; + +namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec +{ + [Collection("WebHostCollection")] + public class AttributeSortTests + { + private TestFixture _fixture; + + public AttributeSortTests(TestFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Cannot_Sort_If_Explicitly_Forbidden() + { + // arrange + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?include=owner&sort=achieved-date"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + + // assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + } +} From ebcb575fdfe87fea1949de5cb14dd433436cabc0 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 06:17:57 -0600 Subject: [PATCH 066/227] chore(csproj): upgrade xunit and include dotnet watch --- build/dependencies.props | 2 +- .../JsonApiDotNetCoreExampleTests.csproj | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 13b9ba4ecb..0ef1b750a7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,7 +5,7 @@ 4.7.10 - 2.2.0 + 2.3.1 8.0.1-beta-1 diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj index 1b40e2dd73..43500cb84b 100755 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -30,5 +30,9 @@
- + + + + +
From 9f1beab49c5c83e41df3a2f53615aeeca063e907 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 06:18:49 -0600 Subject: [PATCH 067/227] feat(DbContextReolver): make the implementation generic and remove injection of DbContext --- .../Data/DbContextResolver.cs | 8 ++++---- .../IServiceCollectionExtensions.cs | 4 ++-- .../Internal/Generics/GenericProcessor.cs | 5 +++-- .../Generics/GenericProcessorFactory.cs | 6 ++++-- .../IServiceCollectionExtensionsTests.cs | 20 +++++++++---------- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DbContextResolver.cs b/src/JsonApiDotNetCore/Data/DbContextResolver.cs index 8aedee0f4e..7cfe0a4278 100644 --- a/src/JsonApiDotNetCore/Data/DbContextResolver.cs +++ b/src/JsonApiDotNetCore/Data/DbContextResolver.cs @@ -1,14 +1,14 @@ -using System; using JsonApiDotNetCore.Extensions; using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Data { - public class DbContextResolver : IDbContextResolver + public class DbContextResolver : IDbContextResolver + where TContext : DbContext { - private readonly DbContext _context; + private readonly TContext _context; - public DbContextResolver(DbContext context) + public DbContextResolver(TContext context) { _context = context; } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index afcc11ee8d..1549e77e0f 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -77,7 +77,8 @@ public static void AddJsonApiInternals( if (jsonApiOptions.ContextGraph == null) jsonApiOptions.BuildContextGraph(null); - services.AddScoped(typeof(DbContext), typeof(TContext)); + services.AddScoped>(); + AddJsonApiInternals(services, jsonApiOptions); } @@ -91,7 +92,6 @@ public static void AddJsonApiInternals( services.AddSingleton(new DbContextOptionsBuilder().Options); } - services.AddScoped(); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>)); diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs index ce76b47dae..781f8ae7f3 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; @@ -10,9 +11,9 @@ namespace JsonApiDotNetCore.Internal.Generics public class GenericProcessor : IGenericProcessor where T : class, IIdentifiable { private readonly DbContext _context; - public GenericProcessor(DbContext context) + public GenericProcessor(IDbContextResolver contextResolver) { - _context = context; + _context = contextResolver.GetContext(); } public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable relationshipIds) diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index a238e4ef9f..6918976590 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,4 +1,5 @@ using System; +using JsonApiDotNetCore.Data; using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Internal.Generics @@ -8,10 +9,11 @@ public class GenericProcessorFactory : IGenericProcessorFactory private readonly DbContext _dbContext; private readonly IServiceProvider _serviceProvider; - public GenericProcessorFactory(DbContext dbContext, + public GenericProcessorFactory( + IDbContextResolver dbContextResolver, IServiceProvider serviceProvider) { - _dbContext = dbContext; + _dbContext = dbContextResolver.GetContext(); _serviceProvider = serviceProvider; } diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs index 95b05df096..5d68306493 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs @@ -1,19 +1,19 @@ -using Xunit; using JsonApiDotNetCore.Builders; -using Microsoft.Extensions.DependencyInjection; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Configuration; -using Microsoft.EntityFrameworkCore; using JsonApiDotNetCore.Data; +using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Formatters; using JsonApiDotNetCore.Internal; -using Microsoft.AspNetCore.Http; +using JsonApiDotNetCore.Internal.Generics; +using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Data; -using Microsoft.Extensions.Caching.Memory; using JsonApiDotNetCoreExample.Models; -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Formatters; -using JsonApiDotNetCore.Internal.Generics; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Xunit; namespace JsonApiDotNetCoreExampleTests.Unit.Extensions { @@ -36,7 +36,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() var provider = services.BuildServiceProvider(); // assert - Assert.NotNull(provider.GetService()); + Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService(typeof(IEntityRepository))); Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); From 6404ba18892716f802a4bc47a6d62a05d6b6e30c Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 19 Dec 2017 12:51:51 -0600 Subject: [PATCH 068/227] feat(*): remove non-EF dependencies on DbContextResolver --- src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs | 9 +++++---- .../Internal/Generics/GenericProcessorFactory.cs | 8 +------- src/JsonApiDotNetCore/Services/IJsonApiContext.cs | 3 --- src/JsonApiDotNetCore/Services/JsonApiContext.cs | 6 ------ .../Repositories/AuthorizedTodoItemsRepository.cs | 3 ++- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 1199389c60..7e7f4345f4 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -20,8 +20,9 @@ public class DefaultEntityRepository { public DefaultEntityRepository( ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) - : base(loggerFactory, jsonApiContext) + IJsonApiContext jsonApiContext, + IDbContextResolver contextResolver) + : base(loggerFactory, jsonApiContext, contextResolver) { } } @@ -50,9 +51,9 @@ public DefaultEntityRepository( public DefaultEntityRepository( ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) + IJsonApiContext jsonApiContext, + IDbContextResolver contextResolver) { - var contextResolver = jsonApiContext.GetDbContextResolver(); _context = contextResolver.GetContext(); _dbSet = contextResolver.GetDbSet(); _jsonApiContext = jsonApiContext; diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 6918976590..4b4e76525c 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,19 +1,13 @@ using System; -using JsonApiDotNetCore.Data; -using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Internal.Generics { public class GenericProcessorFactory : IGenericProcessorFactory { - private readonly DbContext _dbContext; private readonly IServiceProvider _serviceProvider; - public GenericProcessorFactory( - IDbContextResolver dbContextResolver, - IServiceProvider serviceProvider) + public GenericProcessorFactory(IServiceProvider serviceProvider) { - _dbContext = dbContextResolver.GetContext(); _serviceProvider = serviceProvider; } diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 7b1b9e67a8..ee7ee10a35 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Reflection; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; @@ -29,6 +27,5 @@ public interface IJsonApiContext Dictionary RelationshipsToUpdate { get; set; } Type ControllerType { get; set; } TAttribute GetControllerAttribute() where TAttribute : Attribute; - IDbContextResolver GetDbContextResolver(); } } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index b223e47bf5..5304d77b29 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -3,7 +3,6 @@ using System.Linq; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; @@ -15,12 +14,10 @@ namespace JsonApiDotNetCore.Services public class JsonApiContext : IJsonApiContext { private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IDbContextResolver _contextResolver; private readonly IQueryParser _queryParser; private readonly IControllerContext _controllerContext; public JsonApiContext( - IDbContextResolver contextResolver, IContextGraph contextGraph, IHttpContextAccessor httpContextAccessor, JsonApiOptions options, @@ -29,7 +26,6 @@ public JsonApiContext( IQueryParser queryParser, IControllerContext controllerContext) { - _contextResolver = contextResolver; ContextGraph = contextGraph; _httpContextAccessor = httpContextAccessor; Options = options; @@ -81,8 +77,6 @@ public IJsonApiContext ApplyContext(object controller) return this; } - public IDbContextResolver GetDbContextResolver() => _contextResolver; - private PageManager GetPageManager() { if (Options.DefaultPageSize == 0 && (QuerySet == null || QuerySet.PageQuery.PageSize == 0)) diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs index 7e9abf3784..32cb24cdcf 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Repositories/AuthorizedTodoItemsRepository.cs @@ -16,8 +16,9 @@ public class AuthorizedTodoItemsRepository : DefaultEntityRepository public AuthorizedTodoItemsRepository( ILoggerFactory loggerFactory, IJsonApiContext jsonApiContext, + IDbContextResolver contextResolver, IAuthorizationService authService) - : base(loggerFactory, jsonApiContext) + : base(loggerFactory, jsonApiContext, contextResolver) { _logger = loggerFactory.CreateLogger(); _authService = authService; From 0045fcd41006fa8380c1e3d9fbabbc2c02ca7755 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 19 Dec 2017 12:52:15 -0600 Subject: [PATCH 069/227] ci(Build.ps1): check exit codes --- Build.ps1 | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Build.ps1 b/Build.ps1 index 8b4e2cf44c..e51473adf2 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -9,34 +9,52 @@ function Get-Version-Suffix-From-Tag return $final } +function CheckLastExitCode { + param ([int[]]$SuccessCodes = @(0), [scriptblock]$CleanupScript=$null) + + if ($SuccessCodes -notcontains $LastExitCode) { + $msg = "EXE RETURNED EXIT CODE $LastExitCode" + throw $msg + } +} + $revision = @{ $true = $env:APPVEYOR_BUILD_NUMBER; $false = 1 }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL]; $revision = "{0:D4}" -f [convert]::ToInt32($revision, 10) dotnet restore dotnet test ./test/UnitTests/UnitTests.csproj +CheckLastExitCode + dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +CheckLastExitCode + dotnet test ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +CheckLastExitCode dotnet build .\src\JsonApiDotNetCore -c Release +CheckLastExitCode -echo "APPVEYOR_REPO_TAG: $env:APPVEYOR_REPO_TAG" +Write-Output "APPVEYOR_REPO_TAG: $env:APPVEYOR_REPO_TAG" If($env:APPVEYOR_REPO_TAG -eq $true) { $revision = Get-Version-Suffix-From-Tag - echo "VERSION-SUFFIX: $revision" + Write-Output "VERSION-SUFFIX: $revision" IF ([string]::IsNullOrWhitespace($revision)){ - echo "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts" + Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts" dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts + CheckLastExitCode } Else { - echo "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision" + Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision" dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision + CheckLastExitCode } } Else { - echo "VERSION-SUFFIX: alpha1-$revision" - echo "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision" + Write-Output "VERSION-SUFFIX: alpha1-$revision" + Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision" dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision + CheckLastExitCode } \ No newline at end of file From 318582ee558719d72c94844bd4c8bf9a8944e7f7 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 19 Dec 2017 12:54:36 -0600 Subject: [PATCH 070/227] tests(DefaultEntityRepository): fix test setup --- test/UnitTests/Data/DefaultEntityRepository_Tests.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs index e596b35317..50d24409f8 100644 --- a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs +++ b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs @@ -89,13 +89,10 @@ private DefaultEntityRepository GetRepository() .Setup(m => m.RelationshipsToUpdate) .Returns(_relationshipsToUpdate); - _jsonApiContextMock - .Setup(m => m.GetDbContextResolver()) - .Returns(_contextResolverMock.Object); - return new DefaultEntityRepository( _loggFactoryMock.Object, - _jsonApiContextMock.Object); + _jsonApiContextMock.Object, + _contextResolverMock.Object); } } } From 2cb6addce31720f0df8f7e343507128820ac77b6 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 19 Dec 2017 13:13:42 -0600 Subject: [PATCH 071/227] chore(DefaultEntityRepository): drop obsolete constructor --- .../Data/DefaultEntityRepository.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 7e7f4345f4..5b5b0d1a55 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -36,19 +36,6 @@ public class DefaultEntityRepository private readonly IJsonApiContext _jsonApiContext; private readonly IGenericProcessorFactory _genericProcessorFactory; - [Obsolete("DbContext is no longer directly injected into the ctor. Use JsonApiContext.GetDbContextResolver() instead")] - public DefaultEntityRepository( - DbContext context, - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) - { - _context = context; - _dbSet = context.GetDbSet(); - _jsonApiContext = jsonApiContext; - _logger = loggerFactory.CreateLogger>(); - _genericProcessorFactory = _jsonApiContext.GenericProcessorFactory; - } - public DefaultEntityRepository( ILoggerFactory loggerFactory, IJsonApiContext jsonApiContext, From 77933c8585421e85ea63122da870bcafdc79bf86 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 05:49:24 -0600 Subject: [PATCH 072/227] chore(ContextGraph): remove publicly accessible member exposes unnecessary implementation details --- .../Builders/ContextGraphBuilder.cs | 13 +++++------- .../Internal/ContextGraph.cs | 20 +++++++++++++------ .../Internal/IContextGraph.cs | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index e47dec2065..8b35584d0a 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; -using Microsoft.EntityFrameworkCore; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Extensions; -using System.Linq; +using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Builders { @@ -20,11 +20,8 @@ public IContextGraph Build() // this must be done at build so that call order doesn't matter _entities.ForEach(e => e.Links = GetLinkFlags(e.EntityType)); - var graph = new ContextGraph() - { - Entities = _entities, - UsesDbContext = _usesDbContext - }; + var graph = new ContextGraph(_entities, _usesDbContext); + return graph; } diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs index 163196341b..bc3f037bf2 100644 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ContextGraph.cs @@ -1,20 +1,28 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace JsonApiDotNetCore.Internal { public class ContextGraph : IContextGraph { - public List Entities { get; set; } - public bool UsesDbContext { get; set; } + private List _entities; + + public ContextGraph() { } + + public ContextGraph(List entities, bool usesDbContext) + { + _entities = entities; + UsesDbContext = usesDbContext; + } + + public bool UsesDbContext { get; } public ContextEntity GetContextEntity(string entityName) - => Entities.SingleOrDefault(e => string.Equals(e.EntityName, entityName, StringComparison.OrdinalIgnoreCase)); + => _entities.SingleOrDefault(e => string.Equals(e.EntityName, entityName, StringComparison.OrdinalIgnoreCase)); public ContextEntity GetContextEntity(Type entityType) - => Entities.SingleOrDefault(e => e.EntityType == entityType); + => _entities.SingleOrDefault(e => e.EntityType == entityType); public object GetRelationship(TParent entity, string relationshipName) { @@ -33,7 +41,7 @@ public object GetRelationship(TParent entity, string relationshipName) public string GetRelationshipName(string relationshipName) { var entityType = typeof(TParent); - return Entities + return _entities .SingleOrDefault(e => e.EntityType == entityType) ?.Relationships .SingleOrDefault(r => string.Equals(r.PublicRelationshipName, relationshipName, StringComparison.OrdinalIgnoreCase)) diff --git a/src/JsonApiDotNetCore/Internal/IContextGraph.cs b/src/JsonApiDotNetCore/Internal/IContextGraph.cs index 707d6fd32d..5aa05bdacd 100644 --- a/src/JsonApiDotNetCore/Internal/IContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/IContextGraph.cs @@ -8,6 +8,6 @@ public interface IContextGraph string GetRelationshipName(string relationshipName); ContextEntity GetContextEntity(string dbSetName); ContextEntity GetContextEntity(Type entityType); - bool UsesDbContext { get; set; } + bool UsesDbContext { get; } } } From 16719acce01ec91a1dbb26e4485820620cce2ed3 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 05:49:55 -0600 Subject: [PATCH 073/227] chore(EntityResourceService): remove unused var declaration --- src/JsonApiDotNetCore/Services/EntityResourceService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 7db499fd5e..3fc143e1f3 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -166,8 +166,6 @@ private async Task> ApplyPageQueryAsync(IQueryable entities) if (!pageManager.IsPaginated) return entities; - var query = _jsonApiContext.QuerySet?.PageQuery ?? new PageQuery(); - _logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} with {pageManager.PageSize} entities"); return await _entities.PageAsync(entities, pageManager.PageSize, pageManager.CurrentPage); From 8b59408ac2be04c2ef91c9730d4cd042b680c900 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 05:50:34 -0600 Subject: [PATCH 074/227] chore(example csproj): remove unnecessary members --- .../JsonApiDotNetCoreExampleTests.csproj | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj index 43500cb84b..da92260546 100755 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -2,12 +2,7 @@ $(NetCoreAppVersion) - true - JsonApiDotNetCoreExampleTests - Exe - JsonApiDotNetCoreExampleTests - true - true + false From d706d376734d6ca7d1b4ccf3dda98c7bbdc2fb7d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 19 Dec 2017 05:52:28 -0600 Subject: [PATCH 075/227] chore(IQueryableExtensions): fix bad comments --- src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index c40d61b517..ee6b4451c5 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -163,11 +163,10 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression body = Expression.LessThanOrEqual(left, right); break; case FilterOperations.ge: - // {model.Id <= 1} + // {model.Id >= 1} body = Expression.GreaterThanOrEqual(left, right); break; case FilterOperations.like: - // {model.Id <= 1} body = Expression.Call(left, "Contains", null, right); break; default: From 604f4870b9b404d9747ce91166d4c1d4475bedcd Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 3 Jan 2018 06:35:28 -0600 Subject: [PATCH 076/227] chore(EntityResourceService): consolidate ShouldIncludeRelationships check --- src/JsonApiDotNetCore/Services/EntityResourceService.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 3fc143e1f3..cc1ba897e1 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -4,7 +4,6 @@ using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -47,7 +46,7 @@ public virtual async Task> GetAsync() entities = ApplySortAndFilterQuery(entities); - if (_jsonApiContext.QuerySet?.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0) + if (ShouldIncludeRelationships()) entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships); if (_jsonApiContext.Options.IncludeTotalRecordCount) @@ -61,13 +60,16 @@ public virtual async Task> GetAsync() public virtual async Task GetAsync(TId id) { T entity; - if (_jsonApiContext.QuerySet?.IncludedRelationships != null) + if (ShouldIncludeRelationships()) entity = await GetWithRelationshipsAsync(id); else entity = await _entities.GetAsync(id); return entity; } + private bool ShouldIncludeRelationships() + => (_jsonApiContext.QuerySet?.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0); + private async Task GetWithRelationshipsAsync(TId id) { var query = _entities.Get(); From 5f6b9bcad28120a79271adf7534971a1d1ad4e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Tue, 2 Jan 2018 10:46:49 +0100 Subject: [PATCH 077/227] moved Sort into an IQueryable extension method --- .../Data/DefaultEntityRepository.cs | 12 +----------- .../Extensions/IQueryableExtensions.cs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 5b5b0d1a55..b31f4abaed 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -69,17 +69,7 @@ public virtual IQueryable Filter(IQueryable entities, FilterQu public virtual IQueryable Sort(IQueryable entities, List sortQueries) { - if (sortQueries == null || sortQueries.Count == 0) - return entities; - - var orderedEntities = entities.Sort(sortQueries[0]); - - if (sortQueries.Count <= 1) return orderedEntities; - - for (var i = 1; i < sortQueries.Count; i++) - orderedEntities = orderedEntities.Sort(sortQueries[i]); - - return orderedEntities; + return entities.Sort(sortQueries); } public virtual async Task GetAsync(TId id) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index ee6b4451c5..9ba37057a7 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -2,15 +2,30 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using System.Reflection; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; +using JsonApiDotNetCore.Services; namespace JsonApiDotNetCore.Extensions { // ReSharper disable once InconsistentNaming public static class IQueryableExtensions { + public static IQueryable Sort(this IQueryable source, List sortQueries) + { + if (sortQueries == null || sortQueries.Count == 0) + return source; + + var orderedEntities = source.Sort(sortQueries[0]); + + if (sortQueries.Count <= 1) return orderedEntities; + + for (var i = 1; i < sortQueries.Count; i++) + orderedEntities = orderedEntities.Sort(sortQueries[i]); + + return orderedEntities; + } + public static IOrderedQueryable Sort(this IQueryable source, SortQuery sortQuery) { return sortQuery.Direction == SortDirection.Descending From 872b74b1fc10dc597574d66580cf6a890b2b6f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Tue, 2 Jan 2018 10:53:18 +0100 Subject: [PATCH 078/227] moved Page into an IQueryable extension method --- .../Data/DefaultEntityRepository.cs | 31 +++---- .../Extensions/IQueryableExtensions.cs | 16 ++++ .../Acceptance/Spec/PagingTests.cs | 34 ++++---- .../Data/DefaultEntityRepository_Tests.cs | 80 ++++++++++++++++++- 4 files changed, 123 insertions(+), 38 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index b31f4abaed..ed090b8f71 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -146,27 +146,22 @@ public virtual IQueryable Include(IQueryable entities, string public virtual async Task> PageAsync(IQueryable entities, int pageSize, int pageNumber) { - if (pageSize > 0) + if (pageNumber >= 0) { - if (pageNumber == 0) - pageNumber = 1; - - if (pageNumber > 0) - return await entities - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) - .ToListAsync(); - else // page from the end of the set - return (await entities - .OrderByDescending(t => t.Id) - .Skip((Math.Abs(pageNumber) - 1) * pageSize) - .Take(pageSize) - .ToListAsync()) - .OrderBy(t => t.Id) - .ToList(); + return await entities.PageForward(pageSize, pageNumber).ToListAsync(); } - return await entities.ToListAsync(); + // since EntityFramework does not support IQueryable.Reverse(), we need to know the number of queried entities + int numberOfEntities = await this.CountAsync(entities); + + // may be negative + int virtualFirstIndex = numberOfEntities - pageSize * Math.Abs(pageNumber); + int numberOfElementsInPage = Math.Min(pageSize, virtualFirstIndex + pageSize); + + return await entities + .Skip(virtualFirstIndex) + .Take(numberOfElementsInPage) + .ToListAsync(); } } } diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 9ba37057a7..587a295fa0 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -216,5 +216,21 @@ public static IQueryable Select(this IQueryable sourc Expression.Call(typeof(Queryable), "Select", new[] { sourceType, resultType }, source.Expression, Expression.Quote(selector))); } + + public static IQueryable PageForward(this IQueryable source, int pageSize, int pageNumber) + { + if (pageSize > 0) + { + if (pageNumber == 0) + pageNumber = 1; + + if (pageNumber > 0) + return source + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + } + + return source; + } } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs index 02dbd019e0..7d8401f78d 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs @@ -1,7 +1,9 @@ +using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; using Bogus; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Models; @@ -50,7 +52,7 @@ public async Task Can_Paginate_TodoItems_From_Start() { const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; var person = new Person(); - var todoItems = _todoItemFaker.Generate(totalCount); + var todoItems = _todoItemFaker.Generate(totalCount).ToList(); foreach (var todoItem in todoItems) todoItem.Owner = person; @@ -70,12 +72,8 @@ public async Task Can_Paginate_TodoItems_From_Start() { var body = await response.Content.ReadAsStringAsync(); var deserializedBody = GetService().DeserializeList(body); - Assert.NotEmpty(deserializedBody); - Assert.Equal(expectedEntitiesPerPage, deserializedBody.Count); - - var expectedTodoItems = Context.TodoItems.Take(2); - foreach (var todoItem in expectedTodoItems) - Assert.NotNull(deserializedBody.SingleOrDefault(t => t.Id == todoItem.Id)); + var expectedTodoItems = new[] { todoItems[0], todoItems[1] }; + Assert.Equal(expectedTodoItems, deserializedBody, new IdComparer()); } [Fact] @@ -84,7 +82,7 @@ public async Task Can_Paginate_TodoItems_From_End() { const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; var person = new Person(); - var todoItems = _todoItemFaker.Generate(totalCount); + var todoItems = _todoItemFaker.Generate(totalCount).ToList(); foreach (var todoItem in todoItems) todoItem.Owner = person; @@ -104,18 +102,16 @@ public async Task Can_Paginate_TodoItems_From_End() { var body = await response.Content.ReadAsStringAsync(); var deserializedBody = GetService().DeserializeList(body); - Assert.NotEmpty(deserializedBody); - Assert.Equal(expectedEntitiesPerPage, deserializedBody.Count); + var expectedTodoItems = new[] { todoItems[totalCount - 2], todoItems[totalCount - 1] }; + Assert.Equal(expectedTodoItems, deserializedBody, new IdComparer()); + } - var expectedTodoItems = Context.TodoItems - .OrderByDescending(t => t.Id) - .Take(2) - .ToList() - .OrderBy(t => t.Id) - .ToList(); + private class IdComparer : IEqualityComparer + where T : IIdentifiable + { + public bool Equals(T x, T y) => x?.StringId == y?.StringId; - for (int i = 0; i < expectedEntitiesPerPage; i++) - Assert.Equal(expectedTodoItems[i].Id, deserializedBody[i].Id); + public int GetHashCode(T obj) => obj?.StringId?.GetHashCode() ?? 0; } } -} \ No newline at end of file +} diff --git a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs index 50d24409f8..a8ec56fe9c 100644 --- a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs +++ b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs @@ -13,7 +13,8 @@ using Microsoft.Extensions.Logging; using JsonApiDotNetCore.Services; using System.Threading.Tasks; - +using System.Linq; + namespace UnitTests.Data { public class DefaultEntityRepository_Tests : JsonApiControllerMixin @@ -93,6 +94,83 @@ private DefaultEntityRepository GetRepository() _loggFactoryMock.Object, _jsonApiContextMock.Object, _contextResolverMock.Object); + } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + [InlineData(-10)] + public async Task Page_When_PageSize_Is_NonPositive_Does_Nothing(int pageSize) + { + var todoItems = DbSetMock.Create(TodoItems(2, 3, 1)).Object; + var repository = GetRepository(); + + var result = await repository.PageAsync(todoItems, pageSize, 3); + + Assert.Equal(TodoItems(2, 3, 1), result, new IdComparer()); + } + + [Fact] + public async Task Page_When_PageNumber_Is_Zero_Pretends_PageNumber_Is_One() + { + var todoItems = DbSetMock.Create(TodoItems(2, 3, 1)).Object; + var repository = GetRepository(); + + var result = await repository.PageAsync(todoItems, 1, 0); + + Assert.Equal(TodoItems(2), result, new IdComparer()); + } + + [Fact] + public async Task Page_When_PageNumber_Of_PageSize_Does_Not_Exist_Return_Empty_Queryable() + { + var todoItems = DbSetMock.Create(TodoItems(2, 3, 1)).Object; + var repository = GetRepository(); + + var result = await repository.PageAsync(todoItems, 2, 3); + + Assert.Empty(result); + } + + [Theory] + [InlineData(3, 2, new[] { 4, 5, 6 })] + [InlineData(8, 2, new[] { 9 })] + [InlineData(20, 1, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })] + public async Task Page_When_PageNumber_Is_Positive_Returns_PageNumberTh_Page_Of_Size_PageSize(int pageSize, int pageNumber, int[] expectedResult) + { + var todoItems = DbSetMock.Create(TodoItems(1, 2, 3, 4, 5, 6, 7, 8, 9)).Object; + var repository = GetRepository(); + + var result = await repository.PageAsync(todoItems, pageSize, pageNumber); + + Assert.Equal(TodoItems(expectedResult), result, new IdComparer()); + } + + [Theory] + [InlineData(6, -1, new[] { 4, 5, 6, 7, 8, 9 })] + [InlineData(6, -2, new[] { 1, 2, 3 })] + [InlineData(20, -1, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 })] + public async Task Page_When_PageNumber_Is_Negative_Returns_PageNumberTh_Page_From_End(int pageSize, int pageNumber, int[] expectedIds) + { + var todoItems = DbSetMock.Create(TodoItems(1, 2, 3, 4, 5, 6, 7, 8, 9)).Object; + var repository = GetRepository(); + + var result = await repository.PageAsync(todoItems, pageSize, pageNumber); + + Assert.Equal(TodoItems(expectedIds), result, new IdComparer()); + } + + private static TodoItem[] TodoItems(params int[] ids) + { + return ids.Select(id => new TodoItem { Id = id }).ToArray(); + } + + private class IdComparer : IEqualityComparer + where T : IIdentifiable + { + public bool Equals(T x, T y) => x?.StringId == y?.StringId; + + public int GetHashCode(T obj) => obj?.StringId?.GetHashCode() ?? 0; } } } From 916e03c2e7b02224df6e2ecb51561f0b66075c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Tue, 2 Jan 2018 11:07:26 +0100 Subject: [PATCH 079/227] moved Filter into an IQueryable extension method --- src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs | 8 +------- .../Extensions/IQueryableExtensions.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index ed090b8f71..6c270c7396 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -58,13 +58,7 @@ public virtual IQueryable Get() public virtual IQueryable Filter(IQueryable entities, FilterQuery filterQuery) { - if (filterQuery == null) - return entities; - - if (filterQuery.IsAttributeOfRelationship) - return entities.Filter(new RelatedAttrFilterQuery(_jsonApiContext, filterQuery)); - - return entities.Filter(new AttrFilterQuery(_jsonApiContext, filterQuery)); + return entities.Filter(_jsonApiContext, filterQuery); } public virtual IQueryable Sort(IQueryable entities, List sortQueries) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 587a295fa0..6bbb1115b2 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -77,6 +77,17 @@ private static IOrderedQueryable CallGenericOrderMethod(IQuery return (IOrderedQueryable)result; } + public static IQueryable Filter(this IQueryable source, IJsonApiContext jsonApiContext, FilterQuery filterQuery) + { + if (filterQuery == null) + return source; + + if (filterQuery.IsAttributeOfRelationship) + return source.Filter(new RelatedAttrFilterQuery(jsonApiContext, filterQuery)); + + return source.Filter(new AttrFilterQuery(jsonApiContext, filterQuery)); + } + public static IQueryable Filter(this IQueryable source, AttrFilterQuery filterQuery) { if (filterQuery == null) From 0209baef26fbf205d5e18f596c2519202a90f894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Tue, 2 Jan 2018 13:49:48 +0100 Subject: [PATCH 080/227] removed dependency on query realization from EntityResourceService --- .../Data/DefaultEntityRepository.cs | 15 +++++++++++++++ .../Data/IEntityReadRepository.cs | 6 ++++++ .../Services/EntityResourceService.cs | 7 +++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 6c270c7396..45627fd1a6 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -157,5 +157,20 @@ public virtual async Task> PageAsync(IQueryable en .Take(numberOfElementsInPage) .ToListAsync(); } + + public async Task CountAsync(IQueryable entities) + { + return await entities.CountAsync(); + } + + public Task FirstOrDefaultAsync(IQueryable entities) + { + return entities.FirstOrDefaultAsync(); + } + + public async Task> ToListAsync(IQueryable entities) + { + return await entities.ToListAsync(); + } } } diff --git a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs index aad16a9efc..a86b7334a9 100644 --- a/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityReadRepository.cs @@ -27,5 +27,11 @@ public interface IEntityReadRepository Task GetAsync(TId id); Task GetAndIncludeAsync(TId id, string relationshipName); + + Task CountAsync(IQueryable entities); + + Task FirstOrDefaultAsync(IQueryable entities); + + Task> ToListAsync(IQueryable entities); } } diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index cc1ba897e1..7cf640542a 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -5,7 +5,6 @@ using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Services @@ -50,7 +49,7 @@ public virtual async Task> GetAsync() entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships); if (_jsonApiContext.Options.IncludeTotalRecordCount) - _jsonApiContext.PageManager.TotalRecords = await entities.CountAsync(); + _jsonApiContext.PageManager.TotalRecords = await _entities.CountAsync(entities); // pagination should be done last since it will execute the query var pagedEntities = await ApplyPageQueryAsync(entities); @@ -72,12 +71,12 @@ private bool ShouldIncludeRelationships() private async Task GetWithRelationshipsAsync(TId id) { - var query = _entities.Get(); + var query = _entities.Get().Where(e => e.Id.Equals(id)); _jsonApiContext.QuerySet.IncludedRelationships.ForEach(r => { query = _entities.Include(query, r); }); - return await query.FirstOrDefaultAsync(e => e.Id.Equals(id)); + return await _entities.FirstOrDefaultAsync(query); } public virtual async Task GetRelationshipsAsync(TId id, string relationshipName) From 70cb94c38554a592cdde8f77f419dbc6aaca71db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=BCbner?= Date: Wed, 3 Jan 2018 13:41:20 +0100 Subject: [PATCH 081/227] realize query when there is no paging in EntityResourceService.ApplyPageQueryAsync --- src/JsonApiDotNetCore/Services/EntityResourceService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 7cf640542a..c0b4847f13 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -165,7 +165,7 @@ private async Task> ApplyPageQueryAsync(IQueryable entities) { var pageManager = _jsonApiContext.PageManager; if (!pageManager.IsPaginated) - return entities; + return await _entities.ToListAsync(entities); _logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} with {pageManager.PageSize} entities"); From 4425c71903a09db3fe3fa740378c6ae8a3b7e640 Mon Sep 17 00:00:00 2001 From: Lauri Heiskanen Date: Thu, 25 Jan 2018 10:59:21 +0200 Subject: [PATCH 082/227] feat/#226: Support for omitting null valued attributes from responses - NullAttributeResponseBehavior option for configuration - Support for global defaults - Support for client override using a query string parameter --- JsonApiDotnetCore.sln | 28 +++---- .../Builders/DocumentBuilder.cs | 31 ++++---- .../Builders/DocumentBuilderOptions.cs | 16 ++++ .../DocumentBuilderOptionsProvider.cs | 33 +++++++++ .../IDocumentBuilderOptionsProvider.cs | 11 +++ .../Configuration/JsonApiOptions.cs | 4 + .../NullAttributeResponseBehavior.cs | 19 +++++ .../IServiceCollectionExtensions.cs | 1 + .../Serialization/JsonApiDeSerializer.cs | 3 +- .../Services/IJsonApiContext.cs | 2 + .../Services/JsonApiContext.cs | 1 + .../DocumentBuilderBehaviour_Tests.cs | 73 +++++++++++++++++++ .../Builders/DocumentBuilder_Tests.cs | 29 ++++++++ .../Serialization/JsonApiDeSerializerTests.cs | 50 ++++++++++++- 14 files changed, 272 insertions(+), 29 deletions(-) create mode 100644 src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs create mode 100644 src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs create mode 100644 src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs create mode 100644 src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs create mode 100644 test/UnitTests/Builders/DocumentBuilderBehaviour_Tests.cs diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index 385fa4d6ad..0425e09f96 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.10 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{C0EC9E70-EB2E-436F-9D94-FA16FA774123}" EndProject @@ -30,7 +30,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportsExample", "src\Examp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{076E1AE4-FD25-4684-B826-CAAE37FEA0AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -110,22 +110,22 @@ Global {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Debug|x86.Build.0 = Debug|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.Build.0 = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|x64 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|x64 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|x86 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|x86 + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.ActiveCfg = Debug|x64 - {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.Build.0 = Debug|x64 - {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.ActiveCfg = Debug|x86 - {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.Build.0 = Debug|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.ActiveCfg = Debug|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.Build.0 = Debug|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.ActiveCfg = Debug|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x86.Build.0 = Debug|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Release|Any CPU.Build.0 = Release|Any CPU - {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.ActiveCfg = Release|x64 - {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.Build.0 = Release|x64 - {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.ActiveCfg = Release|x86 - {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.Build.0 = Release|x86 + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.ActiveCfg = Release|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.Build.0 = Release|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.ActiveCfg = Release|Any CPU + {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index ac7e1b3ade..9e2517305e 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -13,18 +13,14 @@ public class DocumentBuilder : IDocumentBuilder private readonly IJsonApiContext _jsonApiContext; private readonly IContextGraph _contextGraph; private readonly IRequestMeta _requestMeta; + private readonly DocumentBuilderOptions _documentBuilderOptions; - public DocumentBuilder(IJsonApiContext jsonApiContext) - { - _jsonApiContext = jsonApiContext; - _contextGraph = jsonApiContext.ContextGraph; - } - - public DocumentBuilder(IJsonApiContext jsonApiContext, IRequestMeta requestMeta) + public DocumentBuilder(IJsonApiContext jsonApiContext, IRequestMeta requestMeta=null, IDocumentBuilderOptionsProvider documentBuilderOptionsProvider=null) { _jsonApiContext = jsonApiContext; _contextGraph = jsonApiContext.ContextGraph; _requestMeta = requestMeta; + _documentBuilderOptions = documentBuilderOptionsProvider?.GetDocumentBuilderOptions() ?? new DocumentBuilderOptions(); ; } public Document Build(IIdentifiable entity) @@ -118,8 +114,11 @@ private DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) contextEntity.Attributes.ForEach(attr => { - if(ShouldIncludeAttribute(attr)) - data.Attributes.Add(attr.PublicAttributeName, attr.GetValue(entity)); + var attributeValue = attr.GetValue(entity); + if (ShouldIncludeAttribute(attr, attributeValue)) + { + data.Attributes.Add(attr.PublicAttributeName, attributeValue); + } }); if (contextEntity.Relationships.Count > 0) @@ -128,11 +127,17 @@ private DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) return data; } - private bool ShouldIncludeAttribute(AttrAttribute attr) + private bool ShouldIncludeAttribute(AttrAttribute attr, object attributeValue) + { + return !OmitNullValuedAttribute(attr, attributeValue) + && ((_jsonApiContext.QuerySet == null + || _jsonApiContext.QuerySet.Fields.Count == 0) + || _jsonApiContext.QuerySet.Fields.Contains(attr.InternalAttributeName)); + } + + private bool OmitNullValuedAttribute(AttrAttribute attr, object attributeValue) { - return (_jsonApiContext.QuerySet == null - || _jsonApiContext.QuerySet.Fields.Count == 0 - || _jsonApiContext.QuerySet.Fields.Contains(attr.InternalAttributeName)); + return attributeValue == null && _documentBuilderOptions.OmitNullValuedAttributes; } private void AddRelationships(DocumentData data, ContextEntity contextEntity, IIdentifiable entity) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs new file mode 100644 index 0000000000..ec19977313 --- /dev/null +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JsonApiDotNetCore.Builders +{ + public struct DocumentBuilderOptions + { + public DocumentBuilderOptions(bool omitNullValuedAttributes = false) + { + this.OmitNullValuedAttributes = omitNullValuedAttributes; + } + + public bool OmitNullValuedAttributes { get; private set; } + } +} diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs new file mode 100644 index 0000000000..af7fb78d7c --- /dev/null +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Http; + +namespace JsonApiDotNetCore.Builders +{ + public class DocumentBuilderOptionsProvider : IDocumentBuilderOptionsProvider + { + private readonly IJsonApiContext _jsonApiContext; + private readonly IHttpContextAccessor _httpContextAccessor; + + public DocumentBuilderOptionsProvider(IJsonApiContext jsonApiContext, IHttpContextAccessor httpContextAccessor) + { + _jsonApiContext = jsonApiContext; + _httpContextAccessor = httpContextAccessor; + } + + public DocumentBuilderOptions GetDocumentBuilderOptions() + { + var nullAttributeResponseBehaviorConfig = this._jsonApiContext.Options.NullAttributeResponseBehavior; + if (nullAttributeResponseBehaviorConfig.AllowClientOverride && _httpContextAccessor.HttpContext.Request.Query.TryGetValue("omitNullValuedAttributes", out var omitNullValuedAttributesQs)) + { + if (bool.TryParse(omitNullValuedAttributesQs, out var omitNullValuedAttributes)) + { + return new DocumentBuilderOptions(omitNullValuedAttributes); + } + } + return new DocumentBuilderOptions(this._jsonApiContext.Options.NullAttributeResponseBehavior.OmitNullValuedAttributes); + } + } +} diff --git a/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs new file mode 100644 index 0000000000..d8effd4fe3 --- /dev/null +++ b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JsonApiDotNetCore.Builders +{ + public interface IDocumentBuilderOptionsProvider + { + DocumentBuilderOptions GetDocumentBuilderOptions(); + } +} diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 26e16b0741..f074940d9c 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -17,6 +17,7 @@ public class JsonApiOptions public IContextGraph ContextGraph { get; set; } public bool RelativeLinks { get; set; } public bool AllowCustomQueryParameters { get; set; } + public NullAttributeResponseBehavior NullAttributeResponseBehavior { get; set; } [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] public IContractResolver JsonContractResolver @@ -29,6 +30,7 @@ public IContractResolver JsonContractResolver NullValueHandling = NullValueHandling.Ignore, ContractResolver = new DasherizedResolver() }; + internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); public void BuildContextGraph(Action builder) where TContext : DbContext @@ -49,4 +51,6 @@ public void BuildContextGraph(Action builder) ContextGraph = ContextGraphBuilder.Build(); } } + + } diff --git a/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs new file mode 100644 index 0000000000..1b10140f5e --- /dev/null +++ b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JsonApiDotNetCore.Configuration +{ + public struct NullAttributeResponseBehavior + { + public NullAttributeResponseBehavior(bool omitNullValuedAttributes = false, bool allowClientOverride = false) + { + OmitNullValuedAttributes = omitNullValuedAttributes; + AllowClientOverride = allowClientOverride; + } + + public bool OmitNullValuedAttributes { get; } + public bool AllowClientOverride { get; } + // ... + } +} diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 1549e77e0f..d75ce26c59 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -112,6 +112,7 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions jsonApiOptions) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 1c0c5014f7..6fa02c90c4 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -29,6 +29,7 @@ public object Deserialize(string requestBody) try { var document = JsonConvert.DeserializeObject(requestBody); + _jsonApiContext.DocumentMeta = document.Meta; var entity = DocumentToObject(document.Data); return entity; } @@ -222,4 +223,4 @@ private object SetHasManyRelationship(object entity, return entity; } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index ee7ee10a35..c16da81cfa 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -26,6 +26,8 @@ public interface IJsonApiContext Dictionary AttributesToUpdate { get; set; } Dictionary RelationshipsToUpdate { get; set; } Type ControllerType { get; set; } + Dictionary DocumentMeta { get; set; } + TAttribute GetControllerAttribute() where TAttribute : Attribute; } } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 5304d77b29..ef6b4159ee 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -50,6 +50,7 @@ public JsonApiContext( public Dictionary AttributesToUpdate { get; set; } = new Dictionary(); public Dictionary RelationshipsToUpdate { get; set; } = new Dictionary(); public Type ControllerType { get; set; } + public Dictionary DocumentMeta { get; set; } public IJsonApiContext ApplyContext(object controller) { diff --git a/test/UnitTests/Builders/DocumentBuilderBehaviour_Tests.cs b/test/UnitTests/Builders/DocumentBuilderBehaviour_Tests.cs new file mode 100644 index 0000000000..333950f95f --- /dev/null +++ b/test/UnitTests/Builders/DocumentBuilderBehaviour_Tests.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Http; +using Moq; +using Xunit; + +namespace UnitTests.Builders +{ + public class DocumentBuilderBehaviour_Tests + { + + [Theory] + [InlineData(null, null, null, false)] + [InlineData(false, null, null, false)] + [InlineData(true, null, null, true)] + [InlineData(false, false, "true", false)] + [InlineData(false, true, "true", true)] + [InlineData(true, true, "false", false)] + [InlineData(true, false, "false", true)] + [InlineData(null, false, "false", false)] + [InlineData(null, false, "true", false)] + [InlineData(null, true, "true", true)] + [InlineData(null, true, "false", false)] + [InlineData(null, true, "foo", false)] + [InlineData(null, false, "foo", false)] + [InlineData(true, true, "foo", true)] + [InlineData(true, false, "foo", true)] + [InlineData(null, true, null, false)] + [InlineData(null, false, null, false)] + public void CheckNullBehaviorCombination(bool? omitNullValuedAttributes, bool? allowClientOverride, string clientOverride, bool omitsNulls) + { + + NullAttributeResponseBehavior nullAttributeResponseBehavior; + if (omitNullValuedAttributes.HasValue && allowClientOverride.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(omitNullValuedAttributes.Value, allowClientOverride.Value); + }else if (omitNullValuedAttributes.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(omitNullValuedAttributes.Value); + }else if + (allowClientOverride.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(allowClientOverride: allowClientOverride.Value); + } + else + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(); + } + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupGet(m => m.Options) + .Returns(new JsonApiOptions() {NullAttributeResponseBehavior = nullAttributeResponseBehavior}); + + var httpContext = new DefaultHttpContext(); + if (clientOverride != null) + { + httpContext.Request.QueryString = new QueryString($"?omitNullValuedAttributes={clientOverride}"); + } + var httpContextAccessorMock = new Mock(); + httpContextAccessorMock.SetupGet(m => m.HttpContext).Returns(httpContext); + + var sut = new DocumentBuilderOptionsProvider(jsonApiContextMock.Object, httpContextAccessorMock.Object); + var documentBuilderOptions = sut.GetDocumentBuilderOptions(); + + Assert.Equal(omitsNulls, documentBuilderOptions.OmitNullValuedAttributes); + } + + } +} diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index 2cc4e7f7a3..7946efa058 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -16,10 +16,12 @@ public class DocumentBuilder_Tests private readonly Mock _jsonApiContextMock; private readonly PageManager _pageManager; private readonly JsonApiOptions _options; + private readonly Mock _requestMetaMock; public DocumentBuilder_Tests() { _jsonApiContextMock = new Mock(); + _requestMetaMock = new Mock(); _options = new JsonApiOptions(); @@ -141,11 +143,38 @@ public void Build_Can_Build_CustomIEnumerables() Assert.Equal(1, documents.Data.Count); } + + [Theory] + [InlineData(null,null,true)] + [InlineData(false,null,true)] + [InlineData(true,null,false)] + [InlineData(null,"foo",true)] + [InlineData(false,"foo",true)] + [InlineData(true,"foo",true)] + public void DocumentBuilderOptions(bool? omitNullValuedAttributes, + string attributeValue, + bool resultContainsAttribute) + { + var documentBuilderBehaviourMock = new Mock(); + if (omitNullValuedAttributes.HasValue) + { + documentBuilderBehaviourMock.Setup(m => m.GetDocumentBuilderOptions()) + .Returns(new DocumentBuilderOptions(omitNullValuedAttributes.Value)); + } + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object, null, omitNullValuedAttributes.HasValue ? documentBuilderBehaviourMock.Object : null); + var document = documentBuilder.Build(new Model(){StringProperty = attributeValue}); + + Assert.Equal(resultContainsAttribute, document.Data.Attributes.ContainsKey("StringProperty")); + } + private class Model : Identifiable { [HasOne("related-model", Link.None)] public RelatedModel RelatedModel { get; set; } public int RelatedModelId { get; set; } + [Attr("StringProperty")] + public string StringProperty { get; set; } + } private class RelatedModel : Identifiable diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index 5096cbac31..1e20c0359e 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; @@ -271,6 +271,54 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Rel Assert.Equal(property, result.Property); } + [Fact] + public void Sets_The_DocumentMeta_Property_In_JsonApiContext() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource("independents"); + contextGraphBuilder.AddResource("dependents"); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var genericProcessorFactoryMock = new Mock(); + + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + + var property = Guid.NewGuid().ToString(); + + var content = new Document + { + Meta = new Dictionary() { {"foo", "bar"}}, + Data = new DocumentData + { + Type = "independents", + Id = "1", + Attributes = new Dictionary { { "property", property } + }, + // a common case for this is deserialization in unit tests + Relationships = new Dictionary { { "dependent", new RelationshipData { } } + } + } + }; + + var contentString = JsonConvert.SerializeObject(content); + + // act + var result = deserializer.Deserialize(contentString); + + // assert + jsonApiContextMock.VerifySet(mock => mock.DocumentMeta = content.Meta); + } + + private class TestResource : Identifiable { [Attr("complex-member")] public ComplexType ComplexMember { get; set; } From e828dc93011b68821f4c72eb6150f9a7b82341eb Mon Sep 17 00:00:00 2001 From: Lauri Heiskanen Date: Mon, 29 Jan 2018 17:53:09 +0200 Subject: [PATCH 083/227] End to end tests for null valued attribute handling --- .../NullValuedAttributeHandlingTests.cs | 106 ++++++++++++++++++ .../IServiceCollectionExtensionsTests.cs | 1 + 2 files changed, 107 insertions(+) create mode 100644 test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs new file mode 100644 index 0000000000..250ab80d30 --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs @@ -0,0 +1,106 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCoreExample; +using JsonApiDotNetCoreExample.Data; +using JsonApiDotNetCoreExample.Models; +using Newtonsoft.Json; +using Xunit; + +namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility +{ + [Collection("WebHostCollection")] + public class NullValuedAttributeHandlingTests : IAsyncLifetime + { + private readonly TestFixture _fixture; + private readonly AppDbContext _dbContext; + private readonly TodoItem _todoItem; + + public NullValuedAttributeHandlingTests(TestFixture fixture) + { + _fixture = fixture; + _dbContext = fixture.GetService(); + _todoItem = new TodoItem + { + Description = null, + Ordinal = 1, + CreatedDate = DateTime.Now, + AchievedDate = DateTime.Now.AddDays(2) + }; + _todoItem = _dbContext.TodoItems.Add(_todoItem).Entity; + } + + public async Task InitializeAsync() + { + await _dbContext.SaveChangesAsync(); + } + + public Task DisposeAsync() + { + return Task.CompletedTask; + } + + [Theory] + [InlineData(null, null, null, false)] + [InlineData(true, null, null, true)] + [InlineData(false, true, "true", true)] + [InlineData(false, false, "true", false)] + [InlineData(true, true, "false", false)] + [InlineData(true, false, "false", true)] + [InlineData(null, false, "false", false)] + [InlineData(null, false, "true", false)] + [InlineData(null, true, "true", true)] + [InlineData(null, true, "false", false)] + [InlineData(null, true, "foo", false)] + [InlineData(null, false, "foo", false)] + [InlineData(true, true, "foo", true)] + [InlineData(true, false, "foo", true)] + [InlineData(null, true, null, false)] + [InlineData(null, false, null, false)] + public async Task CheckNullBehaviorCombination(bool? omitNullValuedAttributes, bool? allowClientOverride, + string clientOverride, bool omitsNulls) + { + + // Override some null handling options + NullAttributeResponseBehavior nullAttributeResponseBehavior; + if (omitNullValuedAttributes.HasValue && allowClientOverride.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(omitNullValuedAttributes.Value, allowClientOverride.Value); + } + else if (omitNullValuedAttributes.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(omitNullValuedAttributes.Value); + } + else if (allowClientOverride.HasValue) + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(allowClientOverride: allowClientOverride.Value); + } + else + { + nullAttributeResponseBehavior = new NullAttributeResponseBehavior(); + } + var jsonApiOptions = _fixture.GetService(); + jsonApiOptions.NullAttributeResponseBehavior = nullAttributeResponseBehavior; + jsonApiOptions.AllowCustomQueryParameters = true; + + var httpMethod = new HttpMethod("GET"); + var queryString = allowClientOverride.HasValue + ? $"?omitNullValuedAttributes={clientOverride}" + : ""; + var route = $"/api/v1/todo-items/{_todoItem.Id}{queryString}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializeBody = JsonConvert.DeserializeObject(body); + + // assert. does response contain a null valued attribute + Assert.Equal(omitsNulls, !deserializeBody.Data.Attributes.ContainsKey("description")); + + } + } + +} diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs index 5d68306493..b654727a26 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs @@ -49,6 +49,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); + Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService(typeof(GenericProcessor))); } } From f6a84eb413b711ab79fc80845e8f569eeb10560d Mon Sep 17 00:00:00 2001 From: Biarity Date: Sun, 11 Feb 2018 17:20:24 +1000 Subject: [PATCH 084/227] Fix broken url for IResourceService --- docs/ResourceServices.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ResourceServices.md b/docs/ResourceServices.md index 28629d9e36..17e7763835 100644 --- a/docs/ResourceServices.md +++ b/docs/ResourceServices.md @@ -4,7 +4,7 @@ currentMenu: services # Resource Services -The [IResourceService](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Services/IResourceService.cs) acts as a service layer between the controller and the data access +The [IResourceService](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/src/JsonApiDotNetCore/Services/Contract/IResourceService.cs) acts as a service layer between the controller and the data access layer. This allows you to customize it however you want and not be dependent upon Entity Framework. This is also a good place to implement custom business logic. @@ -123,4 +123,4 @@ public class MyResourcesController : BaseJsonApiController { public override async TaskDeleteAsync(int id) => await base.DeleteAsync(id); } -``` \ No newline at end of file +``` From 2374492e3ff21e459383873efffd20ade80354cd Mon Sep 17 00:00:00 2001 From: Biarity Date: Sat, 10 Feb 2018 18:02:44 +1000 Subject: [PATCH 085/227] Update Pagination.md --- docs/Pagination.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/Pagination.md b/docs/Pagination.md index 6d645cac2b..7d70773757 100644 --- a/docs/Pagination.md +++ b/docs/Pagination.md @@ -13,3 +13,11 @@ The following query would set the page size to 10 and get page 2. If you would like pagination implemented by default, you can specify the page size when setting up the services: + +```C# +public IServiceProvider ConfigureServices(IServiceCollection services) { + services.AddJsonApi( + opt => opt.DefaultPageSize = 10); + // ... +} +``` From 19e90b8fad1902ab763de451fcdb020006176cd1 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 17 Feb 2018 18:16:43 -0600 Subject: [PATCH 086/227] include stack traces when not in production --- .../Configuration/JsonApiOptions.cs | 10 +++++ .../IApplicationBuilderExtensions.cs | 10 +++++ .../Formatters/JsonApiWriter.cs | 15 ++++--- src/JsonApiDotNetCore/Internal/Error.cs | 40 +++++++++++++++++-- .../Internal/JsonApiException.cs | 24 ++++++----- .../Internal/JsonApiExceptionFactory.cs | 29 +++----------- .../JsonApiDotNetCore.csproj | 4 +- 7 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index f074940d9c..8643e28326 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -10,6 +10,16 @@ namespace JsonApiDotNetCore.Configuration { public class JsonApiOptions { + /// + /// Whether or not stack traces should be serialized in Error objects + /// + public static bool DisableErrorStackTraces { get; set; } + + /// + /// Whether or not source URLs should be serialized in Error objects + /// + public static bool DisableErrorSource { get; set; } + public string Namespace { get; set; } public int DefaultPageSize { get; set; } public bool IncludeTotalRecordCount { get; set; } diff --git a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs index c3d7ba2ee7..651fbb44aa 100644 --- a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs @@ -1,5 +1,7 @@ +using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Middleware; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; namespace JsonApiDotNetCore.Extensions { @@ -8,6 +10,14 @@ public static class IApplicationBuilderExtensions { public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool useMvc = true) { + var environment = (IHostingEnvironment)app.ApplicationServices.GetService(typeof(IHostingEnvironment)); + + if(environment.IsProduction()) + { + JsonApiOptions.DisableErrorStackTraces = true; + JsonApiOptions.DisableErrorSource = true; + } + app.UseMiddleware(); if (useMvc) diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs index d644def66d..fcf0ac7850 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs @@ -26,8 +26,6 @@ public async Task WriteAsync(OutputFormatterWriteContext context) if (context == null) throw new ArgumentNullException(nameof(context)); - _logger?.LogInformation("Formatting response as JSONAPI"); - var response = context.HttpContext.Response; using (var writer = context.WriterFactory(response.Body, Encoding.UTF8)) { @@ -40,9 +38,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context) catch (Exception e) { _logger?.LogError(new EventId(), e, "An error ocurred while formatting the response"); - var errors = new ErrorCollection(); - errors.Add(new Error("400", e.Message)); - responseContent = errors.GetJson(); + responseContent = GetErrorResponse(e); response.StatusCode = 400; } @@ -51,9 +47,12 @@ public async Task WriteAsync(OutputFormatterWriteContext context) } } - private string GetResponseBody(object responseObject) + private string GetResponseBody(object responseObject) => _serializer.Serialize(responseObject); + private string GetErrorResponse(Exception e) { - return _serializer.Serialize(responseObject); - } + var errors = new ErrorCollection(); + errors.Add(new Error(400, e.Message, ErrorMeta.FromException(e))); + return errors.GetJson(); + } } } diff --git a/src/JsonApiDotNetCore/Internal/Error.cs b/src/JsonApiDotNetCore/Internal/Error.cs index 0443e1edb7..999611d79e 100644 --- a/src/JsonApiDotNetCore/Internal/Error.cs +++ b/src/JsonApiDotNetCore/Internal/Error.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using JsonApiDotNetCore.Configuration; using Newtonsoft.Json; namespace JsonApiDotNetCore.Internal @@ -8,30 +10,40 @@ public class Error public Error() { } - public Error(string status, string title) + [Obsolete("Use Error constructors with int typed status")] + public Error(string status, string title, ErrorMeta meta = null, string source = null) { Status = status; Title = title; + Meta = meta; + Source = source; } - public Error(int status, string title) + public Error(int status, string title, ErrorMeta meta = null, string source = null) { Status = status.ToString(); Title = title; + Meta = meta; + Source = source; } - public Error(string status, string title, string detail) + [Obsolete("Use Error constructors with int typed status")] + public Error(string status, string title, string detail, ErrorMeta meta = null, string source = null) { Status = status; Title = title; Detail = detail; + Meta = meta; + Source = source; } - public Error(int status, string title, string detail) + public Error(int status, string title, string detail, ErrorMeta meta = null, string source = null) { Status = status.ToString(); Title = title; Detail = detail; + Meta = meta; + Source = source; } [JsonProperty("title")] @@ -45,5 +57,25 @@ public Error(int status, string title, string detail) [JsonIgnore] public int StatusCode => int.Parse(Status); + + [JsonProperty("source")] + public string Source { get; set; } + + [JsonProperty("meta")] + public ErrorMeta Meta { get; set; } + + public bool ShouldSerializeMeta() => (JsonApiOptions.DisableErrorStackTraces == false); + public bool ShouldSerializeSource() => (JsonApiOptions.DisableErrorSource == false); + } + + public class ErrorMeta + { + [JsonProperty("stackTrace")] + public string[] StackTrace { get; set; } + + public static ErrorMeta FromException(Exception e) + => new ErrorMeta { + StackTrace = e.Demystify().ToString().Split(new[] { "\n"}, int.MaxValue, StringSplitOptions.RemoveEmptyEntries) + }; } } diff --git a/src/JsonApiDotNetCore/Internal/JsonApiException.cs b/src/JsonApiDotNetCore/Internal/JsonApiException.cs index 9ce12fe428..5387154954 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiException.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiException.cs @@ -13,30 +13,29 @@ public JsonApiException(ErrorCollection errorCollection) } public JsonApiException(Error error) - : base(error.Title) - => _errors.Add(error); + : base(error.Title) => _errors.Add(error); [Obsolete("Use int statusCode overload instead")] - public JsonApiException(string statusCode, string message) + public JsonApiException(string statusCode, string message, string source = null) : base(message) - => _errors.Add(new Error(statusCode, message, null)); + => _errors.Add(new Error(statusCode, message, null, GetMeta(), source)); [Obsolete("Use int statusCode overload instead")] - public JsonApiException(string statusCode, string message, string detail) + public JsonApiException(string statusCode, string message, string detail, string source = null) : base(message) - => _errors.Add(new Error(statusCode, message, detail)); + => _errors.Add(new Error(statusCode, message, detail, GetMeta(), source)); - public JsonApiException(int statusCode, string message) + public JsonApiException(int statusCode, string message, string source = null) : base(message) - => _errors.Add(new Error(statusCode, message, null)); + => _errors.Add(new Error(statusCode, message, null, GetMeta(), source)); - public JsonApiException(int statusCode, string message, string detail) + public JsonApiException(int statusCode, string message, string detail, string source = null) : base(message) - => _errors.Add(new Error(statusCode, message, detail)); + => _errors.Add(new Error(statusCode, message, detail, GetMeta(), source)); public JsonApiException(int statusCode, string message, Exception innerException) : base(message, innerException) - => _errors.Add(new Error(statusCode, message, innerException.Message)); + => _errors.Add(new Error(statusCode, message, innerException.Message, GetMeta(innerException))); public ErrorCollection GetError() => _errors; @@ -53,5 +52,8 @@ public int GetStatusCode() return 500; } + + private ErrorMeta GetMeta() => ErrorMeta.FromException(this); + private ErrorMeta GetMeta(Exception e) => ErrorMeta.FromException(e); } } diff --git a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs index 36b4969b1d..20ae9ebc62 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs @@ -1,36 +1,17 @@ using System; -using System.Linq; namespace JsonApiDotNetCore.Internal { public static class JsonApiExceptionFactory { - private const string JsonApiException = nameof(JsonApiException); - private const string InvalidCastException = nameof(InvalidCastException); - public static JsonApiException GetException(Exception exception) { - var exceptionType = exception.GetType().ToString().Split('.').Last(); - switch(exceptionType) - { - case JsonApiException: - return (JsonApiException)exception; - case InvalidCastException: - return new JsonApiException(409, exception.Message); - default: - return new JsonApiException(500, exception.Message, GetExceptionDetail(exception.InnerException)); - } - } + var exceptionType = exception.GetType(); - private static string GetExceptionDetail(Exception exception) - { - string detail = null; - while(exception != null) - { - detail = $"{detail}{exception.Message}; "; - exception = exception.InnerException; - } - return detail; + if(exceptionType == typeof(JsonApiException)) + return (JsonApiException)exception; + + return new JsonApiException(500, exceptionType.Name, exception); } } } diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 53c81b2ec1..61d725f6d8 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -15,11 +15,11 @@ https://github.com/json-api-dotnet/JsonApiDotNetCore + - - + \ No newline at end of file From 9bdbb882abdc5d0dcba072fbccba310315628c49 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 10:07:12 -0600 Subject: [PATCH 087/227] add static exception UnSupportedRequestMethod --- .../Controllers/BaseJsonApiController.cs | 17 ++++++++--------- src/JsonApiDotNetCore/Internal/Exceptions.cs | 11 +++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/JsonApiDotNetCore/Internal/Exceptions.cs diff --git a/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs b/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs index a10ea381de..760f8f8d56 100644 --- a/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs +++ b/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs @@ -4,7 +4,6 @@ using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Controllers { @@ -105,7 +104,7 @@ public BaseJsonApiController( public virtual async Task GetAsync() { - if (_getAll == null) throw new JsonApiException(405, "Get requests are not supported"); + if (_getAll == null) throw Exceptions.UnSupportedRequestMethod; var entities = await _getAll.GetAsync(); @@ -114,7 +113,7 @@ public virtual async Task GetAsync() public virtual async Task GetAsync(TId id) { - if (_getById == null) throw new JsonApiException(405, "Get by Id requests are not supported"); + if (_getById == null) throw Exceptions.UnSupportedRequestMethod; var entity = await _getById.GetAsync(id); @@ -126,7 +125,7 @@ public virtual async Task GetAsync(TId id) public virtual async Task GetRelationshipsAsync(TId id, string relationshipName) { - if (_getRelationships == null) throw new JsonApiException(405, "Get Relationships requests are not supported"); + if (_getRelationships == null) throw Exceptions.UnSupportedRequestMethod; var relationship = await _getRelationships.GetRelationshipsAsync(id, relationshipName); if (relationship == null) @@ -137,7 +136,7 @@ public virtual async Task GetRelationshipsAsync(TId id, string re public virtual async Task GetRelationshipAsync(TId id, string relationshipName) { - if (_getRelationship == null) throw new JsonApiException(405, "Get Relationship requests are not supported"); + if (_getRelationship == null) throw Exceptions.UnSupportedRequestMethod; var relationship = await _getRelationship.GetRelationshipAsync(id, relationshipName); @@ -146,7 +145,7 @@ public virtual async Task GetRelationshipAsync(TId id, string rel public virtual async Task PostAsync([FromBody] T entity) { - if (_create == null) throw new JsonApiException(405, "Post requests are not supported"); + if (_create == null) throw Exceptions.UnSupportedRequestMethod; if (entity == null) return UnprocessableEntity(); @@ -161,7 +160,7 @@ public virtual async Task PostAsync([FromBody] T entity) public virtual async Task PatchAsync(TId id, [FromBody] T entity) { - if (_update == null) throw new JsonApiException(405, "Patch requests are not supported"); + if (_update == null) throw Exceptions.UnSupportedRequestMethod; if (entity == null) return UnprocessableEntity(); @@ -176,7 +175,7 @@ public virtual async Task PatchAsync(TId id, [FromBody] T entity) public virtual async Task PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List relationships) { - if (_updateRelationships == null) throw new JsonApiException(405, "Relationship Patch requests are not supported"); + if (_updateRelationships == null) throw Exceptions.UnSupportedRequestMethod; await _updateRelationships.UpdateRelationshipsAsync(id, relationshipName, relationships); @@ -185,7 +184,7 @@ public virtual async Task PatchRelationshipsAsync(TId id, string public virtual async Task DeleteAsync(TId id) { - if (_delete == null) throw new JsonApiException(405, "Delete requests are not supported"); + if (_delete == null) throw Exceptions.UnSupportedRequestMethod; var wasDeleted = await _delete.DeleteAsync(id); diff --git a/src/JsonApiDotNetCore/Internal/Exceptions.cs b/src/JsonApiDotNetCore/Internal/Exceptions.cs new file mode 100644 index 0000000000..6c510e562b --- /dev/null +++ b/src/JsonApiDotNetCore/Internal/Exceptions.cs @@ -0,0 +1,11 @@ +namespace JsonApiDotNetCore.Internal +{ + internal static class Exceptions + { + private const string DOCUMENTATION_URL = "https://json-api-dotnet.github.io/#/errors/"; + private static string BuildUrl(string title) => DOCUMENTATION_URL + title; + + public static JsonApiException UnSupportedRequestMethod { get; } + = new JsonApiException(405, "Request method is not supported.", BuildUrl(nameof(UnSupportedRequestMethod))); + } +} From 0116376ccaeed684ec6ea35d36cd57490964e34a Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 10:23:23 -0600 Subject: [PATCH 088/227] fix build issues and consolidate props definitions --- Directory.Build.props | 20 ++++-- benchmarks/Benchmarks.csproj | 1 - build/dependencies.props | 11 ---- .../JsonApiDotNetCoreExample.csproj | 1 - .../NoEntityFrameworkExample.csproj | 1 - .../OperationsExample.csproj | 65 +++++++++---------- .../ReportsExample/ReportsExample.csproj | 1 - .../IServiceCollectionExtensions.cs | 2 - .../Internal/Generics/GenericProcessor.cs | 2 +- .../JsonApiDotNetCore.csproj | 3 +- .../JsonApiDotNetCoreExampleTests.csproj | 1 - .../NoEntityFrameworkTests.csproj | 1 - .../OperationsExampleTests.csproj | 14 ++-- test/UnitTests/UnitTests.csproj | 1 - 14 files changed, 54 insertions(+), 70 deletions(-) delete mode 100644 build/dependencies.props diff --git a/Directory.Build.props b/Directory.Build.props index d3e19546db..cc81f65974 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,21 +1,27 @@ + netcoreapp2.0 netstandard2.0 + 2.0.1 - 2.0.1 + 2.0.0 2.0.0 + 2.0.0 + + + 2.0.1 + 2.0.1 + + 3.2.6 + 2.0.0 + 4.4.0 - netcoreapp2.0 - 2.0.0 - 2.0.0 - 3.2.6 - 2.0.1 15.3.0-preview-20170427-09 1.1.2 2.3.0-beta3-build3705 @@ -23,4 +29,4 @@ 4.7.99 - \ No newline at end of file + diff --git a/benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj index b5ff121826..1e8b227f3c 100644 --- a/benchmarks/Benchmarks.csproj +++ b/benchmarks/Benchmarks.csproj @@ -1,5 +1,4 @@ - Exe $(NetCoreAppVersion) diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 0ef1b750a7..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,11 +0,0 @@ - - - netcoreapp2.0 - netstandard2.0 - - - 4.7.10 - 2.3.1 - 8.0.1-beta-1 - - diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index a2981cffd1..94e2a404a9 100755 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -1,5 +1,4 @@ - $(NetCoreAppVersion) true diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj index 32506808fe..eed5f1b09e 100755 --- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj +++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj @@ -1,5 +1,4 @@  - $(NetCoreAppVersion) diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj index e033989925..48c2654722 100644 --- a/src/Examples/OperationsExample/OperationsExample.csproj +++ b/src/Examples/OperationsExample/OperationsExample.csproj @@ -1,33 +1,32 @@ - - - - netcoreapp1.0 - true - OperationsExample - Exe - - - - - - - - - - - - - - - - - - - - - - - - - - + + + $(NetCoreAppVersion) + true + OperationsExample + Exe + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj index f8f83e454c..bd4b402071 100644 --- a/src/Examples/ReportsExample/ReportsExample.csproj +++ b/src/Examples/ReportsExample/ReportsExample.csproj @@ -1,5 +1,4 @@ - $(NetCoreAppVersion) diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index e5569f4bc4..cd068ead6a 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -98,8 +98,6 @@ public static void AddJsonApiInternals( if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) AddOperationServices(services); - services.AddScoped(); - services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs index 5f9ffaca0f..8e5d17e56b 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs @@ -16,7 +16,7 @@ public interface IGenericProcessor public class GenericProcessor : GenericProcessor where T : class, IIdentifiable { - public GenericProcessor(DbContext context) : base(context) { } + public GenericProcessor(IDbContextResolver contextResolver) : base(contextResolver) { } } public class GenericProcessor : IGenericProcessor where T : class, IIdentifiable diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 0d16b28e65..9fe109011b 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,5 +1,4 @@  - 2.2.0 $(NetStandardVersion) @@ -23,4 +22,4 @@ - \ No newline at end of file + diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj index da92260546..90bd4050e7 100755 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -1,5 +1,4 @@  - $(NetCoreAppVersion) false diff --git a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj index 5553a7c1eb..646cf9d538 100644 --- a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +++ b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj @@ -1,5 +1,4 @@  - $(NetCoreAppVersion) true diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj index 18e795cb9e..a7727475bd 100644 --- a/test/OperationsExampleTests/OperationsExampleTests.csproj +++ b/test/OperationsExampleTests/OperationsExampleTests.csproj @@ -1,16 +1,16 @@ - netcoreapp1.1 + $(NetCoreAppVersion) false OperationsExampleTests - - - - + + + + + - @@ -20,4 +20,4 @@ PreserveNewest - \ No newline at end of file + diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index 4848455eac..14a0d30e33 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -1,5 +1,4 @@ - $(NetCoreAppVersion) false From 1b14bd0062ba419d143922c5aa5ff7dff7e22507 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 10:37:07 -0600 Subject: [PATCH 089/227] fix tests --- src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index adc3883dd3..ae7f95917b 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -177,7 +177,7 @@ private object SetHasOneRelationship(object entity, if (relationshipAttr == null) throw new JsonApiException(400, $"{_jsonApiContext.RequestEntity.EntityName} does not contain a relationship '{relationshipName}'"); - var data = (Dictionary) relationshipData.ExposedData; + var data = (Dictionary) relationshipData.ExposedData; if (data == null) return entity; From 4c97c19d9f3a6561bab418740fa7d6c03623cdfb Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 16:55:49 -0600 Subject: [PATCH 090/227] feat(operations): remove JSON pointers from previous spec draft --- .../IServiceCollectionExtensions.cs | 3 - .../JsonApiOperationsInputFormatter.cs | 35 ----------- .../DocumentDataPointerReplacement.cs | 59 ------------------- .../Operations/OperationsProcessor.cs | 20 +------ .../ResourceRefPointerReplacement.cs | 34 ----------- .../WebHostCollection.cs | 13 ++-- 6 files changed, 7 insertions(+), 157 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index cd068ead6a..437132f087 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -163,9 +163,6 @@ public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions js { options.InputFormatters.Insert(0, new JsonApiInputFormatter()); - if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) - options.InputFormatters.Insert(0, new JsonApiOperationsInputFormatter()); - options.OutputFormatters.Insert(0, new JsonApiOutputFormatter()); options.Conventions.Insert(0, new DasherizedRoutingConvention(jsonApiOptions.Namespace)); diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs deleted file mode 100644 index 6f114aff33..0000000000 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsInputFormatter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Primitives; - -namespace JsonApiDotNetCore.Formatters -{ - public class JsonApiOperationsInputFormatter : IInputFormatter - { - internal const string PROFILE_EXTENSION = "; rel=\"profile\""; - - public bool CanRead(InputFormatterContext context) - { - if (context == null) - throw new ArgumentNullException(nameof(context)); - - var contentTypeString = context.HttpContext.Request.ContentType; - - var canRead = ( - contentTypeString == "application/vnd.api+json" && - context.HttpContext.Request.Headers.TryGetValue("Link", out StringValues profileExtension) && - profileExtension == PROFILE_EXTENSION - ); - - return canRead; - } - - public async Task ReadAsync(InputFormatterContext context) - { - var reader = context.HttpContext.RequestServices.GetService(); - return await reader.ReadAsync(context); - } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs b/src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs deleted file mode 100644 index 7301353c3e..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/DocumentDataPointerReplacement.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Models.Pointers; -using Newtonsoft.Json.Linq; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Extensions; - -namespace JsonApiDotNetCore.Services.Operations -{ - public class DocumentDataPointerReplacement - where TPointer : Pointer, new() - { - private readonly DocumentData _data; - - public DocumentDataPointerReplacement(DocumentData data) - { - _data = data; - } - - public void ReplacePointers(List parentDoc) - { - _data.Id = GetPointerValue(_data.Id, parentDoc); - _data.Type = GetPointerValue(_data.Type, parentDoc); - - if (_data.Relationships != null) - { - foreach (var relationshipDictionary in _data.Relationships) - { - if (relationshipDictionary.Value.IsHasMany) - { - foreach (var relationship in relationshipDictionary.Value.ManyData) - ReplaceDictionaryPointers(relationship, parentDoc); - } - else - { - ReplaceDictionaryPointers(relationshipDictionary.Value.SingleData, parentDoc); - } - } - } - } - - private void ReplaceDictionaryPointers(Dictionary relationship, List parentDoc) - { - if (relationship.ContainsKey("id")) - relationship["id"] = GetPointerValue(relationship["id"], parentDoc); - - if (relationship.ContainsKey("type")) - relationship["type"] = GetPointerValue(relationship["type"], parentDoc); - } - - private object GetPointerValue(object reference, List parentDoc) - { - if (reference is JObject jObj) - if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) - return pointer.GetValue(parentDoc); - - return reference; - } - } -} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index 2873d243b1..e49e758570 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -61,8 +61,8 @@ private async Task ProcessOperation(Operation op, List outputOps) { var operationsPointer = new OperationsPointer(); - ReplaceDataPointers(op.DataObject, outputOps); - ReplaceRefPointers(op.Ref, outputOps); + // ReplaceDataPointers(op.DataObject, outputOps); + // ReplaceRefPointers(op.Ref, outputOps); var processor = GetOperationsProcessor(op); var resultOp = await processor.ProcessAsync(op); @@ -71,22 +71,6 @@ private async Task ProcessOperation(Operation op, List outputOps) outputOps.Add(resultOp); } - private void ReplaceDataPointers(DocumentData dataObject, List outputOps) - { - if (dataObject == null) return; - - var replacer = new DocumentDataPointerReplacement(dataObject); - replacer.ReplacePointers(outputOps); - } - - private void ReplaceRefPointers(ResourceReference resourceRef, List outputOps) - { - if (resourceRef == null) return; - - var replacer = new ResourceRefPointerReplacement(resourceRef); - replacer.ReplacePointers(outputOps); - } - private IOpProcessor GetOperationsProcessor(Operation op) { switch (op.Op) diff --git a/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs b/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs deleted file mode 100644 index d24d7e879a..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/ResourceRefPointerReplacement.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Models.Pointers; -using Newtonsoft.Json.Linq; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Models.Operations; - -namespace JsonApiDotNetCore.Services.Operations -{ - public class ResourceRefPointerReplacement - where TPointer : Pointer, new() - { - private readonly ResourceReference _ref; - - public ResourceRefPointerReplacement(ResourceReference data) - { - _ref = data; - } - - public void ReplacePointers(List parentDoc) - { - _ref.Id = GetPointerValue(_ref.Id, parentDoc); - _ref.Type = GetPointerValue(_ref.Type, parentDoc); - } - - private object GetPointerValue(object reference, List parentDoc) - { - if (reference is JObject jObj) - if (jObj.TryParse(Pointer.JsonSchema, out Pointer pointer)) - return pointer.GetValue(parentDoc); - - return reference; - } - } -} \ No newline at end of file diff --git a/test/OperationsExampleTests/WebHostCollection.cs b/test/OperationsExampleTests/WebHostCollection.cs index dc4f02a58c..e385ace992 100644 --- a/test/OperationsExampleTests/WebHostCollection.cs +++ b/test/OperationsExampleTests/WebHostCollection.cs @@ -1,13 +1,11 @@ -using System; using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using OperationsExample; -using Xunit; using Microsoft.AspNetCore.TestHost; using Newtonsoft.Json; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using JsonApiDotNetCore.Formatters; +using OperationsExample; +using Xunit; namespace OperationsExampleTests { @@ -35,7 +33,6 @@ public async Task PatchAsync(string route, object data) request.Content = new StringContent(JsonConvert.SerializeObject(data)); request.Content.Headers.ContentLength = 1; request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - request.Content.Headers.Add("Link", JsonApiOperationsInputFormatter.PROFILE_EXTENSION); return await Client.SendAsync(request); } @@ -47,4 +44,4 @@ public async Task PatchAsync(string route, object data) return (response, obj); } } -} \ No newline at end of file +} From 6b50baf72ecd49e18440196d9e3abbc19502f6e9 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 16:57:25 -0600 Subject: [PATCH 091/227] breaking(Document): introduce RO and RIO from spec DocumentData becomes ResourceObject and dictionary in Relationship becomes strongly type ResourceIdentifierObject --- .../Builders/DocumentBuilder.cs | 20 +++++----- src/JsonApiDotNetCore/Models/DocumentData.cs | 21 ++-------- .../Models/RelationshipData.cs | 15 ++++---- .../Models/ResourceIdentifierObject.cs | 16 ++++++++ .../Models/ResourceObject.cs | 14 +++++++ .../Serialization/JsonApiDeSerializer.cs | 4 +- .../UnitTests/Models/RelationshipDataTests.cs | 38 +++++++++++-------- .../Operations/OperationsProcessorTests.cs | 2 +- 8 files changed, 77 insertions(+), 53 deletions(-) create mode 100644 src/JsonApiDotNetCore/Models/ResourceIdentifierObject.cs create mode 100644 src/JsonApiDotNetCore/Models/ResourceObject.cs diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 95227abd58..0e43225b35 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -234,32 +234,32 @@ private bool RelationshipIsIncluded(string relationshipName) _jsonApiContext.IncludedRelationships.Contains(relationshipName); } - private List> GetRelationships(IEnumerable entities) + private List GetRelationships(IEnumerable entities) { var objType = entities.GetElementType(); var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); - var relationships = new List>(); + var relationships = new List(); foreach (var entity in entities) { - relationships.Add(new Dictionary { - {"type", typeName.EntityName }, - {"id", ((IIdentifiable)entity).StringId } + relationships.Add(new ResourceIdentifierObject { + Type = typeName.EntityName, + Id = ((IIdentifiable)entity).StringId }); } return relationships; } - private Dictionary GetRelationship(object entity) + private ResourceIdentifierObject GetRelationship(object entity) { var objType = entity.GetType(); var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); - return new Dictionary { - {"type", typeName.EntityName }, - {"id", ((IIdentifiable)entity).StringId } - }; + return new ResourceIdentifierObject { + Type = typeName.EntityName, + Id = ((IIdentifiable)entity).StringId + }; } } } diff --git a/src/JsonApiDotNetCore/Models/DocumentData.cs b/src/JsonApiDotNetCore/Models/DocumentData.cs index 7b5bdadd5b..ba1ce646c0 100644 --- a/src/JsonApiDotNetCore/Models/DocumentData.cs +++ b/src/JsonApiDotNetCore/Models/DocumentData.cs @@ -1,20 +1,5 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - namespace JsonApiDotNetCore.Models { - public class DocumentData - { - [JsonProperty("type")] - public object Type { get; set; } - - [JsonProperty("id")] - public object Id { get; set; } - - [JsonProperty("attributes")] - public Dictionary Attributes { get; set; } - - [JsonProperty("relationships", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary Relationships { get; set; } - } -} \ No newline at end of file + // TODO: deprecate DocumentData in favor of ResourceObject + public class DocumentData : ResourceObject { } +} diff --git a/src/JsonApiDotNetCore/Models/RelationshipData.cs b/src/JsonApiDotNetCore/Models/RelationshipData.cs index d81b2fe75a..1cfe47c5c7 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipData.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipData.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -22,9 +21,9 @@ public object ExposedData set { if (value is JObject jObject) - SingleData = jObject.ToObject>(); - else if (value is Dictionary dict) - SingleData = (Dictionary)value; + SingleData = jObject.ToObject(); + else if (value is ResourceIdentifierObject dict) + SingleData = (ResourceIdentifierObject)value; else SetManyData(value); } @@ -34,16 +33,16 @@ private void SetManyData(object value) { IsHasMany = true; if (value is JArray jArray) - ManyData = jArray.ToObject>>(); + ManyData = jArray.ToObject>(); else - ManyData = (List>)value; + ManyData = (List)value; } [JsonIgnore] - public List> ManyData { get; set; } + public List ManyData { get; set; } [JsonIgnore] - public Dictionary SingleData { get; set; } + public ResourceIdentifierObject SingleData { get; set; } [JsonIgnore] public bool IsHasMany { get; private set; } diff --git a/src/JsonApiDotNetCore/Models/ResourceIdentifierObject.cs b/src/JsonApiDotNetCore/Models/ResourceIdentifierObject.cs new file mode 100644 index 0000000000..1ebab6c474 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/ResourceIdentifierObject.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace JsonApiDotNetCore.Models +{ + public class ResourceIdentifierObject + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("lid")] + public string LocalId { get; set; } + } +} diff --git a/src/JsonApiDotNetCore/Models/ResourceObject.cs b/src/JsonApiDotNetCore/Models/ResourceObject.cs new file mode 100644 index 0000000000..1a28631407 --- /dev/null +++ b/src/JsonApiDotNetCore/Models/ResourceObject.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace JsonApiDotNetCore.Models +{ + public class ResourceObject : ResourceIdentifierObject + { + [JsonProperty("attributes")] + public Dictionary Attributes { get; set; } + + [JsonProperty("relationships", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary Relationships { get; set; } + } +} diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index ae7f95917b..1765687c0a 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -218,7 +218,9 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; var genericProcessor = _genericProcessorFactory.GetProcessor(typeof(GenericProcessor<>), attr.Type); - var ids = relationshipData.ManyData.Select(r => r["id"].ToString()); + + var ids = relationshipData.ManyData.Select(r => r.Id); + genericProcessor.SetRelationships(entity, attr, ids); } diff --git a/test/UnitTests/Models/RelationshipDataTests.cs b/test/UnitTests/Models/RelationshipDataTests.cs index 780a5faa0b..ff00144b62 100644 --- a/test/UnitTests/Models/RelationshipDataTests.cs +++ b/test/UnitTests/Models/RelationshipDataTests.cs @@ -1,7 +1,7 @@ -using JsonApiDotNetCore.Models; -using System.Collections.Generic; -using Xunit; +using System.Collections.Generic; +using JsonApiDotNetCore.Models; using Newtonsoft.Json.Linq; +using Xunit; namespace UnitTests.Models { @@ -12,9 +12,10 @@ public void Setting_ExposedData_To_List_Sets_ManyData() { // arrange var relationshipData = new RelationshipData(); - var relationships = new List> { - new Dictionary { - { "authors", new { } } + var relationships = new List { + new ResourceIdentifierObject { + Id = "9", + Type = "authors" } }; @@ -23,7 +24,8 @@ public void Setting_ExposedData_To_List_Sets_ManyData() // assert Assert.NotEmpty(relationshipData.ManyData); - Assert.True(relationshipData.ManyData[0].ContainsKey("authors")); + Assert.Equal("authors", relationshipData.ManyData[0].Type); + Assert.Equal("9", relationshipData.ManyData[0].Id); Assert.True(relationshipData.IsHasMany); } @@ -34,7 +36,8 @@ public void Setting_ExposedData_To_JArray_Sets_ManyData() var relationshipData = new RelationshipData(); var relationshipsJson = @"[ { - ""authors"": {} + ""type"": ""authors"", + ""id"": ""9"" } ]"; @@ -45,17 +48,19 @@ public void Setting_ExposedData_To_JArray_Sets_ManyData() // assert Assert.NotEmpty(relationshipData.ManyData); - Assert.True(relationshipData.ManyData[0].ContainsKey("authors")); + Assert.Equal("authors", relationshipData.ManyData[0].Type); + Assert.Equal("9", relationshipData.ManyData[0].Id); Assert.True(relationshipData.IsHasMany); } [Fact] - public void Setting_ExposedData_To_Dictionary_Sets_SingleData() + public void Setting_ExposedData_To_RIO_Sets_SingleData() { // arrange var relationshipData = new RelationshipData(); - var relationship = new Dictionary { - { "authors", new { } } + var relationship = new ResourceIdentifierObject { + Id = "9", + Type = "authors" }; // act @@ -63,7 +68,8 @@ public void Setting_ExposedData_To_Dictionary_Sets_SingleData() // assert Assert.NotNull(relationshipData.SingleData); - Assert.True(relationshipData.SingleData.ContainsKey("authors")); + Assert.Equal("authors", relationshipData.SingleData.Type); + Assert.Equal("9", relationshipData.SingleData.Id); Assert.False(relationshipData.IsHasMany); } @@ -73,7 +79,8 @@ public void Setting_ExposedData_To_JObject_Sets_SingleData() // arrange var relationshipData = new RelationshipData(); var relationshipJson = @"{ - ""authors"": {} + ""id"": ""9"", + ""type"": ""authors"" }"; var relationship = JObject.Parse(relationshipJson); @@ -83,7 +90,8 @@ public void Setting_ExposedData_To_JObject_Sets_SingleData() // assert Assert.NotNull(relationshipData.SingleData); - Assert.True(relationshipData.SingleData.ContainsKey("authors")); + Assert.Equal("authors", relationshipData.SingleData.Type); + Assert.Equal("9", relationshipData.SingleData.Id); Assert.False(relationshipData.IsHasMany); } } diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index 74298f0cca..fb098d3f78 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -98,7 +98,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() m => m.ProcessAsync( It.Is(o => o.DataObject.Type.ToString() == "articles" - && o.DataObject.Relationships["author"].SingleData["id"].ToString() == "9" + && o.DataObject.Relationships["author"].SingleData.Id == "9" ) ) ); From f3cb9d98659a48f5175a3d1517d5a9580445ecdd Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 18 Feb 2018 17:26:09 -0600 Subject: [PATCH 092/227] fix standad tests --- .../Serialization/JsonApiDeSerializer.cs | 8 +- test/JsonApiDotNetCoreExampleTests/results | 19364 ++++++++++++++++ .../Serialization/JsonApiSerializerTests.cs | 8 +- 3 files changed, 19370 insertions(+), 10 deletions(-) create mode 100644 test/JsonApiDotNetCoreExampleTests/results diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 1765687c0a..ef7938dbd3 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -177,11 +177,11 @@ private object SetHasOneRelationship(object entity, if (relationshipAttr == null) throw new JsonApiException(400, $"{_jsonApiContext.RequestEntity.EntityName} does not contain a relationship '{relationshipName}'"); - var data = (Dictionary) relationshipData.ExposedData; + var rio = (ResourceIdentifierObject) relationshipData.ExposedData; - if (data == null) return entity; + if (rio == null) return entity; - var newValue = data["id"]; + var newValue = rio.Id; var foreignKey = attr.InternalRelationshipName + "Id"; var entityProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); @@ -213,7 +213,7 @@ private object SetHasManyRelationship(object entity, if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) { - var data = (List>)relationshipData.ExposedData; + var data = (List)relationshipData.ExposedData; if (data == null) return entity; diff --git a/test/JsonApiDotNetCoreExampleTests/results b/test/JsonApiDotNetCoreExampleTests/results new file mode 100644 index 0000000000..09e896913c --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/results @@ -0,0 +1,19364 @@ +Build started, please wait... +Build completed. + +Test run for /Users/jarednance/dev/json-api-dotnet-core/test/JsonApiDotNetCoreExampleTests/bin/Debug/netcoreapp2.0/JsonApiDotNetCoreExampleTests.dll(.NETCoreApp,Version=v2.0) +Microsoft (R) Test Execution Command Line Tool Version 15.3.0-preview-20170628-02 +Copyright (c) Microsoft Corporation. All rights reserved. + +Starting test execution, please wait... +[xUnit.net 00:00:01.5429620] Discovering: JsonApiDotNetCoreExampleTests +[xUnit.net 00:00:01.7795750] Discovered: JsonApiDotNetCoreExampleTests +[xUnit.net 00:00:01.9136060] Starting: JsonApiDotNetCoreExampleTests +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (46ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (21ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (21ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/camelCasedModels +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/camelCasedModels +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'CamelCasedModels'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample)' with id 'c71c760f-c1d1-4899-8d4b-62a4348b63f7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from CamelCasedModel _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from CamelCasedModel _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "CamelCasedModels" AS "c"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "CamelCasedModels" AS "c" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "CamelCasedModels" AS "c" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "CamelCasedModels" AS "c" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from CamelCasedModel _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from CamelCasedModel _2 in DbSet select [_2]).Skip(__p_0).Ta...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from CamelCasedModel _2 in DbSet select [_2]).Skip(__p_0).Ta...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from CamelCasedModel _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "c"."Id", "c"."CompoundAttr" + FROM "CamelCasedModels" AS "c" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: CamelCasedModel }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "c"."Id", "c"."CompoundAttr" + FROM "CamelCasedModels" AS "c" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (17ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "c"."Id", "c"."CompoundAttr" + FROM "CamelCasedModels" AS "c" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (17ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "c"."Id", "c"."CompoundAttr" + FROM "CamelCasedModels" AS "c" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) in 797.042ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) in 797.042ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 1177.077ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 1177.077ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/camelCasedModels/118 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/camelCasedModels/118 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'CamelCasedModels/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample)' with id '56304397-4d3c-4262-91df-9d2020a11d38' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.DeleteAsync (JsonApiDotNetCoreExample)' with id 'b4ae66ce-aa8f-4c8e-869c-4b784d8bff92' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (118, JsonApiDotNetCoreExample.Models.CamelCasedModel) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (118, JsonApiDotNetCoreExample.Models.CamelCasedModel) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from CamelCasedModel e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from CamelCasedModel e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: CamelCasedModel }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "CamelCasedModels" SET "CompoundAttr" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "CamelCasedModels" SET "CompoundAttr" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "CamelCasedModels" SET "CompoundAttr" = @p0 + WHERE "Id" = @p1; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample) in 354.058ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample) in 354.058ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 419.972ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 419.972ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/camelCasedModels application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/camelCasedModels application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'CamelCasedModels'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample)' with id '666fde0d-b734-495f-ad63-c5150103bbae' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.CamelCasedModel) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.CamelCasedModel) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.CreatedResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample) in 53.052ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 68.79ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PostAsync (JsonApiDotNetCoreExample) in 53.052ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 68.79ms 201 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "CamelCasedModels" ("CompoundAttr") + VALUES (@p0) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/camelCasedModels/120 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/camelCasedModels/120 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'CamelCasedModels/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.PatchAsync (JsonApiDotNetCoreExample)' with id 'e8c838e7-928c-4438-9423-73d694f2a735' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.DeleteAsync (JsonApiDotNetCoreExample)' with id 'd3dc7c59-c458-484c-864d-c679f2275710' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) with arguments (120) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) with arguments (120) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from CamelCasedModel e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from CamelCasedModel e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: CamelCasedModel }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (13ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (13ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."CompoundAttr" + FROM "CamelCasedModels" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) in 54.591ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 73.364ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.CamelCasedModelsController.GetAsync (JsonApiDotNetCoreExample) in 54.591ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 73.364ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/readonly +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/readonly +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'ReadOnly'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample)' with id '9ceae986-2052-4187-bc60-6db234b1ede5' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample)' with id '4de72652-5656-423c-b4be-3cd9c940d171' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample)' with id '521d748c-b696-4748-b738-371680d2c9e3' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support PATCH requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support PATCH requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample) in 25.699ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample) in 25.699ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 41.952ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 41.952ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/readonly +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/readonly +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'ReadOnly'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample)' with id '18714b6d-0833-4259-935e-8efa022d086d' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample)' with id '0fef2165-3efb-4658-933a-7ae6ef0c7232' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample)' with id '1d6daeba-8dfb-4b24-b56b-7a5283a29bc4' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support DELETE requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support DELETE requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample) in 6.393ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample) in 6.393ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.237ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.237ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/readonly +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/readonly +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'ReadOnly'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample)' with id '6a344e07-367a-4086-a290-a9ac9ff653b2' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample)' with id '65f4bfd4-7222-41ed-8406-d267a25771cc' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample)' with id '7151bfbd-129b-4a37-a514-c5cb1561f85c' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support POST requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support POST requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample) in 3.628ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample) in 3.628ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.455ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.455ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/readonly +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/readonly +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'ReadOnly'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Post (JsonApiDotNetCoreExample)' with id 'd692e0ba-f723-4660-aeb5-bb2fab767d08' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Patch (JsonApiDotNetCoreExample)' with id 'bb9f84b7-1768-4c5c-a5d4-8142f3aa7da2' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Delete (JsonApiDotNetCoreExample)' with id 'cadd349f-7374-4fc1-97df-b7df9a994684' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample) in 3.6ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.ReadOnlyController.Get (JsonApiDotNetCoreExample) in 3.6ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.744ms 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.744ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttpdelete +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttpdelete +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpDelete'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample)' with id 'e8ba1352-03b1-4166-9e79-1ce0c48f95f7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample)' with id 'ebe48f67-b775-4198-b4d8-dae0bbabc2e6' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample)' with id '01ed4864-4f42-4865-af7f-c39b40fea67b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample) in 0.719ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 14.875ms 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample) in 0.719ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 14.875ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttpdelete +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttpdelete +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpDelete'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample)' with id '72b19a09-1b1f-4691-a363-cb0f10df7f44' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample)' with id '37d45424-cba6-4b3a-b19c-66490c70208f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample)' with id '6dd43591-857d-4625-8fa4-a261d04da16b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support DELETE requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support DELETE requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample) in 3.513ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample) in 3.513ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.684ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.684ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttpdelete +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttpdelete +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpDelete'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample)' with id 'c95f1a88-8eff-4b37-8f6a-7d8b7398b131' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample)' with id '9ea775d5-e54f-4b2c-b274-e2d8010d4134' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample)' with id 'f9ede477-a111-42f0-a8bf-5b81166908ee' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample) in 0.329ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 15.698ms 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample) in 0.329ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 15.698ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttpdelete +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttpdelete +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpDelete'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Get (JsonApiDotNetCoreExample)' with id 'c702b174-b075-49f0-a851-626c2f1dceac' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Post (JsonApiDotNetCoreExample)' with id 'a34519c4-5ff5-47fa-a55e-fdcddd23ac7d' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Delete (JsonApiDotNetCoreExample)' with id '1cdfd359-36bc-421e-a025-7af36c463692' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample) in 0.378ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.973ms 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpDeleteController.Patch (JsonApiDotNetCoreExample) in 0.378ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.973ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttppatch +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttppatch +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPatch'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample)' with id '0a47ec59-9bd6-4f86-8ae7-784146f24d25' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample)' with id 'c40826a8-bb78-495b-a580-8a34f21f90e1' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample)' with id '65968202-d190-4c70-9ac5-855e064ec85c' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample) in 0.544ms +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.402ms 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample) in 0.544ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.402ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttppatch +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttppatch +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPatch'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample)' with id '9b16d4b3-796c-4630-b944-4a0c28230844' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample)' with id '867fa153-19b0-422e-aa0a-30a3f58f84e0' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample)' with id '82d36401-dc08-4ff0-b285-dd2f8d333f59' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support PATCH requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support PATCH requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample) in 7.468ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample) in 7.468ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 19.429ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 19.429ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttppatch +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttppatch +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPatch'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample)' with id '957f4e51-8d40-4405-a523-0f3096cf96c1' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample)' with id 'a69c8f75-6924-4fcf-b2b3-c5d0277d4340' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample)' with id '74dbbd63-6ca3-4fbd-8077-3b4f30a6f6e0' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample) in 0.608ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample) in 0.608ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 20.436ms 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 20.436ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttppatch +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttppatch +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPatch'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Get (JsonApiDotNetCoreExample)' with id 'e9ebb853-6169-4cc6-ba17-54a9ed00e805' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Patch (JsonApiDotNetCoreExample)' with id 'dab9b84a-0944-4807-bcbc-6dc1e7964c47' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Delete (JsonApiDotNetCoreExample)' with id '7e09310e-ec5e-4829-be57-632f6f7d1c89' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample) in 0.452ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 14.392ms 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPatchController.Post (JsonApiDotNetCoreExample) in 0.452ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 14.392ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttppost +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/nohttppost +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPost'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample)' with id '2c61d7ce-c38b-43b3-b51b-702e595f6b37' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample)' with id 'fded13c7-20e9-402b-9cd0-66aee2c5fee4' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample)' with id '28252322-bbf4-46b2-8941-284cc1b1df1a' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample) in 0.934ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample) in 0.934ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.025ms 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.025ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttppost +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/nohttppost +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPost'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample)' with id 'eab96b94-f493-457f-97de-9b2995d5557a' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample)' with id '38baef8d-7d72-46dd-9f2a-bd1de31f9e15' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample)' with id '5e424bdc-48fd-4059-b3df-2f40347c6fac' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample) in 0.346ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.34ms 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample) in 0.346ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.34ms 200 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttppost +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/nohttppost +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPost'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample)' with id 'aa8ab36f-b617-4d80-8754-7342c289a15b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample)' with id '71ab4fa0-892e-4cfa-bec8-6d1fa27fdc09' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample)' with id '2a0fc13f-0311-4ed2-a6fe-33f0355d1962' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support POST requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: This resource does not support POST requests. + at JsonApiDotNetCore.Controllers.HttpRestrictAttribute.d__2.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs:line 21 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample) in 3.885ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample) in 3.885ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 19.512ms 405 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 19.512ms 405 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttppost +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/nohttppost +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'NoHttpPost'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Get (JsonApiDotNetCoreExample)' with id 'e8d78aa6-b1bc-490e-b743-11e7d5769b09' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Post (JsonApiDotNetCoreExample)' with id '2d2b399d-9677-4946-bf9a-f0c8c4e644c3' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Patch (JsonApiDotNetCoreExample)' with id '9d2d6081-3838-4c95-9310-84cfce59572d' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample) in 0.446ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.61ms 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.Restricted.NoHttpPostController.Delete (JsonApiDotNetCoreExample) in 0.446ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 18.61ms 200 +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from TodoItem _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from TodoItem _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t", + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p51, @p52, @p53, @p54, @p55, @p56, @p57, @p58) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p59, @p60, @p61, @p62, @p63, @p64, @p65, @p66) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (18ms) [Parameters=[@p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p51, @p52, @p53, @p54, @p55, @p56, @p57, @p58) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p59, @p60, @p61, @p62, @p63, @p64, @p65, @p66) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (18ms) [Parameters=[@p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p51, @p52, @p53, @p54, @p55, @p56, @p57, @p58) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p59, @p60, @p61, @p62, @p63, @p64, @p65, @p66) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?sort=-ordinal +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?sort=-ordinal +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem x in DbSet + order by [x].Ordinal desc + select [x]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem x in DbSet + select [x]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem x in DbSet + order by [x].Ordinal desc + select [x]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem x in DbSet + order by [x].Ordinal desc + select [x]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" DESC + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" DESC + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" DESC + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" DESC + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 73.508ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 73.508ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 90.09ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 90.09ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[ordinal]=999999 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[ordinal]=999999 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].Ordinal == 999999 + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where [model].Ordinal == 999999 + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].Ordinal == 999999 + select [model]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].Ordinal == 999999 select [model]).Skip(__p_0)....' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].Ordinal == 999999 select [model]).Skip(__p_0)....' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where [model].Ordinal == 999999 + select [model]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."Ordinal" = 999999 + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.005ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 50.255ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.005ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 50.255ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2594 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2594 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2594) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2594) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 17.158ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 17.158ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 21.735ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 21.735ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2595 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2595 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '432a039f-d92f-4b06-93f6-76d9e6be26be' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2595, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2595, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 22.314ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 27.243ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 22.314ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 27.243ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 9.452ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 9.452ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 9.891ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 9.891ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id 'f11b0d8e-7eb6-44c7-b10f-29a156acd6ba' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.CreatedResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 11.535ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 11.535ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.578ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 16.578ms 201 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2598 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2598 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '432a039f-d92f-4b06-93f6-76d9e6be26be' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2598, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2598, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "AchievedDate" = @p0, "CreatedDate" = @p1, "Description" = @p2 + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 8.845ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 8.845ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 9.112ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 9.112ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?sort=ordinal +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?sort=ordinal +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem x in DbSet + order by [x].Ordinal asc + select [x]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem x in DbSet + select [x]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "x" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem x in DbSet + order by [x].Ordinal asc + select [x]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem x in DbSet + order by [x].Ordinal asc + select [x]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" + ORDER BY "x"."Ordinal" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 14.927ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 14.927ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 15.301ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 15.301ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2603 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2603 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '432a039f-d92f-4b06-93f6-76d9e6be26be' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2603, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2603, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "CreatedDate" = @p0, "Description" = @p1, "Ordinal" = @p2 + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "CreatedDate" = @p0, "Description" = @p1, "Ordinal" = @p2 + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "CreatedDate" = @p0, "Description" = @p1, "Ordinal" = @p2 + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 5.286ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 5.286ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 5.705ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 5.705ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/api/v1/todo-items/2604 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/api/v1/todo-items/2604 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '432a039f-d92f-4b06-93f6-76d9e6be26be' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) with arguments (2604) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) with arguments (2604) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.NoContentResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 204 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 204 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) in 20.385ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) in 20.385ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 24.713ms 204 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 24.713ms 204 +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem t in DbSet + where [t].Id == __todoItem_Id_0 + select [t]).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem t in DbSet + where [t].Id == __todoItem_Id_0 + select [t]).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(TodoItem FirstOrDefault(IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1, + shaper: UnbufferedEntityShaper))), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2605?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2605?include=owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2605) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2605) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("Owner") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 225.239ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 225.49ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 225.239ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 225.49ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[description]=like:ui%20eum%20quo%20sit%20fugiat +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[description]=like:ui%20eum%20quo%20sit%20fugiat +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where bool [model].Description.Contains("ui eum quo sit fugiat") + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where bool [model].Description.Contains("ui eum quo sit fugiat") + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where bool [model].Description.Contains("ui eum quo sit fugiat") + select [model]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where bool [model].Description.Contains("ui eum quo sit fugi...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where bool [model].Description.Contains("ui eum quo sit fugi...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where bool [model].Description.Contains("ui eum quo sit fugiat") + select [model]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE STRPOS("model"."Description", 'ui eum quo sit fugiat') > 0 + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 21.347ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 21.347ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 22.376ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 22.376ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&filter[owner.first-name]=Crawford +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&filter[owner.first-name]=Crawford +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].Owner.FirstName == "Crawford" + select [model]) + .Include("Owner") + .Count()' +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[model].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[model].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + join Person model.Owner in DbSet + on Property([model], "OwnerId") equals (Nullable)Property([model.Owner], "Id") into model.Owner_group + from Person model.Owner in + (from Person model.Owner_groupItem in [model.Owner_group] + select [model.Owner_groupItem]).DefaultIfEmpty() + where [model.Owner]?.FirstName == "Crawford" + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford'), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].Owner.FirstName == "Crawford" + select [model]) + .Include("Owner") + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].Owner.FirstName == "Crawford" select [model])....' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].Owner.FirstName == "Crawford" select [model])....' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[model].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + join Person model.Owner in DbSet + on Property([model], "OwnerId") equals (Nullable)Property([model.Owner], "Id") into model.Owner_group + from Person model.Owner in + (from Person model.Owner_groupItem in [model.Owner_group] + select [model.Owner_groupItem]).DefaultIfEmpty() + where [model.Owner]?.FirstName == "Crawford" + select TodoItem _Include( + queryContext: queryContext, + entity: [model], + included: new object[]{ [model.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId", "model.Owner"."Id", "model.Owner"."FirstName", "model.Owner"."LastName" + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' + LIMIT @__p_1 OFFSET @__p_0, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId", "model.Owner"."Id", "model.Owner"."FirstName", "model.Owner"."LastName" + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId", "model.Owner"."Id", "model.Owner"."FirstName", "model.Owner"."LastName" + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId", "model.Owner"."Id", "model.Owner"."FirstName", "model.Owner"."LastName" + FROM "TodoItems" AS "model" + LEFT JOIN "People" AS "model.Owner" ON "model"."OwnerId" = "model.Owner"."Id" + WHERE "model.Owner"."FirstName" = 'Crawford' + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.283ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.283ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 53.232ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 53.232ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&filter[achieved-date]=2/18/18%2012:00:00%20AM +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&filter[achieved-date]=2/18/18%2012:00:00%20AM +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Filter is not allowed for attribute 'achieved-date'. + at JsonApiDotNetCore.Internal.Query.AttrFilterQuery..ctor(IJsonApiContext jsonApiContext, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs:line 26 + at JsonApiDotNetCore.Extensions.IQueryableExtensions.Filter[TSource](IQueryable`1 source, IJsonApiContext jsonApiContext, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs:line 88 + at JsonApiDotNetCore.Data.DefaultEntityRepository`2.Filter(IQueryable`1 entities, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs:line 61 + at JsonApiDotNetCore.Services.EntityResourceService`2.ApplySortAndFilterQuery(IQueryable`1 entities) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 156 + at JsonApiDotNetCore.Services.EntityResourceService`2.d__4.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 46 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__12.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 109 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__3.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 62 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Filter is not allowed for attribute 'achieved-date'. + at JsonApiDotNetCore.Internal.Query.AttrFilterQuery..ctor(IJsonApiContext jsonApiContext, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs:line 26 + at JsonApiDotNetCore.Extensions.IQueryableExtensions.Filter[TSource](IQueryable`1 source, IJsonApiContext jsonApiContext, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs:line 88 + at JsonApiDotNetCore.Data.DefaultEntityRepository`2.Filter(IQueryable`1 entities, FilterQuery filterQuery) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs:line 61 + at JsonApiDotNetCore.Services.EntityResourceService`2.ApplySortAndFilterQuery(IQueryable`1 entities) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 156 + at JsonApiDotNetCore.Services.EntityResourceService`2.d__4.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 46 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__12.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 109 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__3.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 62 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 7.111ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 7.111ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 7.516ms 400 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 7.516ms 400 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[guid-property]=a23f1cb2-5445-4cad-bda5-629ecc2002e2 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?filter[guid-property]=a23f1cb2-5445-4cad-bda5-629ecc2002e2 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc2002e2 + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc2002e2 + select [model]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2'), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc2002e2 + select [model]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem model in DbSet where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where [model].GuidProperty == a23f1cb2-5445-4cad-bda5-629ecc2002e2 + select [model]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."AchievedDate", "model"."AssigneeId", "model"."CollectionId", "model"."CreatedDate", "model"."Description", "model"."GuidProperty", "model"."Ordinal", "model"."OwnerId" + FROM "TodoItems" AS "model" + WHERE "model"."GuidProperty" = 'a23f1cb2-5445-4cad-bda5-629ecc2002e2' + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 11.26ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 11.26ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 17.365ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 17.365ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&sort=achieved-date +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner&sort=achieved-date +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '2fce3eb8-46a5-44ed-9a98-55e95b5c8e2f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Sort is not allowed for attribute 'achieved-date'. + at JsonApiDotNetCore.Services.QueryParser.ParseSortParameters(String value) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 165 + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 51 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.TodoItemsController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Sort is not allowed for attribute 'achieved-date'. + at JsonApiDotNetCore.Services.QueryParser.ParseSortParameters(String value) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 165 + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 51 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.TodoItemsController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 6ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 6ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 6.407ms 400 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 6.407ms 400 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items application/vnd.api+json; charset=ISO-8859-4 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items application/vnd.api+json; charset=ISO-8859-4 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 0.891ms 415 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 0.891ms 415 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 0.468ms 406 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 0.468ms 406 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '05049b95-e09d-45ad-ad89-bee6f6e0f23b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 58.963ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 58.963ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.167ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.167ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id 'd54e2950-a2b5-4f65-98a5-dd097888aa4b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.Person) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.Person) - ModelState is Valid +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +System.InvalidCastException: Unable to cast object of type 'JsonApiDotNetCoreExample.Models.Person' to type 'JsonApiDotNetCoreExample.Models.TodoItem'. + at lambda_method(Closure , Object , Object[] ) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +System.InvalidCastException: Unable to cast object of type 'JsonApiDotNetCoreExample.Models.Person' to type 'JsonApiDotNetCoreExample.Models.TodoItem'. + at lambda_method(Closure , Object , Object[] ) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 11.067ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 11.067ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 26.767ms 409 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 26.767ms 409 application/vnd.api+json +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItemCollection) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItemCollection) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p0, @p1, @p2); +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p0, @p1, @p2); +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 93.607ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 119.596ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 93.607ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 119.596ms 201 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id 'e4bc225e-4ba0-4fca-a686-db10af6c6128' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.StatusCodeResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 403 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 403 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 5.173ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 5.173ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 20.262ms 403 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 20.262ms 403 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-collections'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.GetAsync (JsonApiDotNetCoreExample)' with id '21ae0180-661e-43c0-aaba-a63666b354fa' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItemCollection) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItemCollection) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p0, @p1, @p2); +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p0, @p1, @p2); +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p0, @p1, @p2); +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.CreatedResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 58.596ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 58.596ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 77.468ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 77.468ms 201 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-collections application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-collections'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.GetAsync (JsonApiDotNetCoreExample)' with id '3a8d48b8-e58c-4ef6-b4b3-166fd71553bc' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +fail: JsonApiDotNetCore.Formatters.JsonApiReader[0] + An error occurred while de-serializing the payload +JsonApiDotNetCore.Internal.JsonApiException: Failed to deserialize request body ---> System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[JsonApiDotNetCore.Models.ResourceIdentifierObject]' to type 'System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.Object]]'. + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.SetHasManyRelationship(Object entity, PropertyInfo[] entityProperties, RelationshipAttribute attr, ContextEntity contextEntity, Dictionary`2 relationships) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 216 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.SetRelationships(Object entity, ContextEntity contextEntity, Dictionary`2 relationships) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 156 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.DocumentToObject(DocumentData data) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 92 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 33 + --- End of inner exception stack trace --- + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 38 + at JsonApiDotNetCore.Formatters.JsonApiReader.ReadAsync(InputFormatterContext context) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs:line 39 +fail: JsonApiDotNetCore.Formatters.JsonApiReader[0] + An error occurred while de-serializing the payload +JsonApiDotNetCore.Internal.JsonApiException: Failed to deserialize request body ---> System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[JsonApiDotNetCore.Models.ResourceIdentifierObject]' to type 'System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.Object]]'. + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.SetHasManyRelationship(Object entity, PropertyInfo[] entityProperties, RelationshipAttribute attr, ContextEntity contextEntity, Dictionary`2 relationships) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 216 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.SetRelationships(Object entity, ContextEntity contextEntity, Dictionary`2 relationships) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 156 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.DocumentToObject(DocumentData data) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 92 + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 33 + --- End of inner exception stack trace --- + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 38 + at JsonApiDotNetCore.Formatters.JsonApiReader.ReadAsync(InputFormatterContext context) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs:line 39 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments () - ModelState is Invalid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) with arguments () - ModelState is Invalid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.StatusCodeResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 422 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 422 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 22.188ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoCollectionsController.PostAsync (JsonApiDotNetCoreExample) in 22.188ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 42.033ms 422 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 42.033ms 422 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +[xUnit.net 00:00:12.5112580] JsonApiDotNetCore.Internal.JsonApiException : Failed to deserialize request body +[xUnit.net 00:00:12.5115070] ---- System.NullReferenceException : Object reference not set to an instance of an object. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +[xUnit.net 00:00:12.5136610] Stack Trace: +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +[xUnit.net 00:00:12.5158820] /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs(38,0): at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) +[xUnit.net 00:00:12.5161330] /Users/jarednance/dev/json-api-dotnet-core/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs(273,0): at JsonApiDotNetCoreExampleTests.Acceptance.Spec.CreatingDataTests.d__8.MoveNext() +[xUnit.net 00:00:12.5165710] --- End of stack trace from previous location where exception was thrown --- +[xUnit.net 00:00:12.5167200] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +[xUnit.net 00:00:12.5168760] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +[xUnit.net 00:00:12.5170850] --- End of stack trace from previous location where exception was thrown --- +[xUnit.net 00:00:12.5171820] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +[xUnit.net 00:00:12.5172640] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +[xUnit.net 00:00:12.5174340] --- End of stack trace from previous location where exception was thrown --- +[xUnit.net 00:00:12.5175190] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +[xUnit.net 00:00:12.5175960] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +[xUnit.net 00:00:12.5180580] ----- Inner Stack Trace ----- +[xUnit.net 00:00:12.5182020] /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs(32,0): at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '72eb1fba-bd67-40f7-841e-5d45f4d87655' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6) + RETURNING "Id", "CreatedDate"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.CreatedResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 78.019ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 102.786ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 78.019ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 102.786ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 POST http://localhost/api/v1/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) with arguments (JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("Id", "AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("Id", "AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "CreatedDate"; +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 72.862ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 94.538ms 201 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample) in 72.862ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 94.538ms 201 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).LastOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).LastOrDefault()' +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'LastOrDefault()' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'LastOrDefault()' could not be translated and will be evaluated locally. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(TodoItem LastOrDefault(IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t", + shaper: UnbufferedEntityShaper))), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/api/v1/todo-items/10099 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 DELETE http://localhost/api/v1/todo-items/10099 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id 'fe31e5b4-7432-4ff5-978a-cd27e2b93135' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '3c77838f-36d1-41ad-b93d-e79ea0456a72' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) with arguments (10099) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) with arguments (10099) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (16ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (16ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.NotFoundResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 404 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 404 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) in 26.655ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample) in 26.655ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 58.036ms 404 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 58.036ms 404 +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2611?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2611?include=owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id 'da4f66ae-3f53-4439-80dc-28886ee0c729' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id 'df4d22d4-25aa-4cc4-b517-33a346cabff2' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2611) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2611) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("Owner") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 81.295ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 101.754ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 81.295ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 101.754ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + DELETE FROM "TodoItems" + WHERE "Id" = @p1; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + DELETE FROM "TodoItems" + WHERE "Id" = @p1; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + DELETE FROM "TodoItems" + WHERE "Id" = @p1; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '45c59ea2-28ca-4bbb-b184-0cd79d273bed' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 41.443ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 41.443ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 57.056ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 57.056ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2612/owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2612/owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}/{relationshipName}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) with arguments (2612, owner) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) with arguments (2612, owner) - ModelState is Valid +trce: JsonApiDotNetCore.Services.EntityResourceService[0] + Looking up 'Owner'... +dbug: JsonApiDotNetCore.Data.DefaultEntityRepository[0] + [JADN] GetAndIncludeAsync(2612, Owner) +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in + (from TodoItem _1 in DbSet + select [_1]).Include("Owner") + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_1].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Relationship Owner not found. + at JsonApiDotNetCore.Services.EntityResourceService`2.d__9.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 102 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__15.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 141 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__6.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 73 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Relationship Owner not found. + at JsonApiDotNetCore.Services.EntityResourceService`2.d__9.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 102 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__15.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 141 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__6.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 73 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) in 58.256ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) in 58.256ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.585ms 404 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.585ms 404 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +Failed JsonApiDotNetCoreExampleTests.Acceptance.Spec.CreatingDataTests.Can_Create_And_Set_HasMany_Relationships +Error Message: + JsonApiDotNetCore.Internal.JsonApiException : Failed to deserialize request body +---- System.NullReferenceException : Object reference not set to an instance of an object. +Stack Trace: + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 38 + at JsonApiDotNetCoreExampleTests.Acceptance.Spec.CreatingDataTests.d__8.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs:line 273 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +----- Inner Stack Trace ----- + at JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(String requestBody) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs:line 32 +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2613/owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2613/owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}/{relationshipName}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) with arguments (2613, owner) - ModelState is Valid +trce: JsonApiDotNetCore.Services.EntityResourceService[0] + Looking up 'Owner'... +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) with arguments (2613, owner) - ModelState is Valid +dbug: JsonApiDotNetCore.Data.DefaultEntityRepository[0] + [JADN] GetAndIncludeAsync(2613, Owner) +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in + (from TodoItem _1 in DbSet + select [_1]).Include("Owner") + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_1].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) in 56.604ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipAsync (JsonApiDotNetCoreExample) in 56.604ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 74.256ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 74.256ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?unknownKey=value +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?unknownKey=value +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '154c85f6-801d-4115-8e42-da8fe75f1bea' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: [unknownKey, value] is not a valid query. + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 75 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.TodoItemsController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: [unknownKey, value] is not a valid query. + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 75 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.TodoItemsController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 4.858ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 4.858ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 24.057ms 400 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 24.057ms 400 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2614?fields[todo-items]=description,created-date +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2614?fields[todo-items]=description,created-date +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id 'ce1f18f1-2c9d-469e-8706-cdda1d627b0c' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '736779bb-b124-40ac-a9e5-58f8ea4bdcc3' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2614) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2614) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem model in DbSet + where bool new TodoItem{ + Id = [model].Id, + Description = [model].Description, + CreatedDate = [model].CreatedDate + } + .Id.Equals((object)__id_0) + select new TodoItem{ + Id = [model].Id, + Description = [model].Description, + CreatedDate = [model].CreatedDate + } + ).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem model in DbSet + where bool new TodoItem{ + Id = [model].Id, + Description = [model].Description, + CreatedDate = [model].CreatedDate + } + .Id.Equals((object)__id_0) + select new TodoItem{ + Id = [model].Id, + Description = [model].Description, + CreatedDate = [model].CreatedDate + } + ).SingleOrDefault()' +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where new TodoItem() {Id = [model].Id, Description = [model].Description, CreatedDate = [model].CreatedDate}.Id.Equals(Convert(__id_0, Object))' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where new TodoItem() {Id = [model].Id, Description = [model].Description, CreatedDate = [model].CreatedDate}.Id.Equals(Convert(__id_0, Object))' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'SingleOrDefault()' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'SingleOrDefault()' could not be translated and will be evaluated locally. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable _Where( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "model"."Id", "model"."Description", "model"."CreatedDate" + FROM "TodoItems" AS "model", + shaper: ValueBufferShaper), + predicate: (ValueBuffer model) => bool new TodoItem{ + Id = int TryReadValue(model, 0, TodoItem.Id), + Description = string TryReadValue(model, 1, TodoItem.Description), + CreatedDate = DateTime TryReadValue(model, 2, TodoItem.CreatedDate) + } + .Id.Equals((object)int GetParameterValue( + queryContext: queryContext, + parameterName: "__id_0"))), + selector: (ValueBuffer model) => new TodoItem{ + Id = int TryReadValue(model, 0, TodoItem.Id), + Description = string TryReadValue(model, 1, TodoItem.Description), + CreatedDate = DateTime TryReadValue(model, 2, TodoItem.CreatedDate) + } + ), + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."Description", "model"."CreatedDate" + FROM "TodoItems" AS "model" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."Description", "model"."CreatedDate" + FROM "TodoItems" AS "model" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "model"."Id", "model"."Description", "model"."CreatedDate" + FROM "TodoItems" AS "model" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 105.374ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 105.374ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 125.325ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 125.325ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from TodoItem t in DbSet + where [t].Id == 2615 + select new TodoItem{ + Id = [t].Id, + Description = [t].Description, + CreatedDate = [t].CreatedDate, + AchievedDate = [t].AchievedDate + } + ' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from TodoItem t in DbSet + where [t].Id == 2615 + select new TodoItem{ + Id = [t].Id, + Description = [t].Description, + CreatedDate = [t].CreatedDate, + AchievedDate = [t].AchievedDate + } + ' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."Description", "t"."CreatedDate", "t"."AchievedDate" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = 2615, + shaper: TypedProjectionShaper), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem t in DbSet + where [t].Id == __todoItem_Id_0 + select new TodoItem{ + Id = [t].Id, + Description = [t].Description, + CreatedDate = [t].CreatedDate, + AchievedDate = [t].AchievedDate + } + ).First()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem t in DbSet + where [t].Id == __todoItem_Id_0 + select new TodoItem{ + Id = [t].Id, + Description = [t].Description, + CreatedDate = [t].CreatedDate, + AchievedDate = [t].AchievedDate + } + ).First()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task First( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."Description", "t"."CreatedDate", "t"."AchievedDate" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1, + shaper: TypedProjectionShaper), + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."Description", "t"."CreatedDate", "t"."AchievedDate" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."Description", "t"."CreatedDate", "t"."AchievedDate" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."Description", "t"."CreatedDate", "t"."AchievedDate" + FROM "TodoItems" AS "t" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2616 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2616 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '99416189-fd56-43fd-accb-b675b7d46314' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '7d80e15e-9750-4047-b86c-88bfc61fd12f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2616, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2616, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (11ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 95.019ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 95.019ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 116.16ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 116.16ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem t in + (from TodoItem _1 in DbSet + select [_1]) + .AsNoTracking() + .Include("Owner") + where [t].Id == __todoItem_Id_0 + select [t]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_1].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem t in DbSet + join Person t.Owner in DbSet + on Property([t], "OwnerId") equals (Nullable)Property([t.Owner], "Id") into t.Owner_group + from Person t.Owner in + (from Person t.Owner_groupItem in [t.Owner_group] + select [t.Owner_groupItem]).DefaultIfEmpty() + where [t].Id == __todoItem_Id_0 + select TodoItem _Include( + queryContext: queryContext, + entity: [t], + included: new object[]{ [t.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + return !(bool ReferenceEquals(included[0], null)) ? + { + entity.Owner = (Person)included[0] + return bool ClrICollectionAccessor, TodoItem>.Add( + instance: included[0], + value: entity) + } + : default(bool) + } + )).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _ToSequence(TodoItem SingleOrDefault(IEnumerable _Select( + source: IEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + return !(bool ReferenceEquals(included[0], null)) ? + { + entity.Owner = (Person)included[0] + return bool ClrICollectionAccessor, TodoItem>.Add( + instance: included[0], + value: entity) + } + : default(bool) + } + )))), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2716 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2716 application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample)' with id '2a9a328a-ccd2-441f-86b9-778e783257c7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id 'f400e30f-a558-41ca-9432-b889d803f5d2' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2716, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) with arguments (2716, JsonApiDotNetCoreExample.Models.TodoItem) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.NotFoundResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 404 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 404 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 27.817ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample) in 27.817ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 47.257ms 404 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 47.257ms 404 +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2617/relationships/owner application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/todo-items/2617/relationships/owner application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}/relationships/{relationshipName}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetRelationshipsAsync (JsonApiDotNetCoreExample)' with id '3fde0ec7-9039-455f-910c-e568544f788a' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) with arguments (2617, owner, System.Collections.Generic.List`1[JsonApiDotNetCore.Models.DocumentData]) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) with arguments (2617, owner, System.Collections.Generic.List`1[JsonApiDotNetCore.Models.DocumentData]) - ModelState is Valid +dbug: JsonApiDotNetCore.Data.DefaultEntityRepository[0] + [JADN] GetAndIncludeAsync(2617, Owner) +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in + (from TodoItem _1 in DbSet + select [_1]).Include("Owner") + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_1].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (12ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (12ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person x in DbSet + where __First_0 == [x].StringId + select [x]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person x in DbSet + where __First_0 == [x].StringId + select [x]).SingleOrDefault()' +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where (__First_0 == [x].StringId)' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where (__First_0 == [x].StringId)' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'SingleOrDefault()' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'SingleOrDefault()' could not be translated and will be evaluated locally. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(Person SingleOrDefault(IEnumerable _Where( + source: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "x"."Id", "x"."FirstName", "x"."LastName" + FROM "People" AS "x", + shaper: UnbufferedEntityShaper), + predicate: (Person x) => string GetParameterValue( + queryContext: queryContext, + parameterName: "__First_0") == x.StringId))), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."FirstName", "x"."LastName" + FROM "People" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."FirstName", "x"."LastName" + FROM "People" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."FirstName", "x"."LastName" + FROM "People" AS "x" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) in 128.36ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) in 128.36ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 147.825ms 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 147.825ms 200 +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem t in + (from TodoItem t in DbSet + select [t]).Include("Owner") + where [t].Id == __todoItem_Id_0 + select [t]).Single()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[t].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem t in DbSet + join Person t.Owner in DbSet + on Property([t], "OwnerId") equals (Nullable)Property([t.Owner], "Id") into t.Owner_group + from Person t.Owner in + (from Person t.Owner_groupItem in [t.Owner_group] + select [t.Owner_groupItem]).DefaultIfEmpty() + where [t].Id == __todoItem_Id_0 + select TodoItem _Include( + queryContext: queryContext, + entity: [t], + included: new object[]{ [t.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).Single()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(TodoItem Single(IEnumerable _Select( + source: IEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )))), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__todoItem_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + WHERE "t"."Id" = @__todoItem_Id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/people/887/relationships/todo-items application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 PATCH http://localhost/api/v1/people/887/relationships/todo-items application/vnd.api+json +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}/relationships/{relationshipName}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.GetRelationshipsAsync (JsonApiDotNetCoreExample)' with id '55bc06aa-666a-4e45-9dba-c3c04b1e2592' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) +dbug: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder[1] + Selected input formatter 'JsonApiDotNetCore.Formatters.JsonApiInputFormatter' for content type 'application/vnd.api+json'. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) with arguments (887, todo-items, System.Collections.Generic.List`1[JsonApiDotNetCore.Models.DocumentData]) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) with arguments (887, todo-items, System.Collections.Generic.List`1[JsonApiDotNetCore.Models.DocumentData]) - ModelState is Valid +dbug: JsonApiDotNetCore.Data.DefaultEntityRepository[0] + [JADN] GetAndIncludeAsync(887, TodoItems) +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person e in + (from Person _1 in DbSet + select [_1]).Include("TodoItems") + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_1].TodoItems' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select Task _IncludeAsync( + queryContext: queryContext, + entity: [e], + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => + from TodoItem e.TodoItems in DbSet + join AnonymousObject _e in + (from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[e]?, "Id") })).Take(1) + on Property([e.TodoItems], "OwnerId") equals (Nullable)object [_e].GetValue(0) + order by object [_e].GetValue(0) asc + select [e.TodoItems], + cancellationToken: ct) + } + , + cancellationToken: ct).Result).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _SelectAsync( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 2, + shaper: BufferedEntityShaper), + selector: (Person e | CancellationToken ct) => Task _ExecuteAsync( + taskFactories: new Func>[]{ () => Task _ToObjectTask(Task _IncludeAsync( + queryContext: queryContext, + entity: e, + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id", + shaper: BufferedEntityShaper), + cancellationToken: ct) + } + , + cancellationToken: Unhandled parameter: ct)) }, + selector: (Object[] results) => (Person)results[0])), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from TodoItem x in DbSet + where + (from string _1 in __relationshipIds_0 + select [_1]).Contains([x].StringId) + select [x]' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from TodoItem x in DbSet + where + (from string _1 in __relationshipIds_0 + select [_1]).Contains([x].StringId) + select [x]' +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where {__relationshipIds_0 => Contains([x].StringId)}' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'where {__relationshipIds_0 => Contains([x].StringId)}' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'Contains([x].StringId)' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'Contains([x].StringId)' could not be translated and will be evaluated locally. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _Where( + source: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x", + shaper: UnbufferedEntityShaper), + predicate: (TodoItem x) => bool Contains( + source: IEnumerable GetParameterValue( + queryContext: queryContext, + parameterName: "__relationshipIds_0"), + value: x.StringId)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "x"."Id", "x"."AchievedDate", "x"."AssigneeId", "x"."CollectionId", "x"."CreatedDate", "x"."Description", "x"."GuidProperty", "x"."Ordinal", "x"."OwnerId" + FROM "TodoItems" AS "x" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p1='?', @p0='?'], CommandType='Text', CommandTimeout='30'] + UPDATE "TodoItems" SET "OwnerId" = @p0 + WHERE "Id" = @p1; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkResult. +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1] + Executing HttpStatusCodeResult, setting HTTP status code 200 +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) in 222.821ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.PatchRelationshipsAsync (JsonApiDotNetCoreExample) in 222.821ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 254.919ms 200 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 254.919ms 200 +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person p in + (from Person p in DbSet + select [p]).Include("TodoItems") + where [p].Id == __person_Id_0 + select [p]).Single()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[p].TodoItems' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person p in DbSet + where [p].Id == __person_Id_0 + order by (Nullable)EF.Property(?[p]?, "Id") asc + select Person _Include( + queryContext: queryContext, + entity: [p], + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Void queryContext.QueryBuffer.IncludeCollection( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: () => + from TodoItem p.TodoItems in DbSet + join AnonymousObject _p in + (from Person p in DbSet + where [p].Id == __person_Id_0 + order by (Nullable)EF.Property(?[p]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[p]?, "Id") })).Take(1) + on Property([p.TodoItems], "OwnerId") equals (Nullable)object [_p].GetValue(0) + order by object [_p].GetValue(0) asc + select [p.TodoItems]) + } + )).Single()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(Person Single(IEnumerable _Select( + source: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + WHERE "p"."Id" = @__person_Id_0 + ORDER BY "p"."Id" + LIMIT 2, + shaper: BufferedEntityShaper), + selector: (Person p) => Person _Include( + queryContext: queryContext, + entity: p, + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Void queryContext.QueryBuffer.IncludeCollection( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: () => IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + WHERE "p0"."Id" = @__person_Id_0 + ORDER BY "p0"."Id" + LIMIT 1 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id", + shaper: BufferedEntityShaper)) + } + )))), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + WHERE "p"."Id" = @__person_Id_0 + ORDER BY "p"."Id" + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + WHERE "p"."Id" = @__person_Id_0 + ORDER BY "p"."Id" + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + WHERE "p"."Id" = @__person_Id_0 + ORDER BY "p"."Id" + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + WHERE "p0"."Id" = @__person_Id_0 + ORDER BY "p0"."Id" + LIMIT 1 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + WHERE "p0"."Id" = @__person_Id_0 + ORDER BY "p0"."Id" + LIMIT 1 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__person_Id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + WHERE "p0"."Id" = @__person_Id_0 + ORDER BY "p0"."Id" + LIMIT 1 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from Person _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from Person _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p", + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + DELETE FROM "People" + WHERE "Id" = @p1; + DELETE FROM "People" + WHERE "Id" = @p2; + DELETE FROM "People" + WHERE "Id" = @p3; + DELETE FROM "People" + WHERE "Id" = @p4; + DELETE FROM "People" + WHERE "Id" = @p5; + DELETE FROM "People" + WHERE "Id" = @p6; + DELETE FROM "People" + WHERE "Id" = @p7; + DELETE FROM "People" + WHERE "Id" = @p8; + DELETE FROM "People" + WHERE "Id" = @p9; + DELETE FROM "People" + WHERE "Id" = @p10; + DELETE FROM "People" + WHERE "Id" = @p11; + DELETE FROM "People" + WHERE "Id" = @p12; + DELETE FROM "People" + WHERE "Id" = @p13; + DELETE FROM "People" + WHERE "Id" = @p14; + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + DELETE FROM "People" + WHERE "Id" = @p19; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p20, @p21) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + DELETE FROM "People" + WHERE "Id" = @p1; + DELETE FROM "People" + WHERE "Id" = @p2; + DELETE FROM "People" + WHERE "Id" = @p3; + DELETE FROM "People" + WHERE "Id" = @p4; + DELETE FROM "People" + WHERE "Id" = @p5; + DELETE FROM "People" + WHERE "Id" = @p6; + DELETE FROM "People" + WHERE "Id" = @p7; + DELETE FROM "People" + WHERE "Id" = @p8; + DELETE FROM "People" + WHERE "Id" = @p9; + DELETE FROM "People" + WHERE "Id" = @p10; + DELETE FROM "People" + WHERE "Id" = @p11; + DELETE FROM "People" + WHERE "Id" = @p12; + DELETE FROM "People" + WHERE "Id" = @p13; + DELETE FROM "People" + WHERE "Id" = @p14; + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + DELETE FROM "People" + WHERE "Id" = @p19; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p20, @p21) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + DELETE FROM "People" + WHERE "Id" = @p1; + DELETE FROM "People" + WHERE "Id" = @p2; + DELETE FROM "People" + WHERE "Id" = @p3; + DELETE FROM "People" + WHERE "Id" = @p4; + DELETE FROM "People" + WHERE "Id" = @p5; + DELETE FROM "People" + WHERE "Id" = @p6; + DELETE FROM "People" + WHERE "Id" = @p7; + DELETE FROM "People" + WHERE "Id" = @p8; + DELETE FROM "People" + WHERE "Id" = @p9; + DELETE FROM "People" + WHERE "Id" = @p10; + DELETE FROM "People" + WHERE "Id" = @p11; + DELETE FROM "People" + WHERE "Id" = @p12; + DELETE FROM "People" + WHERE "Id" = @p13; + DELETE FROM "People" + WHERE "Id" = @p14; + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + DELETE FROM "People" + WHERE "Id" = @p19; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p20, @p21) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p28; + DELETE FROM "People" + WHERE "Id" = @p29; + DELETE FROM "People" + WHERE "Id" = @p30; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p28; + DELETE FROM "People" + WHERE "Id" = @p29; + DELETE FROM "People" + WHERE "Id" = @p30; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p28; + DELETE FROM "People" + WHERE "Id" = @p29; + DELETE FROM "People" + WHERE "Id" = @p30; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '5d8ec96c-5e08-48d8-8af5-20d91d1acfd0' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Include("Owner") + .Count()' +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _3 in DbSet + select [_3]) + .Include("Owner") + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_3].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _3 in DbSet + join Person t.Owner in DbSet + on Property([_3], "OwnerId") equals (Nullable)Property([t.Owner], "Id") into t.Owner_group + from Person t.Owner in + (from Person t.Owner_groupItem in [t.Owner_group] + select [t.Owner_groupItem]).DefaultIfEmpty() + select TodoItem _Include( + queryContext: queryContext, + entity: [_3], + included: new object[]{ [t.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 76.304ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 76.304ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 96.232ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 96.232ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (0ms) [Parameters=[@p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (0ms) [Parameters=[@p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '5b834c60-041f-4099-83c5-05901ad2c3a8' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Include("Owner") + .Count()' +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _3 in DbSet + select [_3]) + .Include("Owner") + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_3].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _3 in DbSet + join Person t.Owner in DbSet + on Property([_3], "OwnerId") equals (Nullable)Property([t.Owner], "Id") into t.Owner_group + from Person t.Owner in + (from Person t.Owner_groupItem in [t.Owner_group] + select [t.Owner_groupItem]).DefaultIfEmpty() + select TodoItem _Include( + queryContext: queryContext, + entity: [_3], + included: new object[]{ [t.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId", "t.Owner"."Id", "t.Owner"."FirstName", "t.Owner"."LastName" + FROM "TodoItems" AS "t" + LEFT JOIN "People" AS "t.Owner" ON "t"."OwnerId" = "t.Owner"."Id" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 80.648ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 80.648ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 100.942ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 100.942ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _1 in DbSet + select [_1]).First()' +warn: Microsoft.EntityFrameworkCore.Query[10103] + Query: '(from Person _1 in DbSet select [_1]).First()' uses First/FirstOrDefault operation without OrderBy and filter which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10103] + Query: '(from Person _1 in DbSet select [_1]).First()' uses First/FirstOrDefault operation without OrderBy and filter which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _1 in DbSet + select [_1]).First()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(Person First(IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1, + shaper: UnbufferedEntityShaper))), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/888?include=non-existent-relationship +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/888?include=non-existent-relationship +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PatchAsync (JsonApiDotNetCoreExample)' with id 'e3d89928-9c88-496c-b73a-f712ea6b3a37' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.DeleteAsync (JsonApiDotNetCoreExample)' with id '0564ca1d-138d-4994-89ff-4c633b77efa6' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (888) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (888) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Invalid relationship non-existent-relationship on people + at JsonApiDotNetCore.Data.DefaultEntityRepository`2.Include(IQueryable`1 entities, String relationshipName) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs:line 139 + at JsonApiDotNetCore.Services.EntityResourceService`2.<>c__DisplayClass7_0.b__0(String r) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 77 + at System.Collections.Generic.List`1.ForEach(Action`1 action) + at JsonApiDotNetCore.Services.EntityResourceService`2.d__7.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 75 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Services.EntityResourceService`2.d__5.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 63 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__13.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 118 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__4.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 65 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Invalid relationship non-existent-relationship on people + at JsonApiDotNetCore.Data.DefaultEntityRepository`2.Include(IQueryable`1 entities, String relationshipName) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs:line 139 + at JsonApiDotNetCore.Services.EntityResourceService`2.<>c__DisplayClass7_0.b__0(String r) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 77 + at System.Collections.Generic.List`1.ForEach(Action`1 action) + at JsonApiDotNetCore.Services.EntityResourceService`2.d__7.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 75 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Services.EntityResourceService`2.d__5.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/EntityResourceService.cs:line 63 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2.d__13.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 118 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() + at JsonApiDotNetCore.Controllers.JsonApiController`2.d__4.MoveNext() in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 65 +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 14.734ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 14.734ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 32.884ms 400 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 32.884ms 400 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug[49m: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2622?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2622?include=owner +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '2e60476c-d745-4d1d-9734-3048cf0e06f7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '892e3c0c-6a62-4b84-bc3b-630712d4abda' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2622) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2622) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("Owner") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[]{ [e.Owner] }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>), + selector: (TransparentIdentifier t1) => TodoItem _Include( + queryContext: queryContext, + entity: t1.Outer, + included: new object[]{ t1.Inner }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + return !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 68.602ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 68.602ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 92.782ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 92.782ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/891?include=todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/891?include=todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PatchAsync (JsonApiDotNetCoreExample)' with id '422cb7bd-76e2-4921-a970-fd3b6e53cbc5' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.DeleteAsync (JsonApiDotNetCoreExample)' with id '704b8366-e2fb-4047-91ac-ef75d37aadf9' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (891) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (891) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("TodoItems") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].TodoItems' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select Task _IncludeAsync( + queryContext: queryContext, + entity: [e], + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => + from TodoItem e.TodoItems in DbSet + join AnonymousObject _e in + (from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[e]?, "Id") })).Take(1) + on Property([e.TodoItems], "OwnerId") equals (Nullable)object [_e].GetValue(0) + order by object [_e].GetValue(0) asc + select [e.TodoItems], + cancellationToken: ct) + } + , + cancellationToken: ct).Result).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _SelectAsync( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1, + shaper: BufferedEntityShaper), + selector: (Person e | CancellationToken ct) => Task _ExecuteAsync( + taskFactories: new Func>[]{ () => Task _ToObjectTask(Task _IncludeAsync( + queryContext: queryContext, + entity: e, + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id", + shaper: BufferedEntityShaper), + cancellationToken: ct) + } + , + cancellationToken: Unhandled parameter: ct)) }, + selector: (Object[] results) => (Person)results[0])), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 121.247ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 121.247ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 140.619ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 140.619ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/888?include=owner.name +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/888?include=owner.name +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PatchAsync (JsonApiDotNetCoreExample)' with id 'b46d9cb1-c51a-434d-9ecd-e4dd6d0d699f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.DeleteAsync (JsonApiDotNetCoreExample)' with id '2deec43b-6907-4519-a36a-21a2dbd0b0f6' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Deeply nested relationships are not supported + at JsonApiDotNetCore.Services.QueryParser.ParseIncludedRelationships(String value) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 176 + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 57 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.PeopleController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/PeopleController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +fail: JsonApiDotNetCore.Middleware.JsonApiExceptionFilter[0] + An unhandled exception occurred during the request +JsonApiDotNetCore.Internal.JsonApiException: Deeply nested relationships are not supported + at JsonApiDotNetCore.Services.QueryParser.ParseIncludedRelationships(String value) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 176 + at JsonApiDotNetCore.Services.QueryParser.Parse(IQueryCollection query) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/QueryParser.cs:line 57 + at JsonApiDotNetCore.Services.JsonApiContext.ApplyContext[T](Object controller) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Services/JsonApiContext.cs:line 70 + at JsonApiDotNetCore.Controllers.BaseJsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs:line 56 + at JsonApiDotNetCore.Controllers.JsonApiController`2..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 40 + at JsonApiDotNetCore.Controllers.JsonApiController`1..ctor(IJsonApiContext jsonApiContext, IResourceService`2 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 17 + at JsonApiDotNetCoreExample.Controllers.PeopleController..ctor(IJsonApiContext jsonApiContext, IResourceService`1 resourceService, ILoggerFactory loggerFactory) in /Users/jarednance/dev/json-api-dotnet-core/src/Examples/JsonApiDotNetCoreExample/Controllers/PeopleController.cs:line 14 + at lambda_method(Closure , IServiceProvider , Object[] ) + at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) + at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() +--- End of stack trace from previous location where exception was thrown --- + at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) + at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 5.157ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 5.157ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 25.495ms 400 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 25.495ms 400 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p2, @p3, @p4); +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p2, @p3, @p4); +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItemCollections" ("Id", "Name", "OwnerId") + VALUES (@p2, @p3, @p4); +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/892?include=todo-items,todo-collections +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/892?include=todo-items,todo-collections +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PatchAsync (JsonApiDotNetCoreExample)' with id '3f6bab1b-ca52-4fbd-a8c4-dee3c0df1851' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.DeleteAsync (JsonApiDotNetCoreExample)' with id '0c5a6576-2492-4aff-80c7-4f36a82e8d14' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (892) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (892) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("TodoItems") + .Include("TodoItemCollections") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].TodoItems' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].TodoItemCollections' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select Task _IncludeAsync( + queryContext: queryContext, + entity: [e], + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task _AwaitMany(new Func[] + { + () => Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => + from TodoItem e.TodoItems in DbSet + join AnonymousObject _e in + (from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[e]?, "Id") })).Take(1) + on Property([e.TodoItems], "OwnerId") equals (Nullable)object [_e].GetValue(0) + order by object [_e].GetValue(0) asc + select [e.TodoItems], + cancellationToken: ct), + () => Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 1, + navigation: Person.TodoItemCollections, + inverseNavigation: TodoItemCollection.Owner, + targetEntityType: EntityType: TodoItemCollection, + clrCollectionAccessor: ClrICollectionAccessor, TodoItemCollection>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => + from TodoItemCollection e.TodoItemCollections in DbSet + join AnonymousObject _e in + (from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + order by (Nullable)EF.Property(?[e]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[e]?, "Id") })).Take(1) + on Property([e.TodoItemCollections], "OwnerId") equals (Nullable)object [_e].GetValue(0) + order by object [_e].GetValue(0) asc + select [e.TodoItemCollections], + cancellationToken: ct) + }) + } + , + cancellationToken: ct).Result).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _SelectAsync( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1, + shaper: BufferedEntityShaper), + selector: (Person e | CancellationToken ct) => Task _ExecuteAsync( + taskFactories: new Func>[]{ () => Task _ToObjectTask(Task _IncludeAsync( + queryContext: queryContext, + entity: e, + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task _AwaitMany(new Func[] + { + () => Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id", + shaper: BufferedEntityShaper), + cancellationToken: ct), + () => Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 1, + navigation: Person.TodoItemCollections, + inverseNavigation: TodoItemCollection.Owner, + targetEntityType: EntityType: TodoItemCollection, + clrCollectionAccessor: ClrICollectionAccessor, TodoItemCollection>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e.TodoItemCollections"."Id", "e.TodoItemCollections"."Name", "e.TodoItemCollections"."OwnerId" + FROM "TodoItemCollections" AS "e.TodoItemCollections" + INNER JOIN ( + SELECT "e1"."Id" + FROM "People" AS "e1" + WHERE "e1"."Id" = @__id_0 + ORDER BY "e1"."Id" + LIMIT 1 + ) AS "t0" ON "e.TodoItemCollections"."OwnerId" = "t0"."Id" + ORDER BY "t0"."Id", + shaper: BufferedEntityShaper), + cancellationToken: ct) + }) + } + , + cancellationToken: Unhandled parameter: ct)) }, + selector: (Object[] results) => (Person)results[0])), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + ORDER BY "e"."Id" + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItems"."Id", "e.TodoItems"."AchievedDate", "e.TodoItems"."AssigneeId", "e.TodoItems"."CollectionId", "e.TodoItems"."CreatedDate", "e.TodoItems"."Description", "e.TodoItems"."GuidProperty", "e.TodoItems"."Ordinal", "e.TodoItems"."OwnerId" + FROM "TodoItems" AS "e.TodoItems" + INNER JOIN ( + SELECT "e0"."Id" + FROM "People" AS "e0" + WHERE "e0"."Id" = @__id_0 + ORDER BY "e0"."Id" + LIMIT 1 + ) AS "t" ON "e.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItemCollections"."Id", "e.TodoItemCollections"."Name", "e.TodoItemCollections"."OwnerId" + FROM "TodoItemCollections" AS "e.TodoItemCollections" + INNER JOIN ( + SELECT "e1"."Id" + FROM "People" AS "e1" + WHERE "e1"."Id" = @__id_0 + ORDER BY "e1"."Id" + LIMIT 1 + ) AS "t0" ON "e.TodoItemCollections"."OwnerId" = "t0"."Id" + ORDER BY "t0"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItemCollections"."Id", "e.TodoItemCollections"."Name", "e.TodoItemCollections"."OwnerId" + FROM "TodoItemCollections" AS "e.TodoItemCollections" + INNER JOIN ( + SELECT "e1"."Id" + FROM "People" AS "e1" + WHERE "e1"."Id" = @__id_0 + ORDER BY "e1"."Id" + LIMIT 1 + ) AS "t0" ON "e.TodoItemCollections"."OwnerId" = "t0"."Id" + ORDER BY "t0"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e.TodoItemCollections"."Id", "e.TodoItemCollections"."Name", "e.TodoItemCollections"."OwnerId" + FROM "TodoItemCollections" AS "e.TodoItemCollections" + INNER JOIN ( + SELECT "e1"."Id" + FROM "People" AS "e1" + WHERE "e1"."Id" = @__id_0 + ORDER BY "e1"."Id" + LIMIT 1 + ) AS "t0" ON "e.TodoItemCollections"."OwnerId" = "t0"."Id" + ORDER BY "t0"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 129.696ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 129.696ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 149.864ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 149.864ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p1, @p2) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p1, @p2) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p0; + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p1, @p2) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p15; + DELETE FROM "People" + WHERE "Id" = @p16; + DELETE FROM "People" + WHERE "Id" = @p17; + DELETE FROM "People" + WHERE "Id" = @p18; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2633?include=owner&include=assignee +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2633?include=owner&include=assignee +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '49eb2ce9-b9a4-4b60-8f0d-9dc16928dad7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '0d5cc266-1ec4-468a-84c2-4323d7e9b49c' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2633) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]) + .Include("Owner") + .Include("Assignee") + .FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].Owner' +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[e].Assignee' +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2633) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + join Person e.Assignee in DbSet + on Property([e], "AssigneeId") equals (Nullable)Property([e.Assignee], "Id") into e.Assignee_group + from Person e.Assignee in + (from Person e.Assignee_groupItem in [e.Assignee_group] + select [e.Assignee_groupItem]).DefaultIfEmpty() + join Person e.Owner in DbSet + on Property([e], "OwnerId") equals (Nullable)Property([e.Owner], "Id") into e.Owner_group + from Person e.Owner in + (from Person e.Owner_groupItem in [e.Owner_group] + select [e.Owner_groupItem]).DefaultIfEmpty() + where bool [e].Id.Equals((object)__id_0) + select TodoItem _Include( + queryContext: queryContext, + entity: [e], + included: new object[] + { + [e.Owner], + [e.Assignee] + }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + return !(bool ReferenceEquals(included[1], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[1], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Assignee, + entity: entity, + value: included[1]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.AssignedTodoItems, + entity: included[1], + value: entity) + } + : default(Void) + } + )).FirstOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task FirstOrDefault( + source: IAsyncEnumerable _Select( + source: IAsyncEnumerable, Person>> _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Assignee"."Id", "e.Assignee"."FirstName", "e.Assignee"."LastName", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Assignee" ON "e"."AssigneeId" = "e.Assignee"."Id" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1, + shaper: TypedCompositeShaper, TodoItem, BufferedOffsetEntityShaper, Person, TransparentIdentifier>, TransparentIdentifier, BufferedOffsetEntityShaper, Person, TransparentIdentifier, Person>>), + selector: (TransparentIdentifier, Person> t3) => TodoItem _Include( + queryContext: queryContext, + entity: t3.Outer.Outer, + included: new object[] + { + t3.Inner, + t3.Outer.Inner + }, + fixup: (QueryContext queryContext | TodoItem entity | Object[] included) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: TodoItem) + !(bool ReferenceEquals(included[0], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[0], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Owner, + entity: entity, + value: included[0]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.TodoItems, + entity: included[0], + value: entity) + } + : default(Void) + return !(bool ReferenceEquals(included[1], null)) ? + { + Void queryContext.QueryBuffer.StartTracking( + entity: included[1], + entityType: EntityType: Person) + Void SetRelationshipSnapshotValue( + stateManager: queryContext.StateManager, + navigation: TodoItem.Assignee, + entity: entity, + value: included[1]) + return Void AddToCollectionSnapshot( + stateManager: queryContext.StateManager, + navigation: Person.AssignedTodoItems, + entity: included[1], + value: entity) + } + : default(Void) + } + )), + cancellationToken: Unhandled parameter: queryContext.CancellationToken)), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Assignee"."Id", "e.Assignee"."FirstName", "e.Assignee"."LastName", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Assignee" ON "e"."AssigneeId" = "e.Assignee"."Id" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (15ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Assignee"."Id", "e.Assignee"."FirstName", "e.Assignee"."LastName", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Assignee" ON "e"."AssigneeId" = "e.Assignee"."Id" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (15ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId", "e.Assignee"."Id", "e.Assignee"."FirstName", "e.Assignee"."LastName", "e.Owner"."Id", "e.Owner"."FirstName", "e.Owner"."LastName" + FROM "TodoItems" AS "e" + LEFT JOIN "People" AS "e.Assignee" ON "e"."AssigneeId" = "e.Assignee"."Id" + LEFT JOIN "People" AS "e.Owner" ON "e"."OwnerId" = "e.Owner"."Id" + WHERE "e"."Id" = @__id_0 + LIMIT 1 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 111.286ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 111.286ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 131.712ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 131.712ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p3; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p3; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "People" + WHERE "Id" = @p3; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people?include=todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people?include=todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PostAsync (JsonApiDotNetCoreExample)' with id '1eaf2dd2-1dd5-46db-ba6f-88148a37f5ec' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _2 in DbSet + select [_2]) + .Include("TodoItems") + .Count()' +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].TodoItems' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _2 in DbSet + select [_2]).Count()' +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[_2].TodoItems' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "People" AS "p"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _3 in DbSet + select [_3]) + .Include("TodoItems") + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _3 in DbSet select [_3]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10105] + Including navigation: '[_3].TodoItems' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _3 in DbSet + order by (Nullable)EF.Property(?[_3]?, "Id") asc + select Task _IncludeAsync( + queryContext: queryContext, + entity: [_3], + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => + from TodoItem p.TodoItems in DbSet + join AnonymousObject __3 in + (from Person _3 in DbSet + order by (Nullable)EF.Property(?[_3]?, "Id") asc + select new AnonymousObject(new object[]{ (object)EF.Property(?[_3]?, "Id") })) + .Skip(__p_0) + .Take(__p_1) + on Property([p.TodoItems], "OwnerId") equals (Nullable)object [__3].GetValue(0) + order by object [__3].GetValue(0) asc + select [p.TodoItems], + cancellationToken: ct) + } + , + cancellationToken: ct).Result) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _SelectAsync( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + ORDER BY "p"."Id" + LIMIT @__p_1 OFFSET @__p_0, + shaper: BufferedEntityShaper), + selector: (Person _3 | CancellationToken ct) => Task _ExecuteAsync( + taskFactories: new Func>[]{ () => Task _ToObjectTask(Task _IncludeAsync( + queryContext: queryContext, + entity: _3, + included: new object[]{ }, + fixup: (QueryContext queryContext | Person entity | Object[] included | CancellationToken ct) => + { + Void queryContext.QueryBuffer.StartTracking( + entity: entity, + entityType: EntityType: Person) + return Task queryContext.QueryBuffer.IncludeCollectionAsync( + includeId: 0, + navigation: Person.TodoItems, + inverseNavigation: TodoItem.Owner, + targetEntityType: EntityType: TodoItem, + clrCollectionAccessor: ClrICollectionAccessor, TodoItem>, + inverseClrPropertySetter: ClrPropertySetter, + tracking: True, + instance: entity, + valuesFactory: (Func>)() => IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + ORDER BY "p0"."Id" + LIMIT @__p_1 OFFSET @__p_0 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id", + shaper: BufferedEntityShaper), + cancellationToken: ct) + } + , + cancellationToken: Unhandled parameter: ct)) }, + selector: (Object[] results) => (Person)results[0])), + queryContext: Unhandled parameter: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: Unhandled parameter: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + ORDER BY "p"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + ORDER BY "p"."Id" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + ORDER BY "p"."Id" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + ORDER BY "p0"."Id" + LIMIT @__p_1 OFFSET @__p_0 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + ORDER BY "p0"."Id" + LIMIT @__p_1 OFFSET @__p_0 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p.TodoItems"."Id", "p.TodoItems"."AchievedDate", "p.TodoItems"."AssigneeId", "p.TodoItems"."CollectionId", "p.TodoItems"."CreatedDate", "p.TodoItems"."Description", "p.TodoItems"."GuidProperty", "p.TodoItems"."Ordinal", "p.TodoItems"."OwnerId" + FROM "TodoItems" AS "p.TodoItems" + INNER JOIN ( + SELECT "p0"."Id" + FROM "People" AS "p0" + ORDER BY "p0"."Id" + LIMIT @__p_1 OFFSET @__p_0 + ) AS "t" ON "p.TodoItems"."OwnerId" = "t"."Id" + ORDER BY "t"."Id" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 91.629ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 91.629ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 111.506ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 111.506ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PostAsync (JsonApiDotNetCoreExample)' with id '101783b6-922d-478e-91c4-973fb0212ed5' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "People" AS "p"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (26ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (26ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 76.867ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 76.867ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 97.983ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 97.983ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id", "CreatedDate"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExampleTests +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '66278d25-d1b4-4a31-8edc-371fd1e02b91' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 51.071ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 51.071ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 73.957ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 73.957ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?', @p71='?', @p72='?', @p73='?', @p74='?', @p75='?', @p76='?', @p77='?', @p78='?', @p79='?', @p80='?', @p81='?', @p82='?', @p83='?', @p84='?', @p85='?', @p86='?', @p87='?', @p88='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p41, @p42, @p43, @p44, @p45, @p46, @p47, @p48) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p49, @p50, @p51, @p52, @p53, @p54, @p55, @p56) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p57, @p58, @p59, @p60, @p61, @p62, @p63, @p64) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p65, @p66, @p67, @p68, @p69, @p70, @p71, @p72) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p73, @p74, @p75, @p76, @p77, @p78, @p79, @p80) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p81, @p82, @p83, @p84, @p85, @p86, @p87, @p88) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?', @p71='?', @p72='?', @p73='?', @p74='?', @p75='?', @p76='?', @p77='?', @p78='?', @p79='?', @p80='?', @p81='?', @p82='?', @p83='?', @p84='?', @p85='?', @p86='?', @p87='?', @p88='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p41, @p42, @p43, @p44, @p45, @p46, @p47, @p48) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p49, @p50, @p51, @p52, @p53, @p54, @p55, @p56) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p57, @p58, @p59, @p60, @p61, @p62, @p63, @p64) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p65, @p66, @p67, @p68, @p69, @p70, @p71, @p72) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p73, @p74, @p75, @p76, @p77, @p78, @p79, @p80) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p81, @p82, @p83, @p84, @p85, @p86, @p87, @p88) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?', @p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?', @p71='?', @p72='?', @p73='?', @p74='?', @p75='?', @p76='?', @p77='?', @p78='?', @p79='?', @p80='?', @p81='?', @p82='?', @p83='?', @p84='?', @p85='?', @p86='?', @p87='?', @p88='?'], CommandType='Text', CommandTimeout='30'] + DELETE FROM "TodoItems" + WHERE "Id" = @p0; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p41, @p42, @p43, @p44, @p45, @p46, @p47, @p48) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p49, @p50, @p51, @p52, @p53, @p54, @p55, @p56) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p57, @p58, @p59, @p60, @p61, @p62, @p63, @p64) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p65, @p66, @p67, @p68, @p69, @p70, @p71, @p72) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p73, @p74, @p75, @p76, @p77, @p78, @p79, @p80) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p81, @p82, @p83, @p84, @p85, @p86, @p87, @p88) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[number]=2 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[number]=2 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '29149bf5-e575-4822-ae33-beb5fce2ffc6' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 2 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 51.095ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 70.672ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 51.095ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 70.672ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _1 in DbSet + select [_1]).Last()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _1 in DbSet + select [_1]).Last()' +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'Last()' could not be translated and will be evaluated locally. +warn: Microsoft.EntityFrameworkCore.Query[20500] + The LINQ expression 'Last()' could not be translated and will be evaluated locally. +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ToSequence(Person Last(IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p", + shaper: UnbufferedEntityShaper))), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/894 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people/894 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PatchAsync (JsonApiDotNetCoreExample)' with id '1d8d8ad3-300b-4985-9917-0527d2f32c84' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.DeleteAsync (JsonApiDotNetCoreExample)' with id '110246c9-516c-4d15-b9ac-04e6d266b51b' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (894) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments (894) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."FirstName", "e"."LastName" + FROM "People" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 51.526ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 72.584ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 51.526ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 72.584ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2647 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2647 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '5aeb7733-aac0-4b6a-a5b0-622a10aef310' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '3b020693-8812-48be-bf1b-028a704a3f50' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2647) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2647) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 43.935ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 43.935ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 66.007ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 66.007ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PostAsync (JsonApiDotNetCoreExample)' with id '53236a0e-5a42-4405-8697-b363307b0742' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "People" AS "p"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 53.752ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 53.752ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 75.703ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 75.703ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2648 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2648 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id 'bc9f4094-da3f-4b54-a4b5-746a2be25e55' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '61e99f52-a4c3-40bd-92cc-955e50e086d9' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2648) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2648) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 43.28ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 43.28ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 67.828ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 67.828ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items/2649 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items/2649 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'custom/route/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.PatchAsync (JsonApiDotNetCoreExample)' with id '81b735cc-1698-4dd5-a086-6eda734699c0' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.DeleteAsync (JsonApiDotNetCoreExample)' with id '2d84b987-9823-450c-982d-b63abe1024f7' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments (2649) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments (2649) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 39.12ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 39.12ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 60.789ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 60.789ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/testValues +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/testValues +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'TestValues'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: JsonApiDotNetCore.Serialization.JsonApiSerializer[0] + Response was not a JSONAPI entity. Serializing as plain JSON. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample) in 1.407ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 32.217ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TestValuesController.Get (JsonApiDotNetCoreExample) in 1.407ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 32.217ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (6ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (6ms) [Parameters=[@p0='?', @p1='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items/2650 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items/2650 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'custom/route/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.PatchAsync (JsonApiDotNetCoreExample)' with id '49ee8a92-89ed-4f38-906c-31ab8083271c' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.DeleteAsync (JsonApiDotNetCoreExample)' with id '744dcbe5-efca-479f-bb8f-d7e1c104d561' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments (2650) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem e in DbSet + where bool [e].Id.Equals((object)__id_0) + select [e]).SingleOrDefault()' +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments (2650) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ToSequence(Task SingleOrDefault( + source: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2, + shaper: UnbufferedEntityShaper), + cancellationToken: queryContext.CancellationToken)), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 43.411ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 43.411ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 65.45ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 65.45ms 200 application/vnd.api+json +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/custom/route/todo-items +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'custom/route/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.PostAsync (JsonApiDotNetCoreExample)' with id '38524268-32e2-49e7-872f-c4f51a0ad8cc' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 54.945ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsCustomController.GetAsync (JsonApiDotNetCoreExample) in 54.945ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 69.838ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 69.838ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2651?omitNullValuedAttributes=true +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2651?omitNullValuedAttributes=true +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2651) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2651) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.765ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.765ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.533ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.533ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2652?omitNullValuedAttributes=false +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2652?omitNullValuedAttributes=false +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2652) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2652) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 3.109ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 3.109ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.54ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.54ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2653 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2653 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2653) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2653) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.247ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.247ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.645ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.645ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2654 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2654 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2654) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2654) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 3.771ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 3.771ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 4.491ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 4.491ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2655?omitNullValuedAttributes= +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2655?omitNullValuedAttributes= +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2655) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2655) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.271ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.271ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.444ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.444ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2656?omitNullValuedAttributes=false +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2656?omitNullValuedAttributes=false +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2656) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2656) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 7.526ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 7.526ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 7.947ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 7.947ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2657?omitNullValuedAttributes=true +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2657?omitNullValuedAttributes=true +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2657) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2657) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.605ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.605ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.794ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.794ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2658?omitNullValuedAttributes=true +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2658?omitNullValuedAttributes=true +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2658) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2658) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.479ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.479ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.849ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.849ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2659?omitNullValuedAttributes=foo +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2659?omitNullValuedAttributes=foo +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2659) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2659) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.266ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.266ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.441ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.441ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2660?omitNullValuedAttributes=foo +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2660?omitNullValuedAttributes=foo +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2660) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2660) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.248ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.248ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.239ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.239ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2661?omitNullValuedAttributes=foo +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2661?omitNullValuedAttributes=foo +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2661) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2661) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.492ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.683ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.492ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.683ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2662?omitNullValuedAttributes=false +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2662?omitNullValuedAttributes=false +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2662) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2662) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.181ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.181ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.539ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.539ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2663?omitNullValuedAttributes=true +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2663?omitNullValuedAttributes=true +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2663) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2663) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.411ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.411ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.782ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.782ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (5ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2664?omitNullValuedAttributes=false +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2664?omitNullValuedAttributes=false +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2664) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2664) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.755ms +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.951ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.755ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.951ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2665?omitNullValuedAttributes=foo +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2665?omitNullValuedAttributes=foo +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2665) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2665) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.481ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.481ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.66ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 2.66ms 200 application/vnd.api+json +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2666?omitNullValuedAttributes= +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items/2666?omitNullValuedAttributes= +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items/{id}'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PatchAsync (JsonApiDotNetCoreExample)' with id '1ee61db8-daf4-41f3-90d2-1cf3db87d448' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.DeleteAsync (JsonApiDotNetCoreExample)' with id '75ab2821-99d0-4a3f-9dbb-3747ee7b296e' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2666) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments (2666) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "e"."Id", "e"."AchievedDate", "e"."AssigneeId", "e"."CollectionId", "e"."CreatedDate", "e"."Description", "e"."GuidProperty", "e"."Ordinal", "e"."OwnerId" + FROM "TodoItems" AS "e" + WHERE "e"."Id" = @__id_0 + LIMIT 2 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.802ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 2.802ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.245ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 3.245ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p2, @p3, @p4, @p5, @p6, @p7, @p8) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p9, @p10, @p11, @p12, @p13, @p14, @p15) + RETURNING "Id", "CreatedDate"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p9, @p10, @p11, @p12, @p13, @p14, @p15) + RETURNING "Id", "CreatedDate"; +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?include=owner +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[todoItem].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +warn: Microsoft.EntityFrameworkCore.Query[10106] + The Include operation for navigation '[todoItem].Owner' is unnecessary and was ignored because the navigation is not reachable in the final query results. See https://go.microsoft.com/fwlink/?linkid=850303 for more information. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@___authService_CurrentUserId_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "todoItem" + WHERE "todoItem"."OwnerId" = @___authService_CurrentUserId_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@___authService_CurrentUserId_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "todoItem" + WHERE "todoItem"."OwnerId" = @___authService_CurrentUserId_0 +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem todoItem in DbSet where [todoItem].OwnerId == (Nullable)___authService...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem todoItem in DbSet where [todoItem].OwnerId == (Nullable)___authService...' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@___authService_CurrentUserId_0='?', @__p_2='?', @__p_1='?'], CommandType='Text', CommandTimeout='30'] + SELECT "todoItem"."Id", "todoItem"."AchievedDate", "todoItem"."AssigneeId", "todoItem"."CollectionId", "todoItem"."CreatedDate", "todoItem"."Description", "todoItem"."GuidProperty", "todoItem"."Ordinal", "todoItem"."OwnerId", "todoItem.Owner"."Id", "todoItem.Owner"."FirstName", "todoItem.Owner"."LastName" + FROM "TodoItems" AS "todoItem" + LEFT JOIN "People" AS "todoItem.Owner" ON "todoItem"."OwnerId" = "todoItem.Owner"."Id" + WHERE "todoItem"."OwnerId" = @___authService_CurrentUserId_0 + LIMIT @__p_2 OFFSET @__p_1 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@___authService_CurrentUserId_0='?', @__p_2='?', @__p_1='?'], CommandType='Text', CommandTimeout='30'] + SELECT "todoItem"."Id", "todoItem"."AchievedDate", "todoItem"."AssigneeId", "todoItem"."CollectionId", "todoItem"."CreatedDate", "todoItem"."Description", "todoItem"."GuidProperty", "todoItem"."Ordinal", "todoItem"."OwnerId", "todoItem.Owner"."Id", "todoItem.Owner"."FirstName", "todoItem.Owner"."LastName" + FROM "TodoItems" AS "todoItem" + LEFT JOIN "People" AS "todoItem.Owner" ON "todoItem"."OwnerId" = "todoItem.Owner"."Id" + WHERE "todoItem"."OwnerId" = @___authService_CurrentUserId_0 + LIMIT @__p_2 OFFSET @__p_1 +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.653ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 48.653ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 74.804ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 74.804ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExampleTests +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/people +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/people'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.PeopleController.PostAsync (JsonApiDotNetCoreExample)' with id '1ded46dd-748a-4bb3-b33b-d64481e8f7d0' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "People" AS "p"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "People" AS "p" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 5 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from Person _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from Person _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: Person }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "p"."Id", "p"."FirstName", "p"."LastName" + FROM "People" AS "p" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 54.361ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.817ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.PeopleController.GetAsync (JsonApiDotNetCoreExample) in 54.361ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 78.817ms 200 application/vnd.api+json +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[5] + Hosting shutdown +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '52af8b31-a0b5-47dc-9061-17639045ff8f' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 0 with 2 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 38.24ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 38.24ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 64.502ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 64.502ms 200 application/vnd.api+json +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[5] + Hosting shutdown +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from TodoItem _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from TodoItem _0 in DbSet + select [_0]' +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t", + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; + DELETE FROM "TodoItems" + WHERE "Id" = @p35; + DELETE FROM "TodoItems" + WHERE "Id" = @p36; + DELETE FROM "TodoItems" + WHERE "Id" = @p37; + DELETE FROM "TodoItems" + WHERE "Id" = @p38; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; + DELETE FROM "TodoItems" + WHERE "Id" = @p35; + DELETE FROM "TodoItems" + WHERE "Id" = @p36; + DELETE FROM "TodoItems" + WHERE "Id" = @p37; + DELETE FROM "TodoItems" + WHERE "Id" = @p38; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (4ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?', @p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?', @p38='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; + DELETE FROM "TodoItems" + WHERE "Id" = @p6; + DELETE FROM "TodoItems" + WHERE "Id" = @p7; + DELETE FROM "TodoItems" + WHERE "Id" = @p8; + DELETE FROM "TodoItems" + WHERE "Id" = @p9; + DELETE FROM "TodoItems" + WHERE "Id" = @p10; + DELETE FROM "TodoItems" + WHERE "Id" = @p11; + DELETE FROM "TodoItems" + WHERE "Id" = @p12; + DELETE FROM "TodoItems" + WHERE "Id" = @p13; + DELETE FROM "TodoItems" + WHERE "Id" = @p14; + DELETE FROM "TodoItems" + WHERE "Id" = @p15; + DELETE FROM "TodoItems" + WHERE "Id" = @p16; + DELETE FROM "TodoItems" + WHERE "Id" = @p17; + DELETE FROM "TodoItems" + WHERE "Id" = @p18; + DELETE FROM "TodoItems" + WHERE "Id" = @p19; + DELETE FROM "TodoItems" + WHERE "Id" = @p20; + DELETE FROM "TodoItems" + WHERE "Id" = @p21; + DELETE FROM "TodoItems" + WHERE "Id" = @p22; + DELETE FROM "TodoItems" + WHERE "Id" = @p23; + DELETE FROM "TodoItems" + WHERE "Id" = @p24; + DELETE FROM "TodoItems" + WHERE "Id" = @p25; + DELETE FROM "TodoItems" + WHERE "Id" = @p26; + DELETE FROM "TodoItems" + WHERE "Id" = @p27; + DELETE FROM "TodoItems" + WHERE "Id" = @p28; + DELETE FROM "TodoItems" + WHERE "Id" = @p29; + DELETE FROM "TodoItems" + WHERE "Id" = @p30; + DELETE FROM "TodoItems" + WHERE "Id" = @p31; + DELETE FROM "TodoItems" + WHERE "Id" = @p32; + DELETE FROM "TodoItems" + WHERE "Id" = @p33; + DELETE FROM "TodoItems" + WHERE "Id" = @p34; + DELETE FROM "TodoItems" + WHERE "Id" = @p35; + DELETE FROM "TodoItems" + WHERE "Id" = @p36; + DELETE FROM "TodoItems" + WHERE "Id" = @p37; + DELETE FROM "TodoItems" + WHERE "Id" = @p38; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p47, @p48, @p49, @p50, @p51, @p52, @p53, @p54) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p55, @p56, @p57, @p58, @p59, @p60, @p61, @p62) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p63, @p64, @p65, @p66, @p67, @p68, @p69, @p70) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p47, @p48, @p49, @p50, @p51, @p52, @p53, @p54) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p55, @p56, @p57, @p58, @p59, @p60, @p61, @p62) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p63, @p64, @p65, @p66, @p67, @p68, @p69, @p70) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[@p39='?', @p40='?', @p41='?', @p42='?', @p43='?', @p44='?', @p45='?', @p46='?', @p47='?', @p48='?', @p49='?', @p50='?', @p51='?', @p52='?', @p53='?', @p54='?', @p55='?', @p56='?', @p57='?', @p58='?', @p59='?', @p60='?', @p61='?', @p62='?', @p63='?', @p64='?', @p65='?', @p66='?', @p67='?', @p68='?', @p69='?', @p70='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p47, @p48, @p49, @p50, @p51, @p52, @p53, @p54) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p55, @p56, @p57, @p58, @p59, @p60, @p61, @p62) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p63, @p64, @p65, @p66, @p67, @p68, @p69, @p70) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2&page[number]=1 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2&page[number]=1 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '8b075eda-2371-4b4f-8774-1f6d937181b9' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page 1 with 2 entities +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 32.06ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 32.06ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 56.326ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 56.326ms 200 application/vnd.api+json +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[5] + Hosting shutdown +dbug: Microsoft.EntityFrameworkCore.Infrastructure[10401] + An 'IServiceProvider' was created for internal use by Entity Framework. +warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] + More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built. +info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] + User profile is available. Using '/Users/jarednance/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-b040dd03-33c5-451e-8f42-3c9dd4e0dfec.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-c8147b66-2deb-407c-9421-1553f0e16d67.xml'. +dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] + Reading data from file '/Users/jarednance/.aspnet/DataProtection-Keys/key-f7fa4a09-6d65-426e-a653-cbd2969e5073.xml'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {b040dd03-33c5-451e-8f42-3c9dd4e0dfec}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {c8147b66-2deb-407c-9421-1553f0e16d67}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] + Found key {f7fa4a09-6d65-426e-a653-cbd2969e5073}. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] + Considering key {c8147b66-2deb-407c-9421-1553f0e16d67} with expiration date 2018-03-03 16:22:35Z as default key. +dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] + Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[11] + Using managed symmetric algorithm 'System.Security.Cryptography.Aes'. +dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ManagedAuthenticatedEncryptorFactory[10] + Using managed keyed hash algorithm 'System.Security.Cryptography.HMACSHA256'. +dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] + Using key {c8147b66-2deb-407c-9421-1553f0e16d67} as the default key. +dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionStartupFilter[0] + Key ring with default key {c8147b66-2deb-407c-9421-1553f0e16d67} was loaded during application startup. +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + + SELECT CASE WHEN COUNT(*) = 0 THEN FALSE ELSE TRUE END + FROM information_schema.tables + WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3] + Hosting starting +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4] + Hosting started +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0] + Loaded hosting startup assembly JsonApiDotNetCoreExample +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + 'from TodoItem _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + 'from TodoItem _0 in DbSet + select [_0]' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IEnumerable _InterceptExceptions( + source: IEnumerable _TrackEntities( + results: IEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t", + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20200] + Beginning transaction with isolation level 'ReadCommitted'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p3='?', @p4='?', @p5='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "People" ("FirstName", "LastName") + VALUES (@p0, @p1) + RETURNING "Id"; + DELETE FROM "TodoItems" + WHERE "Id" = @p2; + DELETE FROM "TodoItems" + WHERE "Id" = @p3; + DELETE FROM "TodoItems" + WHERE "Id" = @p4; + DELETE FROM "TodoItems" + WHERE "Id" = @p5; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37) + RETURNING "Id"; +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@p6='?', @p7='?', @p8='?', @p9='?', @p10='?', @p11='?', @p12='?', @p13='?', @p14='?', @p15='?', @p16='?', @p17='?', @p18='?', @p19='?', @p20='?', @p21='?', @p22='?', @p23='?', @p24='?', @p25='?', @p26='?', @p27='?', @p28='?', @p29='?', @p30='?', @p31='?', @p32='?', @p33='?', @p34='?', @p35='?', @p36='?', @p37='?'], CommandType='Text', CommandTimeout='30'] + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29) + RETURNING "Id"; + INSERT INTO "TodoItems" ("AchievedDate", "AssigneeId", "CollectionId", "CreatedDate", "Description", "GuidProperty", "Ordinal", "OwnerId") + VALUES (@p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37) + RETURNING "Id"; +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20202] + Committing transaction. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Transaction[20204] + Disposing transaction. +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2&page[number]=-1 +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] + Request starting HTTP/1.1 GET http://localhost/api/v1/todo-items?page[size]=2&page[number]=-1 +dbug: Microsoft.AspNetCore.Routing.Tree.TreeRouter[1] + Request successfully matched the route with name '(null)' and template 'api/v1/todo-items'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ActionSelector[2] + Action 'JsonApiDotNetCoreExample.Controllers.TodoItemsController.PostAsync (JsonApiDotNetCoreExample)' with id '0185f6c8-2dbf-416d-abd0-a7a72d063bea' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] + Executing action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) with arguments ((null)) - ModelState is Valid +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +info: Microsoft.EntityFrameworkCore.Infrastructure[10403] + Entity Framework Core 2.0.1-rtm-125 initialized 'AppDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _1 in DbSet + select [_1]).Count()' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _ToSequence(Task GetResult( + valueBuffers: IAsyncEnumerable _Query( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t"), + throwOnNullResult: False, + cancellationToken: queryContext.CancellationToken)), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: JsonApiDotNetCore.Services.EntityResourceService[0] + Applying paging query. Fetching page -1 with 2 entities +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] + SELECT COUNT(*)::INT4 + FROM "TodoItems" AS "t" +dbug: Microsoft.EntityFrameworkCore.Query[10101] + Compiling query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +warn: Microsoft.EntityFrameworkCore.Query[10102] + Query: '(from TodoItem _2 in DbSet select [_2]).Skip(__p_0).Take(__p_1)' uses a row limiting operation (Skip/Take) without OrderBy which may lead to unpredictable results. +dbug: Microsoft.EntityFrameworkCore.Query[10104] + Optimized query model: + '(from TodoItem _2 in DbSet + select [_2]) + .Skip(__p_0) + .Take(__p_1)' +dbug: Microsoft.EntityFrameworkCore.Query[10107] + (QueryContext queryContext) => IAsyncEnumerable _InterceptExceptions( + source: IAsyncEnumerable _TrackEntities( + results: IAsyncEnumerable _ShapedQuery( + queryContext: queryContext, + shaperCommandContext: SelectExpression: + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0, + shaper: UnbufferedEntityShaper), + queryContext: queryContext, + entityTrackingInfos: { itemType: TodoItem }, + entityAccessors: List> + { + Func, + } + ), + contextType: JsonApiDotNetCoreExample.Data.AppDbContext, + logger: DiagnosticsLogger, + queryContext: queryContext) +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000] + Opening connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001] + Opened connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Command[20100] + Executing DbCommand [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +info: Microsoft.EntityFrameworkCore.Database.Command[20101] + Executed DbCommand (1ms) [Parameters=[@__p_1='?', @__p_0='?'], CommandType='Text', CommandTimeout='30'] + SELECT "t"."Id", "t"."AchievedDate", "t"."AssigneeId", "t"."CollectionId", "t"."CreatedDate", "t"."Description", "t"."GuidProperty", "t"."Ordinal", "t"."OwnerId" + FROM "TodoItems" AS "t" + LIMIT @__p_1 OFFSET @__p_0 +dbug: Microsoft.EntityFrameworkCore.Database.Command[20300] + A data reader was disposed. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20002] + Closing connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.EntityFrameworkCore.Database.Connection[20003] + Closed connection to database 'JsonApiDotNetCoreExample' on server 'tcp://localhost:5432'. +dbug: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action method JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample), returned result Microsoft.AspNetCore.Mvc.OkObjectResult. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[4] + No information found on request to perform content negotiation. +dbug: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[2] + Selected output formatter 'JsonApiDotNetCore.Formatters.JsonApiOutputFormatter' and content type '' to write the response. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1] + Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. +info: JsonApiDotNetCore.Formatters.JsonApiWriter[0] + Formatting response as JSONAPI +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 38.909ms +info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] + Executed action JsonApiDotNetCoreExample.Controllers.TodoItemsController.GetAsync (JsonApiDotNetCoreExample) in 38.909ms +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 63.599ms 200 application/vnd.api+json +info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] + Request finished in 63.599ms 200 application/vnd.api+json +dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[5] + Hosting shutdown +[xUnit.net 00:00:22.5994190] Finished: JsonApiDotNetCoreExampleTests + +Total tests: 111. Passed: 110. Failed: 1. Skipped: 0. +Test execution time: 23.7537 Seconds diff --git a/test/UnitTests/Serialization/JsonApiSerializerTests.cs b/test/UnitTests/Serialization/JsonApiSerializerTests.cs index 3630cd6452..8a67b80434 100644 --- a/test/UnitTests/Serialization/JsonApiSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiSerializerTests.cs @@ -1,14 +1,10 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using Moq; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Xunit; namespace UnitTests.Serialization @@ -47,7 +43,7 @@ public void Can_Serialize_Complex_Types() // assert Assert.NotNull(result); - Assert.Equal("{\"data\":{\"type\":\"test-resource\",\"id\":\"\",\"attributes\":{\"complex-member\":{\"compound-name\":\"testname\"}}}}", result); + Assert.Equal("{\"data\":{\"attributes\":{\"complex-member\":{\"compound-name\":\"testname\"}},\"type\":\"test-resource\",\"id\":\"\"}}", result); } private class TestResource : Identifiable From 4a65704a2a2c2785c0645888a4aae7e9763c684f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 1 Mar 2018 06:04:36 -0600 Subject: [PATCH 093/227] fix(deserialization): deserialize operations document --- .../IServiceCollectionExtensions.cs | 1 - .../Formatters/JsonApiOperationsReader.cs | 43 ------------------- .../Formatters/JsonApiReader.cs | 3 +- .../Serialization/JsonApiDeSerializer.cs | 18 +++++++- .../Operations/OperationsProcessor.cs | 6 +-- 5 files changed, 21 insertions(+), 50 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 437132f087..1f2a71e20b 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -129,7 +129,6 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddScoped(); services.AddScoped(typeof(GenericProcessor<>)); services.AddScoped(typeof(GenericProcessor<,>)); diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs deleted file mode 100644 index 912cac2fff..0000000000 --- a/src/JsonApiDotNetCore/Formatters/JsonApiOperationsReader.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models.Operations; -using Microsoft.AspNetCore.Mvc.Formatters; -using Newtonsoft.Json; - -namespace JsonApiDotNetCore.Formatters -{ - public interface IJsonApiOperationsReader - { - Task ReadAsync(InputFormatterContext context); - } - - public class JsonApiOperationsReader : IJsonApiOperationsReader - { - public Task ReadAsync(InputFormatterContext context) - { - if (context == null) - throw new ArgumentNullException(nameof(context)); - - var request = context.HttpContext.Request; - if (request.ContentLength == null || request.ContentLength == 0) - throw new JsonApiException(400, "Content-Length cannot be empty."); - - var body = GetRequestBody(request.Body); - - var operations = JsonConvert.DeserializeObject(body); - - if (operations == null) - throw new JsonApiException(400, "Failed to deserialize operations request."); - - return InputFormatterResult.SuccessAsync(operations); - } - - private string GetRequestBody(Stream body) - { - using (var reader = new StreamReader(body)) - return reader.ReadToEnd(); - } - } -} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs index 274d14bc15..204f3e0491 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs @@ -36,6 +36,7 @@ public Task ReadAsync(InputFormatterContext context) try { var body = GetRequestBody(context.HttpContext.Request.Body); + var model = _jsonApiContext.IsRelationshipPath ? _deSerializer.DeserializeRelationship(body) : _deSerializer.Deserialize(body); @@ -67,4 +68,4 @@ private string GetRequestBody(Stream body) } } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index ef7938dbd3..a32a40c5d4 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -5,6 +5,7 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -28,7 +29,20 @@ public object Deserialize(string requestBody) { try { - var document = JsonConvert.DeserializeObject(requestBody); + // TODO: determine whether or not the token should be re-used rather than performing full + // deserialization again from the string + var bodyJToken = JToken.Parse(requestBody); + if(bodyJToken.SelectToken("operations") != null) + { + var operations = JsonConvert.DeserializeObject(requestBody); + if (operations == null) + throw new JsonApiException(400, "Failed to deserialize operations request."); + + return operations; + } + + var document = bodyJToken.ToObject(); + _jsonApiContext.DocumentMeta = document.Meta; var entity = DocumentToObject(document.Data); return entity; @@ -63,7 +77,7 @@ public List DeserializeList(string requestBody) try { var documents = JsonConvert.DeserializeObject(requestBody); - + var deserializedList = new List(); foreach (var data in documents.Data) { diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index e49e758570..a0ab3f2d65 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Models.Pointers; using Microsoft.EntityFrameworkCore; @@ -21,10 +21,10 @@ public class OperationsProcessor : IOperationsProcessor public OperationsProcessor( IOperationProcessorResolver processorResolver, - DbContext dbContext) + IDbContextResolver dbContextResolver) { _processorResolver = processorResolver; - _dbContext = dbContext; + _dbContext = dbContextResolver.GetContext(); } public async Task> ProcessAsync(List inputOps) From 9b93e42040fbdabc24e81eea3ae6770d49dfe58f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 1 Mar 2018 06:10:31 -0600 Subject: [PATCH 094/227] test(operations): use dbcontext resolver --- .../Services/Operations/OperationsProcessorTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index fb098d3f78..c8d739104b 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Services.Operations; using Microsoft.EntityFrameworkCore; @@ -15,13 +16,15 @@ namespace UnitTests.Services public class OperationsProcessorTests { private readonly Mock _resolverMock; - public readonly Mock _dbContextMock; + public readonly Mock _dbContextResolverMock; public OperationsProcessorTests() { _resolverMock = new Mock(); _dbContextMock = new Mock(); + _dbContextResolverMock = new Mock(); + _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); } [Fact] @@ -88,7 +91,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() _resolverMock.Setup(m => m.LocateCreateService((It.IsAny()))) .Returns(opProcessorMock.Object); - var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextMock.Object); + var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); // act var results = await operationsProcessor.ProcessAsync(operations); From 86c1b56171550cae52668bcdcfe426ba07365dad Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 1 Mar 2018 06:35:32 -0600 Subject: [PATCH 095/227] use local ids instead of JsonPointers --- .../Operations/OperationsProcessor.cs | 41 ++++++++++++++++++- .../Operations/OperationsProcessorTests.cs | 6 ++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index a0ab3f2d65..cefcd2ebca 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Models.Pointers; using Microsoft.EntityFrameworkCore; @@ -61,7 +63,7 @@ private async Task ProcessOperation(Operation op, List outputOps) { var operationsPointer = new OperationsPointer(); - // ReplaceDataPointers(op.DataObject, outputOps); + ReplaceDataPointers(op.DataObject, outputOps); // ReplaceRefPointers(op.Ref, outputOps); var processor = GetOperationsProcessor(op); @@ -71,6 +73,43 @@ private async Task ProcessOperation(Operation op, List outputOps) outputOps.Add(resultOp); } + private void ReplaceDataPointers(DocumentData data, List outputOps) + { + if (data == null) return; + + bool HasLocalId(ResourceIdentifierObject rio) => string.IsNullOrEmpty(rio.LocalId) == false; + string GetIdFromLocalId(string localId) { + var referencedOp = outputOps.FirstOrDefault(o => o.DataObject.LocalId == localId); + if(referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); + return referencedOp.DataObject.Id; + }; + + // are there any circumstances where the primary data would contain an lid? + // if(HasLocalId(data)) + // { + // data.Id = GetIdFromLocalId(data.LocalId); + // } + + if (data.Relationships != null) + { + foreach (var relationshipDictionary in data.Relationships) + { + if (relationshipDictionary.Value.IsHasMany) + { + foreach (var relationship in relationshipDictionary.Value.ManyData) + if(HasLocalId(relationship)) + relationship.Id = GetIdFromLocalId(relationship.LocalId); + } + else + { + var relationship = relationshipDictionary.Value.SingleData; + if(HasLocalId(relationship)) + relationship.Id = GetIdFromLocalId(relationship.LocalId); + } + } + } + } + private IOpProcessor GetOperationsProcessor(Operation op) { switch (op.Op) diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index c8d739104b..04272d25b3 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -24,7 +24,6 @@ public OperationsProcessorTests() _resolverMock = new Mock(); _dbContextMock = new Mock(); _dbContextResolverMock = new Mock(); - _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); } [Fact] @@ -36,6 +35,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() ""op"": ""add"", ""data"": { ""type"": ""authors"", + ""lid"": ""a"", ""attributes"": { ""name"": ""dgeb"" } @@ -51,7 +51,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() ""author"": { ""data"": { ""type"": ""authors"", - ""id"": { ""pointer"": ""/operations/0/data/id"" } + ""lid"": ""a"" } } } @@ -66,6 +66,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() ""data"": { ""type"": ""authors"", ""id"": ""9"", + ""lid"": ""a"", ""attributes"": { ""name"": ""dgeb"" } @@ -91,6 +92,7 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() _resolverMock.Setup(m => m.LocateCreateService((It.IsAny()))) .Returns(opProcessorMock.Object); + _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); // act From 3b08bdb7d435c46c6f4f11b23df263b71ad9a938 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 2 Mar 2018 07:17:02 -0600 Subject: [PATCH 096/227] replace ref.lid with results ids --- .../Models/Operations/ResourceReference.cs | 8 +- .../Operations/OperationsProcessor.cs | 58 +++++++----- .../Operations/OperationsProcessorTests.cs | 90 ++++++++++++++++++- 3 files changed, 123 insertions(+), 33 deletions(-) diff --git a/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs b/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs index a8caa7ca05..5291d61a19 100644 --- a/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs +++ b/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs @@ -2,14 +2,8 @@ namespace JsonApiDotNetCore.Models.Operations { - public class ResourceReference + public class ResourceReference : ResourceIdentifierObject { - [JsonProperty("type")] - public object Type { get; set; } - - [JsonProperty("id")] - public object Id { get; set; } - [JsonProperty("relationship")] public string Relationship { get; set; } } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index cefcd2ebca..b687f1498f 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -33,6 +33,7 @@ public async Task> ProcessAsync(List inputOps) { var outputOps = new List(); var opIndex = 0; + using (var transaction = await _dbContext.Database.BeginTransactionAsync()) { try @@ -63,8 +64,8 @@ private async Task ProcessOperation(Operation op, List outputOps) { var operationsPointer = new OperationsPointer(); - ReplaceDataPointers(op.DataObject, outputOps); - // ReplaceRefPointers(op.Ref, outputOps); + ReplaceLocalIdsInResourceObject(op.DataObject, outputOps); + ReplaceLocalIdsInRef(op.Ref, outputOps); var processor = GetOperationsProcessor(op); var resultOp = await processor.ProcessAsync(op); @@ -73,43 +74,56 @@ private async Task ProcessOperation(Operation op, List outputOps) outputOps.Add(resultOp); } - private void ReplaceDataPointers(DocumentData data, List outputOps) + private void ReplaceLocalIdsInResourceObject(ResourceObject resourceObject, List outputOps) { - if (data == null) return; - - bool HasLocalId(ResourceIdentifierObject rio) => string.IsNullOrEmpty(rio.LocalId) == false; - string GetIdFromLocalId(string localId) { - var referencedOp = outputOps.FirstOrDefault(o => o.DataObject.LocalId == localId); - if(referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); - return referencedOp.DataObject.Id; - }; - - // are there any circumstances where the primary data would contain an lid? - // if(HasLocalId(data)) - // { - // data.Id = GetIdFromLocalId(data.LocalId); - // } - - if (data.Relationships != null) + if (resourceObject == null) return; + + // it is strange to me that a top level resource object might use a lid. + // by not replacing it, we avoid a case where the first operation is an 'add' with an 'lid' + // and we would be unable to locate the matching 'lid' in 'outputOps' + // + // we also create a scenario where I might try to update a resource I just created + // in this case, the 'data.id' will be null, but the 'ref.id' will be replaced by the correct 'id' from 'outputOps' + // + // if(HasLocalId(resourceObject)) + // resourceObject.Id = GetIdFromLocalId(outputOps, resourceObject.LocalId); + + if (resourceObject.Relationships != null) { - foreach (var relationshipDictionary in data.Relationships) + foreach (var relationshipDictionary in resourceObject.Relationships) { if (relationshipDictionary.Value.IsHasMany) { foreach (var relationship in relationshipDictionary.Value.ManyData) if(HasLocalId(relationship)) - relationship.Id = GetIdFromLocalId(relationship.LocalId); + relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); } else { var relationship = relationshipDictionary.Value.SingleData; if(HasLocalId(relationship)) - relationship.Id = GetIdFromLocalId(relationship.LocalId); + relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); } } } } + private void ReplaceLocalIdsInRef(ResourceReference resourceRef, List outputOps) + { + if (resourceRef == null) return; + if(HasLocalId(resourceRef)) + resourceRef.Id = GetIdFromLocalId(outputOps, resourceRef.LocalId); + } + + private bool HasLocalId(ResourceIdentifierObject rio) => string.IsNullOrEmpty(rio.LocalId) == false; + + private string GetIdFromLocalId(List outputOps, string localId) + { + var referencedOp = outputOps.FirstOrDefault(o => o.DataObject.LocalId == localId); + if(referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); + return referencedOp.DataObject.Id; + } + private IOpProcessor GetOperationsProcessor(Operation op) { switch (op.Op) diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index 04272d25b3..0a7fd501ae 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -27,7 +27,7 @@ public OperationsProcessorTests() } [Fact] - public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() + public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_Relationships() { // arrange var request = @"[ @@ -89,9 +89,6 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() _resolverMock.Setup(m => m.LocateCreateService(It.IsAny())) .Returns(opProcessorMock.Object); - _resolverMock.Setup(m => m.LocateCreateService((It.IsAny()))) - .Returns(opProcessorMock.Object); - _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); @@ -108,5 +105,90 @@ public async Task ProcessAsync_Performs_Pointer_ReplacementAsync() ) ); } + + [Fact] + public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_References() + { + // arrange + var request = @"[ + { + ""op"": ""add"", + ""data"": { + ""type"": ""authors"", + ""lid"": ""a"", + ""attributes"": { + ""name"": ""jaredcnance"" + } + } + }, { + ""op"": ""replace"", + ""ref"": { + ""type"": ""authors"", + ""lid"": ""a"" + }, + ""data"": { + ""type"": ""authors"", + ""lid"": ""a"", + ""attributes"": { + ""name"": ""jnance"" + } + } + } + ]"; + + var op1Result = @"{ + ""data"": { + ""type"": ""authors"", + ""id"": ""9"", + ""lid"": ""a"", + ""attributes"": { + ""name"": ""jaredcnance"" + } + } + }"; + + var operations = JsonConvert.DeserializeObject>(request); + var addOperationResult = JsonConvert.DeserializeObject(op1Result); + + var databaseMock = new Mock(_dbContextMock.Object); + var transactionMock = new Mock(); + + databaseMock.Setup(m => m.BeginTransactionAsync(It.IsAny())) + .ReturnsAsync(transactionMock.Object); + + _dbContextMock.Setup(m => m.Database).Returns(databaseMock.Object); + + // setup add + var addOpProcessorMock = new Mock(); + addOpProcessorMock.Setup(m => m.ProcessAsync(It.Is(op => op.DataObject.Type.ToString() == "authors"))) + .ReturnsAsync(addOperationResult); + _resolverMock.Setup(m => m.LocateCreateService(It.IsAny())) + .Returns(addOpProcessorMock.Object); + + // setup update + var updateOpProcessorMock = new Mock(); + updateOpProcessorMock.Setup(m => m.ProcessAsync(It.Is(op => op.DataObject.Type.ToString() == "authors"))) + .ReturnsAsync((Operation)null); + _resolverMock.Setup(m => m.LocateReplaceService(It.IsAny())) + .Returns(updateOpProcessorMock.Object); + + _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); + var operationsProcessor = new OperationsProcessor(_resolverMock.Object, _dbContextResolverMock.Object); + + // act + var results = await operationsProcessor.ProcessAsync(operations); + + // assert + updateOpProcessorMock.Verify( + m => m.ProcessAsync( + It.Is(o => + o.DataObject.Type.ToString() == "authors" + // && o.DataObject.Id == "9" // currently, we will not replace the data.id member + && o.DataObject.Id == null + && o.Ref.Id == "9" + ) + ) + ); + } } } From e2396acafb7920ccabfb6c97a5e7e77e5f9acaea Mon Sep 17 00:00:00 2001 From: Nathan Wise Date: Fri, 23 Mar 2018 15:25:59 -0400 Subject: [PATCH 097/227] Initializing PageOffset to be 1 (instead of default 0) so that the 'next' pagination link is set properly when no 'page[number]' is passed in the query string. --- src/JsonApiDotNetCore/Internal/Query/PageQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Internal/Query/PageQuery.cs b/src/JsonApiDotNetCore/Internal/Query/PageQuery.cs index 8fe66d7d67..7c09d4c386 100644 --- a/src/JsonApiDotNetCore/Internal/Query/PageQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/PageQuery.cs @@ -3,6 +3,6 @@ namespace JsonApiDotNetCore.Internal.Query public class PageQuery { public int PageSize { get; set; } - public int PageOffset { get; set; } + public int PageOffset { get; set; } = 1; } } \ No newline at end of file From a292b2778cba40ea531ec0057547a445b51c3f7f Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sat, 24 Mar 2018 11:43:36 -0500 Subject: [PATCH 098/227] chore(sln): clean up solution --- JsonApiDotnetCore.sln | 64 +++++++++---------- .../Properties/launchSettings.json | 27 ++++++++ 2 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 src/Examples/OperationsExample/Properties/launchSettings.json diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index d62f8db6af..e88699eabf 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2009 +VisualStudioVersion = 15.0.27130.2010 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{C0EC9E70-EB2E-436F-9D94-FA16FA774123}" EndProject @@ -32,9 +32,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "benchmarks\Benchmarks.csproj", "{1F604666-BB0F-413E-922D-9D37C6073285}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExample", "src\Examples\OperationsExample\OperationsExample.csproj", "{CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OperationsExample", "src\Examples\OperationsExample\OperationsExample.csproj", "{CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExampleTests", "test\OperationsExampleTests\OperationsExampleTests.csproj", "{9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OperationsExampleTests", "test\OperationsExampleTests\OperationsExampleTests.csproj", "{9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -114,34 +114,10 @@ Global {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Debug|x86.Build.0 = Debug|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|Any CPU.Build.0 = Release|Any CPU - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|x64 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|x64 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|x86 - {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|x86 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.ActiveCfg = Debug|x64 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.Build.0 = Debug|x64 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.ActiveCfg = Debug|x86 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.Build.0 = Debug|x86 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.Build.0 = Release|Any CPU - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.ActiveCfg = Release|x64 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.Build.0 = Release|x64 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.ActiveCfg = Release|x86 - {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.Build.0 = Release|x86 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.ActiveCfg = Debug|x64 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.Build.0 = Debug|x64 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.ActiveCfg = Debug|x86 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.Build.0 = Debug|x86 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.Build.0 = Release|Any CPU - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.ActiveCfg = Release|x64 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.Build.0 = Release|x64 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.ActiveCfg = Release|x86 - {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.Build.0 = Release|x86 + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.ActiveCfg = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x64.Build.0 = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.ActiveCfg = Release|Any CPU + {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D}.Release|x86.Build.0 = Release|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -154,6 +130,30 @@ Global {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x64.Build.0 = Release|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.ActiveCfg = Release|Any CPU {1F604666-BB0F-413E-922D-9D37C6073285}.Release|x86.Build.0 = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x64.Build.0 = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Debug|x86.Build.0 = Debug|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|Any CPU.Build.0 = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.ActiveCfg = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x64.Build.0 = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.ActiveCfg = Release|Any CPU + {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D}.Release|x86.Build.0 = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.ActiveCfg = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x64.Build.0 = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.ActiveCfg = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Debug|x86.Build.0 = Debug|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|Any CPU.Build.0 = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.ActiveCfg = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x64.Build.0 = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.ActiveCfg = Release|Any CPU + {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -167,9 +167,9 @@ Global {6D4BD85A-A262-44C6-8572-FE3A30410BF3} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {026FBC6C-AF76-4568-9B87-EC73457899FD} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} {FBFB0B0B-EA86-4B41-AB2A-E0249F70C86D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} + {1F604666-BB0F-413E-922D-9D37C6073285} = {076E1AE4-FD25-4684-B826-CAAE37FEA0AA} {CF2C1EB6-8449-4B35-B8C7-F43D6D90632D} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {9CD2C116-D133-4FE4-97DA-A9FEAFF045F1} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} - {1F604666-BB0F-413E-922D-9D37C6073285} = {076E1AE4-FD25-4684-B826-CAAE37FEA0AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2421882-8F0A-4905-928F-B550B192F9A4} diff --git a/src/Examples/OperationsExample/Properties/launchSettings.json b/src/Examples/OperationsExample/Properties/launchSettings.json new file mode 100644 index 0000000000..b0d8e5bd4b --- /dev/null +++ b/src/Examples/OperationsExample/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:53656/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "OperationsExample": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:53657/" + } + } +} \ No newline at end of file From e18fa03841909fd4300fc078534b81afe3c62c1d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 24 Mar 2018 18:49:53 -0500 Subject: [PATCH 099/227] put operation enabling behind a feature flag on global options --- src/Examples/OperationsExample/Startup.cs | 121 +++++++++--------- .../DocumentBuilderOptionsProvider.cs | 3 - .../Configuration/JsonApiOptions.cs | 103 +++++++++++++-- .../IServiceCollectionExtensions.cs | 2 +- .../Serialization/JsonApiDeSerializer.cs | 11 +- 5 files changed, 164 insertions(+), 76 deletions(-) diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs index 1ffedf9116..7e4444dfb5 100644 --- a/src/Examples/OperationsExample/Startup.cs +++ b/src/Examples/OperationsExample/Startup.cs @@ -1,60 +1,61 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.EntityFrameworkCore; -using JsonApiDotNetCore.Extensions; -using System; -using OperationsExample.Data; -using JsonApiDotNetCore.Models; - -namespace OperationsExample -{ - public class Startup - { - public readonly IConfiguration Config; - - public Startup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables(); - - Config = builder.Build(); - } - - public virtual IServiceProvider ConfigureServices(IServiceCollection services) - { - var loggerFactory = new LoggerFactory(); - loggerFactory - .AddConsole(LogLevel.Trace); - services.AddSingleton(loggerFactory); - - services.AddDbContext(options => - { - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); - - services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); - - return services.BuildServiceProvider(); - } - - public virtual void Configure( - IApplicationBuilder app, - IHostingEnvironment env, - ILoggerFactory loggerFactory, - AppDbContext context) - { - context.Database.EnsureCreated(); - - loggerFactory.AddConsole(Config.GetSection("Logging")); - loggerFactory.AddDebug(); - app.UseJsonApi(); - } - - public string GetDbConnectionString() => Config["Data:DefaultConnection"]; - } -} \ No newline at end of file +using System; +using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Models; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using OperationsExample.Data; + + +namespace OperationsExample +{ + public class Startup + { + public readonly IConfiguration Config; + + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables(); + + Config = builder.Build(); + } + + public virtual IServiceProvider ConfigureServices(IServiceCollection services) + { + var loggerFactory = new LoggerFactory(); + loggerFactory.AddConsole(LogLevel.Trace); + + services.AddSingleton(loggerFactory); + + services.AddDbContext(options => + { + options.UseNpgsql(GetDbConnectionString()); + }, ServiceLifetime.Transient); + + services.AddJsonApi(opt => opt.EnableOperations = true); + + return services.BuildServiceProvider(); + } + + public virtual void Configure( + IApplicationBuilder app, + IHostingEnvironment env, + ILoggerFactory loggerFactory, + AppDbContext context) + { + context.Database.EnsureCreated(); + + loggerFactory.AddConsole(Config.GetSection("Logging")); + loggerFactory.AddDebug(); + app.UseJsonApi(); + } + + public string GetDbConnectionString() => Config["Data:DefaultConnection"]; + } +} diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs index af7fb78d7c..37c5d51273 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptionsProvider.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index e61c5cd429..ea8d0554e3 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -10,17 +10,106 @@ namespace JsonApiDotNetCore.Configuration { + /// + /// Global options. + /// https://json-api-dotnet.github.io/#/global-options + /// public class JsonApiOptions { + /// + /// The base URL Namespace + /// + /// + /// options.Namespace = "api/v1"; + /// public string Namespace { get; set; } + + /// + /// The default page size for all resources + /// + /// + /// options.DefaultPageSize = 10; + /// public int DefaultPageSize { get; set; } + + /// + /// Whether or not the total-record count should be included in all document + /// level meta objects. + /// Defaults to false. + /// + /// + /// options.IncludeTotalRecordCount = true; + /// public bool IncludeTotalRecordCount { get; set; } + + /// + /// Whether or not clients can provide ids when creating resources. + /// Defaults to false. When disabled the application will respond + /// with a 403 Forbidden respponse if a client attempts to create a + /// resource with a defined id. + /// + /// + /// options.AllowClientGeneratedIds = true; + /// public bool AllowClientGeneratedIds { get; set; } + + /// + /// The graph of all resources exposed by this application. + /// public IContextGraph ContextGraph { get; set; } + + /// + /// Use relative links for all resources. + /// + /// + /// + /// options.RelativeLinks = true; + /// + /// + /// { + /// "type": "articles", + /// "id": "4309", + /// "relationships": { + /// "author": { + /// "links": { + /// "self": "/api/v1/articles/4309/relationships/author", + /// "related": "/api/v1/articles/4309/author" + /// } + /// } + /// } + /// } + /// + /// public bool RelativeLinks { get; set; } + + /// + /// Whether or not to allow all custom query parameters. + /// + /// + /// + /// options.AllowCustomQueryParameters = true; + /// + /// public bool AllowCustomQueryParameters { get; set; } + + /// + /// The default behavior for serializing null attributes. + /// + /// + /// + /// options.NullAttributeResponseBehavior = new NullAttributeResponseBehavior { + /// // ... + ///}; + /// + /// public NullAttributeResponseBehavior NullAttributeResponseBehavior { get; set; } + /// + /// Whether or not to allow json:api v1.1 operation requests + /// This will be enabled by default in JsonApiDotNetCore v2.2.1 + /// + public bool EnableOperations { get; set; } + [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] public IContractResolver JsonContractResolver { @@ -33,9 +122,6 @@ public IContractResolver JsonContractResolver ContractResolver = new DasherizedResolver() }; - internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); - internal List EnabledExtensions { get; set; } = new List(); - public void BuildContextGraph(Action builder) where TContext : DbContext { BuildContextGraph(builder); @@ -54,11 +140,10 @@ public void BuildContextGraph(Action builder) ContextGraph = ContextGraphBuilder.Build(); } - public void EnableExtension(JsonApiExtension extension) - { - EnabledExtensions.Add(extension); - } - } + public void EnableExtension(JsonApiExtension extension) + => EnabledExtensions.Add(extension); - + internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); + internal List EnabledExtensions { get; set; } = new List(); + } } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 1f2a71e20b..9b33163810 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -95,7 +95,7 @@ public static void AddJsonApiInternals( services.AddSingleton(new DbContextOptionsBuilder().Options); } - if (jsonApiOptions.EnabledExtensions.Contains(JsonApiExtension.Operations)) + if (jsonApiOptions.EnableOperations) AddOperationServices(services); services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index a32a40c5d4..6213edfd63 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -29,11 +29,12 @@ public object Deserialize(string requestBody) { try { - // TODO: determine whether or not the token should be re-used rather than performing full - // deserialization again from the string var bodyJToken = JToken.Parse(requestBody); - if(bodyJToken.SelectToken("operations") != null) + + if(RequestIsOperation(bodyJToken)) { + // TODO: determine whether or not the token should be re-used rather than performing full + // deserialization again from the string var operations = JsonConvert.DeserializeObject(requestBody); if (operations == null) throw new JsonApiException(400, "Failed to deserialize operations request."); @@ -53,6 +54,10 @@ public object Deserialize(string requestBody) } } + private bool RequestIsOperation(JToken bodyJToken) + => _jsonApiContext.Options.EnableOperations + && (bodyJToken.SelectToken("operations") != null); + public TEntity Deserialize(string requestBody) => (TEntity)Deserialize(requestBody); public object DeserializeRelationship(string requestBody) From 3f8b35f911b6ce6b65527f4ac84ae92e7e74440a Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 24 Mar 2018 21:28:37 -0500 Subject: [PATCH 100/227] add docfx documentation boilerplate --- .gitignore | 4 +- JsonApiDotnetCore.sln | 5 +- .../JsonApiDotNetCore.csproj | 4 + src/JsonApiDotNetCore/api/.gitignore | 4 + src/JsonApiDotNetCore/api/.manifest | 683 ++++++++++++++++++ src/JsonApiDotNetCore/api/index.md | 2 + src/JsonApiDotNetCore/articles/intro.md | 1 + src/JsonApiDotNetCore/articles/toc.yml | 2 + src/JsonApiDotNetCore/docfx.json | 52 ++ src/JsonApiDotNetCore/index.md | 4 + src/JsonApiDotNetCore/toc.yml | 5 + 11 files changed, 763 insertions(+), 3 deletions(-) create mode 100644 src/JsonApiDotNetCore/api/.gitignore create mode 100644 src/JsonApiDotNetCore/api/.manifest create mode 100644 src/JsonApiDotNetCore/api/index.md create mode 100644 src/JsonApiDotNetCore/articles/intro.md create mode 100644 src/JsonApiDotNetCore/articles/toc.yml create mode 100644 src/JsonApiDotNetCore/docfx.json create mode 100644 src/JsonApiDotNetCore/index.md create mode 100644 src/JsonApiDotNetCore/toc.yml diff --git a/.gitignore b/.gitignore index cd9f35a530..6630942ad5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ *.user .couscous/ docs/Template-Dark/ -.idea/ \ No newline at end of file +.idea/ +**/_site/ +log.txt diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index e88699eabf..ac45f83cdf 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -15,6 +15,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore + Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject @@ -160,9 +161,9 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {C0EC9E70-EB2E-436F-9D94-FA16FA774123} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} - {97EE048B-16C0-43F6-BDA9-4E762B2F579F} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} + {97EE048B-16C0-43F6-BDA9-4E762B2F579F} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {0B959765-40D2-43B5-87EE-FE2FEF9DBED5} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} - {570165EC-62B5-4684-A139-8D2A30DD4475} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} + {570165EC-62B5-4684-A139-8D2A30DD4475} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {73DA578D-A63F-4956-83ED-6D7102E09140} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {6D4BD85A-A262-44C6-8572-FE3A30410BF3} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {026FBC6C-AF76-4568-9B87-EC73457899FD} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 9fe109011b..c712227334 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -13,7 +13,11 @@ git https://github.com/json-api-dotnet/JsonApiDotNetCore + + bin\Release\netstandard2.0\JsonApiDotNetCore.xml + + diff --git a/src/JsonApiDotNetCore/api/.gitignore b/src/JsonApiDotNetCore/api/.gitignore new file mode 100644 index 0000000000..da7c71b83a --- /dev/null +++ b/src/JsonApiDotNetCore/api/.gitignore @@ -0,0 +1,4 @@ +############### +# temp file # +############### +*.yml diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest new file mode 100644 index 0000000000..c5b25fa365 --- /dev/null +++ b/src/JsonApiDotNetCore/api/.manifest @@ -0,0 +1,683 @@ +{ + "JsonApiDotNetCore.Builders": "JsonApiDotNetCore.Builders.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.AddDbContext``1": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.AddResource``1(System.String)": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.AddResource``2(System.String)": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.Build": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.DocumentLinks": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.GetAttributes(System.Type)": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.GetRelationships(System.Type)": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.ContextGraphBuilder.GetRelationshipType(JsonApiDotNetCore.Models.RelationshipAttribute,System.Reflection.PropertyInfo)": "JsonApiDotNetCore.Builders.ContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilder": "JsonApiDotNetCore.Builders.DocumentBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilder.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IRequestMeta,JsonApiDotNetCore.Builders.IDocumentBuilderOptionsProvider)": "JsonApiDotNetCore.Builders.DocumentBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilder.Build(JsonApiDotNetCore.Models.IIdentifiable)": "JsonApiDotNetCore.Builders.DocumentBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilder.Build(System.Collections.Generic.IEnumerable{JsonApiDotNetCore.Models.IIdentifiable})": "JsonApiDotNetCore.Builders.DocumentBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilder.GetData(JsonApiDotNetCore.Internal.ContextEntity,JsonApiDotNetCore.Models.IIdentifiable)": "JsonApiDotNetCore.Builders.DocumentBuilder.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptions": "JsonApiDotNetCore.Builders.DocumentBuilderOptions.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptions.#ctor(System.Boolean)": "JsonApiDotNetCore.Builders.DocumentBuilderOptions.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptions.OmitNullValuedAttributes": "JsonApiDotNetCore.Builders.DocumentBuilderOptions.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider": "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,Microsoft.AspNetCore.Http.IHttpContextAccessor)": "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider.yml", + "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider.GetDocumentBuilderOptions": "JsonApiDotNetCore.Builders.DocumentBuilderOptionsProvider.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder.AddDbContext``1": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder.AddResource``1(System.String)": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder.AddResource``2(System.String)": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder.Build": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IContextGraphBuilder.DocumentLinks": "JsonApiDotNetCore.Builders.IContextGraphBuilder.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilder": "JsonApiDotNetCore.Builders.IDocumentBuilder.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilder.Build(JsonApiDotNetCore.Models.IIdentifiable)": "JsonApiDotNetCore.Builders.IDocumentBuilder.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilder.Build(System.Collections.Generic.IEnumerable{JsonApiDotNetCore.Models.IIdentifiable})": "JsonApiDotNetCore.Builders.IDocumentBuilder.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilder.GetData(JsonApiDotNetCore.Internal.ContextEntity,JsonApiDotNetCore.Models.IIdentifiable)": "JsonApiDotNetCore.Builders.IDocumentBuilder.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilderOptionsProvider": "JsonApiDotNetCore.Builders.IDocumentBuilderOptionsProvider.yml", + "JsonApiDotNetCore.Builders.IDocumentBuilderOptionsProvider.GetDocumentBuilderOptions": "JsonApiDotNetCore.Builders.IDocumentBuilderOptionsProvider.yml", + "JsonApiDotNetCore.Builders.IMetaBuilder": "JsonApiDotNetCore.Builders.IMetaBuilder.yml", + "JsonApiDotNetCore.Builders.IMetaBuilder.Add(System.Collections.Generic.Dictionary{System.String,System.Object})": "JsonApiDotNetCore.Builders.IMetaBuilder.yml", + "JsonApiDotNetCore.Builders.IMetaBuilder.Add(System.String,System.Object)": "JsonApiDotNetCore.Builders.IMetaBuilder.yml", + "JsonApiDotNetCore.Builders.IMetaBuilder.Build": "JsonApiDotNetCore.Builders.IMetaBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder.#ctor(JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder.GetBasePath(Microsoft.AspNetCore.Http.HttpContext,System.String)": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder.GetPageLink(System.Int32,System.Int32)": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder.GetRelatedRelationLink(System.String,System.String,System.String)": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.LinkBuilder.GetSelfRelationLink(System.String,System.String,System.String)": "JsonApiDotNetCore.Builders.LinkBuilder.yml", + "JsonApiDotNetCore.Builders.MetaBuilder": "JsonApiDotNetCore.Builders.MetaBuilder.yml", + "JsonApiDotNetCore.Builders.MetaBuilder.Add(System.Collections.Generic.Dictionary{System.String,System.Object})": "JsonApiDotNetCore.Builders.MetaBuilder.yml", + "JsonApiDotNetCore.Builders.MetaBuilder.Add(System.String,System.Object)": "JsonApiDotNetCore.Builders.MetaBuilder.yml", + "JsonApiDotNetCore.Builders.MetaBuilder.Build": "JsonApiDotNetCore.Builders.MetaBuilder.yml", + "JsonApiDotNetCore.Configuration": "JsonApiDotNetCore.Configuration.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.AllowClientGeneratedIds": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.AllowCustomQueryParameters": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.BuildContextGraph(System.Action{JsonApiDotNetCore.Builders.IContextGraphBuilder})": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.BuildContextGraph``1(System.Action{JsonApiDotNetCore.Builders.IContextGraphBuilder})": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.ContextGraph": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.DefaultPageSize": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.EnableExtension(JsonApiDotNetCore.Models.JsonApiExtension)": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.EnableOperations": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.IncludeTotalRecordCount": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.JsonContractResolver": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.Namespace": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.NullAttributeResponseBehavior": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.RelativeLinks": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.SerializerSettings": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior": "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.yml", + "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.#ctor(System.Boolean,System.Boolean)": "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.yml", + "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.AllowClientOverride": "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.yml", + "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.OmitNullValuedAttributes": "JsonApiDotNetCore.Configuration.NullAttributeResponseBehavior.yml", + "JsonApiDotNetCore.Controllers": "JsonApiDotNetCore.Controllers.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`1": "JsonApiDotNetCore.Controllers.BaseJsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IGetAllService{`0,System.Int32},JsonApiDotNetCore.Services.IGetByIdService{`0,System.Int32},JsonApiDotNetCore.Services.IGetRelationshipService{`0,System.Int32},JsonApiDotNetCore.Services.IGetRelationshipsService{`0,System.Int32},JsonApiDotNetCore.Services.ICreateService{`0,System.Int32},JsonApiDotNetCore.Services.IUpdateService{`0,System.Int32},JsonApiDotNetCore.Services.IUpdateRelationshipService{`0,System.Int32},JsonApiDotNetCore.Services.IDeleteService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceQueryService{`0,System.Int32},JsonApiDotNetCore.Services.IResourceCmdService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IGetAllService{`0,`1},JsonApiDotNetCore.Services.IGetByIdService{`0,`1},JsonApiDotNetCore.Services.IGetRelationshipService{`0,`1},JsonApiDotNetCore.Services.IGetRelationshipsService{`0,`1},JsonApiDotNetCore.Services.ICreateService{`0,`1},JsonApiDotNetCore.Services.IUpdateService{`0,`1},JsonApiDotNetCore.Services.IUpdateRelationshipService{`0,`1},JsonApiDotNetCore.Services.IDeleteService{`0,`1})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceQueryService{`0,`1},JsonApiDotNetCore.Services.IResourceCmdService{`0,`1})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,`1})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.DeleteAsync(`1)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.GetAsync": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.GetAsync(`1)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.GetRelationshipAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.GetRelationshipsAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.PatchAsync(`1,`0)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.PatchRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.BaseJsonApiController`2.PostAsync(`0)": "JsonApiDotNetCore.Controllers.BaseJsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.DisableQueryAttribute": "JsonApiDotNetCore.Controllers.DisableQueryAttribute.yml", + "JsonApiDotNetCore.Controllers.DisableQueryAttribute.#ctor(JsonApiDotNetCore.Controllers.QueryParams)": "JsonApiDotNetCore.Controllers.DisableQueryAttribute.yml", + "JsonApiDotNetCore.Controllers.DisableQueryAttribute.QueryParams": "JsonApiDotNetCore.Controllers.DisableQueryAttribute.yml", + "JsonApiDotNetCore.Controllers.DisableRoutingConventionAttribute": "JsonApiDotNetCore.Controllers.DisableRoutingConventionAttribute.yml", + "JsonApiDotNetCore.Controllers.HttpReadOnlyAttribute": "JsonApiDotNetCore.Controllers.HttpReadOnlyAttribute.yml", + "JsonApiDotNetCore.Controllers.HttpReadOnlyAttribute.Methods": "JsonApiDotNetCore.Controllers.HttpReadOnlyAttribute.yml", + "JsonApiDotNetCore.Controllers.HttpRestrictAttribute": "JsonApiDotNetCore.Controllers.HttpRestrictAttribute.yml", + "JsonApiDotNetCore.Controllers.HttpRestrictAttribute.Methods": "JsonApiDotNetCore.Controllers.HttpRestrictAttribute.yml", + "JsonApiDotNetCore.Controllers.HttpRestrictAttribute.OnActionExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext,Microsoft.AspNetCore.Mvc.Filters.ActionExecutionDelegate)": "JsonApiDotNetCore.Controllers.HttpRestrictAttribute.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`1": "JsonApiDotNetCore.Controllers.JsonApiCmdController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.JsonApiCmdController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,`1})": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2.DeleteAsync(`1)": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2.PatchAsync(`1,`0)": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2.PatchRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiCmdController`2.PostAsync(`0)": "JsonApiDotNetCore.Controllers.JsonApiCmdController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`1": "JsonApiDotNetCore.Controllers.JsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IGetAllService{`0,System.Int32},JsonApiDotNetCore.Services.IGetByIdService{`0,System.Int32},JsonApiDotNetCore.Services.IGetRelationshipService{`0,System.Int32},JsonApiDotNetCore.Services.IGetRelationshipsService{`0,System.Int32},JsonApiDotNetCore.Services.ICreateService{`0,System.Int32},JsonApiDotNetCore.Services.IUpdateService{`0,System.Int32},JsonApiDotNetCore.Services.IUpdateRelationshipService{`0,System.Int32},JsonApiDotNetCore.Services.IDeleteService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.JsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,System.Int32},Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Controllers.JsonApiController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IGetAllService{`0,`1},JsonApiDotNetCore.Services.IGetByIdService{`0,`1},JsonApiDotNetCore.Services.IGetRelationshipService{`0,`1},JsonApiDotNetCore.Services.IGetRelationshipsService{`0,`1},JsonApiDotNetCore.Services.ICreateService{`0,`1},JsonApiDotNetCore.Services.IUpdateService{`0,`1},JsonApiDotNetCore.Services.IUpdateRelationshipService{`0,`1},JsonApiDotNetCore.Services.IDeleteService{`0,`1})": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,`1})": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,`1},Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.DeleteAsync(`1)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.GetAsync": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.GetAsync(`1)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.GetRelationshipAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.GetRelationshipsAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.PatchAsync(`1,`0)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.PatchRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiController`2.PostAsync(`0)": "JsonApiDotNetCore.Controllers.JsonApiController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiControllerMixin": "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.yml", + "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.Error(JsonApiDotNetCore.Internal.Error)": "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.yml", + "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.Errors(JsonApiDotNetCore.Internal.ErrorCollection)": "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.yml", + "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.Forbidden": "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.yml", + "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.UnprocessableEntity": "JsonApiDotNetCore.Controllers.JsonApiControllerMixin.yml", + "JsonApiDotNetCore.Controllers.JsonApiOperationsController": "JsonApiDotNetCore.Controllers.JsonApiOperationsController.yml", + "JsonApiDotNetCore.Controllers.JsonApiOperationsController.#ctor(JsonApiDotNetCore.Services.Operations.IOperationsProcessor)": "JsonApiDotNetCore.Controllers.JsonApiOperationsController.yml", + "JsonApiDotNetCore.Controllers.JsonApiOperationsController.PatchAsync(JsonApiDotNetCore.Models.Operations.OperationsDocument)": "JsonApiDotNetCore.Controllers.JsonApiOperationsController.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`1": "JsonApiDotNetCore.Controllers.JsonApiQueryController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,System.Int32})": "JsonApiDotNetCore.Controllers.JsonApiQueryController-1.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Services.IResourceService{`0,`1})": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2.GetAsync": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2.GetAsync(`1)": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2.GetRelationshipAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.JsonApiQueryController`2.GetRelationshipsAsync(`1,System.String)": "JsonApiDotNetCore.Controllers.JsonApiQueryController-2.yml", + "JsonApiDotNetCore.Controllers.NoHttpDeleteAttribute": "JsonApiDotNetCore.Controllers.NoHttpDeleteAttribute.yml", + "JsonApiDotNetCore.Controllers.NoHttpDeleteAttribute.Methods": "JsonApiDotNetCore.Controllers.NoHttpDeleteAttribute.yml", + "JsonApiDotNetCore.Controllers.NoHttpPatchAttribute": "JsonApiDotNetCore.Controllers.NoHttpPatchAttribute.yml", + "JsonApiDotNetCore.Controllers.NoHttpPatchAttribute.Methods": "JsonApiDotNetCore.Controllers.NoHttpPatchAttribute.yml", + "JsonApiDotNetCore.Controllers.NoHttpPostAttribute": "JsonApiDotNetCore.Controllers.NoHttpPostAttribute.yml", + "JsonApiDotNetCore.Controllers.NoHttpPostAttribute.Methods": "JsonApiDotNetCore.Controllers.NoHttpPostAttribute.yml", + "JsonApiDotNetCore.Controllers.QueryParams": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.All": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.Fields": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.Filter": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.Include": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.None": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.Page": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Controllers.QueryParams.Sort": "JsonApiDotNetCore.Controllers.QueryParams.yml", + "JsonApiDotNetCore.Data": "JsonApiDotNetCore.Data.yml", + "JsonApiDotNetCore.Data.DbContextResolver`1": "JsonApiDotNetCore.Data.DbContextResolver-1.yml", + "JsonApiDotNetCore.Data.DbContextResolver`1.#ctor(`0)": "JsonApiDotNetCore.Data.DbContextResolver-1.yml", + "JsonApiDotNetCore.Data.DbContextResolver`1.GetContext": "JsonApiDotNetCore.Data.DbContextResolver-1.yml", + "JsonApiDotNetCore.Data.DbContextResolver`1.GetDbSet``1": "JsonApiDotNetCore.Data.DbContextResolver-1.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`1": "JsonApiDotNetCore.Data.DefaultEntityRepository-1.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`1.#ctor(Microsoft.Extensions.Logging.ILoggerFactory,JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Data.DefaultEntityRepository-1.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.#ctor(Microsoft.Extensions.Logging.ILoggerFactory,JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.CountAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.CreateAsync(`0)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.DeleteAsync(`1)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.Filter(System.Linq.IQueryable{`0},JsonApiDotNetCore.Internal.Query.FilterQuery)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.FirstOrDefaultAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.Get": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.GetAndIncludeAsync(`1,System.String)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.GetAsync(`1)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.Include(System.Linq.IQueryable{`0},System.String)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.PageAsync(System.Linq.IQueryable{`0},System.Int32,System.Int32)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.Sort(System.Linq.IQueryable{`0},System.Collections.Generic.List{JsonApiDotNetCore.Internal.Query.SortQuery})": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.ToListAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.UpdateAsync(`1,`0)": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.DefaultEntityRepository`2.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Data.DefaultEntityRepository-2.yml", + "JsonApiDotNetCore.Data.IDbContextResolver": "JsonApiDotNetCore.Data.IDbContextResolver.yml", + "JsonApiDotNetCore.Data.IDbContextResolver.GetContext": "JsonApiDotNetCore.Data.IDbContextResolver.yml", + "JsonApiDotNetCore.Data.IDbContextResolver.GetDbSet``1": "JsonApiDotNetCore.Data.IDbContextResolver.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`1": "JsonApiDotNetCore.Data.IEntityReadRepository-1.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.CountAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.Filter(System.Linq.IQueryable{`0},JsonApiDotNetCore.Internal.Query.FilterQuery)": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.FirstOrDefaultAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.Get": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.GetAndIncludeAsync(`1,System.String)": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.GetAsync(`1)": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.Include(System.Linq.IQueryable{`0},System.String)": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.PageAsync(System.Linq.IQueryable{`0},System.Int32,System.Int32)": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.Sort(System.Linq.IQueryable{`0},System.Collections.Generic.List{JsonApiDotNetCore.Internal.Query.SortQuery})": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityReadRepository`2.ToListAsync(System.Linq.IQueryable{`0})": "JsonApiDotNetCore.Data.IEntityReadRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityRepository`1": "JsonApiDotNetCore.Data.IEntityRepository-1.yml", + "JsonApiDotNetCore.Data.IEntityRepository`2": "JsonApiDotNetCore.Data.IEntityRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`1": "JsonApiDotNetCore.Data.IEntityWriteRepository-1.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`2": "JsonApiDotNetCore.Data.IEntityWriteRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`2.CreateAsync(`0)": "JsonApiDotNetCore.Data.IEntityWriteRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`2.DeleteAsync(`1)": "JsonApiDotNetCore.Data.IEntityWriteRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`2.UpdateAsync(`1,`0)": "JsonApiDotNetCore.Data.IEntityWriteRepository-2.yml", + "JsonApiDotNetCore.Data.IEntityWriteRepository`2.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Data.IEntityWriteRepository-2.yml", + "JsonApiDotNetCore.Extensions": "JsonApiDotNetCore.Extensions.yml", + "JsonApiDotNetCore.Extensions.DbContextExtensions": "JsonApiDotNetCore.Extensions.DbContextExtensions.yml", + "JsonApiDotNetCore.Extensions.DbContextExtensions.GetDbSet``1(Microsoft.EntityFrameworkCore.DbContext)": "JsonApiDotNetCore.Extensions.DbContextExtensions.yml", + "JsonApiDotNetCore.Extensions.IApplicationBuilderExtensions": "JsonApiDotNetCore.Extensions.IApplicationBuilderExtensions.yml", + "JsonApiDotNetCore.Extensions.IApplicationBuilderExtensions.UseJsonApi(Microsoft.AspNetCore.Builder.IApplicationBuilder,System.Boolean)": "JsonApiDotNetCore.Extensions.IApplicationBuilderExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Filter``1(System.Linq.IQueryable{``0},JsonApiDotNetCore.Internal.Query.AttrFilterQuery)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Filter``1(System.Linq.IQueryable{``0},JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Filter``1(System.Linq.IQueryable{``0},JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Internal.Query.FilterQuery)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.OrderBy``1(System.Linq.IQueryable{``0},System.String)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.OrderByDescending``1(System.Linq.IQueryable{``0},System.String)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.PageForward``1(System.Linq.IQueryable{``0},System.Int32,System.Int32)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Select``1(System.Linq.IQueryable{``0},System.Collections.Generic.List{System.String})": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Sort``1(System.Linq.IOrderedQueryable{``0},JsonApiDotNetCore.Internal.Query.SortQuery)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Sort``1(System.Linq.IQueryable{``0},JsonApiDotNetCore.Internal.Query.SortQuery)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.Sort``1(System.Linq.IQueryable{``0},System.Collections.Generic.List{JsonApiDotNetCore.Internal.Query.SortQuery})": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.ThenBy``1(System.Linq.IOrderedQueryable{``0},System.String)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IQueryableExtensions.ThenByDescending``1(System.Linq.IOrderedQueryable{``0},System.String)": "JsonApiDotNetCore.Extensions.IQueryableExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApi(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{JsonApiDotNetCore.Configuration.JsonApiOptions},Microsoft.Extensions.DependencyInjection.IMvcBuilder)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApi``1(Microsoft.Extensions.DependencyInjection.IServiceCollection)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApi``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{JsonApiDotNetCore.Configuration.JsonApiOptions})": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApi``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{JsonApiDotNetCore.Configuration.JsonApiOptions},Microsoft.Extensions.DependencyInjection.IMvcBuilder)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApiInternals(Microsoft.Extensions.DependencyInjection.IServiceCollection,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApiInternals``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.SerializeAsJsonApi(Microsoft.AspNetCore.Mvc.MvcOptions,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", + "JsonApiDotNetCore.Extensions.JObjectExtensions": "JsonApiDotNetCore.Extensions.JObjectExtensions.yml", + "JsonApiDotNetCore.Extensions.JObjectExtensions.TryParse``2(Newtonsoft.Json.Linq.JObject,Newtonsoft.Json.Schema.JSchema,JsonApiDotNetCore.Models.Pointers.Pointer{``1}@)": "JsonApiDotNetCore.Extensions.JObjectExtensions.yml", + "JsonApiDotNetCore.Extensions.StringExtensions": "JsonApiDotNetCore.Extensions.StringExtensions.yml", + "JsonApiDotNetCore.Extensions.StringExtensions.Dasherize(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", + "JsonApiDotNetCore.Extensions.StringExtensions.ToProperCase(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", + "JsonApiDotNetCore.Formatters": "JsonApiDotNetCore.Formatters.yml", + "JsonApiDotNetCore.Formatters.IJsonApiReader": "JsonApiDotNetCore.Formatters.IJsonApiReader.yml", + "JsonApiDotNetCore.Formatters.IJsonApiReader.ReadAsync(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterContext)": "JsonApiDotNetCore.Formatters.IJsonApiReader.yml", + "JsonApiDotNetCore.Formatters.IJsonApiWriter": "JsonApiDotNetCore.Formatters.IJsonApiWriter.yml", + "JsonApiDotNetCore.Formatters.IJsonApiWriter.WriteAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext)": "JsonApiDotNetCore.Formatters.IJsonApiWriter.yml", + "JsonApiDotNetCore.Formatters.JsonApiInputFormatter": "JsonApiDotNetCore.Formatters.JsonApiInputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiInputFormatter.CanRead(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterContext)": "JsonApiDotNetCore.Formatters.JsonApiInputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiInputFormatter.ReadAsync(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterContext)": "JsonApiDotNetCore.Formatters.JsonApiInputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter": "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter.CanWriteResult(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterCanWriteContext)": "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter.WriteAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext)": "JsonApiDotNetCore.Formatters.JsonApiOutputFormatter.yml", + "JsonApiDotNetCore.Formatters.JsonApiReader": "JsonApiDotNetCore.Formatters.JsonApiReader.yml", + "JsonApiDotNetCore.Formatters.JsonApiReader.#ctor(JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Services.IJsonApiContext,Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Formatters.JsonApiReader.yml", + "JsonApiDotNetCore.Formatters.JsonApiReader.ReadAsync(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterContext)": "JsonApiDotNetCore.Formatters.JsonApiReader.yml", + "JsonApiDotNetCore.Formatters.JsonApiWriter": "JsonApiDotNetCore.Formatters.JsonApiWriter.yml", + "JsonApiDotNetCore.Formatters.JsonApiWriter.#ctor(JsonApiDotNetCore.Serialization.IJsonApiSerializer,Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Formatters.JsonApiWriter.yml", + "JsonApiDotNetCore.Formatters.JsonApiWriter.WriteAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext)": "JsonApiDotNetCore.Formatters.JsonApiWriter.yml", + "JsonApiDotNetCore.Internal": "JsonApiDotNetCore.Internal.yml", + "JsonApiDotNetCore.Internal.Constants": "JsonApiDotNetCore.Internal.Constants.yml", + "JsonApiDotNetCore.Internal.Constants.AcceptHeader": "JsonApiDotNetCore.Internal.Constants.yml", + "JsonApiDotNetCore.Internal.Constants.ContentType": "JsonApiDotNetCore.Internal.Constants.yml", + "JsonApiDotNetCore.Internal.ContextEntity": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.Attributes": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.EntityName": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.EntityType": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.IdentityType": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.Links": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextEntity.Relationships": "JsonApiDotNetCore.Internal.ContextEntity.yml", + "JsonApiDotNetCore.Internal.ContextGraph": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.#ctor": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.#ctor(System.Collections.Generic.List{JsonApiDotNetCore.Internal.ContextEntity},System.Boolean)": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.GetContextEntity(System.String)": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.GetContextEntity(System.Type)": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.GetRelationship``1(``0,System.String)": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.GetRelationshipName``1(System.String)": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.ContextGraph.UsesDbContext": "JsonApiDotNetCore.Internal.ContextGraph.yml", + "JsonApiDotNetCore.Internal.DasherizedRoutingConvention": "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.yml", + "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.#ctor(System.String)": "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.yml", + "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.Apply(Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel)": "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.yml", + "JsonApiDotNetCore.Internal.Error": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.Detail": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.Status": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.StatusCode": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.Title": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.ErrorCollection": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.ErrorCollection.#ctor": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.ErrorCollection.Add(JsonApiDotNetCore.Internal.Error)": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.ErrorCollection.Errors": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.ErrorCollection.GetJson": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.Generics": "JsonApiDotNetCore.Internal.Generics.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`1": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-1.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`1.#ctor(JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-1.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.#ctor(JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.SetRelationships(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.#ctor(System.IServiceProvider)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessor": "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.SetRelationships(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory": "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory.GetProcessor``1(System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory.GetProcessor``1(System.Type,System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.IContextGraph": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.IContextGraph.GetContextEntity(System.String)": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.IContextGraph.GetContextEntity(System.Type)": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.IContextGraph.GetRelationship``1(``0,System.String)": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.IContextGraph.GetRelationshipName``1(System.String)": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.IContextGraph.UsesDbContext": "JsonApiDotNetCore.Internal.IContextGraph.yml", + "JsonApiDotNetCore.Internal.JsonApiException": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(JsonApiDotNetCore.Internal.Error)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(JsonApiDotNetCore.Internal.ErrorCollection)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String,System.Exception)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.GetError": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.GetStatusCode": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiExceptionFactory": "JsonApiDotNetCore.Internal.JsonApiExceptionFactory.yml", + "JsonApiDotNetCore.Internal.JsonApiExceptionFactory.GetException(System.Exception)": "JsonApiDotNetCore.Internal.JsonApiExceptionFactory.yml", + "JsonApiDotNetCore.Internal.JsonApiRouteHandler": "JsonApiDotNetCore.Internal.JsonApiRouteHandler.yml", + "JsonApiDotNetCore.Internal.JsonApiRouteHandler.#ctor(Microsoft.AspNetCore.Mvc.Infrastructure.IActionInvokerFactory,Microsoft.AspNetCore.Mvc.Infrastructure.IActionSelector)": "JsonApiDotNetCore.Internal.JsonApiRouteHandler.yml", + "JsonApiDotNetCore.Internal.JsonApiRouteHandler.#ctor(Microsoft.AspNetCore.Mvc.Infrastructure.IActionInvokerFactory,Microsoft.AspNetCore.Mvc.Infrastructure.IActionSelector,Microsoft.AspNetCore.Mvc.Infrastructure.IActionContextAccessor)": "JsonApiDotNetCore.Internal.JsonApiRouteHandler.yml", + "JsonApiDotNetCore.Internal.JsonApiRouteHandler.GetVirtualPath(Microsoft.AspNetCore.Routing.VirtualPathContext)": "JsonApiDotNetCore.Internal.JsonApiRouteHandler.yml", + "JsonApiDotNetCore.Internal.JsonApiRouteHandler.RouteAsync(Microsoft.AspNetCore.Routing.RouteContext)": "JsonApiDotNetCore.Internal.JsonApiRouteHandler.yml", + "JsonApiDotNetCore.Internal.PageManager": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.CurrentPage": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.DefaultPageSize": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.GetPageLinks(JsonApiDotNetCore.Builders.LinkBuilder)": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.IsPaginated": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.PageSize": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.TotalPages": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.PageManager.TotalRecords": "JsonApiDotNetCore.Internal.PageManager.yml", + "JsonApiDotNetCore.Internal.Query": "JsonApiDotNetCore.Internal.Query.yml", + "JsonApiDotNetCore.Internal.Query.AttrFilterQuery": "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Internal.Query.FilterQuery)": "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.FilteredAttribute": "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.FilterOperation": "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.PropertyValue": "JsonApiDotNetCore.Internal.Query.AttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.BaseFilterQuery": "JsonApiDotNetCore.Internal.Query.BaseFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.BaseFilterQuery.GetFilterOperation(System.String)": "JsonApiDotNetCore.Internal.Query.BaseFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.eq": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.ge": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.gt": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.le": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.like": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterOperations.lt": "JsonApiDotNetCore.Internal.Query.FilterOperations.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.#ctor(System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.Attribute": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.IsAttributeOfRelationship": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.Key": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.Operation": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.FilterQuery.Value": "JsonApiDotNetCore.Internal.Query.FilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.PageQuery": "JsonApiDotNetCore.Internal.Query.PageQuery.yml", + "JsonApiDotNetCore.Internal.Query.PageQuery.PageOffset": "JsonApiDotNetCore.Internal.Query.PageQuery.yml", + "JsonApiDotNetCore.Internal.Query.PageQuery.PageSize": "JsonApiDotNetCore.Internal.Query.PageQuery.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet.Fields": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet.Filters": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet.IncludedRelationships": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet.PageQuery": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.QuerySet.SortParameters": "JsonApiDotNetCore.Internal.Query.QuerySet.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Internal.Query.FilterQuery)": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.FilteredAttribute": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.FilteredRelationship": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.FilterOperation": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.PropertyValue": "JsonApiDotNetCore.Internal.Query.RelatedAttrFilterQuery.yml", + "JsonApiDotNetCore.Internal.Query.SortDirection": "JsonApiDotNetCore.Internal.Query.SortDirection.yml", + "JsonApiDotNetCore.Internal.Query.SortDirection.Ascending": "JsonApiDotNetCore.Internal.Query.SortDirection.yml", + "JsonApiDotNetCore.Internal.Query.SortDirection.Descending": "JsonApiDotNetCore.Internal.Query.SortDirection.yml", + "JsonApiDotNetCore.Internal.Query.SortQuery": "JsonApiDotNetCore.Internal.Query.SortQuery.yml", + "JsonApiDotNetCore.Internal.Query.SortQuery.#ctor(JsonApiDotNetCore.Internal.Query.SortDirection,JsonApiDotNetCore.Models.AttrAttribute)": "JsonApiDotNetCore.Internal.Query.SortQuery.yml", + "JsonApiDotNetCore.Internal.Query.SortQuery.Direction": "JsonApiDotNetCore.Internal.Query.SortQuery.yml", + "JsonApiDotNetCore.Internal.Query.SortQuery.SortedAttribute": "JsonApiDotNetCore.Internal.Query.SortQuery.yml", + "JsonApiDotNetCore.Internal.TypeHelper": "JsonApiDotNetCore.Internal.TypeHelper.yml", + "JsonApiDotNetCore.Internal.TypeHelper.ConvertType(System.Object,System.Type)": "JsonApiDotNetCore.Internal.TypeHelper.yml", + "JsonApiDotNetCore.Internal.TypeHelper.ConvertType``1(System.Object)": "JsonApiDotNetCore.Internal.TypeHelper.yml", + "JsonApiDotNetCore.Middleware": "JsonApiDotNetCore.Middleware.yml", + "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter": "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter.yml", + "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter.#ctor(Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter.yml", + "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter.OnException(Microsoft.AspNetCore.Mvc.Filters.ExceptionContext)": "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter.yml", + "JsonApiDotNetCore.Middleware.RequestMiddleware": "JsonApiDotNetCore.Middleware.RequestMiddleware.yml", + "JsonApiDotNetCore.Middleware.RequestMiddleware.#ctor(Microsoft.AspNetCore.Http.RequestDelegate)": "JsonApiDotNetCore.Middleware.RequestMiddleware.yml", + "JsonApiDotNetCore.Middleware.RequestMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext)": "JsonApiDotNetCore.Middleware.RequestMiddleware.yml", + "JsonApiDotNetCore.Models": "JsonApiDotNetCore.Models.yml", + "JsonApiDotNetCore.Models.AttrAttribute": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.#ctor(System.String,System.Boolean,System.Boolean,System.Boolean)": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.GetValue(System.Object)": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.InternalAttributeName": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.IsFilterable": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.IsImmutable": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.IsSortable": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.PublicAttributeName": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.SetValue(System.Object,System.Object)": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.Document": "JsonApiDotNetCore.Models.Document.yml", + "JsonApiDotNetCore.Models.Document.Data": "JsonApiDotNetCore.Models.Document.yml", + "JsonApiDotNetCore.Models.DocumentBase": "JsonApiDotNetCore.Models.DocumentBase.yml", + "JsonApiDotNetCore.Models.DocumentBase.Included": "JsonApiDotNetCore.Models.DocumentBase.yml", + "JsonApiDotNetCore.Models.DocumentBase.Links": "JsonApiDotNetCore.Models.DocumentBase.yml", + "JsonApiDotNetCore.Models.DocumentBase.Meta": "JsonApiDotNetCore.Models.DocumentBase.yml", + "JsonApiDotNetCore.Models.DocumentData": "JsonApiDotNetCore.Models.DocumentData.yml", + "JsonApiDotNetCore.Models.Documents": "JsonApiDotNetCore.Models.Documents.yml", + "JsonApiDotNetCore.Models.Documents.Data": "JsonApiDotNetCore.Models.Documents.yml", + "JsonApiDotNetCore.Models.HasManyAttribute": "JsonApiDotNetCore.Models.HasManyAttribute.yml", + "JsonApiDotNetCore.Models.HasManyAttribute.#ctor(System.String,JsonApiDotNetCore.Models.Link)": "JsonApiDotNetCore.Models.HasManyAttribute.yml", + "JsonApiDotNetCore.Models.HasManyAttribute.SetValue(System.Object,System.Object)": "JsonApiDotNetCore.Models.HasManyAttribute.yml", + "JsonApiDotNetCore.Models.HasOneAttribute": "JsonApiDotNetCore.Models.HasOneAttribute.yml", + "JsonApiDotNetCore.Models.HasOneAttribute.#ctor(System.String,JsonApiDotNetCore.Models.Link)": "JsonApiDotNetCore.Models.HasOneAttribute.yml", + "JsonApiDotNetCore.Models.HasOneAttribute.SetValue(System.Object,System.Object)": "JsonApiDotNetCore.Models.HasOneAttribute.yml", + "JsonApiDotNetCore.Models.Identifiable": "JsonApiDotNetCore.Models.Identifiable.yml", + "JsonApiDotNetCore.Models.Identifiable`1": "JsonApiDotNetCore.Models.Identifiable-1.yml", + "JsonApiDotNetCore.Models.Identifiable`1.GetConcreteId(System.String)": "JsonApiDotNetCore.Models.Identifiable-1.yml", + "JsonApiDotNetCore.Models.Identifiable`1.GetStringId(System.Object)": "JsonApiDotNetCore.Models.Identifiable-1.yml", + "JsonApiDotNetCore.Models.Identifiable`1.Id": "JsonApiDotNetCore.Models.Identifiable-1.yml", + "JsonApiDotNetCore.Models.Identifiable`1.StringId": "JsonApiDotNetCore.Models.Identifiable-1.yml", + "JsonApiDotNetCore.Models.IHasMeta": "JsonApiDotNetCore.Models.IHasMeta.yml", + "JsonApiDotNetCore.Models.IHasMeta.GetMeta(JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Models.IHasMeta.yml", + "JsonApiDotNetCore.Models.IIdentifiable": "JsonApiDotNetCore.Models.IIdentifiable.yml", + "JsonApiDotNetCore.Models.IIdentifiable.StringId": "JsonApiDotNetCore.Models.IIdentifiable.yml", + "JsonApiDotNetCore.Models.IIdentifiable`1": "JsonApiDotNetCore.Models.IIdentifiable-1.yml", + "JsonApiDotNetCore.Models.IIdentifiable`1.Id": "JsonApiDotNetCore.Models.IIdentifiable-1.yml", + "JsonApiDotNetCore.Models.JsonApiExtension": "JsonApiDotNetCore.Models.JsonApiExtension.yml", + "JsonApiDotNetCore.Models.JsonApiExtension.Operations": "JsonApiDotNetCore.Models.JsonApiExtension.yml", + "JsonApiDotNetCore.Models.Link": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Link.All": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Link.None": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Link.Paging": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Link.Related": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Link.Self": "JsonApiDotNetCore.Models.Link.yml", + "JsonApiDotNetCore.Models.Links": "JsonApiDotNetCore.Models.Links.yml", + "JsonApiDotNetCore.Models.Links.Related": "JsonApiDotNetCore.Models.Links.yml", + "JsonApiDotNetCore.Models.Links.Self": "JsonApiDotNetCore.Models.Links.yml", + "JsonApiDotNetCore.Models.LinksAttribute": "JsonApiDotNetCore.Models.LinksAttribute.yml", + "JsonApiDotNetCore.Models.LinksAttribute.#ctor(JsonApiDotNetCore.Models.Link)": "JsonApiDotNetCore.Models.LinksAttribute.yml", + "JsonApiDotNetCore.Models.LinksAttribute.Links": "JsonApiDotNetCore.Models.LinksAttribute.yml", + "JsonApiDotNetCore.Models.Operations": "JsonApiDotNetCore.Models.Operations.yml", + "JsonApiDotNetCore.Models.Operations.Operation": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.Data": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.DataIsList": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.DataList": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.DataObject": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.GetResourceTypeName": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.Op": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.Params": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.Operation.Ref": "JsonApiDotNetCore.Models.Operations.Operation.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode.add": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode.get": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode.remove": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode.replace": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationsDocument": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", + "JsonApiDotNetCore.Models.Operations.OperationsDocument.#ctor": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", + "JsonApiDotNetCore.Models.Operations.OperationsDocument.#ctor(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", + "JsonApiDotNetCore.Models.Operations.OperationsDocument.Operations": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", + "JsonApiDotNetCore.Models.Operations.Params": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.Params.Fields": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.Params.Filter": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.Params.Include": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.Params.Page": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.Params.Sort": "JsonApiDotNetCore.Models.Operations.Params.yml", + "JsonApiDotNetCore.Models.Operations.ResourceReference": "JsonApiDotNetCore.Models.Operations.ResourceReference.yml", + "JsonApiDotNetCore.Models.Operations.ResourceReference.Relationship": "JsonApiDotNetCore.Models.Operations.ResourceReference.yml", + "JsonApiDotNetCore.Models.Pointers": "JsonApiDotNetCore.Models.Pointers.yml", + "JsonApiDotNetCore.Models.Pointers.OperationsPointer": "JsonApiDotNetCore.Models.Pointers.OperationsPointer.yml", + "JsonApiDotNetCore.Models.Pointers.OperationsPointer.GetValue(System.Object)": "JsonApiDotNetCore.Models.Pointers.OperationsPointer.yml", + "JsonApiDotNetCore.Models.Pointers.Pointer`1": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", + "JsonApiDotNetCore.Models.Pointers.Pointer`1.GetValue(System.Object)": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", + "JsonApiDotNetCore.Models.Pointers.Pointer`1.JsonSchema": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", + "JsonApiDotNetCore.Models.Pointers.Pointer`1.PointerAddress": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.#ctor(System.String,JsonApiDotNetCore.Models.Link)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.DocumentLinks": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.Equals(System.Object)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.InternalRelationshipName": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.IsHasMany": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.IsHasOne": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.PublicRelationshipName": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.SetValue(System.Object,System.Object)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.ToString": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.Type": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipData": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.RelationshipData.ExposedData": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.RelationshipData.IsHasMany": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.RelationshipData.Links": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.RelationshipData.ManyData": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.RelationshipData.SingleData": "JsonApiDotNetCore.Models.RelationshipData.yml", + "JsonApiDotNetCore.Models.ResourceAttribute": "JsonApiDotNetCore.Models.ResourceAttribute.yml", + "JsonApiDotNetCore.Models.ResourceAttribute.#ctor(System.String)": "JsonApiDotNetCore.Models.ResourceAttribute.yml", + "JsonApiDotNetCore.Models.ResourceAttribute.ResourceName": "JsonApiDotNetCore.Models.ResourceAttribute.yml", + "JsonApiDotNetCore.Models.ResourceIdentifierObject": "JsonApiDotNetCore.Models.ResourceIdentifierObject.yml", + "JsonApiDotNetCore.Models.ResourceIdentifierObject.Id": "JsonApiDotNetCore.Models.ResourceIdentifierObject.yml", + "JsonApiDotNetCore.Models.ResourceIdentifierObject.LocalId": "JsonApiDotNetCore.Models.ResourceIdentifierObject.yml", + "JsonApiDotNetCore.Models.ResourceIdentifierObject.Type": "JsonApiDotNetCore.Models.ResourceIdentifierObject.yml", + "JsonApiDotNetCore.Models.ResourceObject": "JsonApiDotNetCore.Models.ResourceObject.yml", + "JsonApiDotNetCore.Models.ResourceObject.Attributes": "JsonApiDotNetCore.Models.ResourceObject.yml", + "JsonApiDotNetCore.Models.ResourceObject.Relationships": "JsonApiDotNetCore.Models.ResourceObject.yml", + "JsonApiDotNetCore.Models.RootLinks": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.First": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.Last": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.Next": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.Prev": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.Self": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.ShouldSerializeFirst": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.ShouldSerializeLast": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.ShouldSerializeNext": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.ShouldSerializePrev": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Models.RootLinks.ShouldSerializeSelf": "JsonApiDotNetCore.Models.RootLinks.yml", + "JsonApiDotNetCore.Serialization": "JsonApiDotNetCore.Serialization.yml", + "JsonApiDotNetCore.Serialization.DasherizedResolver": "JsonApiDotNetCore.Serialization.DasherizedResolver.yml", + "JsonApiDotNetCore.Serialization.DasherizedResolver.CreateProperty(System.Reflection.MemberInfo,Newtonsoft.Json.MemberSerialization)": "JsonApiDotNetCore.Serialization.DasherizedResolver.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.Deserialize(System.String)": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.Deserialize``1(System.String)": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.DeserializeList``1(System.String)": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.DeserializeRelationship(System.String)": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.DocumentToObject(JsonApiDotNetCore.Models.DocumentData)": "JsonApiDotNetCore.Serialization.IJsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiSerializer": "JsonApiDotNetCore.Serialization.IJsonApiSerializer.yml", + "JsonApiDotNetCore.Serialization.IJsonApiSerializer.Serialize(System.Object)": "JsonApiDotNetCore.Serialization.IJsonApiSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize(System.String)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.Deserialize``1(System.String)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.DeserializeList``1(System.String)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.DeserializeRelationship(System.String)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.DocumentToObject(JsonApiDotNetCore.Models.DocumentData)": "JsonApiDotNetCore.Serialization.JsonApiDeSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiSerializer": "JsonApiDotNetCore.Serialization.JsonApiSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiSerializer.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Builders.IDocumentBuilder)": "JsonApiDotNetCore.Serialization.JsonApiSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiSerializer.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Builders.IDocumentBuilder,Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Serialization.JsonApiSerializer.yml", + "JsonApiDotNetCore.Serialization.JsonApiSerializer.Serialize(System.Object)": "JsonApiDotNetCore.Serialization.JsonApiSerializer.yml", + "JsonApiDotNetCore.Services": "JsonApiDotNetCore.Services.yml", + "JsonApiDotNetCore.Services.ControllerContext": "JsonApiDotNetCore.Services.ControllerContext.yml", + "JsonApiDotNetCore.Services.ControllerContext.ControllerType": "JsonApiDotNetCore.Services.ControllerContext.yml", + "JsonApiDotNetCore.Services.ControllerContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.ControllerContext.yml", + "JsonApiDotNetCore.Services.ControllerContext.RequestEntity": "JsonApiDotNetCore.Services.ControllerContext.yml", + "JsonApiDotNetCore.Services.EntityResourceService`1": "JsonApiDotNetCore.Services.EntityResourceService-1.yml", + "JsonApiDotNetCore.Services.EntityResourceService`1.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Data.IEntityRepository{`0},Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Services.EntityResourceService-1.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,JsonApiDotNetCore.Data.IEntityRepository{`0,`1},Microsoft.Extensions.Logging.ILoggerFactory)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.CreateAsync(`0)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.DeleteAsync(`1)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.GetAsync": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.GetAsync(`1)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.GetRelationshipAsync(`1,System.String)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.GetRelationshipsAsync(`1,System.String)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.UpdateAsync(`1,`0)": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.EntityResourceService`2.UpdateRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Services.EntityResourceService-2.yml", + "JsonApiDotNetCore.Services.IControllerContext": "JsonApiDotNetCore.Services.IControllerContext.yml", + "JsonApiDotNetCore.Services.IControllerContext.ControllerType": "JsonApiDotNetCore.Services.IControllerContext.yml", + "JsonApiDotNetCore.Services.IControllerContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.IControllerContext.yml", + "JsonApiDotNetCore.Services.IControllerContext.RequestEntity": "JsonApiDotNetCore.Services.IControllerContext.yml", + "JsonApiDotNetCore.Services.ICreateService`1": "JsonApiDotNetCore.Services.ICreateService-1.yml", + "JsonApiDotNetCore.Services.ICreateService`2": "JsonApiDotNetCore.Services.ICreateService-2.yml", + "JsonApiDotNetCore.Services.ICreateService`2.CreateAsync(`0)": "JsonApiDotNetCore.Services.ICreateService-2.yml", + "JsonApiDotNetCore.Services.IDeleteService`1": "JsonApiDotNetCore.Services.IDeleteService-1.yml", + "JsonApiDotNetCore.Services.IDeleteService`2": "JsonApiDotNetCore.Services.IDeleteService-2.yml", + "JsonApiDotNetCore.Services.IDeleteService`2.DeleteAsync(`1)": "JsonApiDotNetCore.Services.IDeleteService-2.yml", + "JsonApiDotNetCore.Services.IGetAllService`1": "JsonApiDotNetCore.Services.IGetAllService-1.yml", + "JsonApiDotNetCore.Services.IGetAllService`2": "JsonApiDotNetCore.Services.IGetAllService-2.yml", + "JsonApiDotNetCore.Services.IGetAllService`2.GetAsync": "JsonApiDotNetCore.Services.IGetAllService-2.yml", + "JsonApiDotNetCore.Services.IGetByIdService`1": "JsonApiDotNetCore.Services.IGetByIdService-1.yml", + "JsonApiDotNetCore.Services.IGetByIdService`2": "JsonApiDotNetCore.Services.IGetByIdService-2.yml", + "JsonApiDotNetCore.Services.IGetByIdService`2.GetAsync(`1)": "JsonApiDotNetCore.Services.IGetByIdService-2.yml", + "JsonApiDotNetCore.Services.IGetRelationshipService`1": "JsonApiDotNetCore.Services.IGetRelationshipService-1.yml", + "JsonApiDotNetCore.Services.IGetRelationshipService`2": "JsonApiDotNetCore.Services.IGetRelationshipService-2.yml", + "JsonApiDotNetCore.Services.IGetRelationshipService`2.GetRelationshipAsync(`1,System.String)": "JsonApiDotNetCore.Services.IGetRelationshipService-2.yml", + "JsonApiDotNetCore.Services.IGetRelationshipsService`1": "JsonApiDotNetCore.Services.IGetRelationshipsService-1.yml", + "JsonApiDotNetCore.Services.IGetRelationshipsService`2": "JsonApiDotNetCore.Services.IGetRelationshipsService-2.yml", + "JsonApiDotNetCore.Services.IGetRelationshipsService`2.GetRelationshipsAsync(`1,System.String)": "JsonApiDotNetCore.Services.IGetRelationshipsService-2.yml", + "JsonApiDotNetCore.Services.IJsonApiContext": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.ApplyContext``1(System.Object)": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.AttributesToUpdate": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.BasePath": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.ContextGraph": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.ControllerType": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.DocumentMeta": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.GenericProcessorFactory": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.IncludedRelationships": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.IsRelationshipData": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.IsRelationshipPath": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.MetaBuilder": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.Options": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.PageManager": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.QuerySet": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.RelationshipsToUpdate": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.RequestEntity": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IQueryAccessor": "JsonApiDotNetCore.Services.IQueryAccessor.yml", + "JsonApiDotNetCore.Services.IQueryAccessor.GetRequired``1(System.String)": "JsonApiDotNetCore.Services.IQueryAccessor.yml", + "JsonApiDotNetCore.Services.IQueryAccessor.TryGetValue``1(System.String,``0@)": "JsonApiDotNetCore.Services.IQueryAccessor.yml", + "JsonApiDotNetCore.Services.IQueryParser": "JsonApiDotNetCore.Services.IQueryParser.yml", + "JsonApiDotNetCore.Services.IQueryParser.Parse(Microsoft.AspNetCore.Http.IQueryCollection)": "JsonApiDotNetCore.Services.IQueryParser.yml", + "JsonApiDotNetCore.Services.IRequestMeta": "JsonApiDotNetCore.Services.IRequestMeta.yml", + "JsonApiDotNetCore.Services.IRequestMeta.GetMeta": "JsonApiDotNetCore.Services.IRequestMeta.yml", + "JsonApiDotNetCore.Services.IResourceCmdService`1": "JsonApiDotNetCore.Services.IResourceCmdService-1.yml", + "JsonApiDotNetCore.Services.IResourceCmdService`2": "JsonApiDotNetCore.Services.IResourceCmdService-2.yml", + "JsonApiDotNetCore.Services.IResourceQueryService`1": "JsonApiDotNetCore.Services.IResourceQueryService-1.yml", + "JsonApiDotNetCore.Services.IResourceQueryService`2": "JsonApiDotNetCore.Services.IResourceQueryService-2.yml", + "JsonApiDotNetCore.Services.IResourceService`1": "JsonApiDotNetCore.Services.IResourceService-1.yml", + "JsonApiDotNetCore.Services.IResourceService`2": "JsonApiDotNetCore.Services.IResourceService-2.yml", + "JsonApiDotNetCore.Services.IUpdateRelationshipService`1": "JsonApiDotNetCore.Services.IUpdateRelationshipService-1.yml", + "JsonApiDotNetCore.Services.IUpdateRelationshipService`2": "JsonApiDotNetCore.Services.IUpdateRelationshipService-2.yml", + "JsonApiDotNetCore.Services.IUpdateRelationshipService`2.UpdateRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Services.IUpdateRelationshipService-2.yml", + "JsonApiDotNetCore.Services.IUpdateService`1": "JsonApiDotNetCore.Services.IUpdateService-1.yml", + "JsonApiDotNetCore.Services.IUpdateService`2": "JsonApiDotNetCore.Services.IUpdateService-2.yml", + "JsonApiDotNetCore.Services.IUpdateService`2.UpdateAsync(`1,`0)": "JsonApiDotNetCore.Services.IUpdateService-2.yml", + "JsonApiDotNetCore.Services.JsonApiContext": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.#ctor(JsonApiDotNetCore.Internal.IContextGraph,Microsoft.AspNetCore.Http.IHttpContextAccessor,JsonApiDotNetCore.Configuration.JsonApiOptions,JsonApiDotNetCore.Builders.IMetaBuilder,JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory,JsonApiDotNetCore.Services.IQueryParser,JsonApiDotNetCore.Services.IControllerContext)": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.ApplyContext``1(System.Object)": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.AttributesToUpdate": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.BasePath": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.ContextGraph": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.ControllerType": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.DocumentMeta": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.GenericProcessorFactory": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.IncludedRelationships": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.IsRelationshipData": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.IsRelationshipPath": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.MetaBuilder": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.Options": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.PageManager": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.QuerySet": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.RelationshipsToUpdate": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.RequestEntity": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.Operations": "JsonApiDotNetCore.Services.Operations.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateCreateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateGetService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateRemoveService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateReplaceService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationsProcessor": "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.yml", + "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.ProcessAsync(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.yml", + "JsonApiDotNetCore.Services.Operations.IOpProcessor": "JsonApiDotNetCore.Services.Operations.IOpProcessor.yml", + "JsonApiDotNetCore.Services.Operations.IOpProcessor.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOpProcessor.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.#ctor(JsonApiDotNetCore.Internal.Generics.IGenericProcessorFactory,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateCreateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateGetService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateRemoveService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateReplaceService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationsProcessor": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", + "JsonApiDotNetCore.Services.Operations.OperationsProcessor.#ctor(JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver,JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", + "JsonApiDotNetCore.Services.Operations.OperationsProcessor.ProcessAsync(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", + "JsonApiDotNetCore.Services.Operations.Processors": "JsonApiDotNetCore.Services.Operations.Processors.yml", + "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`1.#ctor(JsonApiDotNetCore.Services.ICreateService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`2.#ctor(JsonApiDotNetCore.Services.ICreateService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,System.Int32},JsonApiDotNetCore.Services.IGetByIdService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,`1},JsonApiDotNetCore.Services.IGetByIdService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IDeleteService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IDeleteService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.QueryAccessor": "JsonApiDotNetCore.Services.QueryAccessor.yml", + "JsonApiDotNetCore.Services.QueryAccessor.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,Microsoft.Extensions.Logging.ILogger{JsonApiDotNetCore.Services.QueryAccessor})": "JsonApiDotNetCore.Services.QueryAccessor.yml", + "JsonApiDotNetCore.Services.QueryAccessor.GetRequired``1(System.String)": "JsonApiDotNetCore.Services.QueryAccessor.yml", + "JsonApiDotNetCore.Services.QueryAccessor.TryGetValue``1(System.String,``0@)": "JsonApiDotNetCore.Services.QueryAccessor.yml", + "JsonApiDotNetCore.Services.QueryParser": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.#ctor(JsonApiDotNetCore.Services.IControllerContext,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.GetAttribute(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.Parse(Microsoft.AspNetCore.Http.IQueryCollection)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParseFieldsQuery(System.String,System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParseFilterOperation(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParseFilterQuery(System.String,System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParseIncludedRelationships(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParsePageQuery(JsonApiDotNetCore.Internal.Query.PageQuery,System.String,System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.QueryParser.ParseSortParameters(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml" +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/api/index.md b/src/JsonApiDotNetCore/api/index.md new file mode 100644 index 0000000000..78dc9c0057 --- /dev/null +++ b/src/JsonApiDotNetCore/api/index.md @@ -0,0 +1,2 @@ +# PLACEHOLDER +TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! diff --git a/src/JsonApiDotNetCore/articles/intro.md b/src/JsonApiDotNetCore/articles/intro.md new file mode 100644 index 0000000000..c0478cedea --- /dev/null +++ b/src/JsonApiDotNetCore/articles/intro.md @@ -0,0 +1 @@ +# Add your introductions here! diff --git a/src/JsonApiDotNetCore/articles/toc.yml b/src/JsonApiDotNetCore/articles/toc.yml new file mode 100644 index 0000000000..ff89ef1fe0 --- /dev/null +++ b/src/JsonApiDotNetCore/articles/toc.yml @@ -0,0 +1,2 @@ +- name: Introduction + href: intro.md diff --git a/src/JsonApiDotNetCore/docfx.json b/src/JsonApiDotNetCore/docfx.json new file mode 100644 index 0000000000..5c46dcbd88 --- /dev/null +++ b/src/JsonApiDotNetCore/docfx.json @@ -0,0 +1,52 @@ +{ + "metadata": [ + { + "src": [ + { + "files": [ "**.csproj" ], + "src": "C:\\Users\\jnance\\dev\\json-api-dotnet-core\\src\\JsonApiDotNetCore" + } + ], + "dest": "api", + "disableGitFeatures": false, + "properties": { + "targetFramework": "netstandard2.0" + } + } + ], + "build": { + "content": [ + { + "files": [ "api/**.yml", "api/index.md" ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ "images/**" ] + } + ], + "overwrite": [ + { + "files": [ "apidoc/**.md" ], + "exclude": [ "obj/**", "_site/**" ] + } + ], + "dest": "_site", + "globalMetadataFiles": [], + "fileMetadataFiles": [], + "template": [ "default" ], + "postProcessors": [], + "noLangKeyword": false, + "keepFileLink": false, + "cleanupCacheHistory": false, + "disableGitFeatures": false + } +} diff --git a/src/JsonApiDotNetCore/index.md b/src/JsonApiDotNetCore/index.md new file mode 100644 index 0000000000..3ae2506361 --- /dev/null +++ b/src/JsonApiDotNetCore/index.md @@ -0,0 +1,4 @@ +# This is the **HOMEPAGE**. +Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. +## Quick Start Notes: +1. Add images to the *images* folder if the file is referencing an image. diff --git a/src/JsonApiDotNetCore/toc.yml b/src/JsonApiDotNetCore/toc.yml new file mode 100644 index 0000000000..59f8010471 --- /dev/null +++ b/src/JsonApiDotNetCore/toc.yml @@ -0,0 +1,5 @@ +- name: Articles + href: articles/ +- name: Api Documentation + href: api/ + homepage: api/index.md From 9719f7496571e139521b0fcb047442b1775f4dce Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 25 Mar 2018 08:36:44 -0500 Subject: [PATCH 101/227] support bulk add transaction - rename replace to update - rollback failed transactions --- Directory.Build.props | 9 +- .../OperationsExample/Data/AppDbContext.cs | 1 + .../20170827234334_AddArticles.Designer.cs | 33 --- .../Migrations/20170827234334_AddArticles.cs | 32 --- ...80325130426_ArticlesAndAuthors.Designer.cs | 61 +++++ .../20180325130426_ArticlesAndAuthors.cs | 60 +++++ .../Migrations/AppDbContextModelSnapshot.cs | 32 ++- .../OperationsExample/Models/Article.cs | 8 +- .../OperationsExample/Models/Author.cs | 14 ++ .../OperationsExample.csproj | 1 + src/Examples/OperationsExample/Program.cs | 21 +- .../OperationsExample/appsettings.json | 22 +- .../Controllers/JsonApiControllerMixin.cs | 9 +- .../JsonApiOperationsController.cs | 2 + .../Data/DbContextResolver.cs | 2 +- .../IServiceCollectionExtensions.cs | 6 +- .../Extensions/JObjectExtensions.cs | 6 +- .../Models/Operations/OperationCode.cs | 6 +- .../Models/Pointers/OperationsPointer.cs | 10 +- .../Models/Pointers/Pointer.cs | 2 +- .../Serialization/JsonApiDeSerializer.cs | 12 +- .../Serialization/JsonApiSerializer.cs | 7 +- .../Services/IJsonApiContext.cs | 1 + .../Services/JsonApiContext.cs | 1 + .../Operations/OperationProcessorResolver.cs | 20 +- .../Operations/OperationsProcessor.cs | 51 ++-- .../Processors/CreateOpProcessor.cs | 4 + .../Processors/RemoveOpProcessor.cs | 7 +- ...aceOpProcessor.cs => UpdateOpProcessor.cs} | 20 +- src/JsonApiDotNetCore/api/.manifest | 30 +-- .../ReplaceTests.cs => Update/UpdateTests.cs} | 224 +++++++++--------- .../Operations/OperationsProcessorTests.cs | 4 +- 32 files changed, 408 insertions(+), 310 deletions(-) delete mode 100755 src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs delete mode 100755 src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs create mode 100644 src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs create mode 100644 src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs create mode 100644 src/Examples/OperationsExample/Models/Author.cs rename src/JsonApiDotNetCore/Services/Operations/Processors/{ReplaceOpProcessor.cs => UpdateOpProcessor.cs} (79%) rename test/OperationsExampleTests/{Replace/ReplaceTests.cs => Update/UpdateTests.cs} (93%) diff --git a/Directory.Build.props b/Directory.Build.props index cc81f65974..346835dd6c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - + netcoreapp2.0 netstandard2.0 @@ -10,7 +10,6 @@ 2.0.0 2.0.0 - 2.0.1 2.0.1 @@ -19,8 +18,8 @@ 4.4.0 - - + + 15.3.0-preview-20170427-09 1.1.2 @@ -28,5 +27,5 @@ 15.0.3 4.7.99 - + diff --git a/src/Examples/OperationsExample/Data/AppDbContext.cs b/src/Examples/OperationsExample/Data/AppDbContext.cs index d00bfe4765..3d5b3e2e54 100644 --- a/src/Examples/OperationsExample/Data/AppDbContext.cs +++ b/src/Examples/OperationsExample/Data/AppDbContext.cs @@ -10,5 +10,6 @@ public AppDbContext(DbContextOptions options) { } public DbSet
Articles { get; set; } + public DbSet Authors { get; set; } } } diff --git a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs deleted file mode 100755 index 10f16d49cd..0000000000 --- a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.Designer.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using OperationsExample.Data; - -namespace OperationsExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170827234334_AddArticles")] - partial class AddArticles - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.2"); - - modelBuilder.Entity("OperationsExample.Models.Article", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.HasKey("Id"); - - b.ToTable("Articles"); - }); - } - } -} diff --git a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs b/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs deleted file mode 100755 index 308e6f78f5..0000000000 --- a/src/Examples/OperationsExample/Migrations/20170827234334_AddArticles.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; - -namespace OperationsExample.Migrations -{ - public partial class AddArticles : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Articles", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), - Name = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Articles", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Articles"); - } - } -} diff --git a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs new file mode 100644 index 0000000000..e9934cb776 --- /dev/null +++ b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs @@ -0,0 +1,61 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using OperationsExample.Data; +using System; + +namespace OperationsExample.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20180325130426_ArticlesAndAuthors")] + partial class ArticlesAndAuthors + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); + + modelBuilder.Entity("OperationsExample.Models.Article", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("OperationsExample.Models.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); + + modelBuilder.Entity("OperationsExample.Models.Article", b => + { + b.HasOne("OperationsExample.Models.Author", "Author") + .WithMany("Articles") + .HasForeignKey("AuthorId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs new file mode 100644 index 0000000000..1a0d5e309a --- /dev/null +++ b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs @@ -0,0 +1,60 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace OperationsExample.Migrations +{ + public partial class ArticlesAndAuthors : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Authors", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Authors", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Articles", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AuthorId = table.Column(nullable: true), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Articles", x => x.Id); + table.ForeignKey( + name: "FK_Articles_Authors_AuthorId", + column: x => x.AuthorId, + principalTable: "Authors", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_Articles_AuthorId", + table: "Articles", + column: "AuthorId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Articles"); + + migrationBuilder.DropTable( + name: "Authors"); + } + } +} diff --git a/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs index 547bbbf2cf..b4c9a0ebba 100755 --- a/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs @@ -1,9 +1,12 @@ -using System; +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; using OperationsExample.Data; +using System; namespace OperationsExample.Migrations { @@ -12,21 +15,46 @@ partial class AppDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.2"); + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); modelBuilder.Entity("OperationsExample.Models.Article", b => { b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("AuthorId"); + b.Property("Name"); b.HasKey("Id"); + b.HasIndex("AuthorId"); + b.ToTable("Articles"); }); + + modelBuilder.Entity("OperationsExample.Models.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); + + modelBuilder.Entity("OperationsExample.Models.Article", b => + { + b.HasOne("OperationsExample.Models.Author", "Author") + .WithMany("Articles") + .HasForeignKey("AuthorId"); + }); +#pragma warning restore 612, 618 } } } diff --git a/src/Examples/OperationsExample/Models/Article.cs b/src/Examples/OperationsExample/Models/Article.cs index fc4b5d6647..4353c02ee2 100644 --- a/src/Examples/OperationsExample/Models/Article.cs +++ b/src/Examples/OperationsExample/Models/Article.cs @@ -1,10 +1,14 @@ -using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Models; namespace OperationsExample.Models { public class Article : Identifiable { [Attr("name")] - public string Name { get; set; } + public string Name { get; set; } + + [HasOne("author")] + public Author Author { get; set; } + public int AuthorId { get; set; } } } diff --git a/src/Examples/OperationsExample/Models/Author.cs b/src/Examples/OperationsExample/Models/Author.cs new file mode 100644 index 0000000000..7d6039480a --- /dev/null +++ b/src/Examples/OperationsExample/Models/Author.cs @@ -0,0 +1,14 @@ +using JsonApiDotNetCore.Models; +using System.Collections.Generic; + +namespace OperationsExample.Models +{ + public class Author : Identifiable + { + [Attr("name")] + public string Name { get; set; } + + [HasMany("articles")] + public List
Articles { get; set; } + } +} diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj index 48c2654722..ebbdc91fc1 100644 --- a/src/Examples/OperationsExample/OperationsExample.csproj +++ b/src/Examples/OperationsExample/OperationsExample.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Examples/OperationsExample/Program.cs b/src/Examples/OperationsExample/Program.cs index b528f47d15..1c2b6b267a 100644 --- a/src/Examples/OperationsExample/Program.cs +++ b/src/Examples/OperationsExample/Program.cs @@ -1,26 +1,15 @@ -using System.IO; +using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; namespace OperationsExample { public class Program - { - public static void Main(string[] args) - { - var config = new ConfigurationBuilder() - .AddCommandLine(args) - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .Build(); + { + public static void Main(string[] args) => BuildWebHost(args).Run(); - var host = new WebHostBuilder() - .UseConfiguration(config) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); - - host.Run(); - } } } diff --git a/src/Examples/OperationsExample/appsettings.json b/src/Examples/OperationsExample/appsettings.json index c1061281cc..2bcbebd13a 100644 --- a/src/Examples/OperationsExample/appsettings.json +++ b/src/Examples/OperationsExample/appsettings.json @@ -1,13 +1,13 @@ -{ - "Data": { - "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=password" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Trace", - "System": "Trace", - "Microsoft": "Trace" +{ + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=postgres" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "System": "Trace", + "Microsoft": "Trace" + } } - } } diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs index fafc70f161..6fff3a22c8 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs @@ -19,7 +19,8 @@ protected IActionResult Forbidden() protected IActionResult Error(Error error) { - var errorCollection = new ErrorCollection { + var errorCollection = new ErrorCollection + { Errors = new List { error } }; var result = new ObjectResult(errorCollection); @@ -36,16 +37,16 @@ protected IActionResult Errors(ErrorCollection errors) return result; } - private int GetErrorStatusCode(ErrorCollection errors) + private int GetErrorStatusCode(ErrorCollection errors) { var statusCodes = errors.Errors .Select(e => e.StatusCode) .Distinct() .ToList(); - if(statusCodes.Count == 1) + if (statusCodes.Count == 1) return statusCodes[0]; - + return int.Parse(statusCodes.Max().ToString()[0] + "00"); } } diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index f3d0b6651d..69f4be8a89 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -18,6 +18,8 @@ public JsonApiOperationsController( [HttpPatch] public async Task PatchAsync([FromBody] OperationsDocument doc) { + if (doc == null) return new StatusCodeResult(422); + var results = await _operationsProcessor.ProcessAsync(doc.Operations); return Ok(new OperationsDocument(results)); diff --git a/src/JsonApiDotNetCore/Data/DbContextResolver.cs b/src/JsonApiDotNetCore/Data/DbContextResolver.cs index 7cfe0a4278..e681e660bb 100644 --- a/src/JsonApiDotNetCore/Data/DbContextResolver.cs +++ b/src/JsonApiDotNetCore/Data/DbContextResolver.cs @@ -3,7 +3,7 @@ namespace JsonApiDotNetCore.Data { - public class DbContextResolver : IDbContextResolver + public class DbContextResolver : IDbContextResolver where TContext : DbContext { private readonly TContext _context; diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 9b33163810..604d65536b 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -148,12 +148,12 @@ private static void AddOperationServices(IServiceCollection services) services.AddScoped(typeof(IGetOpProcessor<>), typeof(GetOpProcessor<>)); services.AddScoped(typeof(IGetOpProcessor<,>), typeof(GetOpProcessor<,>)); - services.AddScoped(typeof(IReplaceOpProcessor<>), typeof(ReplaceOpProcessor<>)); - services.AddScoped(typeof(IReplaceOpProcessor<,>), typeof(ReplaceOpProcessor<,>)); - services.AddScoped(typeof(IRemoveOpProcessor<>), typeof(RemoveOpProcessor<>)); services.AddScoped(typeof(IRemoveOpProcessor<,>), typeof(RemoveOpProcessor<,>)); + services.AddScoped(typeof(IUpdateOpProcessor<>), typeof(UpdateOpProcessor<>)); + services.AddScoped(typeof(IUpdateOpProcessor<,>), typeof(UpdateOpProcessor<,>)); + services.AddSingleton(); services.AddSingleton(); } diff --git a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs index 70aa070fc6..9871258b54 100644 --- a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs @@ -6,8 +6,8 @@ namespace JsonApiDotNetCore.Extensions { public static class JObjectExtensions { - public static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) - where TPointer : Pointer, new() + internal static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) + where TPointer : Pointer, new() { if (obj.IsValid(schema)) { @@ -19,4 +19,4 @@ public static bool TryParse(this JObject obj, JSchema sc return false; } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs b/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs index ffe3310985..6b6905cd59 100644 --- a/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs +++ b/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs @@ -1,10 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + namespace JsonApiDotNetCore.Models.Operations { + [JsonConverter(typeof(StringEnumConverter))] public enum OperationCode { get = 1, add = 2, - replace = 3, + update = 3, remove = 4 } } diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs index 0df8f64e72..53cdcfec06 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs @@ -5,12 +5,12 @@ namespace JsonApiDotNetCore.Models.Pointers { - public class OperationsPointer : Pointer + internal class OperationsPointer : Pointer { - /// - /// - /// - /// + /// + /// + /// + /// public override object GetValue(object root) { if (root == null) throw new ArgumentNullException(nameof(root)); diff --git a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs index 27f0083904..d5e3a7924b 100644 --- a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs +++ b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs @@ -3,7 +3,7 @@ namespace JsonApiDotNetCore.Models.Pointers { - public abstract class Pointer + internal abstract class Pointer { public static JSchema JsonSchema { get; } = JSchema.Parse("{ 'pointer': {'type': 'string'} }"); diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 6213edfd63..649d6435ff 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -31,8 +31,10 @@ public object Deserialize(string requestBody) { var bodyJToken = JToken.Parse(requestBody); - if(RequestIsOperation(bodyJToken)) + if (RequestIsOperation(bodyJToken)) { + _jsonApiContext.IsBulkOperationRequest = true; + // TODO: determine whether or not the token should be re-used rather than performing full // deserialization again from the string var operations = JsonConvert.DeserializeObject(requestBody); @@ -54,8 +56,8 @@ public object Deserialize(string requestBody) } } - private bool RequestIsOperation(JToken bodyJToken) - => _jsonApiContext.Options.EnableOperations + private bool RequestIsOperation(JToken bodyJToken) + => _jsonApiContext.Options.EnableOperations && (bodyJToken.SelectToken("operations") != null); public TEntity Deserialize(string requestBody) => (TEntity)Deserialize(requestBody); @@ -82,7 +84,7 @@ public List DeserializeList(string requestBody) try { var documents = JsonConvert.DeserializeObject(requestBody); - + var deserializedList = new List(); foreach (var data in documents.Data) { @@ -196,7 +198,7 @@ private object SetHasOneRelationship(object entity, if (relationshipAttr == null) throw new JsonApiException(400, $"{_jsonApiContext.RequestEntity.EntityName} does not contain a relationship '{relationshipName}'"); - var rio = (ResourceIdentifierObject) relationshipData.ExposedData; + var rio = (ResourceIdentifierObject)relationshipData.ExposedData; if (rio == null) return entity; diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs index 8e94835266..20d119ff07 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiSerializer.cs @@ -37,9 +37,12 @@ public string Serialize(object entity) if (entity == null) return GetNullDataResponse(); - if (entity.GetType() == typeof(ErrorCollection) || _jsonApiContext.RequestEntity == null) + if (entity.GetType() == typeof(ErrorCollection) || (_jsonApiContext.RequestEntity == null && _jsonApiContext.IsBulkOperationRequest == false)) return GetErrorJson(entity, _logger); + if (_jsonApiContext.IsBulkOperationRequest) + return _serialize(entity); + if (entity is IEnumerable) return SerializeDocuments(entity); @@ -86,4 +89,4 @@ private string _serialize(object obj) return JsonConvert.SerializeObject(obj, _jsonApiContext.Options.SerializerSettings); } } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index c16da81cfa..a73f0eb53a 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -27,6 +27,7 @@ public interface IJsonApiContext Dictionary RelationshipsToUpdate { get; set; } Type ControllerType { get; set; } Dictionary DocumentMeta { get; set; } + bool IsBulkOperationRequest { get; set; } TAttribute GetControllerAttribute() where TAttribute : Attribute; } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 66dfb46f8e..1ebf5aeea1 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -51,6 +51,7 @@ public JsonApiContext( public Dictionary RelationshipsToUpdate { get; set; } = new Dictionary(); public Type ControllerType { get; set; } public Dictionary DocumentMeta { get; set; } + public bool IsBulkOperationRequest { get; set; } public IJsonApiContext ApplyContext(object controller) { diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index eeadc38e22..13714edbf3 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -9,8 +9,8 @@ public interface IOperationProcessorResolver { IOpProcessor LocateCreateService(Operation operation); IOpProcessor LocateGetService(Operation operation); - IOpProcessor LocateReplaceService(Operation operation); IOpProcessor LocateRemoveService(Operation operation); + IOpProcessor LocateUpdateService(Operation operation); } public class OperationProcessorResolver : IOperationProcessorResolver @@ -22,8 +22,8 @@ public class OperationProcessorResolver : IOperationProcessorResolver // to reduce the cost of subsequent requests. in the future, this may be moved into setup code run at startup private ConcurrentDictionary _createOpProcessors = new ConcurrentDictionary(); private ConcurrentDictionary _getOpProcessors = new ConcurrentDictionary(); - private ConcurrentDictionary _replaceOpProcessors = new ConcurrentDictionary(); private ConcurrentDictionary _removeOpProcessors = new ConcurrentDictionary(); + private ConcurrentDictionary _updateOpProcessors = new ConcurrentDictionary(); public OperationProcessorResolver( IGenericProcessorFactory processorFactory, @@ -69,36 +69,36 @@ public IOpProcessor LocateGetService(Operation operation) return processor; } - public IOpProcessor LocateReplaceService(Operation operation) + public IOpProcessor LocateRemoveService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_replaceOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + if (_removeOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) return cachedProcessor; var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( - typeof(IReplaceOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _replaceOpProcessors[resource] = processor; + _removeOpProcessors[resource] = processor; return processor; } - public IOpProcessor LocateRemoveService(Operation operation) + public IOpProcessor LocateUpdateService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_removeOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) + if (_updateOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) return cachedProcessor; var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( - typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType + typeof(IUpdateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _removeOpProcessors[resource] = processor; + _updateOpProcessors[resource] = processor; return processor; } diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs index b687f1498f..7cb9765606 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs @@ -6,7 +6,6 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Models.Pointers; using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Services.Operations @@ -33,6 +32,7 @@ public async Task> ProcessAsync(List inputOps) { var outputOps = new List(); var opIndex = 0; + OperationCode? lastAttemptedOperation = null; // used for error messages only using (var transaction = await _dbContext.Database.BeginTransactionAsync()) { @@ -40,30 +40,29 @@ public async Task> ProcessAsync(List inputOps) { foreach (var op in inputOps) { + lastAttemptedOperation = op.Op; await ProcessOperation(op, outputOps); opIndex++; } transaction.Commit(); + return outputOps; } catch (JsonApiException e) { - outputOps = new List(); - throw new JsonApiException(e.GetStatusCode(), $"Transaction failed on operation[{opIndex}].", e); + transaction.Rollback(); + throw new JsonApiException(e.GetStatusCode(), $"Transaction failed on operation[{opIndex}] ({lastAttemptedOperation}).", e); } catch (Exception e) { - throw new JsonApiException(500, $"Transaction failed on operation[{opIndex}] for an unexpected reason.", e); + transaction.Rollback(); + throw new JsonApiException(500, $"Transaction failed on operation[{opIndex}] ({lastAttemptedOperation}) for an unexpected reason.", e); } } - - return outputOps; } private async Task ProcessOperation(Operation op, List outputOps) { - var operationsPointer = new OperationsPointer(); - ReplaceLocalIdsInResourceObject(op.DataObject, outputOps); ReplaceLocalIdsInRef(op.Ref, outputOps); @@ -88,39 +87,39 @@ private void ReplaceLocalIdsInResourceObject(ResourceObject resourceObject, List // if(HasLocalId(resourceObject)) // resourceObject.Id = GetIdFromLocalId(outputOps, resourceObject.LocalId); - if (resourceObject.Relationships != null) - { - foreach (var relationshipDictionary in resourceObject.Relationships) - { - if (relationshipDictionary.Value.IsHasMany) - { - foreach (var relationship in relationshipDictionary.Value.ManyData) - if(HasLocalId(relationship)) + if (resourceObject.Relationships != null) + { + foreach (var relationshipDictionary in resourceObject.Relationships) + { + if (relationshipDictionary.Value.IsHasMany) + { + foreach (var relationship in relationshipDictionary.Value.ManyData) + if (HasLocalId(relationship)) relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); - } + } else { var relationship = relationshipDictionary.Value.SingleData; - if(HasLocalId(relationship)) + if (HasLocalId(relationship)) relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); } - } + } } } - private void ReplaceLocalIdsInRef(ResourceReference resourceRef, List outputOps) - { + private void ReplaceLocalIdsInRef(ResourceReference resourceRef, List outputOps) + { if (resourceRef == null) return; - if(HasLocalId(resourceRef)) + if (HasLocalId(resourceRef)) resourceRef.Id = GetIdFromLocalId(outputOps, resourceRef.LocalId); } private bool HasLocalId(ResourceIdentifierObject rio) => string.IsNullOrEmpty(rio.LocalId) == false; - private string GetIdFromLocalId(List outputOps, string localId) + private string GetIdFromLocalId(List outputOps, string localId) { var referencedOp = outputOps.FirstOrDefault(o => o.DataObject.LocalId == localId); - if(referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); + if (referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); return referencedOp.DataObject.Id; } @@ -132,10 +131,10 @@ private IOpProcessor GetOperationsProcessor(Operation op) return _processorResolver.LocateCreateService(op); case OperationCode.get: return _processorResolver.LocateGetService(op); - case OperationCode.replace: - return _processorResolver.LocateReplaceService(op); case OperationCode.remove: return _processorResolver.LocateRemoveService(op); + case OperationCode.update: + return _processorResolver.LocateUpdateService(op); default: throw new JsonApiException(400, $"'{op.Op}' is not a valid operation code"); } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs index 251b81a5d6..4f50bbf4da 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs @@ -61,6 +61,10 @@ public async Task ProcessAsync(Operation operation) _contextGraph.GetContextEntity(operation.GetResourceTypeName()), result); + // we need to persist the original request localId so that subsequent operations + // can locate the result of this operation by its localId + operationResult.DataObject.LocalId = operation.DataObject.LocalId; + return operationResult; } } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs index c96af5bb37..236a76d084 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs @@ -1,4 +1,3 @@ -using System; using System.Threading.Tasks; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Internal; @@ -52,14 +51,12 @@ public async Task ProcessAsync(Operation operation) { var stringId = operation.Ref?.Id?.ToString(); if (string.IsNullOrWhiteSpace(stringId)) - throw new JsonApiException(400, "The data.id parameter is required for delete operations"); + throw new JsonApiException(400, "The ref.id parameter is required for remove operations"); var id = TypeHelper.ConvertType(stringId); var result = await _service.DeleteAsync(id); - var operationResult = new Operation { }; - - return operationResult; + return null; } } } diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs similarity index 79% rename from src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs rename to src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs index 27cf348397..b626fbe746 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/ReplaceOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs @@ -7,18 +7,18 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { - public interface IReplaceOpProcessor : IOpProcessor + public interface IUpdateOpProcessor : IOpProcessor where T : class, IIdentifiable { } - public interface IReplaceOpProcessor : IOpProcessor + public interface IUpdateOpProcessor : IOpProcessor where T : class, IIdentifiable { } - public class ReplaceOpProcessor : ReplaceOpProcessor + public class UpdateOpProcessor : UpdateOpProcessor where T : class, IIdentifiable { - public ReplaceOpProcessor( + public UpdateOpProcessor( IUpdateService service, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, @@ -27,7 +27,7 @@ IContextGraph contextGraph { } } - public class ReplaceOpProcessor : IReplaceOpProcessor + public class UpdateOpProcessor : ICreateOpProcessor where T : class, IIdentifiable { private readonly IUpdateService _service; @@ -35,7 +35,7 @@ public class ReplaceOpProcessor : IReplaceOpProcessor private readonly IDocumentBuilder _documentBuilder; private readonly IContextGraph _contextGraph; - public ReplaceOpProcessor( + public UpdateOpProcessor( IUpdateService service, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, @@ -49,17 +49,15 @@ public ReplaceOpProcessor( public async Task ProcessAsync(Operation operation) { - var model = (T)_deSerializer.DocumentToObject(operation.DataObject); - if (string.IsNullOrWhiteSpace(operation?.DataObject?.Id?.ToString())) throw new JsonApiException(400, "The data.id parameter is required for replace operations"); - var id = TypeHelper.ConvertType(operation.DataObject.Id); - var result = await _service.UpdateAsync(id, model); + var model = (T)_deSerializer.DocumentToObject(operation.DataObject); + var result = await _service.UpdateAsync(model.Id, model); var operationResult = new Operation { - Op = OperationCode.replace + Op = OperationCode.update }; operationResult.Data = _documentBuilder.GetData( diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index c5b25fa365..a8237f4ff1 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -218,7 +218,6 @@ "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApiInternals``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.SerializeAsJsonApi(Microsoft.AspNetCore.Mvc.MvcOptions,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", "JsonApiDotNetCore.Extensions.JObjectExtensions": "JsonApiDotNetCore.Extensions.JObjectExtensions.yml", - "JsonApiDotNetCore.Extensions.JObjectExtensions.TryParse``2(Newtonsoft.Json.Linq.JObject,Newtonsoft.Json.Schema.JSchema,JsonApiDotNetCore.Models.Pointers.Pointer{``1}@)": "JsonApiDotNetCore.Extensions.JObjectExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions": "JsonApiDotNetCore.Extensions.StringExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions.Dasherize(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions.ToProperCase(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", @@ -443,7 +442,7 @@ "JsonApiDotNetCore.Models.Operations.OperationCode.add": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", "JsonApiDotNetCore.Models.Operations.OperationCode.get": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", "JsonApiDotNetCore.Models.Operations.OperationCode.remove": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", - "JsonApiDotNetCore.Models.Operations.OperationCode.replace": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", + "JsonApiDotNetCore.Models.Operations.OperationCode.update": "JsonApiDotNetCore.Models.Operations.OperationCode.yml", "JsonApiDotNetCore.Models.Operations.OperationsDocument": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", "JsonApiDotNetCore.Models.Operations.OperationsDocument.#ctor": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", "JsonApiDotNetCore.Models.Operations.OperationsDocument.#ctor(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Models.Operations.OperationsDocument.yml", @@ -456,13 +455,6 @@ "JsonApiDotNetCore.Models.Operations.Params.Sort": "JsonApiDotNetCore.Models.Operations.Params.yml", "JsonApiDotNetCore.Models.Operations.ResourceReference": "JsonApiDotNetCore.Models.Operations.ResourceReference.yml", "JsonApiDotNetCore.Models.Operations.ResourceReference.Relationship": "JsonApiDotNetCore.Models.Operations.ResourceReference.yml", - "JsonApiDotNetCore.Models.Pointers": "JsonApiDotNetCore.Models.Pointers.yml", - "JsonApiDotNetCore.Models.Pointers.OperationsPointer": "JsonApiDotNetCore.Models.Pointers.OperationsPointer.yml", - "JsonApiDotNetCore.Models.Pointers.OperationsPointer.GetValue(System.Object)": "JsonApiDotNetCore.Models.Pointers.OperationsPointer.yml", - "JsonApiDotNetCore.Models.Pointers.Pointer`1": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", - "JsonApiDotNetCore.Models.Pointers.Pointer`1.GetValue(System.Object)": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", - "JsonApiDotNetCore.Models.Pointers.Pointer`1.JsonSchema": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", - "JsonApiDotNetCore.Models.Pointers.Pointer`1.PointerAddress": "JsonApiDotNetCore.Models.Pointers.Pointer-1.yml", "JsonApiDotNetCore.Models.RelationshipAttribute": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.#ctor(System.String,JsonApiDotNetCore.Models.Link)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.DocumentLinks": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", @@ -572,6 +564,7 @@ "JsonApiDotNetCore.Services.IJsonApiContext.GenericProcessorFactory": "JsonApiDotNetCore.Services.IJsonApiContext.yml", "JsonApiDotNetCore.Services.IJsonApiContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.IJsonApiContext.yml", "JsonApiDotNetCore.Services.IJsonApiContext.IncludedRelationships": "JsonApiDotNetCore.Services.IJsonApiContext.yml", + "JsonApiDotNetCore.Services.IJsonApiContext.IsBulkOperationRequest": "JsonApiDotNetCore.Services.IJsonApiContext.yml", "JsonApiDotNetCore.Services.IJsonApiContext.IsRelationshipData": "JsonApiDotNetCore.Services.IJsonApiContext.yml", "JsonApiDotNetCore.Services.IJsonApiContext.IsRelationshipPath": "JsonApiDotNetCore.Services.IJsonApiContext.yml", "JsonApiDotNetCore.Services.IJsonApiContext.MetaBuilder": "JsonApiDotNetCore.Services.IJsonApiContext.yml", @@ -610,6 +603,7 @@ "JsonApiDotNetCore.Services.JsonApiContext.GenericProcessorFactory": "JsonApiDotNetCore.Services.JsonApiContext.yml", "JsonApiDotNetCore.Services.JsonApiContext.GetControllerAttribute``1": "JsonApiDotNetCore.Services.JsonApiContext.yml", "JsonApiDotNetCore.Services.JsonApiContext.IncludedRelationships": "JsonApiDotNetCore.Services.JsonApiContext.yml", + "JsonApiDotNetCore.Services.JsonApiContext.IsBulkOperationRequest": "JsonApiDotNetCore.Services.JsonApiContext.yml", "JsonApiDotNetCore.Services.JsonApiContext.IsRelationshipData": "JsonApiDotNetCore.Services.JsonApiContext.yml", "JsonApiDotNetCore.Services.JsonApiContext.IsRelationshipPath": "JsonApiDotNetCore.Services.JsonApiContext.yml", "JsonApiDotNetCore.Services.JsonApiContext.MetaBuilder": "JsonApiDotNetCore.Services.JsonApiContext.yml", @@ -623,7 +617,7 @@ "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateCreateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateGetService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateRemoveService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", - "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateReplaceService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.LocateUpdateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.IOperationsProcessor": "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.yml", "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.ProcessAsync(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Services.Operations.IOperationsProcessor.yml", "JsonApiDotNetCore.Services.Operations.IOpProcessor": "JsonApiDotNetCore.Services.Operations.IOpProcessor.yml", @@ -633,7 +627,7 @@ "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateCreateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateGetService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateRemoveService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", - "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateReplaceService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", + "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.LocateUpdateService(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.OperationProcessorResolver.yml", "JsonApiDotNetCore.Services.Operations.OperationsProcessor": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", "JsonApiDotNetCore.Services.Operations.OperationsProcessor.#ctor(JsonApiDotNetCore.Services.Operations.IOperationProcessorResolver,JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", "JsonApiDotNetCore.Services.Operations.OperationsProcessor.ProcessAsync(System.Collections.Generic.List{JsonApiDotNetCore.Models.Operations.Operation})": "JsonApiDotNetCore.Services.Operations.OperationsProcessor.yml", @@ -654,18 +648,18 @@ "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IGetOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor-1.yml", "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IRemoveOpProcessor-2.yml", - "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor-1.yml", - "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IUpdateOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.IUpdateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.IUpdateOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.IUpdateOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-1.yml", "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IDeleteService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-1.yml", "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IDeleteService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.RemoveOpProcessor-2.yml", - "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-1.yml", - "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-1.yml", - "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", - "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", - "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.ReplaceOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IUpdateService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.UpdateOpProcessor-2.yml", "JsonApiDotNetCore.Services.QueryAccessor": "JsonApiDotNetCore.Services.QueryAccessor.yml", "JsonApiDotNetCore.Services.QueryAccessor.#ctor(JsonApiDotNetCore.Services.IJsonApiContext,Microsoft.Extensions.Logging.ILogger{JsonApiDotNetCore.Services.QueryAccessor})": "JsonApiDotNetCore.Services.QueryAccessor.yml", "JsonApiDotNetCore.Services.QueryAccessor.GetRequired``1(System.String)": "JsonApiDotNetCore.Services.QueryAccessor.yml", diff --git a/test/OperationsExampleTests/Replace/ReplaceTests.cs b/test/OperationsExampleTests/Update/UpdateTests.cs similarity index 93% rename from test/OperationsExampleTests/Replace/ReplaceTests.cs rename to test/OperationsExampleTests/Update/UpdateTests.cs index 521dcd979b..de05881963 100644 --- a/test/OperationsExampleTests/Replace/ReplaceTests.cs +++ b/test/OperationsExampleTests/Update/UpdateTests.cs @@ -1,112 +1,112 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using OperationsExample.Data; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - [Collection("WebHostCollection")] - public class ReplaceTests - { - private readonly Fixture _fixture; - private readonly Faker _faker = new Faker(); - - public ReplaceTests(Fixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Update_Article() - { - // arrange - var context = _fixture.GetService(); - var article = ArticleFactory.Get(); - var updates = ArticleFactory.Get(); - context.Articles.Add(article); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new { - op = "replace", - data = new { - type = "articles", - id = article.Id, - attributes = new { - name = updates.Name - } - } - }, - } - }; - - // act - var result = await _fixture.PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(1, result.data.Operations.Count); - - var attrs = result.data.Operations.Single().DataObject.Attributes; - Assert.Equal(updates.Name, attrs["name"]); - } - - [Fact] - public async Task Can_Update_Articles() - { - // arrange - var count = _faker.Random.Int(1, 10); - var context = _fixture.GetService(); - - var articles = ArticleFactory.Get(count); - var updates = ArticleFactory.Get(count); - - context.Articles.AddRange(articles); - context.SaveChanges(); - - var content = new - { - operations = new List() - }; - - for (int i = 0; i < count; i++) - content.operations.Add(new - { - op = "replace", - data = new - { - type = "articles", - id = articles[i].Id, - attributes = new - { - name = updates[i].Name - } - } - }); - - // act - var result = await _fixture.PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(count, result.data.Operations.Count); - - for (int i = 0; i < count; i++) - { - var attrs = result.data.Operations[i].DataObject.Attributes; - Assert.Equal(updates[i].Name, attrs["name"]); - } - } - } -} +using Bogus; +using JsonApiDotNetCore.Models.Operations; +using OperationsExample.Data; +using OperationsExampleTests.Factories; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace OperationsExampleTests.Update +{ + [Collection("WebHostCollection")] + public class UpdateTests + { + private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); + + public UpdateTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Can_Update_Article() + { + // arrange + var context = _fixture.GetService(); + var article = ArticleFactory.Get(); + var updates = ArticleFactory.Get(); + context.Articles.Add(article); + context.SaveChanges(); + + var content = new + { + operations = new[] { + new { + op = "replace", + data = new { + type = "articles", + id = article.Id, + attributes = new { + name = updates.Name + } + } + }, + } + }; + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + + var attrs = result.data.Operations.Single().DataObject.Attributes; + Assert.Equal(updates.Name, attrs["name"]); + } + + [Fact] + public async Task Can_Update_Articles() + { + // arrange + var count = _faker.Random.Int(1, 10); + var context = _fixture.GetService(); + + var articles = ArticleFactory.Get(count); + var updates = ArticleFactory.Get(count); + + context.Articles.AddRange(articles); + context.SaveChanges(); + + var content = new + { + operations = new List() + }; + + for (int i = 0; i < count; i++) + content.operations.Add(new + { + op = "replace", + data = new + { + type = "articles", + id = articles[i].Id, + attributes = new + { + name = updates[i].Name + } + } + }); + + // act + var result = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(count, result.data.Operations.Count); + + for (int i = 0; i < count; i++) + { + var attrs = result.data.Operations[i].DataObject.Attributes; + Assert.Equal(updates[i].Name, attrs["name"]); + } + } + } +} diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index 0a7fd501ae..5b98927119 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using JsonApiDotNetCore.Data; @@ -169,7 +169,7 @@ public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_References() var updateOpProcessorMock = new Mock(); updateOpProcessorMock.Setup(m => m.ProcessAsync(It.Is(op => op.DataObject.Type.ToString() == "authors"))) .ReturnsAsync((Operation)null); - _resolverMock.Setup(m => m.LocateReplaceService(It.IsAny())) + _resolverMock.Setup(m => m.LocateUpdateService(It.IsAny())) .Returns(updateOpProcessorMock.Object); _dbContextResolverMock.Setup(m => m.GetContext()).Returns(_dbContextMock.Object); From aea5385b277c71ec1680dc120fd6de189a855732 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 25 Mar 2018 14:16:57 -0500 Subject: [PATCH 102/227] add tests for bulk operations --- Build.ps1 | 5 +- JsonApiDotnetCore.sln | 4 + build.sh | 3 +- .../JsonApiOperationsController.cs | 38 ++++++- test/OperationsExampleTests/Add/AddTests.cs | 106 ++++++++++++++---- .../Factories/AuthorFactory.cs | 25 +++++ 6 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 test/OperationsExampleTests/Factories/AuthorFactory.cs diff --git a/Build.ps1 b/Build.ps1 index e51473adf2..bfbd989415 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -32,6 +32,9 @@ CheckLastExitCode dotnet test ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj CheckLastExitCode +dotnet test ./test/OperationsExampleTests/OperationsExampleTests.csproj +CheckLastExitCode + dotnet build .\src\JsonApiDotNetCore -c Release CheckLastExitCode @@ -57,4 +60,4 @@ Else { Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision" dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision CheckLastExitCode -} \ No newline at end of file +} diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index ac45f83cdf..4b7cf5ea47 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -15,6 +15,10 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore + .travis.yml = .travis.yml + appveyor.yml = appveyor.yml + Build.ps1 = Build.ps1 + build.sh = build.sh Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection diff --git a/build.sh b/build.sh index 441470e65d..50f2ab9c99 100755 --- a/build.sh +++ b/build.sh @@ -7,4 +7,5 @@ dotnet restore dotnet test ./test/UnitTests/UnitTests.csproj dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj -dotnet test ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj \ No newline at end of file +dotnet test ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +dotnet test ./test/OperationsExampleTests/OperationsExampleTests.csproj diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index 69f4be8a89..c3b667bc7d 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -5,18 +5,50 @@ namespace JsonApiDotNetCore.Controllers { + /// + /// A controller to be used for bulk operations as defined in the json:api 1.1 specification + /// public class JsonApiOperationsController : Controller { private readonly IOperationsProcessor _operationsProcessor; - public JsonApiOperationsController( - IOperationsProcessor operationsProcessor) + /// + /// The processor to handle bulk operations. + /// + public JsonApiOperationsController(IOperationsProcessor operationsProcessor) { _operationsProcessor = operationsProcessor; } + /// + /// Bulk endpoint for json:api operations + /// + /// + /// A json:api operations request document + /// + /// + /// + /// PATCH /api/bulk HTTP/1.1 + /// Content-Type: application/vnd.api+json + /// + /// { + /// "operations": [{ + /// "op": "add", + /// "ref": { + /// "type": "authors" + /// }, + /// "data": { + /// "type": "authors", + /// "attributes": { + /// "name": "jaredcnance" + /// } + /// } + /// }] + /// } + /// + /// [HttpPatch] - public async Task PatchAsync([FromBody] OperationsDocument doc) + public virtual async Task PatchAsync([FromBody] OperationsDocument doc) { if (doc == null) return new StatusCodeResult(422); diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs index 2d765e1633..656cb134b5 100644 --- a/test/OperationsExampleTests/Add/AddTests.cs +++ b/test/OperationsExampleTests/Add/AddTests.cs @@ -3,7 +3,6 @@ using System.Net; using System.Threading.Tasks; using Bogus; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Models.Operations; using Microsoft.EntityFrameworkCore; using OperationsExample.Data; @@ -24,20 +23,20 @@ public AddTests(Fixture fixture) } [Fact] - public async Task Can_Create_Article() + public async Task Can_Create_Author() { // arrange var context = _fixture.GetService(); - var article = ArticleFactory.Get(); + var author = AuthorFactory.Get(); var content = new { operations = new[] { new { op = "add", data = new { - type = "articles", + type = "authors", attributes = new { - name = article.Name + name = author.Name } } } @@ -48,21 +47,21 @@ public async Task Can_Create_Article() var result = await _fixture.PatchAsync("api/bulk", content); // assert - Assert.NotNull(result); + Assert.NotNull(result.response); Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - var id = (string)result.data.Operations.Single().DataObject.Id; - var lastArticle = await context.Articles.SingleAsync(a => a.StringId == id); - Assert.Equal(article.Name, lastArticle.Name); + var id = result.data.Operations.Single().DataObject.Id; + var lastAuthor = await context.Authors.SingleAsync(a => a.StringId == id); + Assert.Equal(author.Name, lastAuthor.Name); } [Fact] - public async Task Can_Create_Articles() + public async Task Can_Create_Authors() { // arrange var expectedCount = _faker.Random.Int(1, 10); var context = _fixture.GetService(); - var articles = ArticleFactory.Get(expectedCount); + var authors = AuthorFactory.Get(expectedCount); var content = new { operations = new List() @@ -76,10 +75,10 @@ public async Task Can_Create_Articles() op = "add", data = new { - type = "articles", + type = "authors", attributes = new { - name = articles[i].Name + name = authors[i].Name } } } @@ -87,19 +86,86 @@ public async Task Can_Create_Articles() } // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await _fixture.PatchAsync("api/bulk", content); // assert - Assert.NotNull(result); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(expectedCount, result.data.Operations.Count); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(expectedCount, data.Operations.Count); for (int i = 0; i < expectedCount; i++) { - var data = result.data.Operations[i].DataObject; - var article = context.Articles.Single(a => a.StringId == data.Id.ToString()); - Assert.Equal(articles[i].Name, article.Name); + var dataObject = data.Operations[i].DataObject; + var author = context.Authors.Single(a => a.StringId == dataObject.ToString()); + Assert.Equal(authors[i].Name, author.Name); } + } + + [Fact] + public async Task Can_Create_Author_With_Article() + { + // arrange + var context = _fixture.GetService(); + var author = AuthorFactory.Get(); + var article = ArticleFactory.Get(); + const string authorLocalId = "author-1"; + + var content = new + { + operations = new object[] { + new { + op = "add", + data = new { + lid = authorLocalId, + type = "authors", + attributes = new { + name = author.Name + }, + } + }, + new { + op = "add", + data = new { + type = "articles", + attributes = new { + name = article.Name + }, + relationships = new { + author = new { + data = new { + type = "authors", + lid = authorLocalId + } + } + } + } + } + } + }; + + // act + var (response, data) = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(2, data.Operations.Count); + + var authorOperationResult = data.Operations[0]; + var id = authorOperationResult.DataObject.Id; + var lastAuthor = await context.Authors + .Include(a => a.Articles) + .SingleAsync(a => a.StringId == id); + var articleOperationResult = data.Operations[1]; + + // author validation + Assert.Equal(authorLocalId, authorOperationResult.DataObject.LocalId); + Assert.Equal(author.Name, lastAuthor.Name); + + // article validation + Assert.Equal(1, lastAuthor.Articles.Count); + Assert.Equal(article.Name, lastAuthor.Articles[0].Name); + Assert.Equal(articleOperationResult.DataObject.Id, lastAuthor.Articles[0].StringId); } } } diff --git a/test/OperationsExampleTests/Factories/AuthorFactory.cs b/test/OperationsExampleTests/Factories/AuthorFactory.cs new file mode 100644 index 0000000000..2afe914b54 --- /dev/null +++ b/test/OperationsExampleTests/Factories/AuthorFactory.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Bogus; +using OperationsExample.Models; + +namespace OperationsExampleTests.Factories +{ + public static class AuthorFactory + { + public static Author Get() + { + var faker = new Faker(); + faker.RuleFor(m => m.Name, f => f.Person.UserName); + return faker.Generate(); + } + + public static List Get(int count) + { + var authors = new List(); + for (int i = 0; i < count; i++) + authors.Add(Get()); + + return authors; + } + } +} From a86963672ce79b8466339d8b0ed51a9af2301752 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 25 Mar 2018 15:25:09 -0500 Subject: [PATCH 103/227] test transaction rollbacks --- src/Examples/OperationsExample/Startup.cs | 3 +- .../Generics/GenericProcessorFactory.cs | 5 +- src/JsonApiDotNetCore/api/.manifest | 2 +- .../Transactions/TransactionFailureTests.cs | 89 +++++++++++++++++++ 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 test/OperationsExampleTests/Transactions/TransactionFailureTests.cs diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs index 7e4444dfb5..6e13b2964d 100644 --- a/src/Examples/OperationsExample/Startup.cs +++ b/src/Examples/OperationsExample/Startup.cs @@ -1,6 +1,5 @@ -using System; +using System; using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 3f88010e0a..585cebd715 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Http; using System; namespace JsonApiDotNetCore.Internal.Generics @@ -30,9 +31,9 @@ public class GenericProcessorFactory : IGenericProcessorFactory { private readonly IServiceProvider _serviceProvider; - public GenericProcessorFactory(IServiceProvider serviceProvider) + public GenericProcessorFactory(IHttpContextAccessor httpContextAccessor) { - _serviceProvider = serviceProvider; + _serviceProvider = httpContextAccessor.HttpContext.RequestServices; } public TInterface GetProcessor(Type openGenericType, Type resourceType) diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index a8237f4ff1..632c57f5eb 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -283,7 +283,7 @@ "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.SetRelationships(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", - "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.#ctor(System.IServiceProvider)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.#ctor(Microsoft.AspNetCore.Http.IHttpContextAccessor)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.IGenericProcessor": "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.yml", diff --git a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs new file mode 100644 index 0000000000..53b1e37b5a --- /dev/null +++ b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Bogus; +using JsonApiDotNetCore.Internal; +using Microsoft.EntityFrameworkCore; +using OperationsExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + [Collection("WebHostCollection")] + public class TransactionFailureTests + { + private readonly Fixture _fixture; + private readonly Faker _faker = new Faker(); + + public TransactionFailureTests(Fixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task Cannot_Create_Author_If_Article_Creation_Fails() + { + // arrange + var context = _fixture.GetService(); + var author = AuthorFactory.Get(); + var article = ArticleFactory.Get(); + + // do this so that the name is random enough for db validations + author.Name = Guid.NewGuid().ToString("N"); + article.Name = Guid.NewGuid().ToString("N"); + + var content = new + { + operations = new object[] { + new { + op = "add", + data = new { + type = "authors", + attributes = new { + name = author.Name + }, + } + }, + new { + op = "add", + data = new { + type = "articles", + attributes = new { + name = article.Name + }, + // by not including the author, the article creation will fail + // relationships = new { + // author = new { + // data = new { + // type = "authors", + // lid = authorLocalId + // } + // } + // } + } + } + } + }; + + // act + var (response, data) = await _fixture.PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + // for now, it is up to application implementations to perform validation and + // provide the proper HTTP response code + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.Equal(1, data.Errors.Count); + Assert.Contains("operation[1] (add)", data.Errors[0].Title); + + var dbAuthors = await context.Authors.Where(a => a.Name == author.Name).ToListAsync(); + var dbArticles = await context.Articles.Where(a => a.Name == article.Name).ToListAsync(); + Assert.Empty(dbAuthors); + Assert.Empty(dbArticles); + } + } +} From a20bd53784a099a683da78d93f200128414c7cb9 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 25 Mar 2018 20:32:35 -0500 Subject: [PATCH 104/227] fix(transactions): locate services using request scoped service provider --- .../Internal/Generics/GenericProcessorFactory.cs | 4 ++++ test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 585cebd715..27d15b163d 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -14,7 +14,9 @@ public interface IGenericProcessorFactory /// Constructs the generic type and locates the service, then casts to TInterface /// /// + /// /// GetProcessor<IGenericProcessor>(typeof(GenericProcessor<>), typeof(TResource)); + /// /// TInterface GetProcessor(Type openGenericType, Type resourceType); @@ -22,7 +24,9 @@ public interface IGenericProcessorFactory /// Constructs the generic type and locates the service, then casts to TInterface /// /// + /// /// GetProcessor<IGenericProcessor>(typeof(GenericProcessor<,>), typeof(TResource), typeof(TId)); + /// /// TInterface GetProcessor(Type openGenericType, Type resourceType, Type keyType); } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs index d7ec6868b9..ce70fced84 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using JsonApiDotNetCore.Services; +using JsonApiDotNetCore.Data; namespace JsonApiDotNetCoreExampleTests.Acceptance { @@ -22,7 +23,7 @@ public TestFixture() _services = _server.Host.Services; Client = _server.CreateClient(); - Context = GetService(); + Context = GetService().GetContext() as AppDbContext; DeSerializer = GetService(); JsonApiContext = GetService(); } From 1bc89eaa1edb3a9cfa6f78d2e909dfd5934c5f55 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 25 Mar 2018 20:36:05 -0500 Subject: [PATCH 105/227] fix(operations test): use update vs replace --- test/UnitTests/Services/Operations/OperationsProcessorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs index 5b98927119..9635c6f6f3 100644 --- a/test/UnitTests/Services/Operations/OperationsProcessorTests.cs +++ b/test/UnitTests/Services/Operations/OperationsProcessorTests.cs @@ -121,7 +121,7 @@ public async Task ProcessAsync_Performs_LocalId_ReplacementAsync_In_References() } } }, { - ""op"": ""replace"", + ""op"": ""update"", ""ref"": { ""type"": ""authors"", ""lid"": ""a"" From 9215ccd7e193e3a95c8197e7ba50c97be8603533 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 27 Mar 2018 06:46:13 -0500 Subject: [PATCH 106/227] introduce ScopedServiceProvider and fix tests --- README.md | 1 - .../NoEntityFrameworkExample/Startup.cs | 5 +- src/Examples/OperationsExample/Startup.cs | 5 +- src/Examples/ReportsExample/Startup.cs | 10 +- .../Configuration/JsonApiOptions.cs | 8 +- .../Extensions/DbContextExtensions.cs | 1 - .../IServiceCollectionExtensions.cs | 4 +- .../Generics/GenericProcessorFactory.cs | 5 +- .../Services/ScopedServiceProvider.cs | 28 ++++++ src/JsonApiDotNetCore/api/.manifest | 8 +- .../CamelCasedModelsControllerTests.cs | 14 +-- .../Extensibility/CustomControllerTests.cs | 4 +- .../NullValuedAttributeHandlingTests.cs | 4 +- .../Extensibility/RepositoryOverrideTests.cs | 4 +- .../Extensibility/RequestMetaTests.cs | 4 +- .../Acceptance/Spec/AttributeFilterTests.cs | 9 +- .../Acceptance/Spec/AttributeSortTests.cs | 4 +- .../Acceptance/Spec/ContentNegotiation.cs | 4 +- .../Acceptance/Spec/CreatingDataTests.cs | 4 +- .../Acceptance/Spec/DeletingDataTests.cs | 8 +- .../Acceptance/Spec/DocumentTests/Included.cs | 4 +- .../Acceptance/Spec/DocumentTests/Meta.cs | 4 +- .../Spec/DocumentTests/PagingTests.cs | 4 +- .../Spec/DocumentTests/Relationships.cs | 4 +- .../Acceptance/Spec/FetchingDataTests.cs | 4 +- .../Spec/FetchingRelationshipsTests.cs | 4 +- .../Acceptance/Spec/PagingTests.cs | 15 ++- .../Acceptance/Spec/QueryParameters.cs | 4 +- .../Acceptance/Spec/SparseFieldSetTests.cs | 4 +- .../Acceptance/Spec/UpdatingDataTests.cs | 4 +- .../Spec/UpdatingRelationshipsTests.cs | 4 +- .../Acceptance/TodoItemsControllerTests.cs | 12 +-- .../Helpers/Startups/AuthorizedStartup.cs | 8 +- .../JsonApiDotNetCoreExampleTests.csproj | 1 + .../TestStartup.cs | 22 +++++ .../IServiceCollectionExtensionsTests.cs | 7 +- .../WebHostCollection.cs | 2 +- .../Extensibility/NoEntityFrameworkTests.cs | 5 +- .../NoEntityFrameworkTests.csproj | 1 + test/NoEntityFrameworkTests/TestStartup.cs | 22 +++++ test/OperationsExampleTests/Add/AddTests.cs | 29 +++--- .../{WebHostCollection.cs => Fixture.cs} | 27 ++++-- test/OperationsExampleTests/Get/GetTests.cs | 41 ++++----- .../OperationsExampleTests.csproj | 1 + .../Remove/RemoveTests.cs | 55 +++++------ test/OperationsExampleTests/TestStartup.cs | 25 +++++ .../Transactions/TransactionFailureTests.cs | 15 +-- .../Update/UpdateTests.cs | 92 +++++++++---------- test/UnitTests/TestScopedServiceProvider.cs | 28 ++++++ 49 files changed, 354 insertions(+), 228 deletions(-) create mode 100644 src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs create mode 100644 test/JsonApiDotNetCoreExampleTests/TestStartup.cs create mode 100644 test/NoEntityFrameworkTests/TestStartup.cs rename test/OperationsExampleTests/{WebHostCollection.cs => Fixture.cs} (64%) create mode 100644 test/OperationsExampleTests/TestStartup.cs create mode 100644 test/UnitTests/TestScopedServiceProvider.cs diff --git a/README.md b/README.md index 1acbbbf799..f396be824b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ [![Build status](https://ci.appveyor.com/api/projects/status/9fvgeoxdikwkom10?svg=true)](https://ci.appveyor.com/project/jaredcnance/jsonapidotnetcore) [![Travis](https://travis-ci.org/json-api-dotnet/JsonApiDotNetCore.svg?branch=master)](https://travis-ci.org/json-api-dotnet/JsonApiDotNetCore) [![NuGet](https://img.shields.io/nuget/v/JsonApiDotNetCore.svg)](https://www.nuget.org/packages/JsonApiDotNetCore/) -[![MyGet CI](https://img.shields.io/myget/research-institute/vpre/JsonApiDotNetCore.svg)](https://www.myget.org/feed/research-institute/package/nuget/JsonApiDotNetCore) [![Join the chat at https://gitter.im/json-api-dotnet-core/Lobby](https://badges.gitter.im/json-api-dotnet-core/Lobby.svg)](https://gitter.im/json-api-dotnet-core/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![FIRST-TIMERS](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](http://www.firsttimersonly.com/) diff --git a/src/Examples/NoEntityFrameworkExample/Startup.cs b/src/Examples/NoEntityFrameworkExample/Startup.cs index 81f743aa5f..dfba27ddd9 100755 --- a/src/Examples/NoEntityFrameworkExample/Startup.cs +++ b/src/Examples/NoEntityFrameworkExample/Startup.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using NoEntityFrameworkExample.Services; using Microsoft.EntityFrameworkCore; +using System; namespace NoEntityFrameworkExample { @@ -27,7 +28,7 @@ public Startup(IHostingEnvironment env) public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) + public virtual IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. var mvcBuilder = services.AddMvc(); @@ -46,6 +47,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(Configuration); services.AddSingleton>(optionsBuilder.Options); services.AddScoped(); + + return services.BuildServiceProvider(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs index 6e13b2964d..78a6d29f69 100644 --- a/src/Examples/OperationsExample/Startup.cs +++ b/src/Examples/OperationsExample/Startup.cs @@ -32,10 +32,7 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services) services.AddSingleton(loggerFactory); - services.AddDbContext(options => - { - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); + services.AddDbContext(options => options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Scoped); services.AddJsonApi(opt => opt.EnableOperations = true); diff --git a/src/Examples/ReportsExample/Startup.cs b/src/Examples/ReportsExample/Startup.cs index fed3707789..72710681b9 100644 --- a/src/Examples/ReportsExample/Startup.cs +++ b/src/Examples/ReportsExample/Startup.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Builder; @@ -9,7 +5,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace ReportsExample { @@ -28,12 +23,13 @@ public Startup(IHostingEnvironment env) Config = builder.Build(); } - public void ConfigureServices(IServiceCollection services) + public virtual void ConfigureServices(IServiceCollection services) { var mvcBuilder = services.AddMvc(); services.AddJsonApi(opt => { - opt.BuildContextGraph(builder => { + opt.BuildContextGraph(builder => + { builder.AddResource("reports"); }); opt.Namespace = "api"; diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index ea8d0554e3..abcb3f6dbf 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -105,9 +105,13 @@ public class JsonApiOptions public NullAttributeResponseBehavior NullAttributeResponseBehavior { get; set; } /// - /// Whether or not to allow json:api v1.1 operation requests - /// This will be enabled by default in JsonApiDotNetCore v2.2.1 + /// Whether or not to allow json:api v1.1 operation requests. + /// This is a beta feature and there may be breaking changes + /// in subsequent releases. /// + /// + /// This will be enabled by default in JsonApiDotNetCore v2.2.1 + /// public bool EnableOperations { get; set; } [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] diff --git a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs index e8b4e3d601..2606342e29 100644 --- a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using System.Reflection; using System; namespace JsonApiDotNetCore.Extensions diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 604d65536b..0b13755edc 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -6,7 +6,6 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Middleware; -using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCore.Services.Operations; @@ -89,7 +88,7 @@ public static void AddJsonApiInternals( this IServiceCollection services, JsonApiOptions jsonApiOptions) { - if (!jsonApiOptions.ContextGraph.UsesDbContext) + if (jsonApiOptions.ContextGraph.UsesDbContext == false) { services.AddScoped(); services.AddSingleton(new DbContextOptionsBuilder().Options); @@ -122,6 +121,7 @@ public static void AddJsonApiInternals( services.AddSingleton(jsonApiOptions.ContextGraph); services.AddScoped(); services.AddSingleton(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs index 27d15b163d..08cba58dd1 100644 --- a/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs +++ b/src/JsonApiDotNetCore/Internal/Generics/GenericProcessorFactory.cs @@ -1,3 +1,4 @@ +using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; using System; @@ -35,9 +36,9 @@ public class GenericProcessorFactory : IGenericProcessorFactory { private readonly IServiceProvider _serviceProvider; - public GenericProcessorFactory(IHttpContextAccessor httpContextAccessor) + public GenericProcessorFactory(IScopedServiceProvider serviceProvider) { - _serviceProvider = httpContextAccessor.HttpContext.RequestServices; + _serviceProvider = serviceProvider; } public TInterface GetProcessor(Type openGenericType, Type resourceType) diff --git a/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs b/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs new file mode 100644 index 0000000000..38e147645f --- /dev/null +++ b/src/JsonApiDotNetCore/Services/ScopedServiceProvider.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Http; +using System; + +namespace JsonApiDotNetCore.Services +{ + /// + /// An interface used to separate the registration of the global ServiceProvider + /// from a request scoped service provider. This is useful in cases when we need to + /// manually resolve services from the request scope (e.g. operation processors) + /// + public interface IScopedServiceProvider : IServiceProvider { } + + /// + /// A service provider that uses the current HttpContext request scope + /// + public class RequestScopedServiceProvider : IScopedServiceProvider + { + private readonly IServiceProvider _serviceProvider; + + public RequestScopedServiceProvider(IHttpContextAccessor httpContextAccessor) + { + _serviceProvider = httpContextAccessor.HttpContext.RequestServices; + } + + /// + public object GetService(Type serviceType) => _serviceProvider.GetService(serviceType); + } +} diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index 632c57f5eb..6aa4a40924 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -283,7 +283,7 @@ "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.SetRelationships(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessor`2.UpdateRelationshipsAsync(System.Object,JsonApiDotNetCore.Models.RelationshipAttribute,System.Collections.Generic.IEnumerable{System.String})": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-2.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", - "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.#ctor(Microsoft.AspNetCore.Http.IHttpContextAccessor)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", + "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.#ctor(JsonApiDotNetCore.Services.IScopedServiceProvider)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.GetProcessor``1(System.Type,System.Type,System.Type)": "JsonApiDotNetCore.Internal.Generics.GenericProcessorFactory.yml", "JsonApiDotNetCore.Internal.Generics.IGenericProcessor": "JsonApiDotNetCore.Internal.Generics.IGenericProcessor.yml", @@ -586,6 +586,7 @@ "JsonApiDotNetCore.Services.IResourceQueryService`2": "JsonApiDotNetCore.Services.IResourceQueryService-2.yml", "JsonApiDotNetCore.Services.IResourceService`1": "JsonApiDotNetCore.Services.IResourceService-1.yml", "JsonApiDotNetCore.Services.IResourceService`2": "JsonApiDotNetCore.Services.IResourceService-2.yml", + "JsonApiDotNetCore.Services.IScopedServiceProvider": "JsonApiDotNetCore.Services.IScopedServiceProvider.yml", "JsonApiDotNetCore.Services.IUpdateRelationshipService`1": "JsonApiDotNetCore.Services.IUpdateRelationshipService-1.yml", "JsonApiDotNetCore.Services.IUpdateRelationshipService`2": "JsonApiDotNetCore.Services.IUpdateRelationshipService-2.yml", "JsonApiDotNetCore.Services.IUpdateRelationshipService`2.UpdateRelationshipsAsync(`1,System.String,System.Collections.Generic.List{JsonApiDotNetCore.Models.DocumentData})": "JsonApiDotNetCore.Services.IUpdateRelationshipService-2.yml", @@ -673,5 +674,8 @@ "JsonApiDotNetCore.Services.QueryParser.ParseFilterQuery(System.String,System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", "JsonApiDotNetCore.Services.QueryParser.ParseIncludedRelationships(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", "JsonApiDotNetCore.Services.QueryParser.ParsePageQuery(JsonApiDotNetCore.Internal.Query.PageQuery,System.String,System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", - "JsonApiDotNetCore.Services.QueryParser.ParseSortParameters(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml" + "JsonApiDotNetCore.Services.QueryParser.ParseSortParameters(System.String)": "JsonApiDotNetCore.Services.QueryParser.yml", + "JsonApiDotNetCore.Services.RequestScopedServiceProvider": "JsonApiDotNetCore.Services.RequestScopedServiceProvider.yml", + "JsonApiDotNetCore.Services.RequestScopedServiceProvider.#ctor(Microsoft.AspNetCore.Http.IHttpContextAccessor)": "JsonApiDotNetCore.Services.RequestScopedServiceProvider.yml", + "JsonApiDotNetCore.Services.RequestScopedServiceProvider.GetService(System.Type)": "JsonApiDotNetCore.Services.RequestScopedServiceProvider.yml" } \ No newline at end of file diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs index b76293adba..533c59839a 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -19,12 +19,12 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance [Collection("WebHostCollection")] public class CamelCasedModelsControllerTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private IJsonApiContext _jsonApiContext; private Faker _faker; - public CamelCasedModelsControllerTests(TestFixture fixture) + public CamelCasedModelsControllerTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); @@ -58,7 +58,7 @@ public async Task Can_Get_CamelCasedModels() // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotEmpty(deserializedBody); - Assert.True(deserializedBody.Count > 0); + Assert.True(deserializedBody.Count > 0); } [Fact] @@ -114,7 +114,7 @@ public async Task Can_Post_CamelCasedModels() var request = new HttpRequestMessage(httpMethod, route); request.Content = new StringContent(JsonConvert.SerializeObject(content)); request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - + // Act var response = await client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); @@ -158,7 +158,7 @@ public async Task Can_Patch_CamelCasedModels() var request = new HttpRequestMessage(httpMethod, route); request.Content = new StringContent(JsonConvert.SerializeObject(content)); request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - + // Act var response = await client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); @@ -173,4 +173,4 @@ public async Task Can_Patch_CamelCasedModels() Assert.Equal(newModel.CompoundAttr, deserializedBody.CompoundAttr); } } -} \ No newline at end of file +} diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs index 9b28ee48de..478f40f14f 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs @@ -17,11 +17,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility [Collection("WebHostCollection")] public class CustomControllerTests { - private TestFixture _fixture; + private TestFixture _fixture; private Faker _todoItemFaker; private Faker _personFaker; - public CustomControllerTests(TestFixture fixture) + public CustomControllerTests(TestFixture fixture) { _fixture = fixture; _todoItemFaker = new Faker() diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs index 250ab80d30..7942ffd919 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs @@ -14,11 +14,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility [Collection("WebHostCollection")] public class NullValuedAttributeHandlingTests : IAsyncLifetime { - private readonly TestFixture _fixture; + private readonly TestFixture _fixture; private readonly AppDbContext _dbContext; private readonly TodoItem _todoItem; - public NullValuedAttributeHandlingTests(TestFixture fixture) + public NullValuedAttributeHandlingTests(TestFixture fixture) { _fixture = fixture; _dbContext = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs index 2813151ad3..09a2791048 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RepositoryOverrideTests.cs @@ -17,9 +17,9 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility [Collection("WebHostCollection")] public class RepositoryOverrideTests { - private TestFixture _fixture; + private TestFixture _fixture; - public RepositoryOverrideTests(TestFixture fixture) + public RepositoryOverrideTests(TestFixture fixture) { _fixture = fixture; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs index 9420ea6891..2397bb5529 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs @@ -16,9 +16,9 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility [Collection("WebHostCollection")] public class RequestMetaTests { - private TestFixture _fixture; + private TestFixture _fixture; - public RequestMetaTests(TestFixture fixture) + public RequestMetaTests(TestFixture fixture) { _fixture = fixture; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index dd7c673b4c..083b2c22d7 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Net; using System.Net.Http; @@ -6,7 +6,6 @@ using Bogus; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Newtonsoft.Json; @@ -18,11 +17,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class AttributeFilterTests { - private TestFixture _fixture; + private TestFixture _fixture; private Faker _todoItemFaker; private readonly Faker _personFaker; - public AttributeFilterTests(TestFixture fixture) + public AttributeFilterTests(TestFixture fixture) { _fixture = fixture; _todoItemFaker = new Faker() @@ -88,7 +87,7 @@ public async Task Can_Filter_On_Related_Attrs() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(included); Assert.NotEmpty(included); - foreach(var item in included) + foreach (var item in included) Assert.Equal(person.FirstName, item.Attributes["first-name"]); } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs index 8525f251d1..6de3293596 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeSortTests.cs @@ -9,9 +9,9 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class AttributeSortTests { - private TestFixture _fixture; + private TestFixture _fixture; - public AttributeSortTests(TestFixture fixture) + public AttributeSortTests(TestFixture fixture) { _fixture = fixture; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiation.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiation.cs index 8f76735ee9..76f5fa4aa7 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiation.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ContentNegotiation.cs @@ -12,8 +12,8 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class ContentNegotiation { - private TestFixture _fixture; - public ContentNegotiation(TestFixture fixture) + private TestFixture _fixture; + public ContentNegotiation(TestFixture fixture) { _fixture = fixture; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs index 2f461c4f74..2c71275473 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs @@ -23,11 +23,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class CreatingDataTests { - private TestFixture _fixture; + private TestFixture _fixture; private IJsonApiContext _jsonApiContext; private Faker _todoItemFaker; - public CreatingDataTests(TestFixture fixture) + public CreatingDataTests(TestFixture fixture) { _fixture = fixture; _jsonApiContext = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs index 8ddb9a56a1..8c506f4a33 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -15,11 +15,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class DeletingDataTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Faker _todoItemFaker; - public DeletingDataTests(TestFixture fixture) + public DeletingDataTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); @@ -40,7 +40,7 @@ public async Task Respond_404_If_EntityDoesNotExist() var server = new TestServer(builder); var client = server.CreateClient(); - + var httpMethod = new HttpMethod("DELETE"); var route = $"/api/v1/todo-items/{maxPersonId + 100}"; var request = new HttpRequestMessage(httpMethod, route); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs index 5d4a4aa4e2..a9aa9c4e67 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs @@ -19,13 +19,13 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests [Collection("WebHostCollection")] public class Included { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Bogus.Faker _personFaker; private Faker _todoItemFaker; private Faker _todoItemCollectionFaker; - public Included(TestFixture fixture) + public Included(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs index 5316753245..bb055e9935 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs @@ -17,9 +17,9 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests [Collection("WebHostCollection")] public class Meta { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; - public Meta(TestFixture fixture) + public Meta(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs index 0aa4ede88b..787c9f07a0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs @@ -18,13 +18,13 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests [Collection("WebHostCollection")] public class PagingTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Faker _personFaker; private Faker _todoItemFaker; private Faker _todoItemCollectionFaker; - public PagingTests(TestFixture fixture) + public PagingTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs index 5c0018354d..6c4bf56839 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs @@ -17,11 +17,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests [Collection("WebHostCollection")] public class Relationships { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Faker _todoItemFaker; - public Relationships(TestFixture fixture) + public Relationships(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs index 208ec2f72d..8573d0b560 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs @@ -20,12 +20,12 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class FetchingDataTests { - private TestFixture _fixture; + private TestFixture _fixture; private IJsonApiContext _jsonApiContext; private Faker _todoItemFaker; private Faker _personFaker; - public FetchingDataTests(TestFixture fixture) + public FetchingDataTests(TestFixture fixture) { _fixture = fixture; _jsonApiContext = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs index ea805c515f..621cb8e349 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs @@ -16,11 +16,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class FetchingRelationshipsTests { - private TestFixture _fixture; + private TestFixture _fixture; private IJsonApiContext _jsonApiContext; private Faker _todoItemFaker; - public FetchingRelationshipsTests(TestFixture fixture) + public FetchingRelationshipsTests(TestFixture fixture) { _fixture = fixture; _jsonApiContext = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs index 7d8401f78d..2d77982e62 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs @@ -10,15 +10,18 @@ using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; -namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec { - public class PagingTests : TestFixture { +namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec +{ + public class PagingTests : TestFixture + { private readonly Faker _todoItemFaker = new Faker() .RuleFor(t => t.Description, f => f.Lorem.Sentence()) .RuleFor(t => t.Ordinal, f => f.Random.Number()) .RuleFor(t => t.CreatedDate, f => f.Date.Past()); [Fact] - public async Task Can_Paginate_TodoItems() { + public async Task Can_Paginate_TodoItems() + { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; @@ -47,7 +50,8 @@ public async Task Can_Paginate_TodoItems() { } [Fact] - public async Task Can_Paginate_TodoItems_From_Start() { + public async Task Can_Paginate_TodoItems_From_Start() + { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; @@ -77,7 +81,8 @@ public async Task Can_Paginate_TodoItems_From_Start() { } [Fact] - public async Task Can_Paginate_TodoItems_From_End() { + public async Task Can_Paginate_TodoItems_From_End() + { // Arrange const int expectedEntitiesPerPage = 2; var totalCount = expectedEntitiesPerPage * 2; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/QueryParameters.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/QueryParameters.cs index c5a02cb6b7..f5f61e156d 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/QueryParameters.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/QueryParameters.cs @@ -13,8 +13,8 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class QueryParameters { - private TestFixture _fixture; - public QueryParameters(TestFixture fixture) + private TestFixture _fixture; + public QueryParameters(TestFixture fixture) { _fixture = fixture; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs index 8c5c6b5249..7286a94fc5 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs @@ -21,10 +21,10 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class SparseFieldSetTests { - private TestFixture _fixture; + private TestFixture _fixture; private readonly AppDbContext _dbContext; - public SparseFieldSetTests(TestFixture fixture) + public SparseFieldSetTests(TestFixture fixture) { _fixture = fixture; _dbContext = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs index d39f69a855..36ea085508 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs @@ -20,12 +20,12 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class UpdatingDataTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Faker _todoItemFaker; private Faker _personFaker; - public UpdatingDataTests(TestFixture fixture) + public UpdatingDataTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs index 5cc3772497..1dffa6ce87 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs @@ -20,12 +20,12 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec [Collection("WebHostCollection")] public class UpdatingRelationshipsTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private Bogus.Faker _personFaker; private Faker _todoItemFaker; - public UpdatingRelationshipsTests(TestFixture fixture) + public UpdatingRelationshipsTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs index 657e282cb8..acd37a535a 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -19,12 +19,12 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance [Collection("WebHostCollection")] public class TodoItemControllerTests { - private TestFixture _fixture; + private TestFixture _fixture; private AppDbContext _context; private IJsonApiContext _jsonApiContext; private Faker _todoItemFaker; - public TodoItemControllerTests(TestFixture fixture) + public TodoItemControllerTests(TestFixture fixture) { _fixture = fixture; _context = fixture.GetService(); @@ -75,7 +75,7 @@ public async Task Can_Filter_TodoItems() var httpMethod = new HttpMethod("GET"); var route = $"/api/v1/todo-items?filter[ordinal]={todoItem.Ordinal}"; var request = new HttpRequestMessage(httpMethod, route); - + // Act var response = await _fixture.Client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); @@ -339,7 +339,7 @@ public async Task Can_Patch_TodoItem() var request = new HttpRequestMessage(httpMethod, route); request.Content = new StringContent(JsonConvert.SerializeObject(content)); request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - + // Act var response = await _fixture.Client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); @@ -484,4 +484,4 @@ public async Task Can_Delete_TodoItem() Assert.Null(_context.TodoItems.FirstOrDefault(t => t.Id == todoItem.Id)); } } -} \ No newline at end of file +} diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/AuthorizedStartup.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/AuthorizedStartup.cs index 21cfa0e0dc..12a207fea8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/AuthorizedStartup.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/AuthorizedStartup.cs @@ -11,14 +11,16 @@ using JsonApiDotNetCore.Data; using JsonApiDotNetCoreExample.Models; using JsonApiDotNetCoreExampleTests.Repositories; +using UnitTests; +using JsonApiDotNetCore.Services; namespace JsonApiDotNetCoreExampleTests.Startups { public class AuthorizedStartup : Startup { public AuthorizedStartup(IHostingEnvironment env) - : base (env) - { } + : base(env) + { } public override IServiceProvider ConfigureServices(IServiceCollection services) { @@ -46,6 +48,8 @@ public override IServiceProvider ConfigureServices(IServiceCollection services) services.AddSingleton(authServicMock.Object); services.AddScoped, AuthorizedTodoItemsRepository>(); + services.AddScoped(); + return services.BuildServiceProvider(); } } diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj index 90bd4050e7..b1df354bf7 100755 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -13,6 +13,7 @@ + diff --git a/test/JsonApiDotNetCoreExampleTests/TestStartup.cs b/test/JsonApiDotNetCoreExampleTests/TestStartup.cs new file mode 100644 index 0000000000..886d6b3424 --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/TestStartup.cs @@ -0,0 +1,22 @@ +using JsonApiDotNetCore.Services; +using JsonApiDotNetCoreExample; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System; +using UnitTests; + +namespace JsonApiDotNetCoreExampleTests +{ + public class TestStartup : Startup + { + public TestStartup(IHostingEnvironment env) : base(env) + { } + + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + base.ConfigureServices(services); + services.AddScoped(); + return services.BuildServiceProvider(); + } + } +} diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs index b654727a26..f6772fa22b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs @@ -10,9 +10,9 @@ using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Microsoft.AspNetCore.Http; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +using UnitTests; using Xunit; namespace JsonApiDotNetCoreExampleTests.Unit.Extensions @@ -25,7 +25,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() // arrange var services = new ServiceCollection(); var jsonApiOptions = new JsonApiOptions(); - + services.AddDbContext(options => { options.UseMemoryCache(new MemoryCache(new MemoryCacheOptions())); @@ -33,6 +33,9 @@ public void AddJsonApiInternals_Adds_All_Required_Services() // act services.AddJsonApiInternals(jsonApiOptions); + // this is required because the DbContextResolver requires access to the current HttpContext + // to get the request scoped DbContext instance + services.AddScoped(); var provider = services.BuildServiceProvider(); // assert diff --git a/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs b/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs index 43a89616df..960b7c1e46 100644 --- a/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs +++ b/test/JsonApiDotNetCoreExampleTests/WebHostCollection.cs @@ -6,6 +6,6 @@ namespace JsonApiDotNetCoreExampleTests { [CollectionDefinition("WebHostCollection")] public class WebHostCollection - : ICollectionFixture> + : ICollectionFixture> { } } diff --git a/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs b/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs index 41a48f2743..e80acc5d50 100644 --- a/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs +++ b/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Newtonsoft.Json; -using NoEntityFrameworkExample; using Xunit; namespace NoEntityFrameworkTests.Acceptance.Extensibility @@ -23,7 +22,7 @@ public class NoEntityFrameworkTests public NoEntityFrameworkTests() { var builder = new WebHostBuilder() - .UseStartup(); + .UseStartup(); _server = new TestServer(builder); _context = _server.GetService(); _context.Database.EnsureCreated(); @@ -97,7 +96,7 @@ public async Task Can_Create_TodoItems() type = "custom-todo-items", attributes = new { - description = description, + description, ordinal = 1 } } diff --git a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj index 646cf9d538..f1d4044e0b 100644 --- a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +++ b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj @@ -17,6 +17,7 @@ + diff --git a/test/NoEntityFrameworkTests/TestStartup.cs b/test/NoEntityFrameworkTests/TestStartup.cs new file mode 100644 index 0000000000..e925e69fd0 --- /dev/null +++ b/test/NoEntityFrameworkTests/TestStartup.cs @@ -0,0 +1,22 @@ +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using NoEntityFrameworkExample; +using System; +using UnitTests; + +namespace NoEntityFrameworkTests +{ + public class TestStartup : Startup + { + public TestStartup(IHostingEnvironment env) : base(env) + { } + + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + base.ConfigureServices(services); + services.AddScoped(); + return services.BuildServiceProvider(); + } + } +} diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs index 656cb134b5..2390973594 100644 --- a/test/OperationsExampleTests/Add/AddTests.cs +++ b/test/OperationsExampleTests/Add/AddTests.cs @@ -11,22 +11,15 @@ namespace OperationsExampleTests { - [Collection("WebHostCollection")] - public class AddTests + public class AddTests : Fixture { - private readonly Fixture _fixture; private readonly Faker _faker = new Faker(); - public AddTests(Fixture fixture) - { - _fixture = fixture; - } - [Fact] public async Task Can_Create_Author() { // arrange - var context = _fixture.GetService(); + var context = GetService(); var author = AuthorFactory.Get(); var content = new { @@ -44,13 +37,13 @@ public async Task Can_Create_Author() }; // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert - Assert.NotNull(result.response); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var id = result.data.Operations.Single().DataObject.Id; + var id = data.Operations.Single().DataObject.Id; var lastAuthor = await context.Authors.SingleAsync(a => a.StringId == id); Assert.Equal(author.Name, lastAuthor.Name); } @@ -60,7 +53,7 @@ public async Task Can_Create_Authors() { // arrange var expectedCount = _faker.Random.Int(1, 10); - var context = _fixture.GetService(); + var context = GetService(); var authors = AuthorFactory.Get(expectedCount); var content = new { @@ -86,7 +79,7 @@ public async Task Can_Create_Authors() } // act - var (response, data) = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert Assert.NotNull(response); @@ -96,7 +89,7 @@ public async Task Can_Create_Authors() for (int i = 0; i < expectedCount; i++) { var dataObject = data.Operations[i].DataObject; - var author = context.Authors.Single(a => a.StringId == dataObject.ToString()); + var author = context.Authors.Single(a => a.StringId == dataObject.Id); Assert.Equal(authors[i].Name, author.Name); } } @@ -105,7 +98,7 @@ public async Task Can_Create_Authors() public async Task Can_Create_Author_With_Article() { // arrange - var context = _fixture.GetService(); + var context = GetService(); var author = AuthorFactory.Get(); var article = ArticleFactory.Get(); const string authorLocalId = "author-1"; @@ -144,7 +137,7 @@ public async Task Can_Create_Author_With_Article() }; // act - var (response, data) = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert Assert.NotNull(response); diff --git a/test/OperationsExampleTests/WebHostCollection.cs b/test/OperationsExampleTests/Fixture.cs similarity index 64% rename from test/OperationsExampleTests/WebHostCollection.cs rename to test/OperationsExampleTests/Fixture.cs index e385ace992..5a594940af 100644 --- a/test/OperationsExampleTests/WebHostCollection.cs +++ b/test/OperationsExampleTests/Fixture.cs @@ -1,29 +1,42 @@ +using System; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Newtonsoft.Json; -using OperationsExample; +using OperationsExample.Data; using Xunit; +[assembly: CollectionBehavior(DisableTestParallelization = true)] namespace OperationsExampleTests { - [CollectionDefinition("WebHostCollection")] - public class WebHostCollection : ICollectionFixture - { } - - public class Fixture + public class Fixture : IDisposable { public Fixture() { - var builder = new WebHostBuilder().UseStartup(); + var builder = new WebHostBuilder().UseStartup(); Server = new TestServer(builder); Client = Server.CreateClient(); } public TestServer Server { get; private set; } public HttpClient Client { get; } + + public void Dispose() + { + try + { + var context = GetService(); + context.Articles.RemoveRange(context.Articles); + context.Authors.RemoveRange(context.Authors); + context.SaveChanges(); + } // it is possible the test may try to do something that is an invalid db operation + // validation should be left up to the test, so we should not bomb the run in the + // disposal of that context + catch (Exception) { } + } + public T GetService() => (T)Server.Host.Services.GetService(typeof(T)); public async Task PatchAsync(string route, object data) diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs index 17c868cebd..efc06424ce 100644 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -10,26 +11,20 @@ namespace OperationsExampleTests { - [Collection("WebHostCollection")] - public class GetTests + public class GetTests : Fixture, IDisposable { - private readonly Fixture _fixture; - private readonly Faker _faker = new Faker(); - - public GetTests(Fixture fixture) - { - _fixture = fixture; - } + private readonly Faker _faker = new Faker(); [Fact] - public async Task Can_Get_Articles() + public async Task Can_Get_Authors() { // arrange var expectedCount = _faker.Random.Int(1, 10); - var context = _fixture.GetService(); + var context = GetService(); context.Articles.RemoveRange(context.Articles); - var articles = ArticleFactory.Get(expectedCount); - context.AddRange(articles); + context.Authors.RemoveRange(context.Authors); + var authors = AuthorFactory.Get(expectedCount); + context.AddRange(authors); context.SaveChanges(); var content = new @@ -37,13 +32,13 @@ public async Task Can_Get_Articles() operations = new[] { new Dictionary { { "op", "get"}, - { "ref", new { type = "articles" } } + { "ref", new { type = "authors" } } } } }; // act - var result = await _fixture.PatchAsync("api/bulk", content); + var result = await PatchAsync("api/bulk", content); // assert Assert.NotNull(result.response); @@ -54,12 +49,12 @@ public async Task Can_Get_Articles() } [Fact] - public async Task Can_Get_Article_By_Id() + public async Task Can_Get_Author_By_Id() { // arrange - var context = _fixture.GetService(); - var article = ArticleFactory.Get(); - context.Articles.Add(article); + var context = GetService(); + var author = AuthorFactory.Get(); + context.Authors.Add(author); context.SaveChanges(); var content = new @@ -67,20 +62,20 @@ public async Task Can_Get_Article_By_Id() operations = new[] { new Dictionary { { "op", "get"}, - { "ref", new { type = "articles", id = article.StringId } } + { "ref", new { type = "authors", id = author.StringId } } } } }; // act - var result = await _fixture.PatchAsync("api/bulk", content); + var result = await PatchAsync("api/bulk", content); // assert Assert.NotNull(result.response); Assert.NotNull(result.data); Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); Assert.Equal(1, result.data.Operations.Count); - Assert.Equal(article.Id.ToString(), result.data.Operations.Single().DataObject.Id); - } + Assert.Equal(author.Id.ToString(), result.data.Operations.Single().DataObject.Id); + } } } diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj index a7727475bd..13f68faf5a 100644 --- a/test/OperationsExampleTests/OperationsExampleTests.csproj +++ b/test/OperationsExampleTests/OperationsExampleTests.csproj @@ -14,6 +14,7 @@ + diff --git a/test/OperationsExampleTests/Remove/RemoveTests.cs b/test/OperationsExampleTests/Remove/RemoveTests.cs index f5229ebbd5..ae647f13b9 100644 --- a/test/OperationsExampleTests/Remove/RemoveTests.cs +++ b/test/OperationsExampleTests/Remove/RemoveTests.cs @@ -10,24 +10,17 @@ namespace OperationsExampleTests { - [Collection("WebHostCollection")] - public class RemoveTests - { - private readonly Fixture _fixture; + public class RemoveTests : Fixture + { private readonly Faker _faker = new Faker(); - public RemoveTests(Fixture fixture) - { - _fixture = fixture; - } - [Fact] - public async Task Can_Remove_Article() + public async Task Can_Remove_Author() { // arrange - var context = _fixture.GetService(); - var article = ArticleFactory.Get(); - context.Articles.Add(article); + var context = GetService(); + var author = AuthorFactory.Get(); + context.Authors.Add(author); context.SaveChanges(); var content = new @@ -35,32 +28,32 @@ public async Task Can_Remove_Article() operations = new[] { new Dictionary { { "op", "remove"}, - { "ref", new { type = "articles", id = article.StringId } } + { "ref", new { type = "authors", id = author.StringId } } } } }; // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(1, result.data.Operations.Count); - Assert.Null(context.Articles.SingleOrDefault(a => a.Id == article.Id)); + Assert.NotNull(response); + Assert.NotNull(data); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Empty(data.Operations); + Assert.Null(context.Authors.SingleOrDefault(a => a.Id == author.Id)); } [Fact] - public async Task Can_Remove_Articles() + public async Task Can_Remove_Authors() { // arrange var count = _faker.Random.Int(1, 10); - var context = _fixture.GetService(); + var context = GetService(); - var articles = ArticleFactory.Get(count); + var authors = AuthorFactory.Get(count); - context.Articles.AddRange(articles); + context.Authors.AddRange(authors); context.SaveChanges(); var content = new @@ -72,21 +65,21 @@ public async Task Can_Remove_Articles() content.operations.Add( new Dictionary { { "op", "remove"}, - { "ref", new { type = "articles", id = articles[i].StringId } } + { "ref", new { type = "authors", id = authors[i].StringId } } } ); // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(count, result.data.Operations.Count); + Assert.NotNull(response); + Assert.NotNull(data); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Empty(data.Operations); for (int i = 0; i < count; i++) - Assert.Null(context.Articles.SingleOrDefault(a => a.Id == articles[i].Id)); + Assert.Null(context.Authors.SingleOrDefault(a => a.Id == authors[i].Id)); } } } diff --git a/test/OperationsExampleTests/TestStartup.cs b/test/OperationsExampleTests/TestStartup.cs new file mode 100644 index 0000000000..26ee1fdbc3 --- /dev/null +++ b/test/OperationsExampleTests/TestStartup.cs @@ -0,0 +1,25 @@ +using JsonApiDotNetCore.Data; +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using OperationsExample; +using OperationsExample.Data; +using System; +using UnitTests; + +namespace OperationsExampleTests +{ + public class TestStartup : Startup + { + public TestStartup(IHostingEnvironment env) : base(env) + { } + + public override IServiceProvider ConfigureServices(IServiceCollection services) + { + base.ConfigureServices(services); + services.AddScoped(); + services.AddSingleton>(); + return services.BuildServiceProvider(); + } + } +} diff --git a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs index 53b1e37b5a..635b9b89e4 100644 --- a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs +++ b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs @@ -1,8 +1,6 @@ using System; -using System.Diagnostics; using System.Linq; using System.Net; -using System.Threading; using System.Threading.Tasks; using Bogus; using JsonApiDotNetCore.Internal; @@ -13,22 +11,15 @@ namespace OperationsExampleTests { - [Collection("WebHostCollection")] - public class TransactionFailureTests + public class TransactionFailureTests : Fixture { - private readonly Fixture _fixture; private readonly Faker _faker = new Faker(); - public TransactionFailureTests(Fixture fixture) - { - _fixture = fixture; - } - [Fact] public async Task Cannot_Create_Author_If_Article_Creation_Fails() { // arrange - var context = _fixture.GetService(); + var context = GetService(); var author = AuthorFactory.Get(); var article = ArticleFactory.Get(); @@ -70,7 +61,7 @@ public async Task Cannot_Create_Author_If_Article_Creation_Fails() }; // act - var (response, data) = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert Assert.NotNull(response); diff --git a/test/OperationsExampleTests/Update/UpdateTests.cs b/test/OperationsExampleTests/Update/UpdateTests.cs index de05881963..5538fa5830 100644 --- a/test/OperationsExampleTests/Update/UpdateTests.cs +++ b/test/OperationsExampleTests/Update/UpdateTests.cs @@ -10,67 +10,65 @@ namespace OperationsExampleTests.Update { - [Collection("WebHostCollection")] - public class UpdateTests + public class UpdateTests : Fixture { - private readonly Fixture _fixture; private readonly Faker _faker = new Faker(); - public UpdateTests(Fixture fixture) - { - _fixture = fixture; - } - [Fact] - public async Task Can_Update_Article() + public async Task Can_Update_Author() { // arrange - var context = _fixture.GetService(); - var article = ArticleFactory.Get(); - var updates = ArticleFactory.Get(); - context.Articles.Add(article); + var context = GetService(); + var author = AuthorFactory.Get(); + var updates = AuthorFactory.Get(); + context.Authors.Add(author); context.SaveChanges(); var content = new { operations = new[] { - new { - op = "replace", - data = new { - type = "articles", - id = article.Id, - attributes = new { + new Dictionary { + { "op", "update" }, + { "ref", new { + type = "authors", + id = author.Id, + } }, + { "data", new { + type = "authors", + id = author.Id, + attributes = new + { name = updates.Name } - } - }, + } }, + } } }; // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(1, result.data.Operations.Count); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(data); + Assert.Equal(1, data.Operations.Count); - var attrs = result.data.Operations.Single().DataObject.Attributes; + var attrs = data.Operations.Single().DataObject.Attributes; Assert.Equal(updates.Name, attrs["name"]); } [Fact] - public async Task Can_Update_Articles() + public async Task Can_Update_Authors() { // arrange var count = _faker.Random.Int(1, 10); - var context = _fixture.GetService(); + var context = GetService(); - var articles = ArticleFactory.Get(count); - var updates = ArticleFactory.Get(count); + var authors = AuthorFactory.Get(count); + var updates = AuthorFactory.Get(count); - context.Articles.AddRange(articles); + context.Authors.AddRange(authors); context.SaveChanges(); var content = new @@ -79,32 +77,34 @@ public async Task Can_Update_Articles() }; for (int i = 0; i < count; i++) - content.operations.Add(new - { - op = "replace", - data = new - { - type = "articles", - id = articles[i].Id, + content.operations.Add(new Dictionary { + { "op", "update" }, + { "ref", new { + type = "authors", + id = authors[i].Id, + } }, + { "data", new { + type = "authors", + id = authors[i].Id, attributes = new { name = updates[i].Name } - } + } }, }); // act - var result = await _fixture.PatchAsync("api/bulk", content); + var (response, data) = await PatchAsync("api/bulk", content); // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(count, result.data.Operations.Count); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(data); + Assert.Equal(count, data.Operations.Count); for (int i = 0; i < count; i++) { - var attrs = result.data.Operations[i].DataObject.Attributes; + var attrs = data.Operations[i].DataObject.Attributes; Assert.Equal(updates[i].Name, attrs["name"]); } } diff --git a/test/UnitTests/TestScopedServiceProvider.cs b/test/UnitTests/TestScopedServiceProvider.cs new file mode 100644 index 0000000000..af68e340b9 --- /dev/null +++ b/test/UnitTests/TestScopedServiceProvider.cs @@ -0,0 +1,28 @@ +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Http; +using Moq; +using System; + +namespace UnitTests +{ + public class TestScopedServiceProvider : IScopedServiceProvider + { + private readonly IServiceProvider _serviceProvider; + private Mock _httpContextAccessorMock = new Mock(); + + public TestScopedServiceProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public object GetService(Type serviceType) + { + if (serviceType == typeof(IHttpContextAccessor)) + { + return _httpContextAccessorMock.Object; + } + + return _serviceProvider.GetService(serviceType); + } + } +} From d3c9269f479b61707a08dce17ce36d1b3c437453 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 27 Mar 2018 07:35:03 -0500 Subject: [PATCH 107/227] move operations AppDbContext into the shared JsonDotNetCoreExample project having a single db makes CI easier to configure --- .../Data/AppDbContext.cs | 9 +- .../20170315140127_initial.Designer.cs | 92 --------------- ...330020650_AddAssignedTodoItems.Designer.cs | 100 ---------------- .../20170330020650_AddAssignedTodoItems.cs | 43 ------- ...20170330234539_AddGuidProperty.Designer.cs | 102 ----------------- .../20170330234539_AddGuidProperty.cs | 24 ---- ...950_AddCreatesAndAchievedDates.Designer.cs | 108 ------------------ ...170424180950_AddCreatesAndAchievedDates.cs | 33 ------ .../20170426232509_AddCamelCasedModel.cs | 30 ----- ....cs => 20180327120810_initial.Designer.cs} | 51 ++++++++- ...7_initial.cs => 20180327120810_initial.cs} | 90 +++++++++++++-- .../Migrations/AppDbContextModelSnapshot.cs | 48 +++++++- .../Models/Article.cs | 20 ++-- .../Models/Author.cs | 2 +- .../JsonApiDotNetCoreExample/Program.cs | 5 +- .../JsonApiDotNetCoreExample/appsettings.json | 21 ++-- .../OperationsExample/Data/AppDbContext.cs | 15 --- ...80325130426_ArticlesAndAuthors.Designer.cs | 61 ---------- .../20180325130426_ArticlesAndAuthors.cs | 60 ---------- .../Migrations/AppDbContextModelSnapshot.cs | 60 ---------- .../OperationsExample.csproj | 1 + src/Examples/OperationsExample/Startup.cs | 3 +- .../OperationsExample/appsettings.json | 2 +- .../appsettings.json | 21 ++-- test/NoEntityFrameworkTests/appsettings.json | 21 ++-- test/OperationsExampleTests/Add/AddTests.cs | 2 +- .../Factories/ArticleFactory.cs | 4 +- .../Factories/AuthorFactory.cs | 2 +- test/OperationsExampleTests/Fixture.cs | 2 +- test/OperationsExampleTests/Get/GetTests.cs | 2 +- .../Remove/RemoveTests.cs | 2 +- test/OperationsExampleTests/TestStartup.cs | 2 +- .../Transactions/TransactionFailureTests.cs | 2 +- .../Update/UpdateTests.cs | 2 +- test/OperationsExampleTests/appsettings.json | 22 ++-- 35 files changed, 246 insertions(+), 818 deletions(-) delete mode 100644 src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.Designer.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.Designer.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.Designer.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs delete mode 100755 src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs rename src/Examples/JsonApiDotNetCoreExample/Migrations/{20170426232509_AddCamelCasedModel.Designer.cs => 20180327120810_initial.Designer.cs} (72%) mode change 100755 => 100644 rename src/Examples/JsonApiDotNetCoreExample/Migrations/{20170315140127_initial.cs => 20180327120810_initial.cs} (54%) rename src/Examples/{OperationsExample => JsonApiDotNetCoreExample}/Models/Article.cs (85%) rename src/Examples/{OperationsExample => JsonApiDotNetCoreExample}/Models/Author.cs (86%) delete mode 100644 src/Examples/OperationsExample/Data/AppDbContext.cs delete mode 100644 src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs delete mode 100644 src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs delete mode 100755 src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs diff --git a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs index ccdf8e8d9f..4266ca9741 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs @@ -1,4 +1,4 @@ -using JsonApiDotNetCoreExample.Models; +using JsonApiDotNetCoreExample.Models; using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; @@ -14,12 +14,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .Property(t => t.CreatedDate).HasDefaultValueSql("CURRENT_TIMESTAMP").IsRequired(); - + modelBuilder.Entity() .HasOne(t => t.Assignee) .WithMany(p => p.AssignedTodoItems) .HasForeignKey(t => t.AssigneeId); - + modelBuilder.Entity() .HasOne(t => t.Owner) .WithMany(p => p.TodoItems) @@ -34,5 +34,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) [Resource("camelCasedModels")] public DbSet CamelCasedModels { get; set; } + + public DbSet
Articles { get; set; } + public DbSet Authors { get; set; } } } diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.Designer.cs deleted file mode 100644 index be31f0ccae..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.Designer.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using JsonApiDotNetCoreExample.Data; - -namespace JsonApiDotNetCoreExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170315140127_initial")] - partial class initial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("FirstName"); - - b.Property("LastName"); - - b.HasKey("Id"); - - b.ToTable("People"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("CollectionId"); - - b.Property("Description"); - - b.Property("Ordinal"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("CollectionId"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItems"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItemCollections"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection") - .WithMany("TodoItems") - .HasForeignKey("CollectionId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItems") - .HasForeignKey("OwnerId"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItemCollections") - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); - }); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.Designer.cs deleted file mode 100755 index 52b60adbcb..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.Designer.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using JsonApiDotNetCoreExample.Data; - -namespace JsonApiDotNetCoreExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170330020650_AddAssignedTodoItems")] - partial class AddAssignedTodoItems - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("FirstName"); - - b.Property("LastName"); - - b.HasKey("Id"); - - b.ToTable("People"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AssigneeId"); - - b.Property("CollectionId"); - - b.Property("Description"); - - b.Property("Ordinal"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("AssigneeId"); - - b.HasIndex("CollectionId"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItems"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItemCollections"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") - .WithMany("AssignedTodoItems") - .HasForeignKey("AssigneeId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection") - .WithMany("TodoItems") - .HasForeignKey("CollectionId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItems") - .HasForeignKey("OwnerId"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItemCollections") - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); - }); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs deleted file mode 100755 index 8a1810a9d8..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace JsonApiDotNetCoreExample.Migrations -{ - public partial class AddAssignedTodoItems : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "AssigneeId", - table: "TodoItems", - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_TodoItems_AssigneeId", - table: "TodoItems", - column: "AssigneeId"); - - migrationBuilder.AddForeignKey( - name: "FK_TodoItems_People_AssigneeId", - table: "TodoItems", - column: "AssigneeId", - principalTable: "People", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_TodoItems_People_AssigneeId", - table: "TodoItems"); - - migrationBuilder.DropIndex( - name: "IX_TodoItems_AssigneeId", - table: "TodoItems"); - - migrationBuilder.DropColumn( - name: "AssigneeId", - table: "TodoItems"); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs deleted file mode 100755 index ded5d1b160..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using JsonApiDotNetCoreExample.Data; - -namespace JsonApiDotNetCoreExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170330234539_AddGuidProperty")] - partial class AddGuidProperty - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("FirstName"); - - b.Property("LastName"); - - b.HasKey("Id"); - - b.ToTable("People"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AssigneeId"); - - b.Property("CollectionId"); - - b.Property("Description"); - - b.Property("GuidProperty"); - - b.Property("Ordinal"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("AssigneeId"); - - b.HasIndex("CollectionId"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItems"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItemCollections"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") - .WithMany("AssignedTodoItems") - .HasForeignKey("AssigneeId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection") - .WithMany("TodoItems") - .HasForeignKey("CollectionId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItems") - .HasForeignKey("OwnerId"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItemCollections") - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); - }); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs deleted file mode 100755 index 27815ce504..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace JsonApiDotNetCoreExample.Migrations -{ - public partial class AddGuidProperty : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "GuidProperty", - table: "TodoItems", - nullable: false, - defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "GuidProperty", - table: "TodoItems"); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.Designer.cs deleted file mode 100755 index 537b3b043a..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.Designer.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using JsonApiDotNetCoreExample.Data; - -namespace JsonApiDotNetCoreExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20170424180950_AddCreatesAndAchievedDates")] - partial class AddCreatesAndAchievedDates - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Person", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("FirstName"); - - b.Property("LastName"); - - b.HasKey("Id"); - - b.ToTable("People"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AchievedDate"); - - b.Property("AssigneeId"); - - b.Property("CollectionId"); - - b.Property("CreatedDate") - .ValueGeneratedOnAdd() - .HasDefaultValueSql("CURRENT_TIMESTAMP"); - - b.Property("Description"); - - b.Property("GuidProperty"); - - b.Property("Ordinal"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("AssigneeId"); - - b.HasIndex("CollectionId"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItems"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.Property("OwnerId"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("TodoItemCollections"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") - .WithMany("AssignedTodoItems") - .HasForeignKey("AssigneeId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection") - .WithMany("TodoItems") - .HasForeignKey("CollectionId"); - - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItems") - .HasForeignKey("OwnerId"); - }); - - modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => - { - b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") - .WithMany("TodoItemCollections") - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); - }); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs deleted file mode 100755 index 1c36034fe3..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170424180950_AddCreatesAndAchievedDates.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace JsonApiDotNetCoreExample.Migrations -{ - public partial class AddCreatesAndAchievedDates : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "AchievedDate", - table: "TodoItems", - nullable: true); - - migrationBuilder.AddColumn( - name: "CreatedDate", - table: "TodoItems", - nullable: false, - defaultValueSql: "CURRENT_TIMESTAMP"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "AchievedDate", - table: "TodoItems"); - - migrationBuilder.DropColumn( - name: "CreatedDate", - table: "TodoItems"); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs deleted file mode 100755 index fbec5e0a79..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; - -namespace JsonApiDotNetCoreExample.Migrations -{ - public partial class AddCamelCasedModel : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "CamelCasedModels", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), - CompoundAttr = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_CamelCasedModels", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "CamelCasedModels"); - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs old mode 100755 new mode 100644 similarity index 72% rename from src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.Designer.cs rename to src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs index e43d2afc1f..c86425b00c --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170426232509_AddCamelCasedModel.Designer.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs @@ -1,21 +1,53 @@ -using System; +// +using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using JsonApiDotNetCoreExample.Data; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; namespace JsonApiDotNetCoreExample.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20170426232509_AddCamelCasedModel")] - partial class AddCamelCasedModel + [Migration("20180327120810_initial")] + partial class initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Article", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); modelBuilder.Entity("JsonApiDotNetCoreExample.Models.CamelCasedModel", b => { @@ -93,6 +125,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("TodoItemCollections"); }); + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Article", b => + { + b.HasOne("JsonApiDotNetCoreExample.Models.Author", "Author") + .WithMany("Articles") + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => { b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") @@ -115,6 +155,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasForeignKey("OwnerId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs similarity index 54% rename from src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs rename to src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs index e0b4e3b40b..ba19b62ef6 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20170315140127_initial.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs @@ -1,6 +1,7 @@ -using System; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Metadata; +using System; +using System.Collections.Generic; namespace JsonApiDotNetCoreExample.Migrations { @@ -8,6 +9,32 @@ public partial class initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "Authors", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Authors", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CamelCasedModels", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + CompoundAttr = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CamelCasedModels", x => x.Id); + }); + migrationBuilder.CreateTable( name: "People", columns: table => new @@ -22,6 +49,26 @@ protected override void Up(MigrationBuilder migrationBuilder) table.PrimaryKey("PK_People", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Articles", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AuthorId = table.Column(nullable: false), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Articles", x => x.Id); + table.ForeignKey( + name: "FK_Articles_Authors_AuthorId", + column: x => x.AuthorId, + principalTable: "Authors", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "TodoItemCollections", columns: table => new @@ -47,14 +94,24 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AchievedDate = table.Column(nullable: true), + AssigneeId = table.Column(nullable: true), CollectionId = table.Column(nullable: true), + CreatedDate = table.Column(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), Description = table.Column(nullable: true), + GuidProperty = table.Column(nullable: false), Ordinal = table.Column(nullable: false), OwnerId = table.Column(nullable: true) }, constraints: table => { table.PrimaryKey("PK_TodoItems", x => x.Id); + table.ForeignKey( + name: "FK_TodoItems_People_AssigneeId", + column: x => x.AssigneeId, + principalTable: "People", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_TodoItems_TodoItemCollections_CollectionId", column: x => x.CollectionId, @@ -69,6 +126,21 @@ protected override void Up(MigrationBuilder migrationBuilder) onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateIndex( + name: "IX_Articles_AuthorId", + table: "Articles", + column: "AuthorId"); + + migrationBuilder.CreateIndex( + name: "IX_TodoItemCollections_OwnerId", + table: "TodoItemCollections", + column: "OwnerId"); + + migrationBuilder.CreateIndex( + name: "IX_TodoItems_AssigneeId", + table: "TodoItems", + column: "AssigneeId"); + migrationBuilder.CreateIndex( name: "IX_TodoItems_CollectionId", table: "TodoItems", @@ -78,18 +150,22 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "IX_TodoItems_OwnerId", table: "TodoItems", column: "OwnerId"); - - migrationBuilder.CreateIndex( - name: "IX_TodoItemCollections_OwnerId", - table: "TodoItemCollections", - column: "OwnerId"); } protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "Articles"); + + migrationBuilder.DropTable( + name: "CamelCasedModels"); + migrationBuilder.DropTable( name: "TodoItems"); + migrationBuilder.DropTable( + name: "Authors"); + migrationBuilder.DropTable( name: "TodoItemCollections"); diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs index 5de99f5078..c0794103fe 100755 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs @@ -1,8 +1,12 @@ -using System; +// +using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using JsonApiDotNetCoreExample.Data; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; namespace JsonApiDotNetCoreExample.Migrations { @@ -11,9 +15,38 @@ partial class AppDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { +#pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "1.1.1"); + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Article", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); modelBuilder.Entity("JsonApiDotNetCoreExample.Models.CamelCasedModel", b => { @@ -91,6 +124,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("TodoItemCollections"); }); + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Article", b => + { + b.HasOne("JsonApiDotNetCoreExample.Models.Author", "Author") + .WithMany("Articles") + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => { b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") @@ -113,6 +154,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("OwnerId") .OnDelete(DeleteBehavior.Cascade); }); +#pragma warning restore 612, 618 } } } diff --git a/src/Examples/OperationsExample/Models/Article.cs b/src/Examples/JsonApiDotNetCoreExample/Models/Article.cs similarity index 85% rename from src/Examples/OperationsExample/Models/Article.cs rename to src/Examples/JsonApiDotNetCoreExample/Models/Article.cs index 4353c02ee2..c633d58bdd 100644 --- a/src/Examples/OperationsExample/Models/Article.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/Article.cs @@ -1,14 +1,14 @@ -using JsonApiDotNetCore.Models; - -namespace OperationsExample.Models -{ - public class Article : Identifiable - { - [Attr("name")] +using JsonApiDotNetCore.Models; + +namespace JsonApiDotNetCoreExample.Models +{ + public class Article : Identifiable + { + [Attr("name")] public string Name { get; set; } [HasOne("author")] public Author Author { get; set; } - public int AuthorId { get; set; } - } -} + public int AuthorId { get; set; } + } +} diff --git a/src/Examples/OperationsExample/Models/Author.cs b/src/Examples/JsonApiDotNetCoreExample/Models/Author.cs similarity index 86% rename from src/Examples/OperationsExample/Models/Author.cs rename to src/Examples/JsonApiDotNetCoreExample/Models/Author.cs index 7d6039480a..c77ad007c8 100644 --- a/src/Examples/OperationsExample/Models/Author.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/Author.cs @@ -1,7 +1,7 @@ using JsonApiDotNetCore.Models; using System.Collections.Generic; -namespace OperationsExample.Models +namespace JsonApiDotNetCoreExample.Models { public class Author : Identifiable { diff --git a/src/Examples/JsonApiDotNetCoreExample/Program.cs b/src/Examples/JsonApiDotNetCoreExample/Program.cs index e4e3fe355e..b9bbe37b6a 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Program.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Program.cs @@ -5,10 +5,7 @@ namespace JsonApiDotNetCoreExample { public class Program { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } + public static void Main(string[] args) => BuildWebHost(args).Run(); public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) diff --git a/src/Examples/JsonApiDotNetCoreExample/appsettings.json b/src/Examples/JsonApiDotNetCoreExample/appsettings.json index ceb4a1ed73..578225ef14 100755 --- a/src/Examples/JsonApiDotNetCoreExample/appsettings.json +++ b/src/Examples/JsonApiDotNetCoreExample/appsettings.json @@ -1,14 +1,13 @@ { - "Data": { - "DefaultConnection": - "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=password" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Trace", - "System": "Trace", - "Microsoft": "Trace" + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "System": "Trace", + "Microsoft": "Trace" + } } - } } diff --git a/src/Examples/OperationsExample/Data/AppDbContext.cs b/src/Examples/OperationsExample/Data/AppDbContext.cs deleted file mode 100644 index 3d5b3e2e54..0000000000 --- a/src/Examples/OperationsExample/Data/AppDbContext.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using OperationsExample.Models; - -namespace OperationsExample.Data -{ - public class AppDbContext : DbContext - { - public AppDbContext(DbContextOptions options) - : base(options) - { } - - public DbSet
Articles { get; set; } - public DbSet Authors { get; set; } - } -} diff --git a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs deleted file mode 100644 index e9934cb776..0000000000 --- a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.Designer.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using OperationsExample.Data; -using System; - -namespace OperationsExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20180325130426_ArticlesAndAuthors")] - partial class ArticlesAndAuthors - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); - - modelBuilder.Entity("OperationsExample.Models.Article", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AuthorId"); - - b.Property("Name"); - - b.HasKey("Id"); - - b.HasIndex("AuthorId"); - - b.ToTable("Articles"); - }); - - modelBuilder.Entity("OperationsExample.Models.Author", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.HasKey("Id"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("OperationsExample.Models.Article", b => - { - b.HasOne("OperationsExample.Models.Author", "Author") - .WithMany("Articles") - .HasForeignKey("AuthorId"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs b/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs deleted file mode 100644 index 1a0d5e309a..0000000000 --- a/src/Examples/OperationsExample/Migrations/20180325130426_ArticlesAndAuthors.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using System; -using System.Collections.Generic; - -namespace OperationsExample.Migrations -{ - public partial class ArticlesAndAuthors : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Authors", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), - Name = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Authors", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Articles", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), - AuthorId = table.Column(nullable: true), - Name = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Articles", x => x.Id); - table.ForeignKey( - name: "FK_Articles_Authors_AuthorId", - column: x => x.AuthorId, - principalTable: "Authors", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_Articles_AuthorId", - table: "Articles", - column: "AuthorId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Articles"); - - migrationBuilder.DropTable( - name: "Authors"); - } - } -} diff --git a/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs deleted file mode 100755 index b4c9a0ebba..0000000000 --- a/src/Examples/OperationsExample/Migrations/AppDbContextModelSnapshot.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using OperationsExample.Data; -using System; - -namespace OperationsExample.Migrations -{ - [DbContext(typeof(AppDbContext))] - partial class AppDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); - - modelBuilder.Entity("OperationsExample.Models.Article", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AuthorId"); - - b.Property("Name"); - - b.HasKey("Id"); - - b.HasIndex("AuthorId"); - - b.ToTable("Articles"); - }); - - modelBuilder.Entity("OperationsExample.Models.Author", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Name"); - - b.HasKey("Id"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("OperationsExample.Models.Article", b => - { - b.HasOne("OperationsExample.Models.Author", "Author") - .WithMany("Articles") - .HasForeignKey("AuthorId"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj index ebbdc91fc1..69ad5653ce 100644 --- a/src/Examples/OperationsExample/OperationsExample.csproj +++ b/src/Examples/OperationsExample/OperationsExample.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs index 78a6d29f69..c11a3e9d26 100644 --- a/src/Examples/OperationsExample/Startup.cs +++ b/src/Examples/OperationsExample/Startup.cs @@ -1,13 +1,12 @@ using System; using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCoreExample.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using OperationsExample.Data; - namespace OperationsExample { diff --git a/src/Examples/OperationsExample/appsettings.json b/src/Examples/OperationsExample/appsettings.json index 2bcbebd13a..0d77cd40f2 100644 --- a/src/Examples/OperationsExample/appsettings.json +++ b/src/Examples/OperationsExample/appsettings.json @@ -1,6 +1,6 @@ { "Data": { - "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=postgres" + "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" }, "Logging": { "IncludeScopes": false, diff --git a/test/JsonApiDotNetCoreExampleTests/appsettings.json b/test/JsonApiDotNetCoreExampleTests/appsettings.json index 7af3457293..e65cee8d0d 100644 --- a/test/JsonApiDotNetCoreExampleTests/appsettings.json +++ b/test/JsonApiDotNetCoreExampleTests/appsettings.json @@ -1,14 +1,13 @@ { - "Data": { - "DefaultConnection": - "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Error", - "System": "Information", - "Microsoft": "Information" + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Error", + "System": "Information", + "Microsoft": "Information" + } } - } } diff --git a/test/NoEntityFrameworkTests/appsettings.json b/test/NoEntityFrameworkTests/appsettings.json index 7067b2bee0..01f85e6699 100644 --- a/test/NoEntityFrameworkTests/appsettings.json +++ b/test/NoEntityFrameworkTests/appsettings.json @@ -1,14 +1,13 @@ { - "Data": { - "DefaultConnection": - "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } } - } } diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs index 2390973594..39e9e8a2a6 100644 --- a/test/OperationsExampleTests/Add/AddTests.cs +++ b/test/OperationsExampleTests/Add/AddTests.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using Bogus; using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; -using OperationsExample.Data; using OperationsExampleTests.Factories; using Xunit; diff --git a/test/OperationsExampleTests/Factories/ArticleFactory.cs b/test/OperationsExampleTests/Factories/ArticleFactory.cs index 1907e2de24..a03bc3fbea 100644 --- a/test/OperationsExampleTests/Factories/ArticleFactory.cs +++ b/test/OperationsExampleTests/Factories/ArticleFactory.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Bogus; -using OperationsExample.Models; +using JsonApiDotNetCoreExample.Models; namespace OperationsExampleTests.Factories { @@ -22,4 +22,4 @@ public static List
Get(int count) return articles; } } -} \ No newline at end of file +} diff --git a/test/OperationsExampleTests/Factories/AuthorFactory.cs b/test/OperationsExampleTests/Factories/AuthorFactory.cs index 2afe914b54..e80b100a59 100644 --- a/test/OperationsExampleTests/Factories/AuthorFactory.cs +++ b/test/OperationsExampleTests/Factories/AuthorFactory.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Bogus; -using OperationsExample.Models; +using JsonApiDotNetCoreExample.Models; namespace OperationsExampleTests.Factories { diff --git a/test/OperationsExampleTests/Fixture.cs b/test/OperationsExampleTests/Fixture.cs index 5a594940af..11621d36e4 100644 --- a/test/OperationsExampleTests/Fixture.cs +++ b/test/OperationsExampleTests/Fixture.cs @@ -2,10 +2,10 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; +using JsonApiDotNetCoreExample.Data; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Newtonsoft.Json; -using OperationsExample.Data; using Xunit; [assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs index efc06424ce..1bf0393fa8 100644 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using Bogus; using JsonApiDotNetCore.Models.Operations; -using OperationsExample.Data; +using JsonApiDotNetCoreExample.Data; using OperationsExampleTests.Factories; using Xunit; diff --git a/test/OperationsExampleTests/Remove/RemoveTests.cs b/test/OperationsExampleTests/Remove/RemoveTests.cs index ae647f13b9..b5e0cffaf3 100644 --- a/test/OperationsExampleTests/Remove/RemoveTests.cs +++ b/test/OperationsExampleTests/Remove/RemoveTests.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Bogus; using JsonApiDotNetCore.Models.Operations; -using OperationsExample.Data; +using JsonApiDotNetCoreExample.Data; using OperationsExampleTests.Factories; using Xunit; diff --git a/test/OperationsExampleTests/TestStartup.cs b/test/OperationsExampleTests/TestStartup.cs index 26ee1fdbc3..449c193177 100644 --- a/test/OperationsExampleTests/TestStartup.cs +++ b/test/OperationsExampleTests/TestStartup.cs @@ -1,9 +1,9 @@ using JsonApiDotNetCore.Data; using JsonApiDotNetCore.Services; +using JsonApiDotNetCoreExample.Data; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using OperationsExample; -using OperationsExample.Data; using System; using UnitTests; diff --git a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs index 635b9b89e4..05dea7f29d 100644 --- a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs +++ b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using Bogus; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; -using OperationsExample.Data; using OperationsExampleTests.Factories; using Xunit; diff --git a/test/OperationsExampleTests/Update/UpdateTests.cs b/test/OperationsExampleTests/Update/UpdateTests.cs index 5538fa5830..c5d0f20900 100644 --- a/test/OperationsExampleTests/Update/UpdateTests.cs +++ b/test/OperationsExampleTests/Update/UpdateTests.cs @@ -1,6 +1,6 @@ using Bogus; using JsonApiDotNetCore.Models.Operations; -using OperationsExample.Data; +using JsonApiDotNetCoreExample.Data; using OperationsExampleTests.Factories; using System.Collections.Generic; using System.Linq; diff --git a/test/OperationsExampleTests/appsettings.json b/test/OperationsExampleTests/appsettings.json index c1061281cc..0d77cd40f2 100644 --- a/test/OperationsExampleTests/appsettings.json +++ b/test/OperationsExampleTests/appsettings.json @@ -1,13 +1,13 @@ -{ - "Data": { - "DefaultConnection": "Host=localhost;Port=5432;Database=OperationsExample;User ID=postgres;Password=password" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Trace", - "System": "Trace", - "Microsoft": "Trace" +{ + "Data": { + "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "System": "Trace", + "Microsoft": "Trace" + } } - } } From 0884b649b269c1aa417f30881f0d28a63b265f6f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 27 Mar 2018 08:56:10 -0500 Subject: [PATCH 108/227] don't use docfx on non-windows platforms --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index c712227334..7b2c112414 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -13,11 +13,16 @@ git https://github.com/json-api-dotnet/JsonApiDotNetCore + + true + bin\Release\netstandard2.0\JsonApiDotNetCore.xml - + + + From 6808741fdf0f0a6768fc28769bd1255206f1d048 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 27 Mar 2018 09:03:36 -0500 Subject: [PATCH 109/227] fix(csproj): correct IsWindows condition check --- .../JsonApiDotNetCore.csproj | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 7b2c112414..fd7ab1631a 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -13,15 +13,7 @@ git https://github.com/json-api-dotnet/JsonApiDotNetCore - - true - - - bin\Release\netstandard2.0\JsonApiDotNetCore.xml - - - - + @@ -31,4 +23,15 @@ + + + true + + + bin\Release\netstandard2.0\JsonApiDotNetCore.xml + + + + + From 82824b164c9406edef285d9b71fa433ea0356eec Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 27 Mar 2018 09:09:53 -0500 Subject: [PATCH 110/227] remove support for JsonPointers --- .../Extensions/JObjectExtensions.cs | 22 --- .../JsonApiDotNetCore.csproj | 2 +- .../Models/Pointers/OperationsPointer.cs | 108 ------------ .../Models/Pointers/Pointer.cs | 22 --- src/JsonApiDotNetCore/api/.manifest | 1 - .../Models/Pointers/OperationsPointerTests.cs | 164 ------------------ 6 files changed, 1 insertion(+), 318 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs delete mode 100644 src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs delete mode 100644 src/JsonApiDotNetCore/Models/Pointers/Pointer.cs delete mode 100644 test/UnitTests/Models/Pointers/OperationsPointerTests.cs diff --git a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs b/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs deleted file mode 100644 index 9871258b54..0000000000 --- a/src/JsonApiDotNetCore/Extensions/JObjectExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; -using JsonApiDotNetCore.Models.Pointers; - -namespace JsonApiDotNetCore.Extensions -{ - public static class JObjectExtensions - { - internal static bool TryParse(this JObject obj, JSchema schema, out Pointer pointer) - where TPointer : Pointer, new() - { - if (obj.IsValid(schema)) - { - pointer = obj.ToObject(); - return true; - } - - pointer = null; - return false; - } - } -} diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index fd7ab1631a..092dd2abcc 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -5,6 +5,7 @@ JsonApiDotNetCore JsonApiDotNetCore + jsonapi;dotnet core;emberjs;ember https://github.com/json-api-dotnet/JsonApiDotNetCore @@ -19,7 +20,6 @@ - diff --git a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs b/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs deleted file mode 100644 index 53cdcfec06..0000000000 --- a/src/JsonApiDotNetCore/Models/Pointers/OperationsPointer.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models.Operations; - -namespace JsonApiDotNetCore.Models.Pointers -{ - internal class OperationsPointer : Pointer - { - /// - /// - /// - /// - public override object GetValue(object root) - { - if (root == null) throw new ArgumentNullException(nameof(root)); - if (PointerAddress == null) throw new InvalidOperationException("Cannot get pointer value from null PointerAddress"); - - if (root is List operations) - return GetValueFromRoot(operations); - - throw new ArgumentException(nameof(root)); - } - - private object GetValueFromRoot(List operations) - { - var pathSegments = PointerAddress.ToLower().Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - if (pathSegments.Length < 4) - throw BadRequestException("number of segments", pathSegments.Length); - - if (pathSegments[0] != "operations") - throw BadRequestException("prefix", pathSegments[0]); - - // /operations/{operationIndex} → operations = [...] - if (int.TryParse(pathSegments[1], out int operationIndex)) - return GetValueFromOperation(operations[operationIndex], pathSegments); - else - throw BadRequestException("operation index", operationIndex); - } - - private object GetValueFromOperation(Operation operation, string[] pathSegments) - { - var operationPropertyName = pathSegments[2]; - - // /operations/0/ref → ref = {...} - if (operationPropertyName == "ref") - return GetValueFromRef(operation.Ref, pathSegments); - - // /operations/0/data → data = {...} - if (operation.DataIsList == false) - return GetValueFromData(operation.DataObject, pathSegments, segementStartIndex: 3); - - // /operations/0/data/{dataIndex} → data = [...] - if (int.TryParse(pathSegments[3], out int dataIndex)) - { - if (operation.DataList.Count >= dataIndex - 1) - return GetValueFromData(operation.DataList[dataIndex], pathSegments, segementStartIndex: 4); - throw BadRequestException("data index", dataIndex, "Pointer references an index in the data array that cannot be found at the specified position."); - } - else - { - throw BadRequestException("data index", dataIndex, "Pointer segement should provide array index but could not be parsed to an integer."); - } - } - - private object GetValueFromRef(ResourceReference reference, string[] pathSegments) - { - const int segementStartIndex = 3; - - // /operations/0/ref/{dataPropertyName} - if (pathSegments.Length <= segementStartIndex) - throw BadRequestException("length", pathSegments.Length, "Pointer does not contain enough segments to locate ref property."); - - var dataPropertyName = pathSegments[segementStartIndex]; - switch (dataPropertyName) - { - case "id": - return reference.Id; - case "type": - return reference.Type; - default: - throw BadRequestException("ref property name", dataPropertyName, "Only 'id' and 'type' pointers are supported."); - } - } - - private object GetValueFromData(DocumentData data, string[] pathSegments, int segementStartIndex) - { - // /operations/0/data/{dataPropertyName} - if (pathSegments.Length <= segementStartIndex) - throw BadRequestException("length", pathSegments.Length, "Pointer does not contain enough segments to locate data property."); - - var dataPropertyName = pathSegments[segementStartIndex]; - switch (dataPropertyName) - { - case "id": - return data.Id; - case "type": - return data.Type; - default: - throw BadRequestException("data property name", dataPropertyName, "Only 'id' and 'type' pointers are supported."); - } - } - - private JsonApiException BadRequestException(string condition, object value, string extraDetail = null) - => new JsonApiException(400, $"Operations pointer has invalid {condition} '{value}' in pointer '{PointerAddress}'. {extraDetail}"); - } -} diff --git a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs b/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs deleted file mode 100644 index d5e3a7924b..0000000000 --- a/src/JsonApiDotNetCore/Models/Pointers/Pointer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Schema; - -namespace JsonApiDotNetCore.Models.Pointers -{ - internal abstract class Pointer - { - public static JSchema JsonSchema { get; } = JSchema.Parse("{ 'pointer': {'type': 'string'} }"); - - /// - /// Location represented by the pointer - /// - /// /operations/0/data/id - [JsonProperty("pointer")] - public string PointerAddress { get; set; } - - /// - /// Get the value located at the PointerAddress in the supplied object - /// - public abstract object GetValue(object root); - } -} diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index 6aa4a40924..211035306f 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -217,7 +217,6 @@ "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApiInternals(Microsoft.Extensions.DependencyInjection.IServiceCollection,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.AddJsonApiInternals``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.SerializeAsJsonApi(Microsoft.AspNetCore.Mvc.MvcOptions,JsonApiDotNetCore.Configuration.JsonApiOptions)": "JsonApiDotNetCore.Extensions.IServiceCollectionExtensions.yml", - "JsonApiDotNetCore.Extensions.JObjectExtensions": "JsonApiDotNetCore.Extensions.JObjectExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions": "JsonApiDotNetCore.Extensions.StringExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions.Dasherize(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", "JsonApiDotNetCore.Extensions.StringExtensions.ToProperCase(System.String)": "JsonApiDotNetCore.Extensions.StringExtensions.yml", diff --git a/test/UnitTests/Models/Pointers/OperationsPointerTests.cs b/test/UnitTests/Models/Pointers/OperationsPointerTests.cs deleted file mode 100644 index 9aafc284dc..0000000000 --- a/test/UnitTests/Models/Pointers/OperationsPointerTests.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Models.Pointers; -using Newtonsoft.Json; -using Xunit; - -namespace UnitTests.Models.Pointers -{ - public class OperationsPointerTests - { - [Fact] - public void GetValue_Can_Get_Value_From_Ref_Id() - { - // arrange - var json = @"[ - { - ""op"": ""add"", - ""ref"": { - ""type"": ""articles"", - ""id"": ""1"" - } - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/0/ref/id"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("1", value.ToString()); - } - - [Fact] - public void GetValue_Can_Get_Value_From_Data_Id() - { - // arrange - var json = @"[ - { - ""op"": ""add"", - ""data"": { - ""id"": ""1"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""dgeb"" - } - } - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/0/data/id"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("1", value.ToString()); - } - - [Fact] - public void GetValue_Can_Get_Value_From_Data_Type() - { - // arrange - var json = @"[ - { - ""op"": ""add"", - ""data"": { - ""id"": ""1"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""dgeb"" - } - } - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/0/data/type"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("authors", value.ToString()); - } - - [Fact] - public void GetValue_Can_Get_Value_From_ListData_Id() - { - // arrange - var json = @"[ - { - ""op"": ""get"", - ""data"": [{ - ""id"": ""1"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""dgeb"" - } - }, { - ""id"": ""2"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""jaredcnance"" - } - }] - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/0/data/1/id"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("2", value.ToString()); - } - - [Fact] - public void GetValue_Can_Get_Value_From_Second_Operations_Data_Id() - { - // arrange - var json = @"[ - { - ""op"": ""get"", - ""data"": { - ""id"": ""1"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""dgeb"" - } - } - },{ - ""op"": ""get"", - ""data"": { - ""id"": ""2"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""jaredcnance"" - } - } - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/1/data/id"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("2", value.ToString()); - } - - [Fact] - public void GetValue_Can_Get_Value_From_Second_Operations_Data_Type() - { - // arrange - var json = @"[ - { - ""op"": ""get"", - ""data"": { - ""id"": ""1"", - ""type"": ""authors"", - ""attributes"": { - ""name"": ""dgeb"" - } - } - },{ - ""op"": ""get"", - ""data"": { - ""id"": ""1"", - ""type"": ""articles"", - ""attributes"": { - ""name"": ""JSON API paints my bikeshed!"" - } - } - }]"; - var operations = JsonConvert.DeserializeObject>(json); - var pointerJson = @"{ ""pointer"": ""/operations/1/data/type"" }"; - var pointer = JsonConvert.DeserializeObject(pointerJson); - var value = pointer.GetValue(operations); - Assert.Equal("articles", value.ToString()); - } - } -} \ No newline at end of file From 4ef0d79ec028a0f99471b772089a5adeecdc8a37 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 29 Mar 2018 06:13:53 -0500 Subject: [PATCH 111/227] fix(OperationProcessorResolver): do not cache opProcessors --- .../Operations/OperationProcessorResolver.cs | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs index 13714edbf3..4215507bc2 100644 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs @@ -1,30 +1,42 @@ -using System.Collections.Concurrent; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models.Operations; using JsonApiDotNetCore.Services.Operations.Processors; namespace JsonApiDotNetCore.Services.Operations { + /// + /// Used to resolve at runtime based on the required operation + /// public interface IOperationProcessorResolver { + /// + /// Locates the correct + /// IOpProcessor LocateCreateService(Operation operation); + + /// + /// Locates the correct + /// IOpProcessor LocateGetService(Operation operation); + + /// + /// Locates the correct + /// IOpProcessor LocateRemoveService(Operation operation); + + /// + /// Locates the correct + /// IOpProcessor LocateUpdateService(Operation operation); } + /// public class OperationProcessorResolver : IOperationProcessorResolver { private readonly IGenericProcessorFactory _processorFactory; private readonly IJsonApiContext _context; - // processor caches -- since there is some associated cost with creating the processors, we store them in memory - // to reduce the cost of subsequent requests. in the future, this may be moved into setup code run at startup - private ConcurrentDictionary _createOpProcessors = new ConcurrentDictionary(); - private ConcurrentDictionary _getOpProcessors = new ConcurrentDictionary(); - private ConcurrentDictionary _removeOpProcessors = new ConcurrentDictionary(); - private ConcurrentDictionary _updateOpProcessors = new ConcurrentDictionary(); - + /// public OperationProcessorResolver( IGenericProcessorFactory processorFactory, IJsonApiContext context) @@ -33,73 +45,55 @@ public OperationProcessorResolver( _context = context; } - // TODO: there may be some optimizations here around the cache such as not caching processors - // if the request only contains a single op + /// public IOpProcessor LocateCreateService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_createOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) - return cachedProcessor; - var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( typeof(ICreateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _createOpProcessors[resource] = processor; - return processor; } + /// public IOpProcessor LocateGetService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_getOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) - return cachedProcessor; - var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( typeof(IGetOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _getOpProcessors[resource] = processor; - return processor; } + /// public IOpProcessor LocateRemoveService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_removeOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) - return cachedProcessor; - var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _removeOpProcessors[resource] = processor; - return processor; } + /// public IOpProcessor LocateUpdateService(Operation operation) { var resource = operation.GetResourceTypeName(); - if (_updateOpProcessors.TryGetValue(resource, out IOpProcessor cachedProcessor)) - return cachedProcessor; - var contextEntity = _context.ContextGraph.GetContextEntity(resource); var processor = _processorFactory.GetProcessor( typeof(IUpdateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType ); - _updateOpProcessors[resource] = processor; - return processor; } } From a6d6ca6f76a02864af2e3d746c1a51cb0e4667cb Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 29 Mar 2018 06:40:48 -0500 Subject: [PATCH 112/227] return 404 if get by id returns null --- .../Operations/Processors/GetOpProcessor.cs | 8 ++ .../Get/GetByIdTests.cs | 78 +++++++++++++++++++ test/OperationsExampleTests/Get/GetTests.cs | 32 +------- 3 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 test/OperationsExampleTests/Get/GetByIdTests.cs diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs index 8bd5b2b0f4..bbcdf0d8a0 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs @@ -90,6 +90,14 @@ private async Task GetByIdAsync(Operation operation) { var id = TypeHelper.ConvertType(operation.Ref.Id); var result = await _getById.GetAsync(id); + + // this is a bit ugly but we need to bomb the entire transaction if the entity cannot be found + // in the future it would probably be better to return a result status along with the doc to + // avoid throwing exceptions on 4xx errors. + // consider response type (status, document) + if (result == null) + throw new JsonApiException(404, $"Could not find '{operation.Ref.Type}' record with id '{operation.Ref.Id}'"); + var doc = _documentBuilder.GetData( _contextGraph.GetContextEntity(operation.GetResourceTypeName()), result); diff --git a/test/OperationsExampleTests/Get/GetByIdTests.cs b/test/OperationsExampleTests/Get/GetByIdTests.cs new file mode 100644 index 0000000000..1dee2867ce --- /dev/null +++ b/test/OperationsExampleTests/Get/GetByIdTests.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Bogus; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCoreExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + public class GetTests : Fixture, IDisposable + { + private readonly Faker _faker = new Faker(); + + [Fact] + public async Task Can_Get_Author_By_Id() + { + // arrange + var context = GetService(); + var author = AuthorFactory.Get(); + context.Authors.Add(author); + context.SaveChanges(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "get"}, + { "ref", new { type = "authors", id = author.StringId } } + } + } + }; + + // act + var result = await PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(result.response); + Assert.NotNull(result.data); + Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); + Assert.Equal(1, result.data.Operations.Count); + Assert.Equal(author.Id.ToString(), result.data.Operations.Single().DataObject.Id); + } + + [Fact] + public async Task Get_Author_By_Id_Returns_404_If_NotFound() + { + // arrange + var authorId = _faker.Random.Int(max: 0).ToString(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "get"}, + { "ref", new { type = "authors", id = authorId } } + } + } + }; + + // act + var (response, data) = await PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + Assert.NotNull(data); + Assert.Equal(1, data.Errors.Count); + Assert.True(data.Errors[0].Detail.Contains("authors"), "The error detail should contain the name of the entity that could not be found."); + Assert.True(data.Errors[0].Detail.Contains(authorId), "The error detail should contain the entity id that could not be found"); + Assert.True(data.Errors[0].Title.Contains("operation[0]"), "The error title should contain the operation identifier that failed"); + } + } +} diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs index 1bf0393fa8..bf1c15e3a4 100644 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ b/test/OperationsExampleTests/Get/GetTests.cs @@ -11,7 +11,7 @@ namespace OperationsExampleTests { - public class GetTests : Fixture, IDisposable + public class GetByIdTests : Fixture, IDisposable { private readonly Faker _faker = new Faker(); @@ -46,36 +46,6 @@ public async Task Can_Get_Authors() Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); Assert.Equal(1, result.data.Operations.Count); Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count); - } - - [Fact] - public async Task Can_Get_Author_By_Id() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - context.Authors.Add(author); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "authors", id = author.StringId } } - } - } - }; - - // act - var result = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Equal(1, result.data.Operations.Count); - Assert.Equal(author.Id.ToString(), result.data.Operations.Single().DataObject.Id); } } } From 9e18ab3339314c71a90633017165a63868f04dc6 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 29 Mar 2018 09:15:13 -0500 Subject: [PATCH 113/227] introduce Is method on attributes for performing case insensitive comparisons --- .../Internal/ContextGraph.cs | 8 +-- .../Internal/Query/AttrFilterQuery.cs | 10 ++-- .../Internal/Query/RelatedAttrFilterQuery.cs | 13 ++--- src/JsonApiDotNetCore/Models/AttrAttribute.cs | 6 ++ .../Models/RelationshipAttribute.cs | 8 ++- src/JsonApiDotNetCore/Services/QueryParser.cs | 57 ++++++++++++------- 6 files changed, 61 insertions(+), 41 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs index bc3f037bf2..d21231f067 100644 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ContextGraph.cs @@ -9,8 +9,8 @@ public class ContextGraph : IContextGraph private List _entities; public ContextGraph() { } - - public ContextGraph(List entities, bool usesDbContext) + + public ContextGraph(List entities, bool usesDbContext) { _entities = entities; UsesDbContext = usesDbContext; @@ -42,9 +42,9 @@ public string GetRelationshipName(string relationshipName) { var entityType = typeof(TParent); return _entities - .SingleOrDefault(e => e.EntityType == entityType) + .SingleOrDefault(e => e.EntityType == entityType) ?.Relationships - .SingleOrDefault(r => string.Equals(r.PublicRelationshipName, relationshipName, StringComparison.OrdinalIgnoreCase)) + .SingleOrDefault(r => r.Is(relationshipName)) ?.InternalRelationshipName; } } diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index e94f872b54..59bb3f0f83 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -17,10 +17,10 @@ public AttrFilterQuery( var attribute = GetAttribute(filterQuery.Attribute); - if(attribute == null) + if (attribute == null) throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); - if(attribute.IsFilterable == false) + if (attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); FilteredAttribute = attribute; @@ -32,9 +32,7 @@ public AttrFilterQuery( public string PropertyValue { get; } public FilterOperations FilterOperation { get; } - private AttrAttribute GetAttribute(string attribute) => - _jsonApiContext.RequestEntity.Attributes.FirstOrDefault( - attr => string.Equals(attr.PublicAttributeName, attribute, StringComparison.OrdinalIgnoreCase) - ); + private AttrAttribute GetAttribute(string attribute) => + _jsonApiContext.RequestEntity.Attributes.FirstOrDefault(attr => attr.Is(attribute)); } } diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 52d7c66f41..5ec658873d 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -22,11 +22,11 @@ public RelatedAttrFilterQuery( throw new JsonApiException(400, $"{relationshipArray[1]} is not a valid relationship on {relationshipArray[0]}."); var attribute = GetAttribute(relationship, relationshipArray[1]); - - if(attribute == null) + + if (attribute == null) throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); - if(attribute.IsFilterable == false) + if (attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); FilteredRelationship = relationship; @@ -41,16 +41,13 @@ public RelatedAttrFilterQuery( public RelationshipAttribute FilteredRelationship { get; } private RelationshipAttribute GetRelationship(string propertyName) - { - return _jsonApiContext.RequestEntity.Relationships - .FirstOrDefault(r => string.Equals(r.PublicRelationshipName, propertyName, StringComparison.OrdinalIgnoreCase)); - } + => _jsonApiContext.RequestEntity.Relationships.FirstOrDefault(r => r.Is(propertyName)); private AttrAttribute GetAttribute(RelationshipAttribute relationship, string attribute) { var relatedContextExntity = _jsonApiContext.ContextGraph.GetContextEntity(relationship.Type); return relatedContextExntity.Attributes - .FirstOrDefault(a => string.Equals(a.PublicAttributeName, attribute, StringComparison.OrdinalIgnoreCase)); + .FirstOrDefault(a => a.Is(attribute)); } } } diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs index 5be036636d..db61cb56ea 100644 --- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs +++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs @@ -47,5 +47,11 @@ public void SetValue(object entity, object newValue) propertyInfo.SetValue(entity, convertedValue); } } + + /// + /// Whether or not the provided exposed name is equivalent to the one defined in on the model + /// + public virtual bool Is(string publicRelationshipName) + => string.Equals(publicRelationshipName, PublicAttributeName, StringComparison.OrdinalIgnoreCase); } } diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 852b602bea..0dbe6a4670 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace JsonApiDotNetCore.Models { @@ -33,5 +33,11 @@ public override bool Equals(object obj) } return IsHasMany == attr.IsHasMany && PublicRelationshipName.Equals(attr.PublicRelationshipName); } + + /// + /// Whether or not the provided exposed name is equivalent to the one defined in on the model + /// + public virtual bool Is(string publicRelationshipName) + => string.Equals(publicRelationshipName, PublicRelationshipName, StringComparison.OrdinalIgnoreCase); } } diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index d9dfab532d..5e705f4bc9 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -8,12 +8,15 @@ using JsonApiDotNetCore.Models; using Microsoft.AspNetCore.Http; -namespace JsonApiDotNetCore.Services { - public interface IQueryParser { +namespace JsonApiDotNetCore.Services +{ + public interface IQueryParser + { QuerySet Parse(IQueryCollection query); } - public class QueryParser : IQueryParser { + public class QueryParser : IQueryParser + { private readonly IControllerContext _controllerContext; private readonly JsonApiOptions _options; @@ -30,41 +33,49 @@ public class QueryParser : IQueryParser { public QueryParser( IControllerContext controllerContext, - JsonApiOptions options) { + JsonApiOptions options) + { _controllerContext = controllerContext; _options = options; } - public virtual QuerySet Parse(IQueryCollection query) { + public virtual QuerySet Parse(IQueryCollection query) + { var querySet = new QuerySet(); - var disabledQueries = _controllerContext.GetControllerAttribute() ? .QueryParams ?? QueryParams.None; + var disabledQueries = _controllerContext.GetControllerAttribute()?.QueryParams ?? QueryParams.None; - foreach (var pair in query) { - if (pair.Key.StartsWith(FILTER)) { + foreach (var pair in query) + { + if (pair.Key.StartsWith(FILTER)) + { if (disabledQueries.HasFlag(QueryParams.Filter) == false) querySet.Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); continue; } - if (pair.Key.StartsWith(SORT)) { + if (pair.Key.StartsWith(SORT)) + { if (disabledQueries.HasFlag(QueryParams.Sort) == false) querySet.SortParameters = ParseSortParameters(pair.Value); continue; } - if (pair.Key.StartsWith(INCLUDE)) { + if (pair.Key.StartsWith(INCLUDE)) + { if (disabledQueries.HasFlag(QueryParams.Include) == false) querySet.IncludedRelationships = ParseIncludedRelationships(pair.Value); continue; } - if (pair.Key.StartsWith(PAGE)) { + if (pair.Key.StartsWith(PAGE)) + { if (disabledQueries.HasFlag(QueryParams.Page) == false) querySet.PageQuery = ParsePageQuery(querySet.PageQuery, pair.Key, pair.Value); continue; } - if (pair.Key.StartsWith(FIELDS)) { + if (pair.Key.StartsWith(FIELDS)) + { if (disabledQueries.HasFlag(QueryParams.Fields) == false) querySet.Fields = ParseFieldsQuery(pair.Key, pair.Value); continue; @@ -77,15 +88,17 @@ public virtual QuerySet Parse(IQueryCollection query) { return querySet; } - protected virtual List ParseFilterQuery(string key, string value) { + protected virtual List ParseFilterQuery(string key, string value) + { // expected input = filter[id]=1 // expected input = filter[id]=eq:1 var queries = new List(); - var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET) [1]; + var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; var values = value.Split(COMMA); - foreach (var val in values) { + foreach (var val in values) + { (var operation, var filterValue) = ParseFilterOperation(val); queries.Add(new FilterQuery(propertyName, filterValue, operation)); } @@ -93,7 +106,8 @@ protected virtual List ParseFilterQuery(string key, string value) { return queries; } - protected virtual(string operation, string value) ParseFilterOperation(string value) { + protected virtual (string operation, string value) ParseFilterOperation(string value) + { if (value.Length < 3) return (string.Empty, value); @@ -159,7 +173,7 @@ protected virtual List ParseSortParameters(string value) var attribute = GetAttribute(propertyName); - if(attribute.IsSortable == false) + if (attribute.IsSortable == false) throw new JsonApiException(400, $"Sort is not allowed for attribute '{attribute.PublicAttributeName}'."); sortParameters.Add(new SortQuery(direction, attribute)); @@ -168,7 +182,8 @@ protected virtual List ParseSortParameters(string value) return sortParameters; } - protected virtual List ParseIncludedRelationships(string value) { + protected virtual List ParseIncludedRelationships(string value) + { const string NESTED_DELIMITER = "."; if (value.Contains(NESTED_DELIMITER)) throw new JsonApiException(400, "Deeply nested relationships are not supported"); @@ -195,7 +210,7 @@ protected virtual List ParseFieldsQuery(string key, string value) { var attr = _controllerContext.RequestEntity .Attributes - .SingleOrDefault(a => string.Equals(a.PublicAttributeName, field, StringComparison.OrdinalIgnoreCase)); + .SingleOrDefault(a => a.Is(field)); if (attr == null) throw new JsonApiException(400, $"'{_controllerContext.RequestEntity.EntityName}' does not contain '{field}'."); @@ -213,9 +228,7 @@ protected virtual AttrAttribute GetAttribute(string propertyName) return _controllerContext .RequestEntity .Attributes - .Single(attr => - string.Equals(attr.PublicAttributeName, propertyName, StringComparison.OrdinalIgnoreCase) - ); + .Single(attr => attr.Is(propertyName)); } catch (InvalidOperationException e) { From 59fc19a539cfb1c23a8ab827a98642013dcb0b7e Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 29 Mar 2018 09:20:08 -0500 Subject: [PATCH 114/227] support get relationship requests in operations --- .../Builders/DocumentBuilderOptions.cs | 6 +-- .../Configuration/JsonApiOptions.cs | 9 ++-- .../IServiceCollectionExtensions.cs | 3 ++ .../Services/EntityResourceService.cs | 2 + .../Operations/Processors/GetOpProcessor.cs | 48 +++++++++++++++-- src/JsonApiDotNetCore/api/.manifest | 6 ++- .../Get/GetRelationshipTests.cs | 52 +++++++++++++++++++ 7 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 test/OperationsExampleTests/Get/GetRelationshipTests.cs diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs index ec19977313..0596d8ce3c 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilderOptions.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace JsonApiDotNetCore.Builders { - public struct DocumentBuilderOptions + public struct DocumentBuilderOptions { public DocumentBuilderOptions(bool omitNullValuedAttributes = false) { diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index abcb3f6dbf..dd76eeba2c 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -52,7 +52,7 @@ public class JsonApiOptions /// options.AllowClientGeneratedIds = true; /// public bool AllowClientGeneratedIds { get; set; } - + /// /// The graph of all resources exposed by this application. /// @@ -107,10 +107,11 @@ public class JsonApiOptions /// /// Whether or not to allow json:api v1.1 operation requests. /// This is a beta feature and there may be breaking changes - /// in subsequent releases. + /// in subsequent releases. For now, it should be considered + /// experimental. /// /// - /// This will be enabled by default in JsonApiDotNetCore v2.2.1 + /// This will be enabled by default in a subsequent patch JsonApiDotNetCore v2.2.x /// public bool EnableOperations { get; set; } @@ -144,7 +145,7 @@ public void BuildContextGraph(Action builder) ContextGraph = ContextGraphBuilder.Build(); } - public void EnableExtension(JsonApiExtension extension) + public void EnableExtension(JsonApiExtension extension) => EnabledExtensions.Add(extension); internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder(); diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 0b13755edc..807d21c018 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -109,6 +109,9 @@ public static void AddJsonApiInternals( services.AddScoped(typeof(IGetByIdService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IGetByIdService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IGetRelationshipService<,>), typeof(EntityResourceService<>)); + services.AddScoped(typeof(IGetRelationshipService<,>), typeof(EntityResourceService<,>)); + services.AddScoped(typeof(IUpdateService<>), typeof(EntityResourceService<>)); services.AddScoped(typeof(IUpdateService<,>), typeof(EntityResourceService<,>)); diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index af86692166..91eabb9cfd 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -96,6 +96,8 @@ public virtual async Task GetRelationshipAsync(TId id, string relationsh _logger.LogTrace($"Looking up '{relationshipName}'..."); var entity = await _entities.GetAndIncludeAsync(id, relationshipName); + // TODO: it would be better if we could distinguish whether or not the relationship was not found, + // vs the relationship not being set on the instance of T if (entity == null) throw new JsonApiException(404, $"Relationship {relationshipName} not found."); diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs index bbcdf0d8a0..d8793d016c 100644 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs +++ b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Internal; @@ -8,41 +10,57 @@ namespace JsonApiDotNetCore.Services.Operations.Processors { + /// + /// Handles all "" operations + /// + /// The resource type public interface IGetOpProcessor : IOpProcessor where T : class, IIdentifiable { } + /// + /// Handles all "" operations + /// + /// The resource type + /// The resource identifier type public interface IGetOpProcessor : IOpProcessor where T : class, IIdentifiable { } + /// public class GetOpProcessor : GetOpProcessor where T : class, IIdentifiable { + /// public GetOpProcessor( IGetAllService getAll, IGetByIdService getById, + IGetRelationshipService getRelationship, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, IContextGraph contextGraph, IJsonApiContext jsonApiContext - ) : base(getAll, getById, deSerializer, documentBuilder, contextGraph, jsonApiContext) + ) : base(getAll, getById, getRelationship, deSerializer, documentBuilder, contextGraph, jsonApiContext) { } } + /// public class GetOpProcessor : IGetOpProcessor where T : class, IIdentifiable { private readonly IGetAllService _getAll; private readonly IGetByIdService _getById; + private readonly IGetRelationshipService _getRelationship; private readonly IJsonApiDeSerializer _deSerializer; private readonly IDocumentBuilder _documentBuilder; private readonly IContextGraph _contextGraph; private readonly IJsonApiContext _jsonApiContext; + /// public GetOpProcessor( IGetAllService getAll, IGetByIdService getById, + IGetRelationshipService getRelationship, IJsonApiDeSerializer deSerializer, IDocumentBuilder documentBuilder, IContextGraph contextGraph, @@ -50,12 +68,14 @@ public GetOpProcessor( { _getAll = getAll; _getById = getById; + _getRelationship = getRelationship; _deSerializer = deSerializer; _documentBuilder = documentBuilder; _contextGraph = contextGraph; _jsonApiContext = jsonApiContext.ApplyContext(this); } + /// public async Task ProcessAsync(Operation operation) { var operationResult = new Operation @@ -63,9 +83,11 @@ public async Task ProcessAsync(Operation operation) Op = OperationCode.get }; - operationResult.Data = string.IsNullOrWhiteSpace(operation.Ref.Id?.ToString()) + operationResult.Data = string.IsNullOrWhiteSpace(operation.Ref.Id) ? await GetAllAsync(operation) - : await GetByIdAsync(operation); + : string.IsNullOrWhiteSpace(operation.Ref.Relationship) + ? await GetByIdAsync(operation) + : await GetRelationshipAsync(operation); return operationResult; } @@ -88,7 +110,7 @@ private async Task GetAllAsync(Operation operation) private async Task GetByIdAsync(Operation operation) { - var id = TypeHelper.ConvertType(operation.Ref.Id); + var id = GetReferenceId(operation); var result = await _getById.GetAsync(id); // this is a bit ugly but we need to bomb the entire transaction if the entity cannot be found @@ -104,5 +126,23 @@ private async Task GetByIdAsync(Operation operation) return doc; } + + private async Task GetRelationshipAsync(Operation operation) + { + var id = GetReferenceId(operation); + var result = await _getRelationship.GetRelationshipAsync(id, operation.Ref.Relationship); + + // TODO: need a better way to get the ContextEntity from a relationship name + // when no generic parameter is available + var relationshipType = _contextGraph.GetContextEntity(operation.GetResourceTypeName()) + .Relationships.Single(r => r.Is(operation.Ref.Relationship)).Type; + var relatedContextEntity = _jsonApiContext.ContextGraph.GetContextEntity(relationshipType); + + var doc = _documentBuilder.GetData(relatedContextEntity, result as IIdentifiable); // TODO: if this is safe, then it should be cast in the GetRelationshipAsync call + + return doc; + } + + private TId GetReferenceId(Operation operation) => TypeHelper.ConvertType(operation.Ref.Id); } } diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index 211035306f..43cb398351 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -381,6 +381,7 @@ "JsonApiDotNetCore.Models.AttrAttribute.#ctor(System.String,System.Boolean,System.Boolean,System.Boolean)": "JsonApiDotNetCore.Models.AttrAttribute.yml", "JsonApiDotNetCore.Models.AttrAttribute.GetValue(System.Object)": "JsonApiDotNetCore.Models.AttrAttribute.yml", "JsonApiDotNetCore.Models.AttrAttribute.InternalAttributeName": "JsonApiDotNetCore.Models.AttrAttribute.yml", + "JsonApiDotNetCore.Models.AttrAttribute.Is(System.String)": "JsonApiDotNetCore.Models.AttrAttribute.yml", "JsonApiDotNetCore.Models.AttrAttribute.IsFilterable": "JsonApiDotNetCore.Models.AttrAttribute.yml", "JsonApiDotNetCore.Models.AttrAttribute.IsImmutable": "JsonApiDotNetCore.Models.AttrAttribute.yml", "JsonApiDotNetCore.Models.AttrAttribute.IsSortable": "JsonApiDotNetCore.Models.AttrAttribute.yml", @@ -459,6 +460,7 @@ "JsonApiDotNetCore.Models.RelationshipAttribute.DocumentLinks": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.Equals(System.Object)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.InternalRelationshipName": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", + "JsonApiDotNetCore.Models.RelationshipAttribute.Is(System.String)": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.IsHasMany": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.IsHasOne": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", "JsonApiDotNetCore.Models.RelationshipAttribute.PublicRelationshipName": "JsonApiDotNetCore.Models.RelationshipAttribute.yml", @@ -638,9 +640,9 @@ "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`2.#ctor(JsonApiDotNetCore.Services.ICreateService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph)": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.CreateOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-1.yml", - "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,System.Int32},JsonApiDotNetCore.Services.IGetByIdService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-1.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`1.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,System.Int32},JsonApiDotNetCore.Services.IGetByIdService{`0,System.Int32},JsonApiDotNetCore.Services.IGetRelationshipService{`0,System.Int32},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-1.yml", "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", - "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,`1},JsonApiDotNetCore.Services.IGetByIdService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", + "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2.#ctor(JsonApiDotNetCore.Services.IGetAllService{`0,`1},JsonApiDotNetCore.Services.IGetByIdService{`0,`1},JsonApiDotNetCore.Services.IGetRelationshipService{`0,`1},JsonApiDotNetCore.Serialization.IJsonApiDeSerializer,JsonApiDotNetCore.Builders.IDocumentBuilder,JsonApiDotNetCore.Internal.IContextGraph,JsonApiDotNetCore.Services.IJsonApiContext)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor`2.ProcessAsync(JsonApiDotNetCore.Models.Operations.Operation)": "JsonApiDotNetCore.Services.Operations.Processors.GetOpProcessor-2.yml", "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor`1": "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor-1.yml", "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor`2": "JsonApiDotNetCore.Services.Operations.Processors.ICreateOpProcessor-2.yml", diff --git a/test/OperationsExampleTests/Get/GetRelationshipTests.cs b/test/OperationsExampleTests/Get/GetRelationshipTests.cs new file mode 100644 index 0000000000..03f276da17 --- /dev/null +++ b/test/OperationsExampleTests/Get/GetRelationshipTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Bogus; +using JsonApiDotNetCore.Models.Operations; +using JsonApiDotNetCoreExample.Data; +using OperationsExampleTests.Factories; +using Xunit; + +namespace OperationsExampleTests +{ + public class GetRelationshipTests : Fixture, IDisposable + { + private readonly Faker _faker = new Faker(); + + [Fact] + public async Task Can_Get_Article_Author() + { + // arrange + var context = GetService(); + var author = AuthorFactory.Get(); + var article = ArticleFactory.Get(); + article.Author = author; + context.Articles.Add(article); + context.SaveChanges(); + + var content = new + { + operations = new[] { + new Dictionary { + { "op", "get"}, + { "ref", new { type = "articles", id = article.StringId, relationship = nameof(article.Author) } } + } + } + }; + + // act + var (response, data) = await PatchAsync("api/bulk", content); + + // assert + Assert.NotNull(response); + Assert.NotNull(data); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(1, data.Operations.Count); + var resourceObject = data.Operations.Single().DataObject; + Assert.Equal(author.Id.ToString(), resourceObject.Id); + Assert.Equal("authors", resourceObject.Type); + } + } +} From 08f71afcb75bf3965b5a25a741f70d85d442a29f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 31 Mar 2018 11:12:20 -0500 Subject: [PATCH 115/227] return 409 for mismatching data types --- .../Internal/JsonApiExceptionFactory.cs | 12 +++++++++-- src/JsonApiDotNetCore/api/.manifest | 21 +++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs index 20ae9ebc62..159c9abc70 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiExceptionFactory.cs @@ -8,9 +8,17 @@ public static JsonApiException GetException(Exception exception) { var exceptionType = exception.GetType(); - if(exceptionType == typeof(JsonApiException)) + if (exceptionType == typeof(JsonApiException)) return (JsonApiException)exception; - + + // TODO: this is for mismatching type requests (e.g. posting an author to articles endpoint) + // however, we can't actually guarantee that this is the source of this exception + // we should probably use an action filter or when we improve the ContextGraph + // we might be able to skip most of deserialization entirely by checking the JToken + // directly + if (exceptionType == typeof(InvalidCastException)) + return new JsonApiException(409, exception.Message, exception); + return new JsonApiException(500, exceptionType.Name, exception); } } diff --git a/src/JsonApiDotNetCore/api/.manifest b/src/JsonApiDotNetCore/api/.manifest index 43cb398351..41d94c66fb 100644 --- a/src/JsonApiDotNetCore/api/.manifest +++ b/src/JsonApiDotNetCore/api/.manifest @@ -54,6 +54,8 @@ "JsonApiDotNetCore.Configuration.JsonApiOptions.BuildContextGraph``1(System.Action{JsonApiDotNetCore.Builders.IContextGraphBuilder})": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", "JsonApiDotNetCore.Configuration.JsonApiOptions.ContextGraph": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", "JsonApiDotNetCore.Configuration.JsonApiOptions.DefaultPageSize": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.DisableErrorSource": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", + "JsonApiDotNetCore.Configuration.JsonApiOptions.DisableErrorStackTraces": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", "JsonApiDotNetCore.Configuration.JsonApiOptions.EnableExtension(JsonApiDotNetCore.Models.JsonApiExtension)": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", "JsonApiDotNetCore.Configuration.JsonApiOptions.EnableOperations": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", "JsonApiDotNetCore.Configuration.JsonApiOptions.IncludeTotalRecordCount": "JsonApiDotNetCore.Configuration.JsonApiOptions.yml", @@ -261,11 +263,15 @@ "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.Apply(Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel)": "JsonApiDotNetCore.Internal.DasherizedRoutingConvention.yml", "JsonApiDotNetCore.Internal.Error": "JsonApiDotNetCore.Internal.Error.yml", "JsonApiDotNetCore.Internal.Error.#ctor": "JsonApiDotNetCore.Internal.Error.yml", - "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String)": "JsonApiDotNetCore.Internal.Error.yml", - "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", - "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", - "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String,JsonApiDotNetCore.Internal.ErrorMeta,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.Int32,System.String,System.String,JsonApiDotNetCore.Internal.ErrorMeta,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String,JsonApiDotNetCore.Internal.ErrorMeta,System.String)": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.#ctor(System.String,System.String,System.String,JsonApiDotNetCore.Internal.ErrorMeta,System.String)": "JsonApiDotNetCore.Internal.Error.yml", "JsonApiDotNetCore.Internal.Error.Detail": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.Meta": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.ShouldSerializeMeta": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.ShouldSerializeSource": "JsonApiDotNetCore.Internal.Error.yml", + "JsonApiDotNetCore.Internal.Error.Source": "JsonApiDotNetCore.Internal.Error.yml", "JsonApiDotNetCore.Internal.Error.Status": "JsonApiDotNetCore.Internal.Error.yml", "JsonApiDotNetCore.Internal.Error.StatusCode": "JsonApiDotNetCore.Internal.Error.yml", "JsonApiDotNetCore.Internal.Error.Title": "JsonApiDotNetCore.Internal.Error.yml", @@ -274,6 +280,9 @@ "JsonApiDotNetCore.Internal.ErrorCollection.Add(JsonApiDotNetCore.Internal.Error)": "JsonApiDotNetCore.Internal.ErrorCollection.yml", "JsonApiDotNetCore.Internal.ErrorCollection.Errors": "JsonApiDotNetCore.Internal.ErrorCollection.yml", "JsonApiDotNetCore.Internal.ErrorCollection.GetJson": "JsonApiDotNetCore.Internal.ErrorCollection.yml", + "JsonApiDotNetCore.Internal.ErrorMeta": "JsonApiDotNetCore.Internal.ErrorMeta.yml", + "JsonApiDotNetCore.Internal.ErrorMeta.FromException(System.Exception)": "JsonApiDotNetCore.Internal.ErrorMeta.yml", + "JsonApiDotNetCore.Internal.ErrorMeta.StackTrace": "JsonApiDotNetCore.Internal.ErrorMeta.yml", "JsonApiDotNetCore.Internal.Generics": "JsonApiDotNetCore.Internal.Generics.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessor`1": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-1.yml", "JsonApiDotNetCore.Internal.Generics.GenericProcessor`1.#ctor(JsonApiDotNetCore.Data.IDbContextResolver)": "JsonApiDotNetCore.Internal.Generics.GenericProcessor-1.yml", @@ -300,11 +309,11 @@ "JsonApiDotNetCore.Internal.JsonApiException": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.#ctor(JsonApiDotNetCore.Internal.Error)": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.#ctor(JsonApiDotNetCore.Internal.ErrorCollection)": "JsonApiDotNetCore.Internal.JsonApiException.yml", - "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String,System.Exception)": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", - "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.Int32,System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", + "JsonApiDotNetCore.Internal.JsonApiException.#ctor(System.String,System.String,System.String,System.String)": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.GetError": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiException.GetStatusCode": "JsonApiDotNetCore.Internal.JsonApiException.yml", "JsonApiDotNetCore.Internal.JsonApiExceptionFactory": "JsonApiDotNetCore.Internal.JsonApiExceptionFactory.yml", From 7ba47cd38e0aefe98ee46b8c9496efcf8648a0ea Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 1 Apr 2018 05:48:14 -0500 Subject: [PATCH 116/227] Update README.md --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index f396be824b..c09fe884b6 100644 --- a/README.md +++ b/README.md @@ -58,13 +58,3 @@ public class Startup } } ``` - -## Development Priorities - -The current priorities for future development (in order): -1. Operations Support ([#150](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/150)) -2. Minor features ([#105](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/105), [#144](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/144), [#162](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/162)) -3. Resource to Entity Mapping ([#112](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/112)) - -If you're interested in working on any of the above features, take a look at the [Contributing Guide](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/CONTRIBUTING.MD) -or hop on the project Gitter for more direct communication. From 3989d3f3fc150baf166bff8d86c0385c93bec1a9 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 4 Apr 2018 15:50:21 -0500 Subject: [PATCH 117/227] fix(ContextGraphBuilder): don't throw if DbContext contains non json:api resource Also begins work for #170 --- .../Data/AppDbContext.cs | 2 + .../Models/NonJsonApiResource.cs | 7 +++ .../Builders/ContextGraphBuilder.cs | 53 +++++++++++++++++-- .../Builders/IContextGraphBuilder.cs | 15 ------ .../IApplicationBuilderExtensions.cs | 38 ++++++++++--- .../Internal/ContextGraph.cs | 32 +++++++++-- .../Internal/IContextGraph.cs | 13 ----- .../Internal/ValidationResults.cs | 16 ++++++ .../Internal/ContextGraphBuilder_Tests.cs | 48 +++++++++++++++++ 9 files changed, 180 insertions(+), 44 deletions(-) create mode 100644 src/Examples/JsonApiDotNetCoreExample/Models/NonJsonApiResource.cs delete mode 100644 src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs delete mode 100644 src/JsonApiDotNetCore/Internal/IContextGraph.cs create mode 100644 src/JsonApiDotNetCore/Internal/ValidationResults.cs create mode 100644 test/UnitTests/Internal/ContextGraphBuilder_Tests.cs diff --git a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs index 4266ca9741..4b9a40f7fd 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs @@ -37,5 +37,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) public DbSet
Articles { get; set; } public DbSet Authors { get; set; } + + public DbSet NonJsonApiResources { get; set; } } } diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/NonJsonApiResource.cs b/src/Examples/JsonApiDotNetCoreExample/Models/NonJsonApiResource.cs new file mode 100644 index 0000000000..7f979f4cfb --- /dev/null +++ b/src/Examples/JsonApiDotNetCoreExample/Models/NonJsonApiResource.cs @@ -0,0 +1,7 @@ +namespace JsonApiDotNetCoreExample.Models +{ + public class NonJsonApiResource + { + public int Id { get; set; } + } +} diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index 643df13bc3..73e355b2de 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -6,12 +6,50 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Builders { + public interface IContextGraphBuilder + { + /// + /// Construct the + /// + IContextGraph Build(); + + /// + /// Add a json:api resource + /// + /// The resource model type + /// The pluralized name that should be exposed by the API + IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; + + /// + /// Add a json:api resource + /// + /// The resource model type + /// The resource model identifier type + /// The pluralized name that should be exposed by the API + IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; + + /// + /// Add all the models that are part of the provided + /// that also implement + /// + /// The implementation type. + IContextGraphBuilder AddDbContext() where T : DbContext; + + /// + /// Which links to include. Defaults to . + /// + Link DocumentLinks { get; set; } + } + public class ContextGraphBuilder : IContextGraphBuilder { private List _entities = new List(); + private List _validationResults = new List(); + private bool _usesDbContext; public Link DocumentLinks { get; set; } = Link.All; @@ -20,7 +58,7 @@ public IContextGraph Build() // this must be done at build so that call order doesn't matter _entities.ForEach(e => e.Links = GetLinkFlags(e.EntityType)); - var graph = new ContextGraph(_entities, _usesDbContext); + var graph = new ContextGraph(_entities, _usesDbContext, _validationResults); return graph; } @@ -117,7 +155,10 @@ public IContextGraphBuilder AddDbContext() where T : DbContext AssertEntityIsNotAlreadyDefined(entityType); - _entities.Add(GetEntity(GetResourceName(property), entityType, GetIdType(entityType))); + var (isJsonApiResource, idType) = GetIdType(entityType); + + if (isJsonApiResource) + _entities.Add(GetEntity(GetResourceName(property), entityType, idType)); } } @@ -133,16 +174,18 @@ private string GetResourceName(PropertyInfo property) return ((ResourceAttribute)resourceAttribute).ResourceName; } - private Type GetIdType(Type resourceType) + private (bool isJsonApiResource, Type idType) GetIdType(Type resourceType) { var interfaces = resourceType.GetInterfaces(); foreach (var type in interfaces) { if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IIdentifiable<>)) - return type.GetGenericArguments()[0]; + return (true, type.GetGenericArguments()[0]); } - throw new ArgumentException("Type does not implement 'IIdentifiable'", nameof(resourceType)); + _validationResults.Add(new ValidationResult(LogLevel.Warning, $"{resourceType} does not implement 'IIdentifiable<>'. ")); + + return (false, null); } private void AssertEntityIsNotAlreadyDefined(Type entityType) diff --git a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs deleted file mode 100644 index 9f3c7bd1a8..0000000000 --- a/src/JsonApiDotNetCore/Builders/IContextGraphBuilder.cs +++ /dev/null @@ -1,15 +0,0 @@ -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models; -using Microsoft.EntityFrameworkCore; - -namespace JsonApiDotNetCore.Builders -{ - public interface IContextGraphBuilder - { - Link DocumentLinks { get; set; } - IContextGraph Build(); - IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; - IContextGraphBuilder AddResource(string pluralizedTypeName) where TResource : class, IIdentifiable; - IContextGraphBuilder AddDbContext() where T : DbContext; - } -} diff --git a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs index 651fbb44aa..996d7eb9de 100644 --- a/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs @@ -1,7 +1,10 @@ +using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Middleware; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Extensions { @@ -9,21 +12,44 @@ namespace JsonApiDotNetCore.Extensions public static class IApplicationBuilderExtensions { public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool useMvc = true) + { + DisableDetailedErrorsIfProduction(app); + LogContextGraphValidations(app); + + app.UseMiddleware(); + + if (useMvc) + app.UseMvc(); + + return app; + } + + private static void DisableDetailedErrorsIfProduction(IApplicationBuilder app) { var environment = (IHostingEnvironment)app.ApplicationServices.GetService(typeof(IHostingEnvironment)); - if(environment.IsProduction()) + if (environment.IsProduction()) { JsonApiOptions.DisableErrorStackTraces = true; JsonApiOptions.DisableErrorSource = true; } + } - app.UseMiddleware(); - - if (useMvc) - app.UseMvc(); + private static void LogContextGraphValidations(IApplicationBuilder app) + { + var logger = app.ApplicationServices.GetService(typeof(ILogger)) as ILogger; + var contextGraph = app.ApplicationServices.GetService(typeof(IContextGraph)) as ContextGraph; - return app; + if (logger != null && contextGraph != null) + { + contextGraph.ValidationResults.ForEach((v) => + logger.Log( + v.LogLevel, + new EventId(), + v.Message, + exception: null, + formatter: (m, e) => m)); + } } } } diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs index d21231f067..c27a01b7d8 100644 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ContextGraph.cs @@ -4,25 +4,47 @@ namespace JsonApiDotNetCore.Internal { + public interface IContextGraph + { + object GetRelationship(TParent entity, string relationshipName); + string GetRelationshipName(string relationshipName); + ContextEntity GetContextEntity(string dbSetName); + ContextEntity GetContextEntity(Type entityType); + bool UsesDbContext { get; } + } + public class ContextGraph : IContextGraph { - private List _entities; + internal List Entities { get; } + internal List ValidationResults { get; } public ContextGraph() { } public ContextGraph(List entities, bool usesDbContext) { - _entities = entities; + Entities = entities; + UsesDbContext = usesDbContext; + ValidationResults = new List(); + } + + // eventually, this is the planned public constructor + // to avoid breaking changes, we will be leaving the original constructor in place + // until the context graph validation process is completed + // you can track progress on this issue here: https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/170 + internal ContextGraph(List entities, bool usesDbContext, List validationResults) + { + Entities = entities; UsesDbContext = usesDbContext; + ValidationResults = validationResults; } public bool UsesDbContext { get; } public ContextEntity GetContextEntity(string entityName) - => _entities.SingleOrDefault(e => string.Equals(e.EntityName, entityName, StringComparison.OrdinalIgnoreCase)); + => Entities.SingleOrDefault(e => string.Equals(e.EntityName, entityName, StringComparison.OrdinalIgnoreCase)); public ContextEntity GetContextEntity(Type entityType) - => _entities.SingleOrDefault(e => e.EntityType == entityType); + => Entities.SingleOrDefault(e => e.EntityType == entityType); public object GetRelationship(TParent entity, string relationshipName) { @@ -41,7 +63,7 @@ public object GetRelationship(TParent entity, string relationshipName) public string GetRelationshipName(string relationshipName) { var entityType = typeof(TParent); - return _entities + return Entities .SingleOrDefault(e => e.EntityType == entityType) ?.Relationships .SingleOrDefault(r => r.Is(relationshipName)) diff --git a/src/JsonApiDotNetCore/Internal/IContextGraph.cs b/src/JsonApiDotNetCore/Internal/IContextGraph.cs deleted file mode 100644 index 5aa05bdacd..0000000000 --- a/src/JsonApiDotNetCore/Internal/IContextGraph.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace JsonApiDotNetCore.Internal -{ - public interface IContextGraph - { - object GetRelationship(TParent entity, string relationshipName); - string GetRelationshipName(string relationshipName); - ContextEntity GetContextEntity(string dbSetName); - ContextEntity GetContextEntity(Type entityType); - bool UsesDbContext { get; } - } -} diff --git a/src/JsonApiDotNetCore/Internal/ValidationResults.cs b/src/JsonApiDotNetCore/Internal/ValidationResults.cs new file mode 100644 index 0000000000..fbaa6eb462 --- /dev/null +++ b/src/JsonApiDotNetCore/Internal/ValidationResults.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Logging; + +namespace JsonApiDotNetCore.Internal +{ + internal class ValidationResult + { + public ValidationResult(LogLevel logLevel, string message) + { + LogLevel = logLevel; + Message = message; + } + + public LogLevel LogLevel { get; set; } + public string Message { get; set; } + } +} diff --git a/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs b/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs new file mode 100644 index 0000000000..ce8316b89d --- /dev/null +++ b/test/UnitTests/Internal/ContextGraphBuilder_Tests.cs @@ -0,0 +1,48 @@ +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Internal; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace UnitTests.Internal +{ + public class ContextGraphBuilder_Tests + { + [Fact] + public void AddDbContext_Does_Not_Throw_If_Context_Contains_Members_That_DoNot_Implement_IIdentifiable() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + + // act + contextGraphBuilder.AddDbContext(); + var contextGraph = contextGraphBuilder.Build() as ContextGraph; + + // assert + Assert.Empty(contextGraph.Entities); + } + + [Fact] + public void Adding_DbContext_Members_That_DoNot_Implement_IIdentifiable_Creates_Warning() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + + // act + contextGraphBuilder.AddDbContext(); + var contextGraph = contextGraphBuilder.Build() as ContextGraph; + + // assert + Assert.Equal(1, contextGraph.ValidationResults.Count); + Assert.Contains(contextGraph.ValidationResults, v => v.LogLevel == LogLevel.Warning); + } + + private class Foo { } + + private class TestContext : DbContext + { + public DbSet Foos { get; set; } + } + } + +} From 132050e96f53189dda2e7bad9b1ed593250a5b00 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Wed, 4 Apr 2018 15:51:18 -0500 Subject: [PATCH 118/227] chore(csproj): bump package version to 2.2.1 --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 5aa6b6b897..c4b9a6d932 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.2.0 + 2.2.1 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore From dd12e38af4317dd51b917b0d7886acd160797f13 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 18:33:55 -0500 Subject: [PATCH 119/227] fix(Deserializer): remove dependency on GenericProcessorFactory Rather than fetching data from the database during deserialization, we can set the relationships with instances that just carry the id. It will then be the responsibility of the repository to handle those relationships --- .../Extensions/TypeExtensions.cs | 23 ++++++++++ .../Serialization/JsonApiDeSerializer.cs | 29 ++++++++---- .../Extensions/TypeExtensions_Tests.cs | 44 +++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 test/UnitTests/Extensions/TypeExtensions_Tests.cs diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index ccc4619966..a78f545e81 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -31,5 +31,28 @@ public static Type GetElementType(this IEnumerable enumerable) return elementType; } + + /// + /// Creates a List{TInterface} where TInterface is the generic for type specified by t + /// + public static List GetEmptyCollection(this Type t) + { + if (t == null) throw new ArgumentNullException(nameof(t)); + + var listType = typeof(List<>).MakeGenericType(t); + var list = (List)Activator.CreateInstance(listType); + return list; + } + + /// + /// Creates a new instance of type t, casting it to the specified TInterface + /// + public static TInterface New(this Type t) + { + if (t == null) throw new ArgumentNullException(nameof(t)); + + var instance = (TInterface)Activator.CreateInstance(t); + return instance; + } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 649d6435ff..37e0314da6 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -9,20 +9,27 @@ using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using JsonApiDotNetCore.Extensions; namespace JsonApiDotNetCore.Serialization { public class JsonApiDeSerializer : IJsonApiDeSerializer { private readonly IJsonApiContext _jsonApiContext; - private readonly IGenericProcessorFactory _genericProcessorFactory; + [Obsolete( + "The deserializer no longer depends on the IGenericProcessorFactory", + error: false)] public JsonApiDeSerializer( IJsonApiContext jsonApiContext, IGenericProcessorFactory genericProcessorFactory) { _jsonApiContext = jsonApiContext; - _genericProcessorFactory = genericProcessorFactory; + } + + public JsonApiDeSerializer(IJsonApiContext jsonApiContext) + { + _jsonApiContext = jsonApiContext; } public object Deserialize(string requestBody) @@ -225,10 +232,11 @@ private object SetHasManyRelationship(object entity, ContextEntity contextEntity, Dictionary relationships) { - var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); + // TODO: is this necessary? if not, remove + // var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); - if (entityProperty == null) - throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain an relationsip named {attr.InternalRelationshipName}"); + // if (entityProperty == null) + // throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a relationsip named '{attr.InternalRelationshipName}'"); var relationshipName = attr.PublicRelationshipName; @@ -238,11 +246,16 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var genericProcessor = _genericProcessorFactory.GetProcessor(typeof(GenericProcessor<>), attr.Type); + var resourceRelationships = attr.Type.GetEmptyCollection(); - var ids = relationshipData.ManyData.Select(r => r.Id); + var relationshipShells = relationshipData.ManyData.Select(r => + { + var instance = attr.Type.New(); + instance.StringId = r.Id; + return instance; + }); - genericProcessor.SetRelationships(entity, attr, ids); + attr.SetValue(entity, relationshipShells); } return entity; diff --git a/test/UnitTests/Extensions/TypeExtensions_Tests.cs b/test/UnitTests/Extensions/TypeExtensions_Tests.cs new file mode 100644 index 0000000000..92534eef5d --- /dev/null +++ b/test/UnitTests/Extensions/TypeExtensions_Tests.cs @@ -0,0 +1,44 @@ +using JsonApiDotNetCore.Models; +using Xunit; +using JsonApiDotNetCore.Extensions; +using System.Collections.Generic; + +namespace UnitTests.Extensions +{ + public class TypeExtensions_Tests + { + [Fact] + public void GetCollection_Creates_List_If_T_Implements_Interface() + { + // arrange + var type = typeof(Model); + + // act + var collection = type.GetEmptyCollection(); + + // assert + Assert.NotNull(collection); + Assert.Empty(collection); + Assert.IsType>(collection); + } + + [Fact] + public void New_Creates_An_Instance_If_T_Implements_Interface() + { + // arrange + var type = typeof(Model); + + // act + var instance = type.New(); + + // assert + Assert.NotNull(instance); + Assert.IsType(instance); + } + + private class Model : IIdentifiable + { + public string StringId { get; set; } + } + } +} From e5a0f6d05452fc78fe6d82268cb7e46fee8c1680 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 19:08:18 -0500 Subject: [PATCH 120/227] fix(typeExtensions): cast to IEnumerable using covariance --- src/JsonApiDotNetCore/Extensions/TypeExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index a78f545e81..efe29620f8 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -35,12 +35,12 @@ public static Type GetElementType(this IEnumerable enumerable) /// /// Creates a List{TInterface} where TInterface is the generic for type specified by t /// - public static List GetEmptyCollection(this Type t) + public static IEnumerable GetEmptyCollection(this Type t) { if (t == null) throw new ArgumentNullException(nameof(t)); var listType = typeof(List<>).MakeGenericType(t); - var list = (List)Activator.CreateInstance(listType); + var list = (IEnumerable)Activator.CreateInstance(listType); return list; } From 79084ba162bee0c69f55390cf5339898d1b5b94f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 20:57:26 -0500 Subject: [PATCH 121/227] fix(Deserializer): properly convert collection type when setting it on the model --- src/JsonApiDotNetCore/Extensions/TypeExtensions.cs | 4 ++-- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 10 ++++++++++ src/JsonApiDotNetCore/Models/HasManyAttribute.cs | 2 +- .../Serialization/JsonApiDeSerializer.cs | 10 ++++++---- test/UnitTests/Extensions/TypeExtensions_Tests.cs | 6 +++--- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index efe29620f8..8cc7c0dffe 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -35,12 +35,12 @@ public static Type GetElementType(this IEnumerable enumerable) /// /// Creates a List{TInterface} where TInterface is the generic for type specified by t /// - public static IEnumerable GetEmptyCollection(this Type t) + public static IEnumerable GetEmptyCollection(this Type t) { if (t == null) throw new ArgumentNullException(nameof(t)); var listType = typeof(List<>).MakeGenericType(t); - var list = (IEnumerable)Activator.CreateInstance(listType); + var list = (IEnumerable)Activator.CreateInstance(listType); return list; } diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index cc64b398dd..2493bfab4a 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -1,10 +1,20 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Reflection; namespace JsonApiDotNetCore.Internal { public static class TypeHelper { + public static IList ConvertCollection(IEnumerable collection, Type targetType) + { + var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(targetType)) as IList; + foreach(var item in collection) + list.Add(ConvertType(item, targetType)); + return list; + } + public static object ConvertType(object value, Type type) { if (value == null) diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs index b4fd1b42ec..7d2fa87ec4 100644 --- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs @@ -12,7 +12,7 @@ public override void SetValue(object entity, object newValue) .GetType() .GetProperty(InternalRelationshipName); - propertyInfo.SetValue(entity, newValue); + propertyInfo.SetValue(entity, newValue); } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 37e0314da6..70246cb351 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; @@ -9,7 +10,6 @@ using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using JsonApiDotNetCore.Extensions; namespace JsonApiDotNetCore.Serialization { @@ -246,8 +246,6 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var resourceRelationships = attr.Type.GetEmptyCollection(); - var relationshipShells = relationshipData.ManyData.Select(r => { var instance = attr.Type.New(); @@ -255,7 +253,11 @@ private object SetHasManyRelationship(object entity, return instance; }); - attr.SetValue(entity, relationshipShells); + var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); + + // var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); + + attr.SetValue(entity, convertedCollection); } return entity; diff --git a/test/UnitTests/Extensions/TypeExtensions_Tests.cs b/test/UnitTests/Extensions/TypeExtensions_Tests.cs index 92534eef5d..f59fa37be0 100644 --- a/test/UnitTests/Extensions/TypeExtensions_Tests.cs +++ b/test/UnitTests/Extensions/TypeExtensions_Tests.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Models; using Xunit; -using JsonApiDotNetCore.Extensions; -using System.Collections.Generic; namespace UnitTests.Extensions { @@ -14,7 +14,7 @@ public void GetCollection_Creates_List_If_T_Implements_Interface() var type = typeof(Model); // act - var collection = type.GetEmptyCollection(); + var collection = type.GetEmptyCollection(); // assert Assert.NotNull(collection); From be33bac61e45b29c53ceb8b2fe0b88201f903b33 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 07:10:26 -0500 Subject: [PATCH 122/227] set new HasManyRelationships with EntityState.Unchanged --- .../Data/DefaultEntityRepository.cs | 19 +++++++ .../Data/IEntityRepository.cs | 4 -- .../Extensions/DbContextExtensions.cs | 16 ++---- .../Request/HasManyRelationshipPointers.cs | 49 +++++++++++++++++++ .../Serialization/JsonApiDeSerializer.cs | 10 +--- .../Services/IJsonApiContext.cs | 2 + .../Services/JsonApiContext.cs | 3 +- 7 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index e551bb9491..c4ebf2f738 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -85,10 +85,29 @@ public virtual async Task GetAndIncludeAsync(TId id, string relationshi public virtual async Task CreateAsync(TEntity entity) { _dbSet.Add(entity); + + DetachHasManyPointers(); + await _context.SaveChangesAsync(); return entity; } + /// + /// This is used to allow creation of HasMany relationships when the + /// dependent side of the relationship already exists. + /// + private void DetachHasManyPointers() + { + var relationships = _jsonApiContext.HasManyRelationshipPointers.Get(); + foreach(var relationship in relationships) + { + foreach(var pointer in relationship.Value) + { + _context.Entry(pointer).State = EntityState.Unchanged; + } + } + } + public virtual async Task UpdateAsync(TId id, TEntity entity) { var oldEntity = await GetAsync(id); diff --git a/src/JsonApiDotNetCore/Data/IEntityRepository.cs b/src/JsonApiDotNetCore/Data/IEntityRepository.cs index 4c35d6ea3f..e8bb68ef90 100644 --- a/src/JsonApiDotNetCore/Data/IEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityRepository.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Data diff --git a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs index 2606342e29..3cb5ccc359 100644 --- a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs @@ -1,20 +1,12 @@ -using Microsoft.EntityFrameworkCore; using System; +using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Extensions { public static class DbContextExtensions { - public static DbSet GetDbSet(this DbContext context) where T : class - { - var contextProperties = context.GetType().GetProperties(); - foreach(var property in contextProperties) - { - if (property.PropertyType == typeof(DbSet)) - return (DbSet)property.GetValue(context); - } - - throw new ArgumentException($"DbSet of type {typeof(T).FullName} not found on the DbContext", nameof(T)); - } + [Obsolete("This is no longer required since the introduction of context.Set", error: false)] + public static DbSet GetDbSet(this DbContext context) where T : class + => context.Set(); } } diff --git a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs new file mode 100644 index 0000000000..721274e3d6 --- /dev/null +++ b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace JsonApiDotNetCore.Request +{ + /// + /// Stores information to set relationships for the request resource. + /// These relationships must already exist and should not be re-created. + /// + /// The expected use case is POST-ing or PATCH-ing + /// an entity with HasMany relaitonships: + /// + /// { + /// "data": { + /// "type": "photos", + /// "attributes": { + /// "title": "Ember Hamster", + /// "src": "http://example.com/images/productivity.png" + /// }, + /// "relationships": { + /// "tags": { + /// "data": [ + /// { "type": "tags", "id": "2" }, + /// { "type": "tags", "id": "3" } + /// ] + /// } + /// } + /// } + /// } + /// + /// + public class HasManyRelationshipPointers + { + private Dictionary _hasManyRelationships = new Dictionary(); + + /// + /// Add the relationship to the list of relationships that should be + /// set in the repository layer. + /// + public void Add(Type dependentType, IList entities) + => _hasManyRelationships[dependentType] = entities; + + /// + /// Get all the models that should be associated + /// + public Dictionary Get() => _hasManyRelationships; + } +} diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 70246cb351..9723f79dac 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -232,12 +232,6 @@ private object SetHasManyRelationship(object entity, ContextEntity contextEntity, Dictionary relationships) { - // TODO: is this necessary? if not, remove - // var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); - - // if (entityProperty == null) - // throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a relationsip named '{attr.InternalRelationshipName}'"); - var relationshipName = attr.PublicRelationshipName; if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) @@ -255,9 +249,9 @@ private object SetHasManyRelationship(object entity, var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); - // var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); - attr.SetValue(entity, convertedCollection); + + _jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection); } return entity; diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index a73f0eb53a..132630446d 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -6,6 +6,7 @@ using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Request; namespace JsonApiDotNetCore.Services { @@ -28,6 +29,7 @@ public interface IJsonApiContext Type ControllerType { get; set; } Dictionary DocumentMeta { get; set; } bool IsBulkOperationRequest { get; set; } + HasManyRelationshipPointers HasManyRelationshipPointers { get; } TAttribute GetControllerAttribute() where TAttribute : Attribute; } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 1ebf5aeea1..a8bd9fe5de 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Request; using Microsoft.AspNetCore.Http; namespace JsonApiDotNetCore.Services @@ -52,6 +52,7 @@ public JsonApiContext( public Type ControllerType { get; set; } public Dictionary DocumentMeta { get; set; } public bool IsBulkOperationRequest { get; set; } + public HasManyRelationshipPointers HasManyRelationshipPointers { get; } = new HasManyRelationshipPointers(); public IJsonApiContext ApplyContext(object controller) { From af0e77f638744e2f5a880bb58a76a496bc098e09 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 07:26:15 -0500 Subject: [PATCH 123/227] ensure pointers are attached prior to adding the entity --- src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index c4ebf2f738..3c85bdae80 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -84,10 +84,9 @@ public virtual async Task GetAndIncludeAsync(TId id, string relationshi public virtual async Task CreateAsync(TEntity entity) { + AttachHasManyPointers(); _dbSet.Add(entity); - DetachHasManyPointers(); - await _context.SaveChangesAsync(); return entity; } @@ -96,7 +95,7 @@ public virtual async Task CreateAsync(TEntity entity) /// This is used to allow creation of HasMany relationships when the /// dependent side of the relationship already exists. /// - private void DetachHasManyPointers() + private void AttachHasManyPointers() { var relationships = _jsonApiContext.HasManyRelationshipPointers.Get(); foreach(var relationship in relationships) From 11dafb92b4288ed09e2f4fa4afb496816ded3d6c Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 15:33:58 -0500 Subject: [PATCH 124/227] fix tests --- .../Unit => UnitTests}/Builders/MetaBuilderTests.cs | 6 +++--- .../Extensions/IServiceCollectionExtensionsTests.cs | 7 +++---- .../Unit => UnitTests}/Models/AttributesEqualsTests.cs | 2 +- test/UnitTests/UnitTests.csproj | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Builders/MetaBuilderTests.cs (97%) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Extensions/IServiceCollectionExtensionsTests.cs (92%) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Models/AttributesEqualsTests.cs (97%) diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs b/test/UnitTests/Builders/MetaBuilderTests.cs similarity index 97% rename from test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs rename to test/UnitTests/Builders/MetaBuilderTests.cs index 5cd0b765de..0b784ef5b7 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs +++ b/test/UnitTests/Builders/MetaBuilderTests.cs @@ -1,8 +1,8 @@ -using Xunit; -using JsonApiDotNetCore.Builders; using System.Collections.Generic; +using JsonApiDotNetCore.Builders; +using Xunit; -namespace JsonApiDotNetCoreExampleTests.Unit.Builders +namespace UnitTests.Builders { public class MetaBuilderTests { diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs similarity index 92% rename from test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs rename to test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs index f6772fa22b..4fe2f09ff1 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs @@ -10,12 +10,11 @@ using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; -using UnitTests; using Xunit; +using Microsoft.EntityFrameworkCore; -namespace JsonApiDotNetCoreExampleTests.Unit.Extensions +namespace UnitTests.Extensions { public class IServiceCollectionExtensionsTests { @@ -28,7 +27,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() services.AddDbContext(options => { - options.UseMemoryCache(new MemoryCache(new MemoryCacheOptions())); + options.UseInMemoryDatabase(); }, ServiceLifetime.Transient); // act diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs b/test/UnitTests/Models/AttributesEqualsTests.cs similarity index 97% rename from test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs rename to test/UnitTests/Models/AttributesEqualsTests.cs index 107dd1d593..0b989169ef 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs +++ b/test/UnitTests/Models/AttributesEqualsTests.cs @@ -1,7 +1,7 @@ using JsonApiDotNetCore.Models; using Xunit; -namespace JsonApiDotNetCoreExampleTests.Unit.Models +namespace UnitTests.Models { public class AttributesEqualsTests { diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index 14a0d30e33..a6ed346e7d 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -12,5 +12,6 @@ + From 621091985edf4e5d0a32df59104f2db2c2af33d3 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Thu, 19 Apr 2018 22:56:53 -0500 Subject: [PATCH 125/227] #162 Adds new boolean value for 'canInclude' to ResourceAttribute. Updates DefaultEntityRepository to check this value when including relationship entities and to throw if set to false. --- .../Data/DefaultEntityRepository.cs | 15 +++++++++++---- src/JsonApiDotNetCore/Models/HasManyAttribute.cs | 4 ++-- src/JsonApiDotNetCore/Models/HasOneAttribute.cs | 4 ++-- .../Models/RelationshipAttribute.cs | 7 ++++--- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index e551bb9491..b6bcda29b3 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -131,11 +131,18 @@ public virtual IQueryable Include(IQueryable entities, string { var entity = _jsonApiContext.RequestEntity; var relationship = entity.Relationships.FirstOrDefault(r => r.PublicRelationshipName == relationshipName); - if (relationship != null) - return entities.Include(relationship.InternalRelationshipName); + if (relationship == null) + { + throw new JsonApiException(400, $"Invalid relationship {relationshipName} on {entity.EntityName}", + $"{entity.EntityName} does not have a relationship named {relationshipName}"); + } + + if (!relationship.CanInclude) + { + throw new JsonApiException(400, $"Including the relationship {relationshipName} on {entity.EntityName} is not allowed"); + } + return entities.Include(relationship.InternalRelationshipName); - throw new JsonApiException(400, $"Invalid relationship {relationshipName} on {entity.EntityName}", - $"{entity.EntityName} does not have a relationship named {relationshipName}"); } public virtual async Task> PageAsync(IQueryable entities, int pageSize, int pageNumber) diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs index b4fd1b42ec..4519dc8cb6 100644 --- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs @@ -2,8 +2,8 @@ namespace JsonApiDotNetCore.Models { public class HasManyAttribute : RelationshipAttribute { - public HasManyAttribute(string publicName, Link documentLinks = Link.All) - : base(publicName, documentLinks) + public HasManyAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true) + : base(publicName, documentLinks, canInclude) { } public override void SetValue(object entity, object newValue) diff --git a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs index 0dd20e73e7..f863c8819b 100644 --- a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs @@ -2,8 +2,8 @@ namespace JsonApiDotNetCore.Models { public class HasOneAttribute : RelationshipAttribute { - public HasOneAttribute(string publicName, Link documentLinks = Link.All) - : base(publicName, documentLinks) + public HasOneAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true) + : base(publicName, documentLinks, canInclude) { } public override void SetValue(object entity, object newValue) diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 0dbe6a4670..2781ecfb53 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -4,10 +4,11 @@ namespace JsonApiDotNetCore.Models { public abstract class RelationshipAttribute : Attribute { - protected RelationshipAttribute(string publicName, Link documentLinks) + protected RelationshipAttribute(string publicName, Link documentLinks, bool canInclude) { PublicRelationshipName = publicName; DocumentLinks = documentLinks; + CanInclude = canInclude; } public string PublicRelationshipName { get; } @@ -16,6 +17,7 @@ protected RelationshipAttribute(string publicName, Link documentLinks) public bool IsHasMany => GetType() == typeof(HasManyAttribute); public bool IsHasOne => GetType() == typeof(HasOneAttribute); public Link DocumentLinks { get; } = Link.All; + public bool CanInclude { get; } public abstract void SetValue(object entity, object newValue); @@ -26,8 +28,7 @@ public override string ToString() public override bool Equals(object obj) { - var attr = obj as RelationshipAttribute; - if (attr == null) + if (!(obj is RelationshipAttribute attr)) { return false; } From 0723567a8cd2771279ce5502fdb782c27bb0bfa5 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Thu, 19 Apr 2018 22:59:05 -0500 Subject: [PATCH 126/227] #162 Adds unit test to test the new canInclude ResourceAttribute property. --- .../JsonApiDotNetCoreExample/Models/Person.cs | 3 +++ .../Acceptance/Spec/DocumentTests/Included.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs b/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs index 8acf87c405..5aa7c83c12 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs @@ -20,6 +20,9 @@ public class Person : Identifiable, IHasMeta [HasMany("todo-collections")] public virtual List TodoItemCollections { get; set; } + + [HasOne("unincludeable-item", Link.All, false)] + public virtual TodoItem UnIncludeableItem { get; set; } public Dictionary GetMeta(IJsonApiContext context) { diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs index a9aa9c4e67..343526f7d8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs @@ -335,5 +335,29 @@ public async Task Request_ToIncludeDeeplyNestedRelationships_Returns_400() // assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + [Fact] + public async Task Request_ToIncludeRelationshipMarkedCanIncludeFalse_Returns_400() + { + // arrange + var person = _context.People.First(); + + var builder = new WebHostBuilder() + .UseStartup(); + + var httpMethod = new HttpMethod("GET"); + + var route = $"/api/v1/people/{person.Id}?include=unincludeable-item"; + + var server = new TestServer(builder); + var client = server.CreateClient(); + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await client.SendAsync(request); + + // assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } } } From 41b0415a24af79f54eef6453ca51e9b13df86bdb Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 21 Apr 2018 17:54:56 -0500 Subject: [PATCH 127/227] make private service methods protected virtual --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 4 ++-- src/JsonApiDotNetCore/Services/EntityResourceService.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index c4b9a6d932..8cd4435ad8 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.2.1 + 2.2.2 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore @@ -35,4 +35,4 @@ - \ No newline at end of file + diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index 91eabb9cfd..bc7a2adb52 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -146,7 +146,7 @@ public virtual async Task DeleteAsync(TId id) return await _entities.DeleteAsync(id); } - private IQueryable ApplySortAndFilterQuery(IQueryable entities) + protected virtual IQueryable ApplySortAndFilterQuery(IQueryable entities) { var query = _jsonApiContext.QuerySet; @@ -163,7 +163,7 @@ private IQueryable ApplySortAndFilterQuery(IQueryable entities) return entities; } - private async Task> ApplyPageQueryAsync(IQueryable entities) + protected virtual async Task> ApplyPageQueryAsync(IQueryable entities) { var pageManager = _jsonApiContext.PageManager; if (!pageManager.IsPaginated) @@ -174,7 +174,7 @@ private async Task> ApplyPageQueryAsync(IQueryable entities) return await _entities.PageAsync(entities, pageManager.PageSize, pageManager.CurrentPage); } - private IQueryable IncludeRelationships(IQueryable entities, List relationships) + protected virtual IQueryable IncludeRelationships(IQueryable entities, List relationships) { _jsonApiContext.IncludedRelationships = relationships; From 0cfa4e63fd19341220c3dbd3efe5ec4493082507 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 21 Apr 2018 18:05:11 -0500 Subject: [PATCH 128/227] allow custom attribute filters --- .../Extensions/IQueryableExtensions.cs | 2 +- .../Internal/Query/AttrFilterQuery.cs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 73e3a14a3e..4d7be752e3 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -90,7 +90,7 @@ public static IQueryable Filter(this IQueryable sourc public static IQueryable Filter(this IQueryable source, AttrFilterQuery filterQuery) { - if (filterQuery == null) + if (filterQuery == null || filterQuery.IsAttribute == false) return source; var concreteType = typeof(TSource); diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index 59bb3f0f83..c8dee16828 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -18,7 +18,9 @@ public AttrFilterQuery( var attribute = GetAttribute(filterQuery.Attribute); if (attribute == null) - throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); + return; // we don't want to throw...we should allow custom filter implementations + + IsAttribute = true; if (attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); @@ -32,6 +34,12 @@ public AttrFilterQuery( public string PropertyValue { get; } public FilterOperations FilterOperation { get; } + /// + /// Whether or not the filter is an actual attribute on the model. + /// We use this to allow custom filters that have to be handled by the application. + /// + internal bool IsAttribute { get; set; } + private AttrAttribute GetAttribute(string attribute) => _jsonApiContext.RequestEntity.Attributes.FirstOrDefault(attr => attr.Is(attribute)); } From 4ec71e0293ac9f64d4ffac47cfaff7a87ccc7648 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 21 Apr 2018 18:26:05 -0500 Subject: [PATCH 129/227] add ctor without logger factory --- src/JsonApiDotNetCore/Controllers/JsonApiController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiController.cs index 97350127ba..929e76e5aa 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiController.cs @@ -17,6 +17,12 @@ public JsonApiController( : base(jsonApiContext, resourceService, loggerFactory) { } + public JsonApiController( + IJsonApiContext jsonApiContext, + IResourceService resourceService) + : base(jsonApiContext, resourceService) + { } + public JsonApiController( IJsonApiContext jsonApiContext, IGetAllService getAll = null, From 8c06ae39b2d59cb66838ad6af069b9b592a93bc2 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 21 Apr 2018 18:05:11 -0500 Subject: [PATCH 130/227] Revert "allow custom attribute filters" This reverts commit 1c80eb72a524a806d0fdc49b9e7aff34b681c86a. --- .../Extensions/IQueryableExtensions.cs | 2 +- .../Internal/Query/AttrFilterQuery.cs | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 4d7be752e3..73e3a14a3e 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -90,7 +90,7 @@ public static IQueryable Filter(this IQueryable sourc public static IQueryable Filter(this IQueryable source, AttrFilterQuery filterQuery) { - if (filterQuery == null || filterQuery.IsAttribute == false) + if (filterQuery == null) return source; var concreteType = typeof(TSource); diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index c8dee16828..59bb3f0f83 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -18,9 +18,7 @@ public AttrFilterQuery( var attribute = GetAttribute(filterQuery.Attribute); if (attribute == null) - return; // we don't want to throw...we should allow custom filter implementations - - IsAttribute = true; + throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); if (attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{attribute.PublicAttributeName}'."); @@ -34,12 +32,6 @@ public AttrFilterQuery( public string PropertyValue { get; } public FilterOperations FilterOperation { get; } - /// - /// Whether or not the filter is an actual attribute on the model. - /// We use this to allow custom filters that have to be handled by the application. - /// - internal bool IsAttribute { get; set; } - private AttrAttribute GetAttribute(string attribute) => _jsonApiContext.RequestEntity.Attributes.FirstOrDefault(attr => attr.Is(attribute)); } From 6726794a7688066ee9c9c9fc6e29eaea658faf15 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 22 Apr 2018 07:40:44 -0500 Subject: [PATCH 131/227] fix documentation link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c09fe884b6..ae66e3a07c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ See the [examples](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/mas ## Installation And Usage -See [the documentation](https://json-api-dotnet.github.io/JsonApiDotNetCore/) for detailed usage. +See [the documentation](https://json-api-dotnet.github.io/#/) for detailed usage. ### Models From bf79a20bc730e883784ed94ebe484f07c58cb2eb Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 22 Apr 2018 07:43:38 -0500 Subject: [PATCH 132/227] chore(docs): removed obsolete docs --- couscous.yml | 116 -------------------------- docs/ContextGraph.md | 58 ------------- docs/Controllers.md | 93 --------------------- docs/CustomQueryFormat.md | 13 --- docs/EntityRepositories.md | 44 ---------- docs/Errors.md | 38 --------- docs/Filtering.md | 50 ------------ docs/IncludingRelationships.md | 54 ------------- docs/Index.md | 7 -- docs/Installation.md | 29 ------- docs/Layers.md | 57 ------------- docs/Meta.md | 29 ------- docs/Middleware.md | 20 ----- docs/Models.md | 106 ------------------------ docs/Operations.md | 33 -------- docs/Options.md | 111 ------------------------- docs/Pagination.md | 23 ------ docs/ResourceServices.md | 126 ----------------------------- docs/Routing.md | 65 --------------- docs/Sorting.md | 12 --- docs/SparseFieldsets.md | 20 ----- docs/Usage.md | 144 --------------------------------- docs/service_table.png | Bin 169430 -> 0 bytes 23 files changed, 1248 deletions(-) delete mode 100644 couscous.yml delete mode 100644 docs/ContextGraph.md delete mode 100644 docs/Controllers.md delete mode 100644 docs/CustomQueryFormat.md delete mode 100644 docs/EntityRepositories.md delete mode 100644 docs/Errors.md delete mode 100644 docs/Filtering.md delete mode 100644 docs/IncludingRelationships.md delete mode 100644 docs/Index.md delete mode 100644 docs/Installation.md delete mode 100644 docs/Layers.md delete mode 100644 docs/Meta.md delete mode 100644 docs/Middleware.md delete mode 100644 docs/Models.md delete mode 100644 docs/Operations.md delete mode 100644 docs/Options.md delete mode 100644 docs/Pagination.md delete mode 100644 docs/ResourceServices.md delete mode 100644 docs/Routing.md delete mode 100644 docs/Sorting.md delete mode 100644 docs/SparseFieldsets.md delete mode 100644 docs/Usage.md delete mode 100644 docs/service_table.png diff --git a/couscous.yml b/couscous.yml deleted file mode 100644 index 2acaad12d7..0000000000 --- a/couscous.yml +++ /dev/null @@ -1,116 +0,0 @@ -template: - # Name of the directory containing the website template (default is "website") - # directory: docs/Template-Dark - # Or if you are using a remote template, you can set the Git URL - url: https://github.com/jaredcnance/Template-Dark.git - # Name of the index file (default is "README.md") - index: index.md - -# List of directories to include in the processing (by default it's empty, so all markdown files are parsed) -# Paths are relative to the optional source path given when generating the website, repository root by default -include: - - docs - -# List of directories to exclude from the processing (default contains "vendor" and "website") -# Paths are relative to the optional include paths given when generating the website, repository root by default -exclude: - # This special entry will ask Couscous to read the exluded directories from your ".gitignore" file - - %gitignore% - -# scripts: - # Scripts to execute before generating the website - # before: - # - cp bin/couscous.phar website/ - # Scripts to execute after generating the website - # after: - # - rm website/couscous.phar - -# Set this variable to use a Custom Domain -# The content of this variable will be directly inserted into the CNAME file -# cname: docs.yourdomain.com - -# Set the target branch in which to deploy the generated website -branch: gh-pages - -# Base URL of the published website (no "/" at the end!) -# You are advised to set and use this variable to write your links in the HTML layouts -baseUrl: https://json-api-dotnet.github.io/JsonApiDotNetCore/ -github: - user: research-institute - repo: json-api-dotnet-core - -title: JSONAPI .Net Core -subTitle: killing boilerplate in dotnet web APIs - -# The left menu bar -menu: - sections: - intro: - name: Getting Started - items: - about: - text: About - relativeUrl: index.html - installation: - text: Installation - relativeUrl: installation.html - usage: - text: Step by Step - relativeUrl: usage.html - usage: - name: Usage - items: - models: - text: Models - relativeUrl: models.html - contextgraph: - text: Context Graph - relativeUrl: contextgraph.html - meta: - text: Meta - relativeUrl: meta.html - options: - text: Global Options - relativeUrl: options.html - errors: - text: Custom Errors - relativeUrl: errors.html - filtering: - text: Filtering - relativeUrl: filtering.html - includingrelationships: - text: Including Relationships - relativeUrl: includingrelationships.html - pagination: - text: Pagination - relativeUrl: pagination.html - routing: - text: Routing - relativeUrl: routing.html - sorting: - text: Sorting - relativeUrl: sorting.html - sparsefields: - text: Sparse Fieldsets - relativeUrl: sparsefieldsets.html - extensibility: - name: Extensibility - items: - layers: - text: The Layers - relativeUrl: layers.html - controllers: - text: Controllers - relativeUrl: controllers.html - services: - text: Resource Services - relativeUrl: resourceservices.html - repositories: - text: Entity Repositories - relativeUrl: entityrepositories.html - middleware: - text: Middleware - relativeUrl: middleware.html - customqueryformat: - text: Custom Query Formats - relativeUrl: customqueryformat.html \ No newline at end of file diff --git a/docs/ContextGraph.md b/docs/ContextGraph.md deleted file mode 100644 index f5b8394b83..0000000000 --- a/docs/ContextGraph.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -currentMenu: contextgraph ---- - -# Context Graph - -The [ContextGraph](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Internal/ContextGraph.cs) is a map of all the json:api resources and their relationships that your API serves. -It is built at app startup and available as a singleton through Dependency Injection. - -When you call `services.AddJsonApi()`, the graph is constructed from the context. - -### Defining Non-EF Resources - -If you have models that are not members of a `DbContext`, -you can manually create this graph like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // Add framework services. - var mvcBuilder = services.AddMvc(); - - services.AddJsonApi(options => { - options.Namespace = "api/v1"; - options.BuildContextGraph((builder) => { - builder.AddResource("my-models"); - }); - }, mvcBuilder); - // ... -} -``` - -### Changing Resource Names - -If a DbContext is specified when adding the services, the context will be used to define the resources and their names. By default, these names will be hyphenated. - -```csharp -public class AppDbContext : DbContext { - // this will be translated into "my-models" - public DbSet MyModels { get; set; } -} -``` - -However, you can specify a custom name like so: - -```csharp -public class AppDbContext : DbContext { - // this will be translated into "someModels" - [Resource("someModels")] - public DbSet MyModels { get; set; } -} -``` - - - - - diff --git a/docs/Controllers.md b/docs/Controllers.md deleted file mode 100644 index 0ec47b8774..0000000000 --- a/docs/Controllers.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -currentMenu: controllers ---- - -# Controllers - -You need to create controllers that inherit from [JsonApiController<TEntity>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Controllers/JsonApiController.cs). - -```csharp -public class ThingsController : JsonApiController -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Non-Integer Type Keys - -If your model is using a type other than `int` for the primary key, -you should explicitly declare it in the controller -and service generic type definitions: - -```csharp -public class ThingsController : JsonApiController - //---------------------- ^^^^ -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - //--------------------- ^^^^ - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Limiting Write Access - -It is possible to limit write resource access on the controller entirely using the following attributes: - -- `NoHttpPost`: disallow POST requests -- `NoHttpPatch`: disallow PATCH requests -- `NoHttpDelete`: disallow DELETE requests -- `HttpReadOnly`: all of the above - -```csharp -[HttpReadOnly] -public class ThingsController : JsonApiController -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Additional customizations - -If you need additional customization at the controller level, you can override the virtual -methods. Please be aware that this is not the place for advanced business logic -which should be performed at the [service](resourceservices.html) or [repository](entityrepositories.html) layers. Here is an example override at the controller layer: - -```csharp -public class TodoItemsController : JsonApiController -{ - public TodoItemsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } - - [HttpGet] - public override async Task GetAsync() - { - // custom code - if(RequestIsValid() == false) - return BadRequest(); - - // return result from base class - return await base.GetAsync(); - } - - // some custom validation logic - private bool RequestIsValid() => true; -} -``` diff --git a/docs/CustomQueryFormat.md b/docs/CustomQueryFormat.md deleted file mode 100644 index b23993d333..0000000000 --- a/docs/CustomQueryFormat.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -currentMenu: customqueryformat ---- - -# Custom Query Formats - -For information on the default query parameter formats, see the documentation for each query method. - -In order to customize the query formats, you need to implement the `IQueryParser` interface and inject it like so: - -```csharp -services.AddScoped(); -``` \ No newline at end of file diff --git a/docs/EntityRepositories.md b/docs/EntityRepositories.md deleted file mode 100644 index 62d156e427..0000000000 --- a/docs/EntityRepositories.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -currentMenu: repositories ---- - -# Entity Repositories - -If you want to use EF, but need additional data access logic (such as authorization), you can implement custom methods for accessing the data by creating an implementation of -[IEntityRepository<Entity, TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/IEntityRepository.cs). If you only need minor changes you can override the -methods defined in [DefaultEntityRepository<TEntity, TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs). - -The repository should then be -add to the service collection in `Startup.cs` like so: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddScoped, MyAuthorizedEntityRepository>(); - // ... -} -``` - -A sample implementation that performs data authorization might look like: - -```csharp -public class MyAuthorizedEntityRepository : DefaultEntityRepository -{ - private readonly ILogger _logger; - private readonly IAuthenticationService _authenticationService; - - public MyAuthorizedEntityRepository( - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext, - IAuthenticationService authenticationService) - : base(loggerFactory, jsonApiContext) - { - _logger = loggerFactory.CreateLogger(); - _authenticationService = authenticationService; - } - - public override IQueryable Get() - { - return base.Get().Where(e => e.UserId == _authenticationService.UserId); - } -} -``` diff --git a/docs/Errors.md b/docs/Errors.md deleted file mode 100644 index 59f4f6da21..0000000000 --- a/docs/Errors.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -currentMenu: errors ---- - -# Custom Errors - -By default, errors will only contain the properties defined by the internal [Error](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Internal/Error.cs) class. However, you can create your own by inheriting from `Error` and either throwing it in a `JsonApiException` or returning the error from your controller. - -```csharp -// custom error definition -public class CustomError : Error { - public CustomError(string status, string title, string detail, string myProp) - : base(status, title, detail) - { - MyCustomProperty = myProp; - } - public string MyCustomProperty { get; set; } -} - -// throwing a custom error -public void MyMethod() { - var error = new CustomError("507", "title", "detail", "custom"); - throw new JsonApiException(error); -} - -// returning from controller -[HttpPost] -public override async Task PostAsync([FromBody] MyEntity entity) -{ - if(_db.IsFull) - return Error(new CustomError("507", "Database is full.", "Theres no more room.", "Sorry.")); - - if(model.Validations.IsValid == false) - return Errors(model.Validations.GetErrors()); - - // ... -} -``` \ No newline at end of file diff --git a/docs/Filtering.md b/docs/Filtering.md deleted file mode 100644 index c258fe4f73..0000000000 --- a/docs/Filtering.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -currentMenu: filtering ---- - -# Filtering - -You can filter resources by attributes using the `filter` query parameter. -By default, all attributes are filterable. -The filtering strategy we have selected, uses the following form: - -``` -?filter[attribute]=value -``` - -For operations other than equality, the query can be prefixed with an operation -identifier): - -``` -?filter[attribute]=eq:value -?filter[attribute]=lt:value -?filter[attribute]=gt:value -?filter[attribute]=le:value -?filter[attribute]=ge:value -?filter[attribute]=like:value -``` - -### Custom Filters - -You can customize the filter implementation by overriding the method in the `DefaultEntityRepository` like so: - -```csharp -public class MyEntityRepository : DefaultEntityRepository -{ - public MyEntityRepository( - AppDbContext context, - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) - : base(context, loggerFactory, jsonApiContext) - { } - - public override IQueryable Filter(IQueryable entities, FilterQuery filterQuery) - { - // use the base filtering method - entities = base.Filter(entities, filterQuery); - - // implement custom method - return ApplyMyCustomFilter(entities, filterQuery); - } -} -``` diff --git a/docs/IncludingRelationships.md b/docs/IncludingRelationships.md deleted file mode 100644 index e11657ebdf..0000000000 --- a/docs/IncludingRelationships.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -currentMenu: includingrelationships ---- - -# Including Relationships - -JADNC supports [request include params](http://jsonapi-resources.com/v0.9/guide/resources.html#Included-relationships-side-loading-resources) out of the box, for side loading related resources. - -Here’s an example from the spec: - -```http -GET /articles/1?include=comments HTTP/1.1 -Accept: application/vnd.api+json -``` - -Will get you the following payload: - -```json -{ - "data": { - "type": "articles", - "id": "1", - "attributes": { - "title": "JSON API paints my bikeshed!" - }, - "relationships": { - "comments": { - "links": { - "self": "http://example.com/articles/1/relationships/comments", - "related": "http://example.com/articles/1/comments" - }, - "data": [ - { "type": "comments", "id": "5" }, - { "type": "comments", "id": "12" } - ] - } - } - }, - "included": [{ - "type": "comments", - "id": "5", - "attributes": { - "body": "First!" - } - }, { - "type": "comments", - "id": "12", - "attributes": { - "body": "I like XML better" - } - }] -} -``` - diff --git a/docs/Index.md b/docs/Index.md deleted file mode 100644 index 64b0861155..0000000000 --- a/docs/Index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -currentMenu: about ---- - -# JSON API .Net Core - -A framework for building [json:api](http://jsonapi.org/) compliant web servers. It allows you to eliminate a significant amount of boilerplate while offering out-of-the-box features such as sorting, filtering and pagination. This library provides all the required middleware to build a complete server. All you need to focus on is defining the resources and implementing your custom business logic. This library has been designed around dependency injection making extensibility incredibly easy. \ No newline at end of file diff --git a/docs/Installation.md b/docs/Installation.md deleted file mode 100644 index 367d5d3a2e..0000000000 --- a/docs/Installation.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -currentMenu: installation ---- - -# Installation - -- CLI -``` -$ dotnet add package jsonapidotnetcore -``` - -- Visual Studio -``` -Install-Package JsonApiDotnetCore -``` - -- *.csproj -```xml - - - - -``` - -Click [here](https://www.nuget.org/packages/JsonApiDotnetCore/) for the latest NuGet version. - -For pre-releases (develop branch), add the [MyGet](https://www.myget.org/feed/Details/research-institute) package feed -(https://www.myget.org/F/research-institute/api/v3/index.json) -to your nuget configuration. \ No newline at end of file diff --git a/docs/Layers.md b/docs/Layers.md deleted file mode 100644 index 5c71030274..0000000000 --- a/docs/Layers.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -currentMenu: layers ---- - -# The Layers - -By default, data retrieval is distributed across 3 layers: - -1. [JsonApiController](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Controllers/JsonApiController.cs) (required) -2. [IResourceService](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Services/IResourceService.cs) (default [EntityResourceService](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Services/EntityResourceService.cs)) -3. [IEntityRepository](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/IEntityRepository.cs) (default [DefaultEntityRepository](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs)) - -Customization can be done at any of these layers. However, it is recommended that you make your customizations at the service or the repository layer when possible to keep the controllers free of unnecessary logic. You can use the following as a general rule of -thumb for where to put business logic: - -- **Controller**: simple validation logic that should result in the return of specific HTTP status codes such as model validation -- **IResourceService**: advanced BL and replacement of data access mechanisms -- **IEntityRepository**: custom logic that builds on the EF APIs, such as Authorization of data - -## Replacing Services / Repositories - -Replacing services is done on a per resource basis and can be done through simple DI -in your Startup.cs file: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) -{ - // custom service - services.AddScoped, CustomPersonService>(); - - // custom repository - services.AddScoped, AuthorizedTodoItemRepository>(); - - // ... -} -``` - -## Not Using Entity Framework? - -Out of the box, the library uses your `DbContext` to create a "ContextGraph" or map of all your models and their relationships. If, however, you have models that are not members of a `DbContext`, you can manually create this graph like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // Add framework services. - var mvcBuilder = services.AddMvc(); - - services.AddJsonApi(options => { - options.Namespace = "api/v1"; - options.BuildContextGraph((builder) => { - builder.AddResource("my-models"); - }); - }, mvcBuilder); - // ... -} -``` diff --git a/docs/Meta.md b/docs/Meta.md deleted file mode 100644 index 10b1a23e9a..0000000000 --- a/docs/Meta.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -currentMenu: meta ---- - -# Meta - -Meta objects can be assigned in two ways: - - Resource meta - - Request Meta - -Resource meta can be defined by implementing `IHasMeta` on the model class: - -```csharp -public class Person : Identifiable, IHasMeta -{ - // ... - - public Dictionary GetMeta(IJsonApiContext context) - { - return new Dictionary { - { "copyright", "Copyright 2015 Example Corp." }, - { "authors", new string[] { "Jared Nance" } } - }; - } -} -``` - -Request Meta can be added by injecting a service that implements `IRequestMeta`. -In the event of a key collision, the Request Meta will take precendence. diff --git a/docs/Middleware.md b/docs/Middleware.md deleted file mode 100644 index 681136ca9b..0000000000 --- a/docs/Middleware.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -currentMenu: middleware ---- - -# Configure Middleware and Services - -Add the following to your `Startup.ConfigureServices` method. -Replace `AppDbContext` with your DbContext. - -```csharp -services.AddJsonApi(); -``` - -Add the middleware to the `Startup.Configure` method. -Note that under the hood, this will call `app.UseMvc()` -so there is no need to add that as well. - -```csharp -app.UseJsonApi(); -``` \ No newline at end of file diff --git a/docs/Models.md b/docs/Models.md deleted file mode 100644 index 73d9afdc43..0000000000 --- a/docs/Models.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -currentMenu: models ---- - -# Defining Models - -Models must implement [IIdentifiable<TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Models/IIdentifiable.cs). -The easiest way to do this is to inherit [Identifiable<TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Models/Identifiable.cs) where `TId` is the type of the primary key, like so: - -```csharp -public class Person : Identifiable -{ } -``` - -You can use the non-generic `Identifiable` if your primary key is an integer: - -```csharp -public class Person : Identifiable -{ } -``` - -If you need to hang annotations or attributes on the `Id` property, you can override the virtual member: - -```csharp -public class Person : Identifiable -{ - [Key] - [Column("person_id")] - public override int Id { get; set; } -} -``` - -If your model must inherit from another class, you can always implement the interface yourself. -In the following example, ApplicationUser inherits IdentityUser which already contains an Id property of -type string. - -```csharp -public class ApplicationUser -: IdentityUser, IIdentifiable -{ - [NotMapped] - public string StringId { get => this.Id; set => Id = value; } -} -``` - -## Specifying Public Attributes - -If you want an attribute on your model to be publicly available, -add the `AttrAttribute` and provide the outbound name. - -```csharp -public class Person : Identifiable -{ - [Attr("first-name")] - public string FirstName { get; set; } -} -``` - -### Immutability - -Attributes can be marked as immutable which will prevent `PATCH` requests -from updating them: - -```csharp -public class Person : Identifiable -{ - [Attr("first-name", immutable: true)] - public string FirstName { get; set; } -} -``` - -## Relationships - -In order for navigation properties to be identified in the model, -they should be labeled with the appropriate attribute (either `HasOne` or `HasMany`). - -```csharp -public class Person : Identifiable -{ - [Attr("first-name")] - public string FirstName { get; set; } - - [HasMany("todo-items")] - public virtual List TodoItems { get; set; } -} -``` - -Dependent relationships should contain a property in the form `{RelationshipName}Id`. -For example, a `TodoItem` may have an `Owner` and so the Id attribute should be `OwnerId` like so: - -```csharp -public class TodoItem : Identifiable -{ - [Attr("description")] - public string Description { get; set; } - - public int OwnerId { get; set; } - - [HasOne("owner")] - public virtual Person Owner { get; set; } -} -``` - -## Resource Names - -See [ContextGraph](contextGraph.html) for details on how the resource names are determined. \ No newline at end of file diff --git a/docs/Operations.md b/docs/Operations.md deleted file mode 100644 index 697f9171b2..0000000000 --- a/docs/Operations.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -currentMenu: operations ---- - -# Operations - -Operations is currently an unofficial proposal. It allows you to perform bulk operations in a single transaction. - -### Enabling - -To enable the operations extension, modify you `Startup.ConfigureServices` method: - -```csharp -services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); -``` - -### Controllers - -To create a bulk operations controller, inherit `JsonApiOperationsController`: - -```csharp -[Route("api/bulk")] -public class OperationsController : JsonApiOperationsController -{ - public OperationsController(IOperationsProcessor processor) - : base(processor) - { } -} -``` - -### Example - -There is a working example in the `/src/examples/OperationsExample` directory of the repository. \ No newline at end of file diff --git a/docs/Options.md b/docs/Options.md deleted file mode 100644 index 3f94f4031e..0000000000 --- a/docs/Options.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -currentMenu: options ---- - -# Global Options - -## Client Generated Ids - -By default, the server will respond with a `403 Forbidden` HTTP Status Code if a `POST` request is -received with a client generated id. However, this can be allowed by setting the `AllowClientGeneratedIds` -flag in the options: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.AllowClientGeneratedIds = true); - // ... -} -``` - -## Pagination - -If you would like pagination implemented by default, you can specify the page size -when setting up the services: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.DefaultPageSize = 10); - // ... -} -``` - -### Total Record Count - -The total number of records can be added to the document meta by setting it in the options: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi(opt => - { - opt.DefaultPageSize = 5; - opt.IncludeTotalRecordCount = true; - }); - // ... -} -``` - -## Relative Links - -All links are absolute by default. However, you can configure relative links: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.RelativeLinks = true); - // ... -} -``` - - -```http -GET /api/v1/articles/4309 HTTP/1.1 -Accept: application/vnd.api+json -``` - -```json -{ - "type": "articles", - "id": "4309", - "attributes": { - "name": "Voluptas iure est molestias." - }, - "relationships": { - "author": { - "links": { - "self": "/api/v1/articles/4309/relationships/author", - "related": "/api/v1/articles/4309/author" - } - } - } -} -``` - -## Custom Query Parameters - -If you would like to use custom query params (parameters not reserved by the json:api specification), you can set `AllowCustomQueryParameters = true`. The default behavior is to return an `HTTP 400 Bad Request` for unknown query parameters. - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.AllowCustomQueryParameters = true); - // ... -} -``` - -## Custom Serializer Settings - -We use Json.Net for all serialization needs. If you want to change the default serializer settings, you can: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.SerializerSettings = new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore, - ContractResolver = new DasherizedResolver() - }); - // ... -} -``` \ No newline at end of file diff --git a/docs/Pagination.md b/docs/Pagination.md deleted file mode 100644 index 7d70773757..0000000000 --- a/docs/Pagination.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -currentMenu: pagination ---- - -# Pagination - -Resources can be paginated. -The following query would set the page size to 10 and get page 2. - -``` -?page[size]=10&page[number]=2 -``` - -If you would like pagination implemented by default, you can specify the page size -when setting up the services: - -```C# -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.DefaultPageSize = 10); - // ... -} -``` diff --git a/docs/ResourceServices.md b/docs/ResourceServices.md deleted file mode 100644 index 17e7763835..0000000000 --- a/docs/ResourceServices.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -currentMenu: services ---- - -# Resource Services - -The [IResourceService](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/src/JsonApiDotNetCore/Services/Contract/IResourceService.cs) acts as a service layer between the controller and the data access -layer. This allows you to customize it however you want and not be dependent upon Entity -Framework. This is also a good place to implement custom business logic. - -### Supplementing Default Behavior - -A simple example would be to send notifications when an entity gets created: - -```csharp -public class TodoItemService : EntityResourceService { - - private readonly INotificationService _notificationService; - - public TodoItemService( - IJsonApiContext jsonApiContext, - IEntityRepository repository, - ILoggerFactory loggerFactory, - // Get the notification service via DI - INotificationService notificationService) - : base(jsonApiContext, repository, loggerFactory) - { - _notificationService = notificationService; - } - - public override async Task CreateAsync(TEntity entity) - { - // call the base implementation which uses Entity Framework - var newEntity = await base.CreateAsync(entity); - - // custom code - _notificationService.Notify($"Entity created: { newEntity.Id }"); - - // don't forget to return the new entity - return entity; - } -} -``` - -### Not Using Entity Framework? - -As previously discussed, this library uses Entity Framework by default. -If you'd like to use another ORM that does not implement `IQueryable`, -you can inject a custom service like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // add the service override for MyModel - services.AddScoped, MyModelService>(); - - // add your own DAO - services.AddScoped(); - // ... -} - - -// MyModelService.cs -public class MyModelService : IResourceService -{ - private readonly IMyModelDAL _dal; - public MyModelService(IMyModelDAL dal) - { - _dal = dal; - } - - public Task> GetAsync() - { - return await _dal.GetModelAsync(); - } -} -``` - -### Limited Requirements - -In some cases it may be necessary to only expose a few methods on the resource. -For this reason, we have created a hierarchy of service interfaces that can be used to get the -exact implementation you require. Below is a table outlining these interfaces: - -![interfaces](service_table.png) - - - In order to take advantage of these interfaces you first need to inject the service for each implemented interface. - Using Autofac, as an example, this is simply: - -```csharp -public class MyResourceService : ICreateService, IDeleteService { - // ... -} -``` - -```csharp -public class Startup { - public IServiceProvider ConfigureServices(IServiceCollection services) { - builder.RegisterType().AsImplementedInterfaces(); - } -} -``` - -Then in the controller, you should inherit the base controller and pass the services into -the named, optional base parameters: - -```csharp -public class MyResourcesController : BaseJsonApiController { - - public MyResourcesController( - IJsonApiContext jsonApiContext, - ICreateService create, - IDeleteService delete - ) : base(jsonApiContext, create: create, delete: delete) { } - - [HttpPost] - public override async Task PostAsync([FromBody] MyResource entity) - => await base.PostAsync(entity); - - [HttpDelete("{id}")] - public override async TaskDeleteAsync(int id) - => await base.DeleteAsync(id); -} -``` diff --git a/docs/Routing.md b/docs/Routing.md deleted file mode 100644 index 008438dd39..0000000000 --- a/docs/Routing.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -currentMenu: routing ---- - -# Routing - -By default the library will configure routes for each controller. -Based on the [recommendations](http://jsonapi.org/recommendations/) -outlined in the JSONAPI spec, routes are hyphenated. - -```http -GET /api/compound-models HTTP/1.1 -Accept: application/vnd.api+json -``` - -## Namespacing and Versioning URLs - -You can add a namespace to the URL by specifying it in `ConfigureServices`: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.Namespace = "api/v1"); -} -``` - -## Disable Convention - -You can disable the dasherized convention and specify your own template -by using the `DisableRoutingConvention` Attribute. - -```csharp -[Route("[controller]")] -[DisableRoutingConvention] -public class CamelCasedModelsController : JsonApiController { - public CamelCasedModelsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -It is important to note that your routes *must* still end with the model name in the same format -as the resource name. This is so that we can build accurrate resource links in the json:api document. -For example, if you define a resource as `MyModels` the controller route must match: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi(options => { - options.BuildContextGraph((builder) => { - // resource definition - builder.AddResource("myModels"); - }); - }); -} - -// controller definition -[Route("api/myModels")] -[DisableRoutingConvention] -public class TodoItemsController : JsonApiController { - //... -} -``` diff --git a/docs/Sorting.md b/docs/Sorting.md deleted file mode 100644 index 6a5367d8d9..0000000000 --- a/docs/Sorting.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -currentMenu: sorting ---- - -# Sorting - -Resources can be sorted by an attribute: - -``` -?sort=attribute // ascending -?sort=-attribute // descending -``` diff --git a/docs/SparseFieldsets.md b/docs/SparseFieldsets.md deleted file mode 100644 index 16e66a2c89..0000000000 --- a/docs/SparseFieldsets.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -currentMenu: sparsefields ---- - -# Sparse Fieldsets - -We currently support top-level field selection. -What this means is you can restrict which fields are returned by a query using the `fields` query parameter, but this does not yet apply to included relationships. - -- Currently valid: -```http -GET /articles?fields[articles]=title,body HTTP/1.1 -Accept: application/vnd.api+json -``` - -- Not yet supported: -```http -GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1 -Accept: application/vnd.api+json -``` \ No newline at end of file diff --git a/docs/Usage.md b/docs/Usage.md deleted file mode 100644 index 07ac168a21..0000000000 --- a/docs/Usage.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -currentMenu: usage ---- - -# Usage - -The most basic use case leverages Entity Framework. -The shortest path to a running API looks like: - -- Create a new web app -- Install -- Define models -- Define the DbContext -- Define controllers -- Add Middleware and Services -- Seed the database -- Run Migrations -- Start the app - -This page will walk you through the **simplest** use case. More detailed examples can be found in the detailed usage subsections. - - -### Create a New Web App - -``` -$ mkdir MyApp -$ cd MyApp -$ dotnet new webapi -``` - -### Install - -See [Installation](installation.html) - -### Models - -Define your domain models such that they implement `IIdentifiable`. -The easiest way to do this is to inherit `Identifiable`: - -```csharp -public class Person : Identifiable -{ - [Attr("name")] - public string Name { get; set; } -} -``` - -### DbContext - -Nothing special here, just an ordinary DbContext - -```csharp -public class AppDbContext : DbContext -{ - public AppDbContext(DbContextOptions options) - : base(options) { } - - public DbSet People { get; set; } -} -``` - -### Controllers - -You need to create controllers that inherit from `JsonApiController` or `JsonApiController` -where `TEntity` is the model that inherits from `Identifiable`. - -```csharp -public class PeopleController : JsonApiController -{ - public PeopleController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Middleware and Services - -Finally, add the services by adding the following to your -`Startup.ConfigureServices`: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) -{ - // add the db context like you normally would - services.AddDbContext(options => - { // use whatever provider you want, this is just an example - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); - - // add jsonapi dotnet core - services.AddJsonApi(); - // ... -} -``` - -Add the middleware to the `Startup.Configure` method. -Note that under the hood, this will call `app.UseMvc()` -so there is no need to add that as well. - -```csharp -public void Configure(IApplicationBuilder app) -{ - app.UseJsonApi(); -} -``` - -### Seeding the Database - -One way to seed the database is in your Configure method: - -```csharp -public void Configure( - IApplicationBuilder app, - AppDbContext context) -{ - context.Database.EnsureCreated(); - if(context.People.Count == 0) - { - context.People.Add(new Person { - Name = "John Doe" - }); - context.SaveChanges(); - } - // ... - app.UseJsonApi(); -} -``` - -### Run Migrations - -``` -$ dotnet ef migrations add AddPeople -$ dotnet ef database update -``` - -### Start the App - -``` -$ dotnet run -$ curl http://localhost:5000/people -``` diff --git a/docs/service_table.png b/docs/service_table.png deleted file mode 100644 index d6ae6113701fd95297b6f233c2e1a06b1ae6ff00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169430 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 URm3p;(Jt_3c)|ozuImu-Ujne*k^lez From d62df1c6217d5eabdca1b370ab6aadc84337861d Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 22 Apr 2018 07:43:59 -0500 Subject: [PATCH 133/227] chore(contrib): link to documentation --- CONTRIBUTING.MD | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 0e14787fec..8ce50e6c68 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -2,10 +2,14 @@ ## Workflow -1. Search through the issues to see if your particular issue has already been discovered and possibly addressed -2. Open an issue if you can't find anything helpful -3. Open a PR for proposed changes +1. Search through the issues to see if your particular issue has already been discovered and possibly addressed +2. Open an issue if you can't find anything helpful +3. Open a PR for proposed changes ## Commit Guidelines I have chosen to loosely follow the [Angular Commit Guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit) + +# Documentation + +If you'd like to help us improve our documentation, please checkout our [GitHub pages repository](https://github.com/json-api-dotnet/json-api-dotnet.github.io) where we host our documentation. From 0d1ba6e9fa3b76dad9d9b280e6d7b1c9d64a7417 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Mon, 23 Apr 2018 07:54:23 -0500 Subject: [PATCH 134/227] #162 Adds parameter name to new attribute value for example. --- src/Examples/JsonApiDotNetCoreExample/Models/Person.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs b/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs index 5aa7c83c12..d140b23b6b 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/Person.cs @@ -21,7 +21,7 @@ public class Person : Identifiable, IHasMeta [HasMany("todo-collections")] public virtual List TodoItemCollections { get; set; } - [HasOne("unincludeable-item", Link.All, false)] + [HasOne("unincludeable-item", Link.All, canInclude: false)] public virtual TodoItem UnIncludeableItem { get; set; } public Dictionary GetMeta(IJsonApiContext context) From 2b916465b3570c4c3e25edbe31e6b805b34e9854 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 24 Apr 2018 13:09:27 -0500 Subject: [PATCH 135/227] #258 Adds new utility to provide substrings of a given string as Span given a char delimeter. Language version updated to 7.2 due to need for ref Struct to utilize Span as a field. --- .../Internal/SpanSplitter.cs | 64 +++++++++++ .../JsonApiDotNetCore.csproj | 7 ++ test/UnitTests/Internal/SpanSplitterTests.cs | 107 ++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 src/JsonApiDotNetCore/Internal/SpanSplitter.cs create mode 100644 test/UnitTests/Internal/SpanSplitterTests.cs diff --git a/src/JsonApiDotNetCore/Internal/SpanSplitter.cs b/src/JsonApiDotNetCore/Internal/SpanSplitter.cs new file mode 100644 index 0000000000..268bcab195 --- /dev/null +++ b/src/JsonApiDotNetCore/Internal/SpanSplitter.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using JsonApiDotNetCore.Extensions; + +namespace JsonApiDotNetCore.Internal +{ + public readonly ref struct SpanSplitter + { + private readonly ReadOnlySpan _span; + private readonly List _delimeterIndexes; + private readonly List> _substringIndexes; + + public int Count => _substringIndexes.Count(); + public ReadOnlySpan this[int index] => GetSpanForSubstring(index + 1); + + public SpanSplitter(ref string str, char delimeter) + { + _span = str.AsSpan(); + _delimeterIndexes = str.IndexesOf(delimeter).ToList(); + _substringIndexes = new List>(); + BuildSubstringIndexes(); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => throw new NotSupportedException(); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException(); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() => throw new NotSupportedException(); + + private ReadOnlySpan GetSpanForSubstring(int substringNumber) + { + if (substringNumber > Count) + { + throw new ArgumentOutOfRangeException($"There are only {Count} substrings given the delimeter and base string provided"); + } + + var indexes = _substringIndexes[substringNumber - 1]; + return _span.Slice(indexes.Item1, indexes.Item2); + } + + private void BuildSubstringIndexes() + { + var start = 0; + var end = 0; + foreach (var index in _delimeterIndexes) + { + end = index; + if (start > end) break; + _substringIndexes.Add(new Tuple(start, end - start)); + start = ++end; + } + + if (end <= _span.Length) + { + _substringIndexes.Add(new Tuple(start, _span.Length - start)); + } + } + } +} diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index c4b9a6d932..f13c10ead7 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -21,6 +21,7 @@ + @@ -31,6 +32,12 @@ bin\Release\netstandard2.0\JsonApiDotNetCore.xml + + 7.2 + + + 7.2 + diff --git a/test/UnitTests/Internal/SpanSplitterTests.cs b/test/UnitTests/Internal/SpanSplitterTests.cs new file mode 100644 index 0000000000..016ee8ec82 --- /dev/null +++ b/test/UnitTests/Internal/SpanSplitterTests.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JsonApiDotNetCore.Internal; +using Xunit; + +namespace UnitTests.Internal +{ + public class SpanSplitterTests : SpanSplitterTestsBase + { + [Fact] + public void StringWithDelimeterSplitsIntoCorrectNumberSubstrings() + { + GivenMultipleCommaDelimetedString(); + WhenSplittingIntoSubstrings(); + AssertCorrectSubstringsReturned(); + } + + [Fact] + public void StringWithSingleDelimeterSplitsIntoCorrectNumberSubstrings() + { + GivenSingleCommaDelimetedString(); + WhenSplittingIntoSubstrings(); + AssertCorrectSubstringsReturned(); + } + + [Fact] + public void StringWithNoDelimeterSplitsIntoSingleSubstring() + { + GivenNonCommaDelimetedString(); + WhenSplittingIntoSubstrings(); + AssertCorrectSubstringsReturned(); + } + + [Fact] + public void StringWithDelimeterAtEndSplitsIntoCorrectSubstring() + { + GivenStringWithCommaDelimeterAtEnd(); + WhenSplittingIntoSubstrings(); + AssertCorrectSubstringsReturned(); + } + + [Fact] + public void StringWithDelimeterAtBeginningSplitsIntoCorrectSubstring() + { + GivenStringWithCommaDelimeterAtBeginning(); + WhenSplittingIntoSubstrings(); + AssertCorrectSubstringsReturned(); + } + } + + public abstract class SpanSplitterTestsBase + { + private string _baseString; + private char _delimeter; + private readonly List _substrings = new List(); + + protected void GivenMultipleCommaDelimetedString() + { + _baseString = "This,Is,A,TestString"; + _delimeter = ','; + } + + protected void GivenSingleCommaDelimetedString() + { + _baseString = "This,IsATestString"; + _delimeter = ','; + } + + protected void GivenNonCommaDelimetedString() + { + _baseString = "ThisIsATestString"; + } + + protected void GivenStringWithCommaDelimeterAtEnd() + { + _baseString = "This,IsATestString,"; + _delimeter = ','; + } + + protected void GivenStringWithCommaDelimeterAtBeginning() + { + _baseString = "/api/v1/articles"; + _delimeter = '/'; + } + + protected void WhenSplittingIntoSubstrings() + { + SpanSplitter spanSplitter; + spanSplitter = new SpanSplitter(ref _baseString, _delimeter); + for (var i = 0; i < spanSplitter.Count; i++) + { + var span = spanSplitter[i]; + _substrings.Add(span.ToString()); + } + } + + protected void AssertCorrectSubstringsReturned() + { + Assert.NotEmpty(_substrings); + var stringSplitArray = _baseString.Split(_delimeter); + Assert.Equal(stringSplitArray.Length, _substrings.Count); + Assert.True(stringSplitArray.SequenceEqual(_substrings)); + } + } +} From 85f09d171ded19c828659b1dda62e16960bbd478 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 24 Apr 2018 13:20:19 -0500 Subject: [PATCH 136/227] #258 Updates LinkBuilder, RelatedAttrFilterQuery, RequestMiddleware, JsonApiContext, and QueryParser to utilize new SpanSplitter library to avoid unnecessary intermediate string creation. --- src/JsonApiDotNetCore/Builders/LinkBuilder.cs | 23 ++++++++++--------- .../Extensions/StringExtensions.cs | 13 +++++++++++ .../Internal/Query/RelatedAttrFilterQuery.cs | 15 ++++++------ .../Middleware/RequestMiddleware.cs | 8 +++++-- .../Services/JsonApiContext.cs | 9 +++++--- src/JsonApiDotNetCore/Services/QueryParser.cs | 21 +++++++++++------ 6 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index dced1225a9..8b4b30f948 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -1,3 +1,6 @@ +using System; +using System.Text; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; @@ -20,20 +23,18 @@ public string GetBasePath(HttpContext context, string entityName) : $"{r.Scheme}://{r.Host}{GetNamespaceFromPath(r.Path, entityName)}"; } - private string GetNamespaceFromPath(string path, string entityName) + private static string GetNamespaceFromPath(string path, string entityName) { - var nSpace = string.Empty; - var segments = path.Split('/'); - - for (var i = 1; i < segments.Length; i++) + var sb = new StringBuilder(); + var entityNameSpan = entityName.AsSpan(); + var subSpans = new SpanSplitter(ref path, '/'); + for (var i = 1; i < subSpans.Count; i++) { - if (segments[i].ToLower() == entityName) - break; - - nSpace += $"/{segments[i]}"; + var span = subSpans[i]; + if (entityNameSpan.SequenceEqual(span)) break; + sb.Append($"/{span.ToString()}"); } - - return nSpace; + return sb.ToString(); } public string GetSelfRelationLink(string parent, string parentId, string child) diff --git a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs index 24d5bc8d58..e962baae3d 100644 --- a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using System.Text; namespace JsonApiDotNetCore.Extensions @@ -50,5 +52,16 @@ public static string Dasherize(this string str) } return str; } + + public static IEnumerable IndexesOf(this string str, char delimeter) + { + var indexes = new List(); + for (var i = str.IndexOf(delimeter); i > -1 ; i = str.IndexOf(delimeter, i+1)) + { + indexes.Add(i); + } + return indexes; + } + } } diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 5ec658873d..f4d8114a70 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -8,20 +8,21 @@ namespace JsonApiDotNetCore.Internal.Query public class RelatedAttrFilterQuery : BaseFilterQuery { private readonly IJsonApiContext _jsonApiContext; - + public RelatedAttrFilterQuery( IJsonApiContext jsonApiCopntext, FilterQuery filterQuery) { _jsonApiContext = jsonApiCopntext; - - var relationshipArray = filterQuery.Attribute.Split('.'); - - var relationship = GetRelationship(relationshipArray[0]); + var filterQueryAttribute = filterQuery.Attribute; + var relationshipSubSpans = new SpanSplitter(ref filterQueryAttribute, '.'); + var relationship1 = relationshipSubSpans[0].ToString(); + var relationship2 = relationshipSubSpans[1].ToString(); + var relationship = GetRelationship(relationshipSubSpans[0].ToString()); if (relationship == null) - throw new JsonApiException(400, $"{relationshipArray[1]} is not a valid relationship on {relationshipArray[0]}."); + throw new JsonApiException(400, $"{relationship2} is not a valid relationship on {relationship1}."); - var attribute = GetAttribute(relationship, relationshipArray[1]); + var attribute = GetAttribute(relationship, relationship2); if (attribute == null) throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 6e2612c9a6..54a116489d 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Http; @@ -54,8 +55,11 @@ private static bool IsValidAcceptHeader(HttpContext context) private static bool ContainsMediaTypeParameters(string mediaType) { - var mediaTypeArr = mediaType.Split(';'); - return (mediaTypeArr[0] == Constants.ContentType && mediaTypeArr.Length == 2); + const char delimeter = ';'; + var sliceLength = mediaType.IndexOf(delimeter); + if (sliceLength < 0) return false; + var mediaTypeSlice = mediaType.AsSpan().Slice(0, sliceLength); + return mediaTypeSlice.Length == 2 && mediaTypeSlice.SequenceEqual(Constants.ContentType.AsSpan()); } private static void FlushResponse(HttpContext context, int statusCode) diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 1ebf5aeea1..0f07624a4e 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -64,7 +64,7 @@ public IJsonApiContext ApplyContext(object controller) throw new JsonApiException(500, $"A resource has not been properly defined for type '{typeof(T)}'. Ensure it has been registered on the ContextGraph."); var context = _httpContextAccessor.HttpContext; - var path = context.Request.Path.Value.Split('/'); + var requestPath = context.Request.Path.Value; if (context.Request.Query.Count > 0) { @@ -75,10 +75,13 @@ public IJsonApiContext ApplyContext(object controller) var linkBuilder = new LinkBuilder(this); BasePath = linkBuilder.GetBasePath(context, _controllerContext.RequestEntity.EntityName); PageManager = GetPageManager(); - IsRelationshipPath = path[path.Length - 2] == "relationships"; + + var pathSpans = new SpanSplitter(ref requestPath, '/'); + IsRelationshipPath = pathSpans[pathSpans.Count - 2].ToString() == "relationships"; + return this; } - + private PageManager GetPageManager() { if (Options.DefaultPageSize == 0 && (QuerySet == null || QuerySet.PageQuery.PageSize == 0)) diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 5e705f4bc9..f988664c62 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -3,6 +3,7 @@ using System.Linq; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; @@ -93,16 +94,16 @@ protected virtual List ParseFilterQuery(string key, string value) // expected input = filter[id]=1 // expected input = filter[id]=eq:1 var queries = new List(); + var openBracketIndex = key.IndexOf(OPEN_BRACKET); + var closedBracketIndex = key.IndexOf(CLOSE_BRACKET); + var propertyNameSlice = key.AsSpan().Slice(openBracketIndex + 1, closedBracketIndex - openBracketIndex - 1); + var propertyName = propertyNameSlice.ToString(); - var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; - - var values = value.Split(COMMA); - foreach (var val in values) + var spanSplitter = new SpanSplitter(ref value, COMMA); + for (var i = 0; i < spanSplitter.Count; i++) { - (var operation, var filterValue) = ParseFilterOperation(val); - queries.Add(new FilterQuery(propertyName, filterValue, operation)); + queries.Add(BuildFilterQuery(spanSplitter[i], propertyName)); } - return queries; } @@ -235,5 +236,11 @@ protected virtual AttrAttribute GetAttribute(string propertyName) throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'", e); } } + + private FilterQuery BuildFilterQuery(ReadOnlySpan query, string propertyName) + { + var (operation, filterValue) = ParseFilterOperation(query.ToString()); + return new FilterQuery(propertyName, filterValue, operation); + } } } From a7d33903f89e4e95b9a0f28c716da5698d8a8ab3 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 24 Apr 2018 13:41:51 -0500 Subject: [PATCH 137/227] #258 Fixes Error in ContainsMediaTypeParameters method's logic. ContentNegotion tests pass. --- src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 54a116489d..a7bbebb7f4 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -56,10 +56,9 @@ private static bool IsValidAcceptHeader(HttpContext context) private static bool ContainsMediaTypeParameters(string mediaType) { const char delimeter = ';'; - var sliceLength = mediaType.IndexOf(delimeter); - if (sliceLength < 0) return false; - var mediaTypeSlice = mediaType.AsSpan().Slice(0, sliceLength); - return mediaTypeSlice.Length == 2 && mediaTypeSlice.SequenceEqual(Constants.ContentType.AsSpan()); + var subSpans = new SpanSplitter(ref mediaType, delimeter); + if (subSpans.Count == 0) return false; + return subSpans.Count == 2 && subSpans[0].ToString() == Constants.ContentType; } private static void FlushResponse(HttpContext context, int statusCode) From 6ab917f732ed8b5de634c5e7c3c70d597720eb34 Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 24 Apr 2018 20:31:10 -0500 Subject: [PATCH 138/227] #258 Removes extra ToString() on the span and fixes naming to be more accurate --- .../Internal/Query/RelatedAttrFilterQuery.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index f4d8114a70..8602a24f30 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -15,14 +15,14 @@ public RelatedAttrFilterQuery( { _jsonApiContext = jsonApiCopntext; var filterQueryAttribute = filterQuery.Attribute; - var relationshipSubSpans = new SpanSplitter(ref filterQueryAttribute, '.'); - var relationship1 = relationshipSubSpans[0].ToString(); - var relationship2 = relationshipSubSpans[1].ToString(); - var relationship = GetRelationship(relationshipSubSpans[0].ToString()); + var filterQuerySubSpans = new SpanSplitter(ref filterQueryAttribute, '.'); + var subSpan1 = filterQuerySubSpans[0].ToString(); + var subSpan2 = filterQuerySubSpans[1].ToString(); + var relationship = GetRelationship(subSpan1); if (relationship == null) - throw new JsonApiException(400, $"{relationship2} is not a valid relationship on {relationship1}."); + throw new JsonApiException(400, $"{subSpan2} is not a valid relationship on {subSpan1}."); - var attribute = GetAttribute(relationship, relationship2); + var attribute = GetAttribute(relationship, subSpan2); if (attribute == null) throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); From 86d76356f72a04d79d64a3043181578744bd06fc Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 24 Apr 2018 20:52:15 -0500 Subject: [PATCH 139/227] #258 Adds extension method for splitting with spans. Updates usages and unit tests to use extension method. --- src/JsonApiDotNetCore/Builders/LinkBuilder.cs | 3 ++- src/JsonApiDotNetCore/Extensions/StringExtensions.cs | 6 ++++++ .../Internal/Query/RelatedAttrFilterQuery.cs | 3 ++- src/JsonApiDotNetCore/Internal/SpanSplitter.cs | 7 ++++++- src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs | 3 ++- src/JsonApiDotNetCore/Services/JsonApiContext.cs | 3 ++- src/JsonApiDotNetCore/Services/QueryParser.cs | 2 +- test/UnitTests/Internal/SpanSplitterTests.cs | 3 ++- 8 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index 8b4b30f948..b2bfcae168 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; @@ -27,7 +28,7 @@ private static string GetNamespaceFromPath(string path, string entityName) { var sb = new StringBuilder(); var entityNameSpan = entityName.AsSpan(); - var subSpans = new SpanSplitter(ref path, '/'); + var subSpans = path.SpanSplit('/'); for (var i = 1; i < subSpans.Count; i++) { var span = subSpans[i]; diff --git a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs index e962baae3d..c64795cae1 100644 --- a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using JsonApiDotNetCore.Internal; namespace JsonApiDotNetCore.Extensions { @@ -62,6 +63,11 @@ public static IEnumerable IndexesOf(this string str, char delimeter) } return indexes; } + + public static SpanSplitter SpanSplit(this string str, char delimeter) + { + return SpanSplitter.Split(str, delimeter); + } } } diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 8602a24f30..6415b0c575 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; @@ -15,7 +16,7 @@ public RelatedAttrFilterQuery( { _jsonApiContext = jsonApiCopntext; var filterQueryAttribute = filterQuery.Attribute; - var filterQuerySubSpans = new SpanSplitter(ref filterQueryAttribute, '.'); + var filterQuerySubSpans = filterQueryAttribute.SpanSplit('.'); var subSpan1 = filterQuerySubSpans[0].ToString(); var subSpan2 = filterQuerySubSpans[1].ToString(); var relationship = GetRelationship(subSpan1); diff --git a/src/JsonApiDotNetCore/Internal/SpanSplitter.cs b/src/JsonApiDotNetCore/Internal/SpanSplitter.cs index 268bcab195..0f9aecbb59 100644 --- a/src/JsonApiDotNetCore/Internal/SpanSplitter.cs +++ b/src/JsonApiDotNetCore/Internal/SpanSplitter.cs @@ -15,7 +15,7 @@ public readonly ref struct SpanSplitter public int Count => _substringIndexes.Count(); public ReadOnlySpan this[int index] => GetSpanForSubstring(index + 1); - public SpanSplitter(ref string str, char delimeter) + private SpanSplitter(ref string str, char delimeter) { _span = str.AsSpan(); _delimeterIndexes = str.IndexesOf(delimeter).ToList(); @@ -23,6 +23,11 @@ public SpanSplitter(ref string str, char delimeter) BuildSubstringIndexes(); } + public static SpanSplitter Split(string str, char delimeter) + { + return new SpanSplitter(ref str, delimeter); + } + [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object obj) => throw new NotSupportedException(); diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index a7bbebb7f4..8b6111fef9 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -56,7 +57,7 @@ private static bool IsValidAcceptHeader(HttpContext context) private static bool ContainsMediaTypeParameters(string mediaType) { const char delimeter = ';'; - var subSpans = new SpanSplitter(ref mediaType, delimeter); + var subSpans = mediaType.SpanSplit(delimeter); if (subSpans.Count == 0) return false; return subSpans.Count == 2 && subSpans[0].ToString() == Constants.ContentType; } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 0f07624a4e..b45b68c97b 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -3,6 +3,7 @@ using System.Linq; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; @@ -76,7 +77,7 @@ public IJsonApiContext ApplyContext(object controller) BasePath = linkBuilder.GetBasePath(context, _controllerContext.RequestEntity.EntityName); PageManager = GetPageManager(); - var pathSpans = new SpanSplitter(ref requestPath, '/'); + var pathSpans = requestPath.SpanSplit('/'); IsRelationshipPath = pathSpans[pathSpans.Count - 2].ToString() == "relationships"; return this; diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index f988664c62..ddff31b5f1 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -99,7 +99,7 @@ protected virtual List ParseFilterQuery(string key, string value) var propertyNameSlice = key.AsSpan().Slice(openBracketIndex + 1, closedBracketIndex - openBracketIndex - 1); var propertyName = propertyNameSlice.ToString(); - var spanSplitter = new SpanSplitter(ref value, COMMA); + var spanSplitter = value.SpanSplit(COMMA); for (var i = 0; i < spanSplitter.Count; i++) { queries.Add(BuildFilterQuery(spanSplitter[i], propertyName)); diff --git a/test/UnitTests/Internal/SpanSplitterTests.cs b/test/UnitTests/Internal/SpanSplitterTests.cs index 016ee8ec82..61160e7462 100644 --- a/test/UnitTests/Internal/SpanSplitterTests.cs +++ b/test/UnitTests/Internal/SpanSplitterTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using Xunit; @@ -88,7 +89,7 @@ protected void GivenStringWithCommaDelimeterAtBeginning() protected void WhenSplittingIntoSubstrings() { SpanSplitter spanSplitter; - spanSplitter = new SpanSplitter(ref _baseString, _delimeter); + spanSplitter = _baseString.SpanSplit(_delimeter); for (var i = 0; i < spanSplitter.Count; i++) { var span = spanSplitter[i]; From 6fc48de9f017b56b6f474fcdc0ae7c978c2c235f Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Wed, 25 Apr 2018 14:13:03 -0500 Subject: [PATCH 140/227] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index ae66e3a07c..2250ef4568 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,16 @@ A framework for building [json:api](http://jsonapi.org/) compliant web APIs. The ultimate goal of this library is to eliminate as much boilerplate as possible by offering out-of-the-box features such as sorting, filtering and pagination. You just need to focus on defining the resources and implementing your custom business logic. This library has been designed around dependency injection making extensibility incredibly easy. +## Getting Started + +These are some steps you can take to help you understand what this project is and how you can use it: + +- [What is json:api and why should I use it?](https://nordicapis.com/the-benefits-of-using-json-api/) +- [The json:api specification](http://jsonapi.org/format/) +- [Demo [Video]](https://youtu.be/KAMuo6K7VcE) +- [Our documentation](https://json-api-dotnet.github.io) +- Check out the examples in the next section + ## Examples See the [examples](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/src/Examples) directory for up-to-date sample applications. There is also a [Todo List App](https://github.com/json-api-dotnet/TodoListExample) that includes a JADNC API and an EmberJs client. From a7774b552ac51e4139403a7b4892aa78cff1acbe Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 28 Apr 2018 20:01:32 -0500 Subject: [PATCH 141/227] refactor(LinkBuilder): reduce allocations --- ...espaceFromPath_Benchmarks-report-github.md | 16 ++++ ...uilder_ GetNamespaceFromPath_Benchmarks.cs | 90 +++++++++++++++++++ benchmarks/Program.cs | 4 +- src/JsonApiDotNetCore/Builders/LinkBuilder.cs | 36 +++++--- 4 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.LinkBuilder.LinkBuilder_GetNamespaceFromPath_Benchmarks-report-github.md create mode 100644 benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.LinkBuilder.LinkBuilder_GetNamespaceFromPath_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.LinkBuilder.LinkBuilder_GetNamespaceFromPath_Benchmarks-report-github.md new file mode 100644 index 0000000000..72951396e8 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.LinkBuilder.LinkBuilder_GetNamespaceFromPath_Benchmarks-report-github.md @@ -0,0 +1,16 @@ +``` ini + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.1.4 + [Host] : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT + Job-XFMVNE : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT + +LaunchCount=3 TargetCount=20 WarmupCount=10 + +``` +| Method | Mean | Error | StdDev | Gen 0 | Allocated | +|--------------------------- |-----------:|----------:|----------:|-------:|----------:| +| UsingSplit | 1,197.6 ns | 11.929 ns | 25.933 ns | 0.9251 | 1456 B | +| UsingSpanWithStringBuilder | 1,542.0 ns | 15.249 ns | 33.792 ns | 0.9460 | 1488 B | +| UsingSpanWithNoAlloc | 272.6 ns | 2.265 ns | 5.018 ns | 0.0863 | 136 B | diff --git a/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs new file mode 100644 index 0000000000..0604a68083 --- /dev/null +++ b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs @@ -0,0 +1,90 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Threading; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; +using BenchmarkDotNet.Attributes.Jobs; +using JsonApiDotNetCore.Extensions; + +namespace Benchmarks.LinkBuilder +{ + [MarkdownExporter, SimpleJob(launchCount : 3, warmupCount : 10, targetCount : 20), MemoryDiagnoser] + public class LinkBuilder_GetNamespaceFromPath_Benchmarks + { + private const string PATH = "/api/some-really-long-namespace-path/resources/current/articles"; + private const string ENTITY_NAME = "articles"; + + [Benchmark] + public void UsingSplit() => GetNamespaceFromPath_BySplitting(PATH, ENTITY_NAME); + + [Benchmark] + public void UsingSpanWithStringBuilder() => GetNamespaceFromPath_Using_Span_With_StringBuilder(PATH, ENTITY_NAME); + + [Benchmark] + public void UsingSpanWithNoAlloc() => GetNamespaceFromPath_Using_Span_No_Alloc(PATH, ENTITY_NAME); + + public static string GetNamespaceFromPath_BySplitting(string path, string entityName) + { + var nSpace = string.Empty; + var segments = path.Split('/'); + + for (var i = 1; i < segments.Length; i++) + { + if (segments[i].ToLower() == entityName) + break; + + nSpace += $"/{segments[i]}"; + } + + return nSpace; + } + + public static string GetNamespaceFromPath_Using_Span_No_Alloc(string path, string entityName) + { + var entityNameSpan = entityName.AsSpan(); + var pathSpan = path.AsSpan(); + const char delimiter = '/'; + for (var i = 0; i < pathSpan.Length; i++) + { + if(pathSpan[i].Equals(delimiter)) + { + var nextPosition = i+1; + if(pathSpan.Length > i + entityNameSpan.Length) + { + var possiblePathSegment = pathSpan.Slice(nextPosition, entityNameSpan.Length); + if (entityNameSpan.SequenceEqual(possiblePathSegment)) + { + // check to see if it's the last position in the string + // or if the next character is a / + var lastCharacterPosition = nextPosition + entityNameSpan.Length; + + if(lastCharacterPosition == pathSpan.Length || pathSpan.Length >= lastCharacterPosition + 2 && pathSpan[lastCharacterPosition + 1].Equals(delimiter)) + { + return pathSpan.Slice(0, i).ToString(); + } + } + } + } + } + + return string.Empty; + } + + public static string GetNamespaceFromPath_Using_Span_With_StringBuilder(string path, string entityName) + { + var sb = new StringBuilder(); + var entityNameSpan = entityName.AsSpan(); + var subSpans = path.SpanSplit('/'); + for (var i = 1; i < subSpans.Count; i++) + { + var span = subSpans[i]; + if (entityNameSpan.SequenceEqual(span)) + break; + + sb.Append($"/{span.ToString()}"); + } + return sb.ToString(); + } + } +} diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index 7665d5fb97..813153ecb5 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Running; +using Benchmarks.LinkBuilder; using Benchmarks.Query; using Benchmarks.Serialization; @@ -8,7 +9,8 @@ static void Main(string[] args) { var switcher = new BenchmarkSwitcher(new[] { typeof(JsonApiDeserializer_Benchmarks), typeof(JsonApiSerializer_Benchmarks), - typeof(QueryParser_Benchmarks) + typeof(QueryParser_Benchmarks), + typeof(LinkBuilder_GetNamespaceFromPath_Benchmarks) }); switcher.Run(args); } diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index b2bfcae168..9c3d19b05b 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -1,7 +1,4 @@ using System; -using System.Text; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Services; using Microsoft.AspNetCore.Http; @@ -20,22 +17,39 @@ public string GetBasePath(HttpContext context, string entityName) { var r = context.Request; return (_context.Options.RelativeLinks) - ? $"{GetNamespaceFromPath(r.Path, entityName)}" + ? GetNamespaceFromPath(r.Path, entityName) : $"{r.Scheme}://{r.Host}{GetNamespaceFromPath(r.Path, entityName)}"; } private static string GetNamespaceFromPath(string path, string entityName) { - var sb = new StringBuilder(); var entityNameSpan = entityName.AsSpan(); - var subSpans = path.SpanSplit('/'); - for (var i = 1; i < subSpans.Count; i++) + var pathSpan = path.AsSpan(); + const char delimiter = '/'; + for (var i = 0; i < pathSpan.Length; i++) { - var span = subSpans[i]; - if (entityNameSpan.SequenceEqual(span)) break; - sb.Append($"/{span.ToString()}"); + if(pathSpan[i].Equals(delimiter)) + { + var nextPosition = i + 1; + if(pathSpan.Length > i + entityNameSpan.Length) + { + var possiblePathSegment = pathSpan.Slice(nextPosition, entityNameSpan.Length); + if (entityNameSpan.SequenceEqual(possiblePathSegment)) + { + // check to see if it's the last position in the string + // or if the next character is a / + var lastCharacterPosition = nextPosition + entityNameSpan.Length; + + if(lastCharacterPosition == pathSpan.Length || pathSpan.Length >= lastCharacterPosition + 2 && pathSpan[lastCharacterPosition].Equals(delimiter)) + { + return pathSpan.Slice(0, i).ToString(); + } + } + } + } } - return sb.ToString(); + + return string.Empty; } public string GetSelfRelationLink(string parent, string parentId, string child) From 8beb2e50fe38ca7d3cc3c0b0297512bee94b2ceb Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 1 May 2018 10:46:39 -0500 Subject: [PATCH 142/227] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b8a1d74643..7ac38bba9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ services: before_script: - psql -c 'create database JsonApiDotNetCoreExample;' -U postgres mono: none -dotnet: 2.0.3 # https://www.microsoft.com/net/download/linux +dotnet: 2.1.105 # https://www.microsoft.com/net/download/linux branches: only: - master From e3741253b852bd4bf385345e2b57844a95a2fb67 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 1 May 2018 20:33:00 -0500 Subject: [PATCH 143/227] benchamrk: don't duplicate the final version's definition --- ...uilder_ GetNamespaceFromPath_Benchmarks.cs | 36 ++----------------- src/JsonApiDotNetCore/Builders/LinkBuilder.cs | 2 +- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs index 0604a68083..d53294e749 100644 --- a/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs +++ b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs @@ -1,7 +1,5 @@ using System; -using System.Diagnostics; using System.Text; -using System.Threading; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes.Exporters; using BenchmarkDotNet.Attributes.Jobs; @@ -22,7 +20,7 @@ public class LinkBuilder_GetNamespaceFromPath_Benchmarks public void UsingSpanWithStringBuilder() => GetNamespaceFromPath_Using_Span_With_StringBuilder(PATH, ENTITY_NAME); [Benchmark] - public void UsingSpanWithNoAlloc() => GetNamespaceFromPath_Using_Span_No_Alloc(PATH, ENTITY_NAME); + public void Current() => GetNameSpaceFromPath_Current(PATH, ENTITY_NAME); public static string GetNamespaceFromPath_BySplitting(string path, string entityName) { @@ -40,36 +38,8 @@ public static string GetNamespaceFromPath_BySplitting(string path, string entity return nSpace; } - public static string GetNamespaceFromPath_Using_Span_No_Alloc(string path, string entityName) - { - var entityNameSpan = entityName.AsSpan(); - var pathSpan = path.AsSpan(); - const char delimiter = '/'; - for (var i = 0; i < pathSpan.Length; i++) - { - if(pathSpan[i].Equals(delimiter)) - { - var nextPosition = i+1; - if(pathSpan.Length > i + entityNameSpan.Length) - { - var possiblePathSegment = pathSpan.Slice(nextPosition, entityNameSpan.Length); - if (entityNameSpan.SequenceEqual(possiblePathSegment)) - { - // check to see if it's the last position in the string - // or if the next character is a / - var lastCharacterPosition = nextPosition + entityNameSpan.Length; - - if(lastCharacterPosition == pathSpan.Length || pathSpan.Length >= lastCharacterPosition + 2 && pathSpan[lastCharacterPosition + 1].Equals(delimiter)) - { - return pathSpan.Slice(0, i).ToString(); - } - } - } - } - } - - return string.Empty; - } + public static string GetNameSpaceFromPath_Current(string path, string entityName) + => JsonApiDotNetCore.Builders.LinkBuilder.GetNamespaceFromPath(path, entityName); public static string GetNamespaceFromPath_Using_Span_With_StringBuilder(string path, string entityName) { diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index 9c3d19b05b..c3769eccbc 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -21,7 +21,7 @@ public string GetBasePath(HttpContext context, string entityName) : $"{r.Scheme}://{r.Host}{GetNamespaceFromPath(r.Path, entityName)}"; } - private static string GetNamespaceFromPath(string path, string entityName) + internal static string GetNamespaceFromPath(string path, string entityName) { var entityNameSpan = entityName.AsSpan(); var pathSpan = path.AsSpan(); From b647f94ab037624d359f59ea0ba905cc47e104ea Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 1 May 2018 21:26:19 -0500 Subject: [PATCH 144/227] add benchmarks to RequestMiddleware --- ...TypeParameters_Benchmarks-report-github.md | 14 ++++++++++ benchmarks/Program.cs | 4 ++- .../ContainsMediaTypeParameters_Benchmarks.cs | 26 +++++++++++++++++++ .../Middleware/RequestMiddleware.cs | 22 +++++++++++----- 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RequestMiddleware.ContainsMediaTypeParameters_Benchmarks-report-github.md create mode 100644 benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RequestMiddleware.ContainsMediaTypeParameters_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RequestMiddleware.ContainsMediaTypeParameters_Benchmarks-report-github.md new file mode 100644 index 0000000000..066e7b2036 --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.RequestMiddleware.ContainsMediaTypeParameters_Benchmarks-report-github.md @@ -0,0 +1,14 @@ +``` ini + +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.1.4 + [Host] : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT + DefaultJob : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT + + +``` +| Method | Mean | Error | StdDev | Gen 0 | Allocated | +|----------- |----------:|----------:|----------:|-------:|----------:| +| UsingSplit | 157.28 ns | 2.9689 ns | 5.8602 ns | 0.2134 | 336 B | +| Current | 39.96 ns | 0.6489 ns | 0.6070 ns | - | 0 B | diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index 813153ecb5..989272c7f1 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -1,6 +1,7 @@ using BenchmarkDotNet.Running; using Benchmarks.LinkBuilder; using Benchmarks.Query; +using Benchmarks.RequestMiddleware; using Benchmarks.Serialization; namespace Benchmarks { @@ -10,7 +11,8 @@ static void Main(string[] args) { typeof(JsonApiDeserializer_Benchmarks), typeof(JsonApiSerializer_Benchmarks), typeof(QueryParser_Benchmarks), - typeof(LinkBuilder_GetNamespaceFromPath_Benchmarks) + typeof(LinkBuilder_GetNamespaceFromPath_Benchmarks), + typeof(ContainsMediaTypeParameters_Benchmarks) }); switcher.Run(args); } diff --git a/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs b/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs new file mode 100644 index 0000000000..9826bd158a --- /dev/null +++ b/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs @@ -0,0 +1,26 @@ +using System; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; +using JsonApiDotNetCore.Internal; + +namespace Benchmarks.RequestMiddleware +{ + [MarkdownExporter, MemoryDiagnoser] + public class ContainsMediaTypeParameters_Benchmarks + { + private const string MEDIA_TYPE = "application/vnd.api+json; version=1"; + + [Benchmark] + public void UsingSplit() => UsingSplitImpl(MEDIA_TYPE); + + [Benchmark] + public void Current() + => JsonApiDotNetCore.Middleware.RequestMiddleware.ContainsMediaTypeParameters(MEDIA_TYPE); + + private bool UsingSplitImpl(string mediaType) + { + var mediaTypeArr = mediaType.Split(';'); + return (mediaTypeArr[0] == Constants.ContentType && mediaTypeArr.Length == 2); + } + } +} diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index 8b6111fef9..0ce54c8589 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -54,12 +53,23 @@ private static bool IsValidAcceptHeader(HttpContext context) return true; } - private static bool ContainsMediaTypeParameters(string mediaType) + internal static bool ContainsMediaTypeParameters(string mediaType) { - const char delimeter = ';'; - var subSpans = mediaType.SpanSplit(delimeter); - if (subSpans.Count == 0) return false; - return subSpans.Count == 2 && subSpans[0].ToString() == Constants.ContentType; + var incomingMediaTypeSpan = mediaType.AsSpan(); + + // if the content type is not application/vnd.api+json then continue on + if(incomingMediaTypeSpan.Length < Constants.ContentType.Length) + return false; + + var incomingContentType = incomingMediaTypeSpan.Slice(0, Constants.ContentType.Length); + if(incomingContentType.SequenceEqual(Constants.ContentType.AsSpan()) == false) + return false; + + // anything appended to "application/vnd.api+json;" will be considered a media type param + return ( + incomingMediaTypeSpan.Length >= Constants.ContentType.Length + 2 + && incomingMediaTypeSpan[Constants.ContentType.Length] == ';' + ); } private static void FlushResponse(HttpContext context, int statusCode) From 0f4ccf660d97d14bffae2fe346ba7216ef3611ac Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 1 May 2018 22:24:57 -0500 Subject: [PATCH 145/227] add benchmarks for IsRelationshipPath --- ...IsRelationship_Benchmarks-report-github.md | 12 +++++ .../PathIsRelationship_Benchmarks.cs | 24 ++++++++++ benchmarks/Program.cs | 4 +- .../ContainsMediaTypeParameters_Benchmarks.cs | 1 - .../Services/JsonApiContext.cs | 44 +++++++++++++++---- 5 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.JsonApiContext.PathIsRelationship_Benchmarks-report-github.md create mode 100644 benchmarks/JsonApiContext/PathIsRelationship_Benchmarks.cs diff --git a/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.JsonApiContext.PathIsRelationship_Benchmarks-report-github.md b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.JsonApiContext.PathIsRelationship_Benchmarks-report-github.md new file mode 100644 index 0000000000..6be58e241a --- /dev/null +++ b/benchmarks/BenchmarkDotNet.Artifacts/results/Benchmarks.JsonApiContext.PathIsRelationship_Benchmarks-report-github.md @@ -0,0 +1,12 @@ +```ini +BenchmarkDotNet=v0.10.10, OS=Mac OS X 10.12 +Processor=Intel Core i5-5257U CPU 2.70GHz (Broadwell), ProcessorCount=4 +.NET Core SDK=2.1.4 + [Host] : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT + DefaultJob : .NET Core 2.0.5 (Framework 4.6.0.0), 64bit RyuJIT +``` + +| Method | Mean | Error | StdDev | Gen 0 | Allocated | +| ---------- | --------: | ---------: | ---------: | -----: | --------: | +| UsingSplit | 421.08 ns | 19.3905 ns | 54.0529 ns | 0.4725 | 744 B | +| Current | 52.23 ns | 0.8052 ns | 0.7532 ns | - | 0 B | diff --git a/benchmarks/JsonApiContext/PathIsRelationship_Benchmarks.cs b/benchmarks/JsonApiContext/PathIsRelationship_Benchmarks.cs new file mode 100644 index 0000000000..83fe6fc53c --- /dev/null +++ b/benchmarks/JsonApiContext/PathIsRelationship_Benchmarks.cs @@ -0,0 +1,24 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; + +namespace Benchmarks.JsonApiContext +{ + [MarkdownExporter, MemoryDiagnoser] + public class PathIsRelationship_Benchmarks + { + private const string PATH = "https://example.com/api/v1/namespace/articles/relationships/author/"; + + [Benchmark] + public void Current() + => JsonApiDotNetCore.Services.JsonApiContext.PathIsRelationship(PATH); + + [Benchmark] + public void UsingSplit() => UsingSplitImpl(PATH); + + private bool UsingSplitImpl(string path) + { + var split = path.Split('/'); + return split[split.Length - 2] == "relationships"; + } + } +} diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index 989272c7f1..9a2c45dffb 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Running; +using Benchmarks.JsonApiContext; using Benchmarks.LinkBuilder; using Benchmarks.Query; using Benchmarks.RequestMiddleware; @@ -12,7 +13,8 @@ static void Main(string[] args) { typeof(JsonApiSerializer_Benchmarks), typeof(QueryParser_Benchmarks), typeof(LinkBuilder_GetNamespaceFromPath_Benchmarks), - typeof(ContainsMediaTypeParameters_Benchmarks) + typeof(ContainsMediaTypeParameters_Benchmarks), + typeof(PathIsRelationship_Benchmarks) }); switcher.Run(args); } diff --git a/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs b/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs index 9826bd158a..ed64c98335 100644 --- a/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs +++ b/benchmarks/RequestMiddleware/ContainsMediaTypeParameters_Benchmarks.cs @@ -1,4 +1,3 @@ -using System; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes.Exporters; using JsonApiDotNetCore.Internal; diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index b45b68c97b..2665217fef 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; @@ -65,7 +63,6 @@ public IJsonApiContext ApplyContext(object controller) throw new JsonApiException(500, $"A resource has not been properly defined for type '{typeof(T)}'. Ensure it has been registered on the ContextGraph."); var context = _httpContextAccessor.HttpContext; - var requestPath = context.Request.Path.Value; if (context.Request.Query.Count > 0) { @@ -73,15 +70,46 @@ public IJsonApiContext ApplyContext(object controller) IncludedRelationships = QuerySet.IncludedRelationships; } - var linkBuilder = new LinkBuilder(this); - BasePath = linkBuilder.GetBasePath(context, _controllerContext.RequestEntity.EntityName); + BasePath = new LinkBuilder(this).GetBasePath(context, _controllerContext.RequestEntity.EntityName); PageManager = GetPageManager(); - - var pathSpans = requestPath.SpanSplit('/'); - IsRelationshipPath = pathSpans[pathSpans.Count - 2].ToString() == "relationships"; + IsRelationshipPath = PathIsRelationship(context.Request.Path.Value); return this; } + + internal static bool PathIsRelationship(string requestPath) + { + // while(!Debugger.IsAttached) { Thread.Sleep(1000); } + const string relationships = "relationships"; + const char pathSegmentDelimiter = '/'; + + var span = requestPath.AsSpan(); + + // we need to iterate over the string, from the end, + // checking whether or not the 2nd to last path segment + // is "relationships" + // -2 is chosen in case the path ends with '/' + for(var i = requestPath.Length - 2; i >= 0; i--) + { + // if there are not enough characters left in the path to + // contain "relationships" + if(i < relationships.Length) + return false; + + // we have found the first instance of '/' + if(span[i] == pathSegmentDelimiter) + { + // in the case of a "relationships" route, the next + // path segment will be "relationships" + return ( + span.Slice(i - relationships.Length, relationships.Length) + .SequenceEqual(relationships.AsSpan()) + ); + } + } + + return false; + } private PageManager GetPageManager() { From d94287ef0cf9b786140a5ba483e134dd122d12d6 Mon Sep 17 00:00:00 2001 From: Jacob Hilty Date: Fri, 4 May 2018 13:16:56 -0400 Subject: [PATCH 146/227] Closes #273 --- src/JsonApiDotNetCore/Builders/LinkBuilder.cs | 4 +- .../Internal/Query/QueryConstants.cs | 15 +++++ .../Services/QueryComposer.cs | 38 +++++++++++++ src/JsonApiDotNetCore/Services/QueryParser.cs | 39 +++++-------- .../Spec/DocumentTests/PagingTests.cs | 1 + test/UnitTests/Services/QueryComposerTests.cs | 57 +++++++++++++++++++ 6 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 src/JsonApiDotNetCore/Internal/Query/QueryConstants.cs create mode 100644 src/JsonApiDotNetCore/Services/QueryComposer.cs create mode 100644 test/UnitTests/Services/QueryComposerTests.cs diff --git a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs index dced1225a9..42b82e6255 100644 --- a/src/JsonApiDotNetCore/Builders/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/LinkBuilder.cs @@ -48,7 +48,9 @@ public string GetRelatedRelationLink(string parent, string parentId, string chil public string GetPageLink(int pageOffset, int pageSize) { - return $"{_context.BasePath}/{_context.RequestEntity.EntityName}?page[size]={pageSize}&page[number]={pageOffset}"; + var filterQueryComposer = new QueryComposer(); + var filters = filterQueryComposer.Compose(_context); + return $"{_context.BasePath}/{_context.RequestEntity.EntityName}?page[size]={pageSize}&page[number]={pageOffset}{filters}"; } } } diff --git a/src/JsonApiDotNetCore/Internal/Query/QueryConstants.cs b/src/JsonApiDotNetCore/Internal/Query/QueryConstants.cs new file mode 100644 index 0000000000..3117ff7cb3 --- /dev/null +++ b/src/JsonApiDotNetCore/Internal/Query/QueryConstants.cs @@ -0,0 +1,15 @@ +namespace JsonApiDotNetCore.Internal.Query{ + public static class QueryConstants { + public const string FILTER = "filter"; + public const string SORT = "sort"; + public const string INCLUDE = "include"; + public const string PAGE = "page"; + public const string FIELDS = "fields"; + public const char OPEN_BRACKET = '['; + public const char CLOSE_BRACKET = ']'; + public const char COMMA = ','; + public const char COLON = ':'; + public const string COLON_STR = ":"; + + } +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Services/QueryComposer.cs b/src/JsonApiDotNetCore/Services/QueryComposer.cs new file mode 100644 index 0000000000..8fbf16339b --- /dev/null +++ b/src/JsonApiDotNetCore/Services/QueryComposer.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Internal.Query; +using Microsoft.Extensions.Logging; + +namespace JsonApiDotNetCore.Services +{ + public interface IQueryComposer + { + string Compose(IJsonApiContext jsonApiContext); + } + + public class QueryComposer : IQueryComposer + { + public string Compose(IJsonApiContext jsonApiContext) + { + string result = ""; + if(jsonApiContext != null && jsonApiContext.QuerySet != null) + { + List filterQueries = jsonApiContext.QuerySet.Filters; + if (filterQueries.Count > 0) + { + foreach (FilterQuery filter in filterQueries) + { + result += ComposeSingleFilter(filter); + } + } + } + return result; + } + + private string ComposeSingleFilter(FilterQuery query) + { + var result = "&filter"; + result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + query.Operation + query.Value; + return result; + } + } +} diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 5e705f4bc9..d7ac2d90bf 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -20,17 +20,6 @@ public class QueryParser : IQueryParser private readonly IControllerContext _controllerContext; private readonly JsonApiOptions _options; - private const string FILTER = "filter"; - private const string SORT = "sort"; - private const string INCLUDE = "include"; - private const string PAGE = "page"; - private const string FIELDS = "fields"; - private const char OPEN_BRACKET = '['; - private const char CLOSE_BRACKET = ']'; - private const char COMMA = ','; - private const char COLON = ':'; - private const string COLON_STR = ":"; - public QueryParser( IControllerContext controllerContext, JsonApiOptions options) @@ -46,35 +35,35 @@ public virtual QuerySet Parse(IQueryCollection query) foreach (var pair in query) { - if (pair.Key.StartsWith(FILTER)) + if (pair.Key.StartsWith(QueryConstants.FILTER)) { if (disabledQueries.HasFlag(QueryParams.Filter) == false) querySet.Filters.AddRange(ParseFilterQuery(pair.Key, pair.Value)); continue; } - if (pair.Key.StartsWith(SORT)) + if (pair.Key.StartsWith(QueryConstants.SORT)) { if (disabledQueries.HasFlag(QueryParams.Sort) == false) querySet.SortParameters = ParseSortParameters(pair.Value); continue; } - if (pair.Key.StartsWith(INCLUDE)) + if (pair.Key.StartsWith(QueryConstants.INCLUDE)) { if (disabledQueries.HasFlag(QueryParams.Include) == false) querySet.IncludedRelationships = ParseIncludedRelationships(pair.Value); continue; } - if (pair.Key.StartsWith(PAGE)) + if (pair.Key.StartsWith(QueryConstants.PAGE)) { if (disabledQueries.HasFlag(QueryParams.Page) == false) querySet.PageQuery = ParsePageQuery(querySet.PageQuery, pair.Key, pair.Value); continue; } - if (pair.Key.StartsWith(FIELDS)) + if (pair.Key.StartsWith(QueryConstants.FIELDS)) { if (disabledQueries.HasFlag(QueryParams.Fields) == false) querySet.Fields = ParseFieldsQuery(pair.Key, pair.Value); @@ -94,9 +83,9 @@ protected virtual List ParseFilterQuery(string key, string value) // expected input = filter[id]=eq:1 var queries = new List(); - var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; + var propertyName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1]; - var values = value.Split(COMMA); + var values = value.Split(QueryConstants.COMMA); foreach (var val in values) { (var operation, var filterValue) = ParseFilterOperation(val); @@ -111,7 +100,7 @@ protected virtual (string operation, string value) ParseFilterOperation(string v if (value.Length < 3) return (string.Empty, value); - var operation = value.Split(COLON); + var operation = value.Split(QueryConstants.COLON); if (operation.Length == 1) return (string.Empty, value); @@ -121,7 +110,7 @@ protected virtual (string operation, string value) ParseFilterOperation(string v return (string.Empty, value); var prefix = operation[0]; - value = string.Join(COLON_STR, operation.Skip(1)); + value = string.Join(QueryConstants.COLON_STR, operation.Skip(1)); return (prefix, value); } @@ -132,7 +121,7 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri // page[number]=1 pageQuery = pageQuery ?? new PageQuery(); - var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; + var propertyName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1]; const string SIZE = "size"; const string NUMBER = "number"; @@ -157,7 +146,7 @@ protected virtual List ParseSortParameters(string value) var sortParameters = new List(); const char DESCENDING_SORT_OPERATOR = '-'; - var sortSegments = value.Split(COMMA); + var sortSegments = value.Split(QueryConstants.COMMA); foreach (var sortSegment in sortSegments) { @@ -189,14 +178,14 @@ protected virtual List ParseIncludedRelationships(string value) throw new JsonApiException(400, "Deeply nested relationships are not supported"); return value - .Split(COMMA) + .Split(QueryConstants.COMMA) .ToList(); } protected virtual List ParseFieldsQuery(string key, string value) { // expected: fields[TYPE]=prop1,prop2 - var typeName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; + var typeName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1]; const string ID = "Id"; var includedFields = new List { ID }; @@ -205,7 +194,7 @@ protected virtual List ParseFieldsQuery(string key, string value) if (string.Equals(typeName, _controllerContext.RequestEntity.EntityName, StringComparison.OrdinalIgnoreCase) == false) return includedFields; - var fields = value.Split(COMMA); + var fields = value.Split(QueryConstants.COMMA); foreach (var field in fields) { var attr = _controllerContext.RequestEntity diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs index 787c9f07a0..faae94a3d8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/PagingTests.cs @@ -23,6 +23,7 @@ public class PagingTests private Faker _personFaker; private Faker _todoItemFaker; private Faker _todoItemCollectionFaker; + private DateTime CurrentTime; public PagingTests(TestFixture fixture) { diff --git a/test/UnitTests/Services/QueryComposerTests.cs b/test/UnitTests/Services/QueryComposerTests.cs new file mode 100644 index 0000000000..e1bd892756 --- /dev/null +++ b/test/UnitTests/Services/QueryComposerTests.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Internal.Query; +using JsonApiDotNetCore.Services; +using Microsoft.AspNetCore.Http; +using Moq; +using Xunit; + +namespace UnitTests.Services +{ + public class QueryComposerTests + { + private readonly Mock _jsonApiContext; + + public QueryComposerTests() + { + _jsonApiContext = new Mock(); + } + + [Fact] + public void Can_Compose_FilterStringForUrl() + { + // arrange + var filter = new FilterQuery("attribute", "value", "="); + var querySet = new QuerySet(); + List filters = new List(); + filters.Add(filter); + querySet.Filters=filters; + + _jsonApiContext + .Setup(m => m.QuerySet) + .Returns(querySet); + + var queryComposer = new QueryComposer(); + // act + var filterString = queryComposer.Compose(_jsonApiContext.Object); + // assert + Assert.Equal("&filter[attribute]=value", filterString); + } + + [Fact] + public void NoFilter_Compose_EmptyStringReturned() + { + // arrange + var querySet = new QuerySet(); + + _jsonApiContext + .Setup(m => m.QuerySet) + .Returns(querySet); + + var queryComposer = new QueryComposer(); + // act + var filterString = queryComposer.Compose(_jsonApiContext.Object); + // assert + Assert.Equal("", filterString); + } + } +} \ No newline at end of file From ca7c4ea8457911da50e8f9396a16be10335c80bc Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 6 May 2018 16:56:19 -0500 Subject: [PATCH 147/227] clean up unused changes --- ...uilder_ GetNamespaceFromPath_Benchmarks.cs | 22 ---- .../Extensions/StringExtensions.cs | 19 --- .../Internal/Query/RelatedAttrFilterQuery.cs | 17 ++- .../Internal/SpanSplitter.cs | 69 ----------- src/JsonApiDotNetCore/Services/QueryParser.cs | 15 ++- test/UnitTests/Internal/SpanSplitterTests.cs | 108 ------------------ 6 files changed, 14 insertions(+), 236 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Internal/SpanSplitter.cs delete mode 100644 test/UnitTests/Internal/SpanSplitterTests.cs diff --git a/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs index d53294e749..05728321c3 100644 --- a/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs +++ b/benchmarks/LinkBuilder/LinkBuilder_ GetNamespaceFromPath_Benchmarks.cs @@ -1,9 +1,6 @@ -using System; -using System.Text; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes.Exporters; using BenchmarkDotNet.Attributes.Jobs; -using JsonApiDotNetCore.Extensions; namespace Benchmarks.LinkBuilder { @@ -16,9 +13,6 @@ public class LinkBuilder_GetNamespaceFromPath_Benchmarks [Benchmark] public void UsingSplit() => GetNamespaceFromPath_BySplitting(PATH, ENTITY_NAME); - [Benchmark] - public void UsingSpanWithStringBuilder() => GetNamespaceFromPath_Using_Span_With_StringBuilder(PATH, ENTITY_NAME); - [Benchmark] public void Current() => GetNameSpaceFromPath_Current(PATH, ENTITY_NAME); @@ -40,21 +34,5 @@ public static string GetNamespaceFromPath_BySplitting(string path, string entity public static string GetNameSpaceFromPath_Current(string path, string entityName) => JsonApiDotNetCore.Builders.LinkBuilder.GetNamespaceFromPath(path, entityName); - - public static string GetNamespaceFromPath_Using_Span_With_StringBuilder(string path, string entityName) - { - var sb = new StringBuilder(); - var entityNameSpan = entityName.AsSpan(); - var subSpans = path.SpanSplit('/'); - for (var i = 1; i < subSpans.Count; i++) - { - var span = subSpans[i]; - if (entityNameSpan.SequenceEqual(span)) - break; - - sb.Append($"/{span.ToString()}"); - } - return sb.ToString(); - } } } diff --git a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs index c64795cae1..24d5bc8d58 100644 --- a/src/JsonApiDotNetCore/Extensions/StringExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/StringExtensions.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; using System.Text; -using JsonApiDotNetCore.Internal; namespace JsonApiDotNetCore.Extensions { @@ -53,21 +50,5 @@ public static string Dasherize(this string str) } return str; } - - public static IEnumerable IndexesOf(this string str, char delimeter) - { - var indexes = new List(); - for (var i = str.IndexOf(delimeter); i > -1 ; i = str.IndexOf(delimeter, i+1)) - { - indexes.Add(i); - } - return indexes; - } - - public static SpanSplitter SpanSplit(this string str, char delimeter) - { - return SpanSplitter.Split(str, delimeter); - } - } } diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 6415b0c575..d567de200a 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -11,20 +11,17 @@ public class RelatedAttrFilterQuery : BaseFilterQuery private readonly IJsonApiContext _jsonApiContext; public RelatedAttrFilterQuery( - IJsonApiContext jsonApiCopntext, + IJsonApiContext jsonApiContext, FilterQuery filterQuery) { - _jsonApiContext = jsonApiCopntext; - var filterQueryAttribute = filterQuery.Attribute; - var filterQuerySubSpans = filterQueryAttribute.SpanSplit('.'); - var subSpan1 = filterQuerySubSpans[0].ToString(); - var subSpan2 = filterQuerySubSpans[1].ToString(); - var relationship = GetRelationship(subSpan1); - if (relationship == null) - throw new JsonApiException(400, $"{subSpan2} is not a valid relationship on {subSpan1}."); + _jsonApiContext = jsonApiContext; - var attribute = GetAttribute(relationship, subSpan2); + var relationshipArray = filterQuery.Attribute.Split('.'); + var relationship = GetRelationship(relationshipArray[0]); + if (relationship == null) + throw new JsonApiException(400, $"{relationshipArray[1]} is not a valid relationship on {relationshipArray[0]}."); + var attribute = GetAttribute(relationship, relationshipArray[1]); if (attribute == null) throw new JsonApiException(400, $"'{filterQuery.Attribute}' is not a valid attribute."); diff --git a/src/JsonApiDotNetCore/Internal/SpanSplitter.cs b/src/JsonApiDotNetCore/Internal/SpanSplitter.cs deleted file mode 100644 index 0f9aecbb59..0000000000 --- a/src/JsonApiDotNetCore/Internal/SpanSplitter.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using JsonApiDotNetCore.Extensions; - -namespace JsonApiDotNetCore.Internal -{ - public readonly ref struct SpanSplitter - { - private readonly ReadOnlySpan _span; - private readonly List _delimeterIndexes; - private readonly List> _substringIndexes; - - public int Count => _substringIndexes.Count(); - public ReadOnlySpan this[int index] => GetSpanForSubstring(index + 1); - - private SpanSplitter(ref string str, char delimeter) - { - _span = str.AsSpan(); - _delimeterIndexes = str.IndexesOf(delimeter).ToList(); - _substringIndexes = new List>(); - BuildSubstringIndexes(); - } - - public static SpanSplitter Split(string str, char delimeter) - { - return new SpanSplitter(ref str, delimeter); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) => throw new NotSupportedException(); - - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() => throw new NotSupportedException(); - - [EditorBrowsable(EditorBrowsableState.Never)] - public override string ToString() => throw new NotSupportedException(); - - private ReadOnlySpan GetSpanForSubstring(int substringNumber) - { - if (substringNumber > Count) - { - throw new ArgumentOutOfRangeException($"There are only {Count} substrings given the delimeter and base string provided"); - } - - var indexes = _substringIndexes[substringNumber - 1]; - return _span.Slice(indexes.Item1, indexes.Item2); - } - - private void BuildSubstringIndexes() - { - var start = 0; - var end = 0; - foreach (var index in _delimeterIndexes) - { - end = index; - if (start > end) break; - _substringIndexes.Add(new Tuple(start, end - start)); - start = ++end; - } - - if (end <= _span.Length) - { - _substringIndexes.Add(new Tuple(start, _span.Length - start)); - } - } - } -} diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index ddff31b5f1..34bf525e8e 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -3,7 +3,6 @@ using System.Linq; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; @@ -94,16 +93,16 @@ protected virtual List ParseFilterQuery(string key, string value) // expected input = filter[id]=1 // expected input = filter[id]=eq:1 var queries = new List(); - var openBracketIndex = key.IndexOf(OPEN_BRACKET); - var closedBracketIndex = key.IndexOf(CLOSE_BRACKET); - var propertyNameSlice = key.AsSpan().Slice(openBracketIndex + 1, closedBracketIndex - openBracketIndex - 1); - var propertyName = propertyNameSlice.ToString(); - var spanSplitter = value.SpanSplit(COMMA); - for (var i = 0; i < spanSplitter.Count; i++) + var propertyName = key.Split(OPEN_BRACKET, CLOSE_BRACKET)[1]; + + var values = value.Split(COMMA); + foreach (var val in values) { - queries.Add(BuildFilterQuery(spanSplitter[i], propertyName)); + (var operation, var filterValue) = ParseFilterOperation(val); + queries.Add(new FilterQuery(propertyName, filterValue, operation)); } + return queries; } diff --git a/test/UnitTests/Internal/SpanSplitterTests.cs b/test/UnitTests/Internal/SpanSplitterTests.cs deleted file mode 100644 index 61160e7462..0000000000 --- a/test/UnitTests/Internal/SpanSplitterTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Internal; -using Xunit; - -namespace UnitTests.Internal -{ - public class SpanSplitterTests : SpanSplitterTestsBase - { - [Fact] - public void StringWithDelimeterSplitsIntoCorrectNumberSubstrings() - { - GivenMultipleCommaDelimetedString(); - WhenSplittingIntoSubstrings(); - AssertCorrectSubstringsReturned(); - } - - [Fact] - public void StringWithSingleDelimeterSplitsIntoCorrectNumberSubstrings() - { - GivenSingleCommaDelimetedString(); - WhenSplittingIntoSubstrings(); - AssertCorrectSubstringsReturned(); - } - - [Fact] - public void StringWithNoDelimeterSplitsIntoSingleSubstring() - { - GivenNonCommaDelimetedString(); - WhenSplittingIntoSubstrings(); - AssertCorrectSubstringsReturned(); - } - - [Fact] - public void StringWithDelimeterAtEndSplitsIntoCorrectSubstring() - { - GivenStringWithCommaDelimeterAtEnd(); - WhenSplittingIntoSubstrings(); - AssertCorrectSubstringsReturned(); - } - - [Fact] - public void StringWithDelimeterAtBeginningSplitsIntoCorrectSubstring() - { - GivenStringWithCommaDelimeterAtBeginning(); - WhenSplittingIntoSubstrings(); - AssertCorrectSubstringsReturned(); - } - } - - public abstract class SpanSplitterTestsBase - { - private string _baseString; - private char _delimeter; - private readonly List _substrings = new List(); - - protected void GivenMultipleCommaDelimetedString() - { - _baseString = "This,Is,A,TestString"; - _delimeter = ','; - } - - protected void GivenSingleCommaDelimetedString() - { - _baseString = "This,IsATestString"; - _delimeter = ','; - } - - protected void GivenNonCommaDelimetedString() - { - _baseString = "ThisIsATestString"; - } - - protected void GivenStringWithCommaDelimeterAtEnd() - { - _baseString = "This,IsATestString,"; - _delimeter = ','; - } - - protected void GivenStringWithCommaDelimeterAtBeginning() - { - _baseString = "/api/v1/articles"; - _delimeter = '/'; - } - - protected void WhenSplittingIntoSubstrings() - { - SpanSplitter spanSplitter; - spanSplitter = _baseString.SpanSplit(_delimeter); - for (var i = 0; i < spanSplitter.Count; i++) - { - var span = spanSplitter[i]; - _substrings.Add(span.ToString()); - } - } - - protected void AssertCorrectSubstringsReturned() - { - Assert.NotEmpty(_substrings); - var stringSplitArray = _baseString.Split(_delimeter); - Assert.Equal(stringSplitArray.Length, _substrings.Count); - Assert.True(stringSplitArray.SequenceEqual(_substrings)); - } - } -} From 0332870cc5baf64b367e13b60e5b7c9479df47fb Mon Sep 17 00:00:00 2001 From: Faraz Ahmed Date: Mon, 7 May 2018 15:12:06 -0400 Subject: [PATCH 148/227] added changes for fix and fixed tests --- .../Services/QueryComposer.cs | 2 +- test/UnitTests/Services/QueryComposerTests.cs | 29 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryComposer.cs b/src/JsonApiDotNetCore/Services/QueryComposer.cs index 8fbf16339b..9747f6d47d 100644 --- a/src/JsonApiDotNetCore/Services/QueryComposer.cs +++ b/src/JsonApiDotNetCore/Services/QueryComposer.cs @@ -31,7 +31,7 @@ public string Compose(IJsonApiContext jsonApiContext) private string ComposeSingleFilter(FilterQuery query) { var result = "&filter"; - result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + query.Operation + query.Value; + result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + "=" + query.Operation + ":" + query.Value; return result; } } diff --git a/test/UnitTests/Services/QueryComposerTests.cs b/test/UnitTests/Services/QueryComposerTests.cs index e1bd892756..cf54d10a5a 100644 --- a/test/UnitTests/Services/QueryComposerTests.cs +++ b/test/UnitTests/Services/QueryComposerTests.cs @@ -17,10 +17,10 @@ public QueryComposerTests() } [Fact] - public void Can_Compose_FilterStringForUrl() + public void Can_ComposeEqual_FilterStringForUrl() { // arrange - var filter = new FilterQuery("attribute", "value", "="); + var filter = new FilterQuery("attribute", "value", "eq"); var querySet = new QuerySet(); List filters = new List(); filters.Add(filter); @@ -34,7 +34,28 @@ public void Can_Compose_FilterStringForUrl() // act var filterString = queryComposer.Compose(_jsonApiContext.Object); // assert - Assert.Equal("&filter[attribute]=value", filterString); + Assert.Equal("&filter[attribute]=eq:value", filterString); + } + + [Fact] + public void Can_ComposeLessThan_FilterStringForUrl() + { + // arrange + var filter = new FilterQuery("attribute", "value", "le"); + var querySet = new QuerySet(); + List filters = new List(); + filters.Add(filter); + querySet.Filters = filters; + + _jsonApiContext + .Setup(m => m.QuerySet) + .Returns(querySet); + + var queryComposer = new QueryComposer(); + // act + var filterString = queryComposer.Compose(_jsonApiContext.Object); + // assert + Assert.Equal("&filter[attribute]=le:value", filterString); } [Fact] @@ -54,4 +75,4 @@ public void NoFilter_Compose_EmptyStringReturned() Assert.Equal("", filterString); } } -} \ No newline at end of file +} From 38f7c191e4eba20725491e5d7e29e4885d638436 Mon Sep 17 00:00:00 2001 From: Faraz Ahmed Date: Mon, 7 May 2018 15:20:17 -0400 Subject: [PATCH 149/227] fixes #277 From 1ac47484e4e878d59643ec31b032006aa7b30952 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Mon, 7 May 2018 15:08:18 -0500 Subject: [PATCH 150/227] bump package version --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index ccebe08784..53649bb7e7 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.2.2 + 2.2.3 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore From ffaacf68a1e049ee3dc1d12227abaafc83e5e549 Mon Sep 17 00:00:00 2001 From: Faraz Ahmed Date: Mon, 7 May 2018 16:12:27 -0400 Subject: [PATCH 151/227] validation fix --- src/JsonApiDotNetCore/Services/QueryComposer.cs | 3 ++- test/UnitTests/Services/QueryComposerTests.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Services/QueryComposer.cs b/src/JsonApiDotNetCore/Services/QueryComposer.cs index 9747f6d47d..8e0819a438 100644 --- a/src/JsonApiDotNetCore/Services/QueryComposer.cs +++ b/src/JsonApiDotNetCore/Services/QueryComposer.cs @@ -31,7 +31,8 @@ public string Compose(IJsonApiContext jsonApiContext) private string ComposeSingleFilter(FilterQuery query) { var result = "&filter"; - result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + "=" + query.Operation + ":" + query.Value; + var operation = string.IsNullOrWhiteSpace(query.Operation) ? query.Operation : query.Operation + ":"; + result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + "=" + operation + query.Value; return result; } } diff --git a/test/UnitTests/Services/QueryComposerTests.cs b/test/UnitTests/Services/QueryComposerTests.cs index cf54d10a5a..91df486212 100644 --- a/test/UnitTests/Services/QueryComposerTests.cs +++ b/test/UnitTests/Services/QueryComposerTests.cs @@ -42,9 +42,11 @@ public void Can_ComposeLessThan_FilterStringForUrl() { // arrange var filter = new FilterQuery("attribute", "value", "le"); + var filter2 = new FilterQuery("attribute2", "value2", ""); var querySet = new QuerySet(); List filters = new List(); filters.Add(filter); + filters.Add(filter2); querySet.Filters = filters; _jsonApiContext @@ -55,7 +57,7 @@ public void Can_ComposeLessThan_FilterStringForUrl() // act var filterString = queryComposer.Compose(_jsonApiContext.Object); // assert - Assert.Equal("&filter[attribute]=le:value", filterString); + Assert.Equal("&filter[attribute]=le:value&filter[attribute2]=value2", filterString); } [Fact] From 19e976bb03420ed78b4b09e749fa352568772ecb Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Tue, 8 May 2018 08:27:54 -0500 Subject: [PATCH 152/227] #218 Defaults data to be included in relationships rather than only when "include" for that relationship is set. --- .../Builders/DocumentBuilder.cs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 0e43225b35..3edea50e13 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -158,20 +158,17 @@ private void AddRelationships(DocumentData data, ContextEntity contextEntity, II if (r.DocumentLinks.HasFlag(Link.Related)) relationshipData.Links.Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, r.PublicRelationshipName); } - - if (RelationshipIsIncluded(r.PublicRelationshipName)) - { - var navigationEntity = _jsonApiContext.ContextGraph - .GetRelationship(entity, r.InternalRelationshipName); - - if (navigationEntity == null) - relationshipData.SingleData = null; - else if (navigationEntity is IEnumerable) - relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); - else - relationshipData.SingleData = GetRelationship(navigationEntity); - } - + + var navigationEntity = _jsonApiContext.ContextGraph + .GetRelationship(entity, r.InternalRelationshipName); + + if (navigationEntity == null) + relationshipData.SingleData = null; + else if (navigationEntity is IEnumerable) + relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); + else + relationshipData.SingleData = GetRelationship(navigationEntity); + data.Relationships.Add(r.PublicRelationshipName, relationshipData); }); } From 4ccae8b58b34a6e3fef4a91c2a69e11adea90e0a Mon Sep 17 00:00:00 2001 From: Corey Floyd Date: Fri, 11 May 2018 09:53:21 -0500 Subject: [PATCH 153/227] #218 Adds unit test verify relationhip data included in resource relationships with id and type set. --- .../Builders/DocumentBuilder_Tests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index 7946efa058..36d280054c 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -28,6 +28,7 @@ public DocumentBuilder_Tests() _options.BuildContextGraph(builder => { builder.AddResource("models"); + builder.AddResource("related-models"); }); _jsonApiContextMock @@ -121,6 +122,37 @@ public void Related_Links_Can_Be_Disabled() Assert.Null(document.Data.Relationships["related-model"].Links); } + [Fact] + public void Related_Data_Included_In_Relationships_By_Default() + { + // arrange + const string relationshipName = "related-models"; + const int relatedId = 1; + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model + { + RelatedModel = new RelatedModel + { + Id = relatedId + } + }; + + // act + var document = documentBuilder.Build(entity); + + // assert + var relationshipData = document.Data.Relationships[relationshipName]; + Assert.NotNull(relationshipData); + Assert.NotNull(relationshipData.SingleData); + Assert.NotNull(relationshipData.SingleData); + Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); + Assert.Equal(relationshipName, relationshipData.SingleData.Type); + } + [Fact] public void Build_Can_Build_Arrays() { From 3e46dee7a8cbdd024f20691c2b4a7ad3734a04b3 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 15 May 2018 10:37:19 -0500 Subject: [PATCH 154/227] fix tests by separating relationship and type names --- .../Builders/DocumentBuilder_Tests.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index 36d280054c..b2131f6ec9 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -60,7 +60,7 @@ public DocumentBuilder_Tests() [Fact] public void Includes_Paging_Links_By_Default() { - // arrange + // arrange _pageManager.PageSize = 1; _pageManager.TotalRecords = 1; _pageManager.CurrentPage = 1; @@ -126,7 +126,8 @@ public void Related_Links_Can_Be_Disabled() public void Related_Data_Included_In_Relationships_By_Default() { // arrange - const string relationshipName = "related-models"; + const string relatedTypeName = "related-models"; + const string relationshipName = "related-model"; const int relatedId = 1; _jsonApiContextMock .Setup(m => m.ContextGraph) @@ -148,9 +149,9 @@ public void Related_Data_Included_In_Relationships_By_Default() var relationshipData = document.Data.Relationships[relationshipName]; Assert.NotNull(relationshipData); Assert.NotNull(relationshipData.SingleData); - Assert.NotNull(relationshipData.SingleData); - Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); - Assert.Equal(relationshipName, relationshipData.SingleData.Type); + Assert.NotNull(relationshipData.SingleData); + Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); + Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); } [Fact] @@ -177,12 +178,12 @@ public void Build_Can_Build_CustomIEnumerables() [Theory] - [InlineData(null,null,true)] - [InlineData(false,null,true)] - [InlineData(true,null,false)] - [InlineData(null,"foo",true)] - [InlineData(false,"foo",true)] - [InlineData(true,"foo",true)] + [InlineData(null, null, true)] + [InlineData(false, null, true)] + [InlineData(true, null, false)] + [InlineData(null, "foo", true)] + [InlineData(false, "foo", true)] + [InlineData(true, "foo", true)] public void DocumentBuilderOptions(bool? omitNullValuedAttributes, string attributeValue, bool resultContainsAttribute) @@ -194,7 +195,7 @@ public void DocumentBuilderOptions(bool? omitNullValuedAttributes, .Returns(new DocumentBuilderOptions(omitNullValuedAttributes.Value)); } var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object, null, omitNullValuedAttributes.HasValue ? documentBuilderBehaviourMock.Object : null); - var document = documentBuilder.Build(new Model(){StringProperty = attributeValue}); + var document = documentBuilder.Build(new Model() { StringProperty = attributeValue }); Assert.Equal(resultContainsAttribute, document.Data.Attributes.ContainsKey("StringProperty")); } From a5730bfdedfa95b2f8f265c37a9e47fa4ff314f6 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 15 May 2018 11:24:09 -0500 Subject: [PATCH 155/227] chore(csproj): bump package version also add build property for docfx targets closes #283 --- .../JsonApiDotNetCore.csproj | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 53649bb7e7..eb649ed5dc 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,9 +1,10 @@  - 2.2.3 + 2.2.4 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore + 7.2 @@ -25,20 +26,16 @@ - - + + true - - + true bin\Release\netstandard2.0\JsonApiDotNetCore.xml - - 7.2 - - - 7.2 - - + + From 3c98b70375dbcec7c13a91903eba479b8816b271 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Tue, 15 May 2018 14:09:56 -0500 Subject: [PATCH 156/227] fix(#218): include independent hasOne identifier in all requests for the dependent side of the relationship by default --- .../Builders/DocumentBuilder.cs | 85 ++++++++++++------- .../Models/HasOneAttribute.cs | 54 ++++++++++-- .../Serialization/JsonApiDeSerializer.cs | 6 +- .../Builders/DocumentBuilder_Tests.cs | 29 +++++++ 4 files changed, 134 insertions(+), 40 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 3edea50e13..49d40e0f28 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -13,9 +13,9 @@ public class DocumentBuilder : IDocumentBuilder private readonly IJsonApiContext _jsonApiContext; private readonly IContextGraph _contextGraph; private readonly IRequestMeta _requestMeta; - private readonly DocumentBuilderOptions _documentBuilderOptions; + private readonly DocumentBuilderOptions _documentBuilderOptions; - public DocumentBuilder(IJsonApiContext jsonApiContext, IRequestMeta requestMeta=null, IDocumentBuilderOptionsProvider documentBuilderOptionsProvider=null) + public DocumentBuilder(IJsonApiContext jsonApiContext, IRequestMeta requestMeta = null, IDocumentBuilderOptionsProvider documentBuilderOptionsProvider = null) { _jsonApiContext = jsonApiContext; _contextGraph = jsonApiContext.ContextGraph; @@ -143,34 +143,42 @@ private bool OmitNullValuedAttribute(AttrAttribute attr, object attributeValue) private void AddRelationships(DocumentData data, ContextEntity contextEntity, IIdentifiable entity) { data.Relationships = new Dictionary(); + contextEntity.Relationships.ForEach(r => + data.Relationships.Add( + r.PublicRelationshipName, + GetRelationshipData(r, contextEntity, entity) + ) + ); + } + + private RelationshipData GetRelationshipData(RelationshipAttribute attr, ContextEntity contextEntity, IIdentifiable entity) + { var linkBuilder = new LinkBuilder(_jsonApiContext); - contextEntity.Relationships.ForEach(r => + var relationshipData = new RelationshipData(); + + if (attr.DocumentLinks.HasFlag(Link.None) == false) { - var relationshipData = new RelationshipData(); + relationshipData.Links = new Links(); + if (attr.DocumentLinks.HasFlag(Link.Self)) + relationshipData.Links.Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.StringId, attr.PublicRelationshipName); - if (r.DocumentLinks.HasFlag(Link.None) == false) - { - relationshipData.Links = new Links(); - if (r.DocumentLinks.HasFlag(Link.Self)) - relationshipData.Links.Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.StringId, r.PublicRelationshipName); + if (attr.DocumentLinks.HasFlag(Link.Related)) + relationshipData.Links.Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, attr.PublicRelationshipName); + } - if (r.DocumentLinks.HasFlag(Link.Related)) - relationshipData.Links.Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, r.PublicRelationshipName); - } - - var navigationEntity = _jsonApiContext.ContextGraph - .GetRelationship(entity, r.InternalRelationshipName); - - if (navigationEntity == null) - relationshipData.SingleData = null; - else if (navigationEntity is IEnumerable) - relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); - else - relationshipData.SingleData = GetRelationship(navigationEntity); - - data.Relationships.Add(r.PublicRelationshipName, relationshipData); - }); + // this only includes the navigation property, we need to actually check the navigation property Id + var navigationEntity = _jsonApiContext.ContextGraph.GetRelationship(entity, attr.InternalRelationshipName); + if (navigationEntity == null) + relationshipData.SingleData = attr.IsHasOne + ? GetIndependentRelationshipIdentifier((HasOneAttribute)attr, entity) + : null; + else if (navigationEntity is IEnumerable) + relationshipData.ManyData = GetRelationships((IEnumerable)navigationEntity); + else + relationshipData.SingleData = GetRelationship(navigationEntity); + + return relationshipData; } private List GetIncludedEntities(List included, ContextEntity contextEntity, IIdentifiable entity) @@ -240,23 +248,40 @@ private List GetRelationships(IEnumerable enti var relationships = new List(); foreach (var entity in entities) { - relationships.Add(new ResourceIdentifierObject { + relationships.Add(new ResourceIdentifierObject + { Type = typeName.EntityName, Id = ((IIdentifiable)entity).StringId }); } return relationships; } + private ResourceIdentifierObject GetRelationship(object entity) { var objType = entity.GetType(); + var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(objType); - var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType); - - return new ResourceIdentifierObject { - Type = typeName.EntityName, + return new ResourceIdentifierObject + { + Type = contextEntity.EntityName, Id = ((IIdentifiable)entity).StringId }; } + + private ResourceIdentifierObject GetIndependentRelationshipIdentifier(HasOneAttribute hasOne, IIdentifiable entity) + { + var independentRelationshipIdentifier = hasOne.GetIdentifiablePropertyValue(entity); + if (independentRelationshipIdentifier == null) + return null; + + var relatedContextEntity = _jsonApiContext.ContextGraph.GetContextEntity(hasOne.Type); + + return new ResourceIdentifierObject + { + Type = relatedContextEntity.EntityName, + Id = independentRelationshipIdentifier.ToString() + }; + } } } diff --git a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs index f863c8819b..de7b7822f6 100644 --- a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs @@ -2,21 +2,61 @@ namespace JsonApiDotNetCore.Models { public class HasOneAttribute : RelationshipAttribute { - public HasOneAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true) + /// + /// Create a HasOne relational link to another entity + /// + /// + /// The relationship name as exposed by the API + /// Which links are available. Defaults to + /// Whether or not this relationship can be included using the ?include=public-name query string + /// The foreign key property name. Defaults to "{RelationshipName}Id" + /// + /// + /// Using an alternative foreign key: + /// + /// + /// public class Article : Identifiable + /// { + /// [HasOne("author", withForiegnKey: nameof(AuthorKey)] + /// public Author Author { get; set; } + /// public int AuthorKey { get; set; } + /// } + /// + /// + /// + public HasOneAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true, string withForiegnKey = null) : base(publicName, documentLinks, canInclude) - { } + { + _explicitIdentifiablePropertyName = withForiegnKey; + } + + private readonly string _explicitIdentifiablePropertyName; + + /// + /// The independent entity identifier. + /// + public string IdentifiablePropertyName => string.IsNullOrWhiteSpace(_explicitIdentifiablePropertyName) + ? $"{InternalRelationshipName}Id" + : _explicitIdentifiablePropertyName; public override void SetValue(object entity, object newValue) { - var propertyName = (newValue.GetType() == Type) - ? InternalRelationshipName - : $"{InternalRelationshipName}Id"; - + var propertyName = (newValue.GetType() == Type) + ? InternalRelationshipName + : IdentifiablePropertyName; + var propertyInfo = entity .GetType() .GetProperty(propertyName); - + propertyInfo.SetValue(entity, newValue); } + + // HACK: this will likely require boxing + // we should be able to move some of the reflection into the ContextGraphBuilder + internal object GetIdentifiablePropertyValue(object entity) => entity + .GetType() + .GetProperty(IdentifiablePropertyName) + .GetValue(entity); } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 649d6435ff..6fb7af55e1 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -175,7 +175,7 @@ private object SetRelationships( foreach (var attr in contextEntity.Relationships) { entity = attr.IsHasOne - ? SetHasOneRelationship(entity, entityProperties, attr, contextEntity, relationships) + ? SetHasOneRelationship(entity, entityProperties, (HasOneAttribute)attr, contextEntity, relationships) : SetHasManyRelationship(entity, entityProperties, attr, contextEntity, relationships); } @@ -184,7 +184,7 @@ private object SetRelationships( private object SetHasOneRelationship(object entity, PropertyInfo[] entityProperties, - RelationshipAttribute attr, + HasOneAttribute attr, ContextEntity contextEntity, Dictionary relationships) { @@ -204,7 +204,7 @@ private object SetHasOneRelationship(object entity, var newValue = rio.Id; - var foreignKey = attr.InternalRelationshipName + "Id"; + var foreignKey = attr.IdentifiablePropertyName; var entityProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); if (entityProperty == null) throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a foreign key property '{foreignKey}' for has one relationship '{attr.InternalRelationshipName}'"); diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index b2131f6ec9..dbca1bebb4 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -145,6 +145,35 @@ public void Related_Data_Included_In_Relationships_By_Default() // act var document = documentBuilder.Build(entity); + // assert + var relationshipData = document.Data.Relationships[relationshipName]; + Assert.NotNull(relationshipData); + Assert.NotNull(relationshipData.SingleData); + Assert.NotNull(relationshipData.SingleData); + Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); + Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); + } + + [Fact] + public void IndependentIdentifier__Included_In_HasOne_Relationships_By_Default() + { + // arrange + const string relatedTypeName = "related-models"; + const string relationshipName = "related-model"; + const int relatedId = 1; + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model + { + RelatedModelId = relatedId + }; + + // act + var document = documentBuilder.Build(entity); + // assert var relationshipData = document.Data.Relationships[relationshipName]; Assert.NotNull(relationshipData); From f34cca7c9f518f7351394839668effffa10e73c4 Mon Sep 17 00:00:00 2001 From: Milos Date: Fri, 25 May 2018 10:44:14 +0200 Subject: [PATCH 157/227] Add Negative filter --- src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs | 4 ++++ src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 73e3a14a3e..79eda6c598 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -195,6 +195,10 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression case FilterOperations.like: body = Expression.Call(left, "Contains", null, right); break; + // {model.Id != 1} + case FilterOperations.ne: + body = Expression.NotEqual(left, right); + break; default: throw new JsonApiException(500, $"Unknown filter operation {operation}"); } diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs index 260dc32655..e3c207ce47 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs @@ -8,6 +8,7 @@ public enum FilterOperations gt = 2, le = 3, ge = 4, - like = 5 + like = 5, + ne = 6 } -} \ No newline at end of file +} From 6210cc6355150fc4443062cd47993bd5dcd23870 Mon Sep 17 00:00:00 2001 From: Milos Date: Fri, 25 May 2018 17:19:54 +0200 Subject: [PATCH 158/227] Add NotEqual acceptance test --- .../Acceptance/Spec/AttributeFilterTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index 083b2c22d7..df68f06eb0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -105,5 +105,32 @@ public async Task Cannot_Filter_If_Explicitly_Forbidden() // assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + [Fact] + public async Task Can_Filter_On_Not_Equal_Values() + { + // arrange + var context = _fixture.GetService(); + var todoItems = _todoItemFaker.Generate(5); + context.TodoItems.AddRange(todoItems); + await context.SaveChangesAsync(); + + var lastTodoItem = context.TodoItems.Last(); + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?filter[guid-property]=ne:{lastTodoItem.GuidProperty}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedTodoItems = _fixture + .GetService() + .DeserializeList(body); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(deserializedTodoItems.Count(), todoItems.Count() -1); + Assert.False(deserializedTodoItems.Any(i => i.GuidProperty == lastTodoItem.GuidProperty)); + } } } From 4126f36265d94a5eadd3ece10a3caa8526e1562b Mon Sep 17 00:00:00 2001 From: Milos Date: Fri, 25 May 2018 17:55:19 +0200 Subject: [PATCH 159/227] Changed Count --- .../Acceptance/Spec/AttributeFilterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index df68f06eb0..e1d92be3b6 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -129,7 +129,7 @@ public async Task Can_Filter_On_Not_Equal_Values() // assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(deserializedTodoItems.Count(), todoItems.Count() -1); + Assert.Equal(deserializedTodoItems.Count, todoItems.Count() -1); Assert.False(deserializedTodoItems.Any(i => i.GuidProperty == lastTodoItem.GuidProperty)); } } From 91a5699d469278da3f1072a236e062135db1abb1 Mon Sep 17 00:00:00 2001 From: Milos Date: Sat, 26 May 2018 23:58:46 +0200 Subject: [PATCH 160/227] Fix NotEqual filter test --- .../Acceptance/Spec/AttributeFilterTests.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index e1d92be3b6..b84b57e31b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -111,13 +111,13 @@ public async Task Can_Filter_On_Not_Equal_Values() { // arrange var context = _fixture.GetService(); - var todoItems = _todoItemFaker.Generate(5); - context.TodoItems.AddRange(todoItems); + var todoItem = _todoItemFaker.Generate(); + context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); - var lastTodoItem = context.TodoItems.Last(); + var totalCount = context.TodoItems.Count(); var httpMethod = new HttpMethod("GET"); - var route = $"/api/v1/todo-items?filter[guid-property]=ne:{lastTodoItem.GuidProperty}"; + var route = $"/api/v1/todo-items?page[size]={totalCount}&filter[ordinal]=ne:{todoItem.Ordinal}"; var request = new HttpRequestMessage(httpMethod, route); // act @@ -129,8 +129,7 @@ public async Task Can_Filter_On_Not_Equal_Values() // assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(deserializedTodoItems.Count, todoItems.Count() -1); - Assert.False(deserializedTodoItems.Any(i => i.GuidProperty == lastTodoItem.GuidProperty)); + Assert.False(deserializedTodoItems.Any(i => i.Ordinal == todoItem.Ordinal)); } } } From 7ad0eb8040dea726401a42efa16a6ab82ea54756 Mon Sep 17 00:00:00 2001 From: Milos Date: Tue, 29 May 2018 12:25:41 +0200 Subject: [PATCH 161/227] Add IN filter for array searching --- .../Extensions/IQueryableExtensions.cs | 107 +++++++++++++----- .../Internal/Query/FilterOperations.cs | 3 +- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 24 ++++ src/JsonApiDotNetCore/Services/QueryParser.cs | 47 +++++--- .../Acceptance/Spec/AttributeFilterTests.cs | 71 ++++++++++++ 5 files changed, 208 insertions(+), 44 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 79eda6c598..c392da2b93 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Services; @@ -101,21 +102,30 @@ public static IQueryable Filter(this IQueryable sourc try { - // convert the incoming value to the target value type - // "1" -> 1 - var convertedValue = TypeHelper.ConvertType(filterQuery.PropertyValue, property.PropertyType); - // {model} - var parameter = Expression.Parameter(concreteType, "model"); - // {model.Id} - var left = Expression.PropertyOrField(parameter, property.Name); - // {1} - var right = Expression.Constant(convertedValue, property.PropertyType); - - var body = GetFilterExpressionLambda(left, right, filterQuery.FilterOperation); - - var lambda = Expression.Lambda>(body, parameter); - - return source.Where(lambda); + if (filterQuery.FilterOperation == FilterOperations.@in ) + { + string[] propertyValues = filterQuery.PropertyValue.Split(','); + var lambdaIn = ArrayContainsPredicate(propertyValues, property.Name); + + return source.Where(lambdaIn); + } + else + { // convert the incoming value to the target value type + // "1" -> 1 + var convertedValue = TypeHelper.ConvertType(filterQuery.PropertyValue, property.PropertyType); + // {model} + var parameter = Expression.Parameter(concreteType, "model"); + // {model.Id} + var left = Expression.PropertyOrField(parameter, property.Name); + // {1} + var right = Expression.Constant(convertedValue, property.PropertyType); + + var body = GetFilterExpressionLambda(left, right, filterQuery.FilterOperation); + + var lambda = Expression.Lambda>(body, parameter); + + return source.Where(lambda); + } } catch (FormatException) { @@ -140,26 +150,36 @@ public static IQueryable Filter(this IQueryable sourc try { - // convert the incoming value to the target value type - // "1" -> 1 - var convertedValue = TypeHelper.ConvertType(filterQuery.PropertyValue, relatedAttr.PropertyType); - // {model} - var parameter = Expression.Parameter(concreteType, "model"); + if (filterQuery.FilterOperation == FilterOperations.@in) + { + string[] propertyValues = filterQuery.PropertyValue.Split(','); + var lambdaIn = ArrayContainsPredicate(propertyValues, relatedAttr.Name, relation.Name); + + return source.Where(lambdaIn); + } + else + { + // convert the incoming value to the target value type + // "1" -> 1 + var convertedValue = TypeHelper.ConvertType(filterQuery.PropertyValue, relatedAttr.PropertyType); + // {model} + var parameter = Expression.Parameter(concreteType, "model"); - // {model.Relationship} - var leftRelationship = Expression.PropertyOrField(parameter, relation.Name); + // {model.Relationship} + var leftRelationship = Expression.PropertyOrField(parameter, relation.Name); - // {model.Relationship.Attr} - var left = Expression.PropertyOrField(leftRelationship, relatedAttr.Name); + // {model.Relationship.Attr} + var left = Expression.PropertyOrField(leftRelationship, relatedAttr.Name); - // {1} - var right = Expression.Constant(convertedValue, relatedAttr.PropertyType); + // {1} + var right = Expression.Constant(convertedValue, relatedAttr.PropertyType); - var body = GetFilterExpressionLambda(left, right, filterQuery.FilterOperation); + var body = GetFilterExpressionLambda(left, right, filterQuery.FilterOperation); - var lambda = Expression.Lambda>(body, parameter); + var lambda = Expression.Lambda>(body, parameter); - return source.Where(lambda); + return source.Where(lambda); + } } catch (FormatException) { @@ -206,6 +226,35 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression return body; } + private static Expression> ArrayContainsPredicate(string[] propertyValues, string fieldname, string relationName = null) + { + ParameterExpression entity = Expression.Parameter(typeof(TSource), "entity"); + MemberExpression member; + if (!string.IsNullOrEmpty(relationName)) + { + var relation = Expression.PropertyOrField(entity, relationName); + member = Expression.Property(relation, fieldname); + } + else + member = Expression.Property(entity, fieldname); + + var containsMethods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => m.Name == "Contains"); + MethodInfo method = null; + foreach (var m in containsMethods) + { + if (m.GetParameters().Count() == 2) + { + method = m; + break; + } + } + method = method.MakeGenericMethod(member.Type); + var obj = TypeHelper.ConvertListType(propertyValues, member.Type); + + var exprContains = Expression.Call(method, new Expression[] { Expression.Constant(obj), member }); + return Expression.Lambda>(exprContains, entity); + } + public static IQueryable Select(this IQueryable source, List columns) { if (columns == null || columns.Count == 0) diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs index e3c207ce47..88a2da2ee8 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs @@ -9,6 +9,7 @@ public enum FilterOperations le = 3, ge = 4, like = 5, - ne = 6 + ne = 6, + @in = 7, // prefix with @ to use keyword } } diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index cc64b398dd..15bd322e54 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Reflection; namespace JsonApiDotNetCore.Internal @@ -54,5 +56,27 @@ public static T ConvertType(object value) { return (T)ConvertType(value, typeof(T)); } + + /// + /// Convert collection of query string params to Collection of concrete Type + /// + /// Collection like ["10","20","30"] + /// Non array type. For e.g. int + /// Collection of concrete type + public static object ConvertListType(IEnumerable values, Type type) + { + var convertedArray = new List(); + foreach (var value in values) + { + convertedArray.Add(ConvertType(value, type)); + } + var listType = typeof(List<>).MakeGenericType(type); + IList list = (IList)Activator.CreateInstance(listType); + foreach (var item in convertedArray) + { + list.Add(item); + } + return list; + } } } diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index b1a1c26f31..239ee8a3b8 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -82,14 +82,23 @@ protected virtual List ParseFilterQuery(string key, string value) // expected input = filter[id]=1 // expected input = filter[id]=eq:1 var queries = new List(); - var propertyName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1]; - var values = value.Split(QueryConstants.COMMA); - foreach (var val in values) + // InArray case + var op = GetFilterOperation(value); + if (op == FilterOperations.@in.ToString()) + { + (var operation, var filterValue) = ParseFilterOperation(value); + queries.Add(new FilterQuery(propertyName, filterValue, op)); + } + else { - (var operation, var filterValue) = ParseFilterOperation(val); - queries.Add(new FilterQuery(propertyName, filterValue, operation)); + var values = value.Split(QueryConstants.COMMA); + foreach (var val in values) + { + (var operation, var filterValue) = ParseFilterOperation(val); + queries.Add(new FilterQuery(propertyName, filterValue, operation)); + } } return queries; @@ -100,19 +109,15 @@ protected virtual (string operation, string value) ParseFilterOperation(string v if (value.Length < 3) return (string.Empty, value); - var operation = value.Split(QueryConstants.COLON); + var operation = GetFilterOperation(value); + var values = value.Split(QueryConstants.COLON); - if (operation.Length == 1) - return (string.Empty, value); - - // remove prefix from value - if (Enum.TryParse(operation[0], out FilterOperations op) == false) + if (string.IsNullOrEmpty(operation)) return (string.Empty, value); - var prefix = operation[0]; - value = string.Join(QueryConstants.COLON_STR, operation.Skip(1)); + value = string.Join(QueryConstants.COLON_STR, values.Skip(1)); - return (prefix, value); + return (operation, value); } protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value) @@ -225,6 +230,20 @@ protected virtual AttrAttribute GetAttribute(string propertyName) } } + private string GetFilterOperation(string value) + { + var operation = value.Split(QueryConstants.COLON); + + if (operation.Length == 1) + return string.Empty; + + // remove prefix from value + if (Enum.TryParse(operation[0], out FilterOperations op) == false) + return string.Empty; + + return operation[0]; + } + private FilterQuery BuildFilterQuery(ReadOnlySpan query, string propertyName) { var (operation, filterValue) = ParseFilterOperation(query.ToString()); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index b84b57e31b..b8927f71a8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -8,6 +9,7 @@ using JsonApiDotNetCore.Serialization; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; @@ -131,5 +133,74 @@ public async Task Can_Filter_On_Not_Equal_Values() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.False(deserializedTodoItems.Any(i => i.Ordinal == todoItem.Ordinal)); } + + [Fact] + public async Task Can_Filter_On_In_Array_Values() + { + // arrange + var context = _fixture.GetService(); + var todoItems = _todoItemFaker.Generate(3); + var guids = new List(); + foreach (var item in todoItems) + { + context.TodoItems.Add(item); + guids.Add(item.GuidProperty); + } + context.SaveChanges(); + + var totalCount = context.TodoItems.Count(); + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?filter[guid-property]=in:{string.Join(",", guids)}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedTodoItems = _fixture + .GetService() + .DeserializeList(body); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(guids.Count(), deserializedTodoItems.Count()); + foreach (var item in deserializedTodoItems) + Assert.True(guids.Contains(item.GuidProperty)); + } + + [Fact] + public async Task Can_Filter_On_Related_In_Array_Values() + { + // arrange + var context = _fixture.GetService(); + var todoItems = _todoItemFaker.Generate(3); + var ownerFirstNames = new List(); + foreach (var item in todoItems) + { + var person = _personFaker.Generate(); + ownerFirstNames.Add(person.FirstName); + item.Owner = person; + context.TodoItems.Add(item); + } + context.SaveChanges(); + + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?include=owner&filter[owner.first-name]=in:{string.Join(",", ownerFirstNames)}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var documents = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + var included = documents.Included; + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(ownerFirstNames.Count(), documents.Data.Count()); + Assert.NotNull(included); + Assert.NotEmpty(included); + foreach (var item in included) + Assert.True(ownerFirstNames.Contains(item.Attributes["first-name"])); + + } } } From 912f45c6b31a55864cd3bba7ab592250102dbe79 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Jun 2018 05:45:57 -0500 Subject: [PATCH 162/227] fix(HasOneAttribute): return null if property doesnt exist --- src/JsonApiDotNetCore/Models/HasOneAttribute.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs index de7b7822f6..03fdb200fc 100644 --- a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs @@ -54,9 +54,20 @@ public override void SetValue(object entity, object newValue) // HACK: this will likely require boxing // we should be able to move some of the reflection into the ContextGraphBuilder + /// + /// Gets the value of the independent identifier (e.g. Article.AuthorId) + /// + /// + /// + /// An instance of dependent resource + /// + /// + /// + /// The property value or null if the property does not exist on the model. + /// internal object GetIdentifiablePropertyValue(object entity) => entity .GetType() .GetProperty(IdentifiablePropertyName) - .GetValue(entity); + ?.GetValue(entity); } } From 40c8ffe77940b1e0063c7e78d08c9cda6289ae5b Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Jun 2018 06:11:02 -0500 Subject: [PATCH 163/227] fix(DocumentBuilder): handle case when hasOne relationship type is unknown --- src/JsonApiDotNetCore/Builders/DocumentBuilder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 49d40e0f28..088a2bf092 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -276,6 +276,8 @@ private ResourceIdentifierObject GetIndependentRelationshipIdentifier(HasOneAttr return null; var relatedContextEntity = _jsonApiContext.ContextGraph.GetContextEntity(hasOne.Type); + if (relatedContextEntity == null) // TODO: this should probably be a debug log at minimum + return null; return new ResourceIdentifierObject { From 65bb454108bca0d9f28629977ce23ce5fe587f71 Mon Sep 17 00:00:00 2001 From: Milos Date: Wed, 6 Jun 2018 10:16:03 +0200 Subject: [PATCH 164/227] Code improvements of "in" filtering --- .../Extensions/IQueryableExtensions.cs | 29 ++++++++++++------- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 12 +++----- src/JsonApiDotNetCore/Services/QueryParser.cs | 13 +++++---- .../Acceptance/Spec/AttributeFilterTests.cs | 12 ++++++-- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index c392da2b93..994fc08070 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -12,6 +12,23 @@ namespace JsonApiDotNetCore.Extensions // ReSharper disable once InconsistentNaming public static class IQueryableExtensions { + private static MethodInfo _containsMethod; + private static MethodInfo ContainsMethod + { + get + { + if (_containsMethod == null) + { + _containsMethod = typeof(Enumerable) + .GetMethods(BindingFlags.Static | BindingFlags.Public) + .Where(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Count() == 2) + .First(); + } + return _containsMethod; + } + } + + public static IQueryable Sort(this IQueryable source, List sortQueries) { if (sortQueries == null || sortQueries.Count == 0) @@ -238,17 +255,7 @@ private static Expression> ArrayContainsPredicate(s else member = Expression.Property(entity, fieldname); - var containsMethods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => m.Name == "Contains"); - MethodInfo method = null; - foreach (var m in containsMethods) - { - if (m.GetParameters().Count() == 2) - { - method = m; - break; - } - } - method = method.MakeGenericMethod(member.Type); + var method = ContainsMethod.MakeGenericMethod(member.Type); var obj = TypeHelper.ConvertListType(propertyValues, member.Type); var exprContains = Expression.Call(method, new Expression[] { Expression.Constant(obj), member }); diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index 15bd322e54..5135473cdb 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -63,19 +63,15 @@ public static T ConvertType(object value) /// Collection like ["10","20","30"] /// Non array type. For e.g. int /// Collection of concrete type - public static object ConvertListType(IEnumerable values, Type type) + public static IList ConvertListType(IEnumerable values, Type type) { - var convertedArray = new List(); - foreach (var value in values) - { - convertedArray.Add(ConvertType(value, type)); - } var listType = typeof(List<>).MakeGenericType(type); IList list = (IList)Activator.CreateInstance(listType); - foreach (var item in convertedArray) + foreach (var value in values) { - list.Add(item); + list.Add(ConvertType(value, type)); } + return list; } } diff --git a/src/JsonApiDotNetCore/Services/QueryParser.cs b/src/JsonApiDotNetCore/Services/QueryParser.cs index 239ee8a3b8..7e17352815 100644 --- a/src/JsonApiDotNetCore/Services/QueryParser.cs +++ b/src/JsonApiDotNetCore/Services/QueryParser.cs @@ -85,8 +85,8 @@ protected virtual List ParseFilterQuery(string key, string value) var propertyName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1]; // InArray case - var op = GetFilterOperation(value); - if (op == FilterOperations.@in.ToString()) + string op = GetFilterOperation(value); + if (string.Equals(op, FilterOperations.@in.ToString(), StringComparison.OrdinalIgnoreCase)) { (var operation, var filterValue) = ParseFilterOperation(value); queries.Add(new FilterQuery(propertyName, filterValue, op)); @@ -232,16 +232,17 @@ protected virtual AttrAttribute GetAttribute(string propertyName) private string GetFilterOperation(string value) { - var operation = value.Split(QueryConstants.COLON); + var values = value.Split(QueryConstants.COLON); - if (operation.Length == 1) + if (values.Length == 1) return string.Empty; + var operation = values[0]; // remove prefix from value - if (Enum.TryParse(operation[0], out FilterOperations op) == false) + if (Enum.TryParse(operation, out FilterOperations op) == false) return string.Empty; - return operation[0]; + return operation; } private FilterQuery BuildFilterQuery(ReadOnlySpan query, string propertyName) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index b8927f71a8..428e3cadf3 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -139,12 +139,17 @@ public async Task Can_Filter_On_In_Array_Values() { // arrange var context = _fixture.GetService(); - var todoItems = _todoItemFaker.Generate(3); + var todoItems = _todoItemFaker.Generate(5); var guids = new List(); + var notInGuids = new List(); foreach (var item in todoItems) { context.TodoItems.Add(item); - guids.Add(item.GuidProperty); + // Exclude 2 items + if (guids.Count < (todoItems.Count() - 2)) + guids.Add(item.GuidProperty); + else + notInGuids.Add(item.GuidProperty); } context.SaveChanges(); @@ -164,7 +169,10 @@ public async Task Can_Filter_On_In_Array_Values() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(guids.Count(), deserializedTodoItems.Count()); foreach (var item in deserializedTodoItems) + { Assert.True(guids.Contains(item.GuidProperty)); + Assert.False(notInGuids.Contains(item.GuidProperty)); + } } [Fact] From a9342e2b1219c1f087b362931f0c87705ac5511f Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 18:33:55 -0500 Subject: [PATCH 165/227] fix(Deserializer): remove dependency on GenericProcessorFactory Rather than fetching data from the database during deserialization, we can set the relationships with instances that just carry the id. It will then be the responsibility of the repository to handle those relationships --- .../Extensions/TypeExtensions.cs | 23 ++++++++++ .../Serialization/JsonApiDeSerializer.cs | 29 ++++++++---- .../Extensions/TypeExtensions_Tests.cs | 44 +++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 test/UnitTests/Extensions/TypeExtensions_Tests.cs diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index ccc4619966..a78f545e81 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -31,5 +31,28 @@ public static Type GetElementType(this IEnumerable enumerable) return elementType; } + + /// + /// Creates a List{TInterface} where TInterface is the generic for type specified by t + /// + public static List GetEmptyCollection(this Type t) + { + if (t == null) throw new ArgumentNullException(nameof(t)); + + var listType = typeof(List<>).MakeGenericType(t); + var list = (List)Activator.CreateInstance(listType); + return list; + } + + /// + /// Creates a new instance of type t, casting it to the specified TInterface + /// + public static TInterface New(this Type t) + { + if (t == null) throw new ArgumentNullException(nameof(t)); + + var instance = (TInterface)Activator.CreateInstance(t); + return instance; + } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 6fb7af55e1..d55cb48a2e 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -9,20 +9,27 @@ using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using JsonApiDotNetCore.Extensions; namespace JsonApiDotNetCore.Serialization { public class JsonApiDeSerializer : IJsonApiDeSerializer { private readonly IJsonApiContext _jsonApiContext; - private readonly IGenericProcessorFactory _genericProcessorFactory; + [Obsolete( + "The deserializer no longer depends on the IGenericProcessorFactory", + error: false)] public JsonApiDeSerializer( IJsonApiContext jsonApiContext, IGenericProcessorFactory genericProcessorFactory) { _jsonApiContext = jsonApiContext; - _genericProcessorFactory = genericProcessorFactory; + } + + public JsonApiDeSerializer(IJsonApiContext jsonApiContext) + { + _jsonApiContext = jsonApiContext; } public object Deserialize(string requestBody) @@ -225,10 +232,11 @@ private object SetHasManyRelationship(object entity, ContextEntity contextEntity, Dictionary relationships) { - var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); + // TODO: is this necessary? if not, remove + // var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); - if (entityProperty == null) - throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain an relationsip named {attr.InternalRelationshipName}"); + // if (entityProperty == null) + // throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a relationsip named '{attr.InternalRelationshipName}'"); var relationshipName = attr.PublicRelationshipName; @@ -238,11 +246,16 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var genericProcessor = _genericProcessorFactory.GetProcessor(typeof(GenericProcessor<>), attr.Type); + var resourceRelationships = attr.Type.GetEmptyCollection(); - var ids = relationshipData.ManyData.Select(r => r.Id); + var relationshipShells = relationshipData.ManyData.Select(r => + { + var instance = attr.Type.New(); + instance.StringId = r.Id; + return instance; + }); - genericProcessor.SetRelationships(entity, attr, ids); + attr.SetValue(entity, relationshipShells); } return entity; diff --git a/test/UnitTests/Extensions/TypeExtensions_Tests.cs b/test/UnitTests/Extensions/TypeExtensions_Tests.cs new file mode 100644 index 0000000000..92534eef5d --- /dev/null +++ b/test/UnitTests/Extensions/TypeExtensions_Tests.cs @@ -0,0 +1,44 @@ +using JsonApiDotNetCore.Models; +using Xunit; +using JsonApiDotNetCore.Extensions; +using System.Collections.Generic; + +namespace UnitTests.Extensions +{ + public class TypeExtensions_Tests + { + [Fact] + public void GetCollection_Creates_List_If_T_Implements_Interface() + { + // arrange + var type = typeof(Model); + + // act + var collection = type.GetEmptyCollection(); + + // assert + Assert.NotNull(collection); + Assert.Empty(collection); + Assert.IsType>(collection); + } + + [Fact] + public void New_Creates_An_Instance_If_T_Implements_Interface() + { + // arrange + var type = typeof(Model); + + // act + var instance = type.New(); + + // assert + Assert.NotNull(instance); + Assert.IsType(instance); + } + + private class Model : IIdentifiable + { + public string StringId { get; set; } + } + } +} From a0b284dfbc369a91df561cd89216a2fa9921da94 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 19:08:18 -0500 Subject: [PATCH 166/227] fix(typeExtensions): cast to IEnumerable using covariance --- src/JsonApiDotNetCore/Extensions/TypeExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index a78f545e81..efe29620f8 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -35,12 +35,12 @@ public static Type GetElementType(this IEnumerable enumerable) /// /// Creates a List{TInterface} where TInterface is the generic for type specified by t /// - public static List GetEmptyCollection(this Type t) + public static IEnumerable GetEmptyCollection(this Type t) { if (t == null) throw new ArgumentNullException(nameof(t)); var listType = typeof(List<>).MakeGenericType(t); - var list = (List)Activator.CreateInstance(listType); + var list = (IEnumerable)Activator.CreateInstance(listType); return list; } From 1e134cf53a63b4c195873a82833b21a738c1430b Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sat, 7 Apr 2018 20:57:26 -0500 Subject: [PATCH 167/227] fix(Deserializer): properly convert collection type when setting it on the model --- src/JsonApiDotNetCore/Extensions/TypeExtensions.cs | 4 ++-- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 8 ++++++++ src/JsonApiDotNetCore/Models/HasManyAttribute.cs | 2 +- .../Serialization/JsonApiDeSerializer.cs | 10 ++++++---- test/UnitTests/Extensions/TypeExtensions_Tests.cs | 6 +++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs index efe29620f8..8cc7c0dffe 100644 --- a/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/TypeExtensions.cs @@ -35,12 +35,12 @@ public static Type GetElementType(this IEnumerable enumerable) /// /// Creates a List{TInterface} where TInterface is the generic for type specified by t /// - public static IEnumerable GetEmptyCollection(this Type t) + public static IEnumerable GetEmptyCollection(this Type t) { if (t == null) throw new ArgumentNullException(nameof(t)); var listType = typeof(List<>).MakeGenericType(t); - var list = (IEnumerable)Activator.CreateInstance(listType); + var list = (IEnumerable)Activator.CreateInstance(listType); return list; } diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index 5135473cdb..0a3e01d0d1 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -7,6 +7,14 @@ namespace JsonApiDotNetCore.Internal { public static class TypeHelper { + public static IList ConvertCollection(IEnumerable collection, Type targetType) + { + var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(targetType)) as IList; + foreach(var item in collection) + list.Add(ConvertType(item, targetType)); + return list; + } + public static object ConvertType(object value, Type type) { if (value == null) diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs index 4519dc8cb6..c2d7594400 100644 --- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs @@ -12,7 +12,7 @@ public override void SetValue(object entity, object newValue) .GetType() .GetProperty(InternalRelationshipName); - propertyInfo.SetValue(entity, newValue); + propertyInfo.SetValue(entity, newValue); } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index d55cb48a2e..723e831e1e 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; @@ -9,7 +10,6 @@ using JsonApiDotNetCore.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using JsonApiDotNetCore.Extensions; namespace JsonApiDotNetCore.Serialization { @@ -246,8 +246,6 @@ private object SetHasManyRelationship(object entity, if (data == null) return entity; - var resourceRelationships = attr.Type.GetEmptyCollection(); - var relationshipShells = relationshipData.ManyData.Select(r => { var instance = attr.Type.New(); @@ -255,7 +253,11 @@ private object SetHasManyRelationship(object entity, return instance; }); - attr.SetValue(entity, relationshipShells); + var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); + + // var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); + + attr.SetValue(entity, convertedCollection); } return entity; diff --git a/test/UnitTests/Extensions/TypeExtensions_Tests.cs b/test/UnitTests/Extensions/TypeExtensions_Tests.cs index 92534eef5d..f59fa37be0 100644 --- a/test/UnitTests/Extensions/TypeExtensions_Tests.cs +++ b/test/UnitTests/Extensions/TypeExtensions_Tests.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Models; using Xunit; -using JsonApiDotNetCore.Extensions; -using System.Collections.Generic; namespace UnitTests.Extensions { @@ -14,7 +14,7 @@ public void GetCollection_Creates_List_If_T_Implements_Interface() var type = typeof(Model); // act - var collection = type.GetEmptyCollection(); + var collection = type.GetEmptyCollection(); // assert Assert.NotNull(collection); From bc621fada955ba1c6096d593b837edcd133e97c3 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 07:10:26 -0500 Subject: [PATCH 168/227] set new HasManyRelationships with EntityState.Unchanged --- .../Data/DefaultEntityRepository.cs | 19 +++++++ .../Data/IEntityRepository.cs | 4 -- .../Extensions/DbContextExtensions.cs | 16 ++---- .../Request/HasManyRelationshipPointers.cs | 49 +++++++++++++++++++ .../Serialization/JsonApiDeSerializer.cs | 10 +--- .../Services/IJsonApiContext.cs | 2 + .../Services/JsonApiContext.cs | 2 + 7 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index b6bcda29b3..fe85c84049 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -85,10 +85,29 @@ public virtual async Task GetAndIncludeAsync(TId id, string relationshi public virtual async Task CreateAsync(TEntity entity) { _dbSet.Add(entity); + + DetachHasManyPointers(); + await _context.SaveChangesAsync(); return entity; } + /// + /// This is used to allow creation of HasMany relationships when the + /// dependent side of the relationship already exists. + /// + private void DetachHasManyPointers() + { + var relationships = _jsonApiContext.HasManyRelationshipPointers.Get(); + foreach(var relationship in relationships) + { + foreach(var pointer in relationship.Value) + { + _context.Entry(pointer).State = EntityState.Unchanged; + } + } + } + public virtual async Task UpdateAsync(TId id, TEntity entity) { var oldEntity = await GetAsync(id); diff --git a/src/JsonApiDotNetCore/Data/IEntityRepository.cs b/src/JsonApiDotNetCore/Data/IEntityRepository.cs index 4c35d6ea3f..e8bb68ef90 100644 --- a/src/JsonApiDotNetCore/Data/IEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/IEntityRepository.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Data diff --git a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs index 2606342e29..3cb5ccc359 100644 --- a/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/DbContextExtensions.cs @@ -1,20 +1,12 @@ -using Microsoft.EntityFrameworkCore; using System; +using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Extensions { public static class DbContextExtensions { - public static DbSet GetDbSet(this DbContext context) where T : class - { - var contextProperties = context.GetType().GetProperties(); - foreach(var property in contextProperties) - { - if (property.PropertyType == typeof(DbSet)) - return (DbSet)property.GetValue(context); - } - - throw new ArgumentException($"DbSet of type {typeof(T).FullName} not found on the DbContext", nameof(T)); - } + [Obsolete("This is no longer required since the introduction of context.Set", error: false)] + public static DbSet GetDbSet(this DbContext context) where T : class + => context.Set(); } } diff --git a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs new file mode 100644 index 0000000000..721274e3d6 --- /dev/null +++ b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace JsonApiDotNetCore.Request +{ + /// + /// Stores information to set relationships for the request resource. + /// These relationships must already exist and should not be re-created. + /// + /// The expected use case is POST-ing or PATCH-ing + /// an entity with HasMany relaitonships: + /// + /// { + /// "data": { + /// "type": "photos", + /// "attributes": { + /// "title": "Ember Hamster", + /// "src": "http://example.com/images/productivity.png" + /// }, + /// "relationships": { + /// "tags": { + /// "data": [ + /// { "type": "tags", "id": "2" }, + /// { "type": "tags", "id": "3" } + /// ] + /// } + /// } + /// } + /// } + /// + /// + public class HasManyRelationshipPointers + { + private Dictionary _hasManyRelationships = new Dictionary(); + + /// + /// Add the relationship to the list of relationships that should be + /// set in the repository layer. + /// + public void Add(Type dependentType, IList entities) + => _hasManyRelationships[dependentType] = entities; + + /// + /// Get all the models that should be associated + /// + public Dictionary Get() => _hasManyRelationships; + } +} diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 723e831e1e..5ef13609d6 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -232,12 +232,6 @@ private object SetHasManyRelationship(object entity, ContextEntity contextEntity, Dictionary relationships) { - // TODO: is this necessary? if not, remove - // var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName); - - // if (entityProperty == null) - // throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a relationsip named '{attr.InternalRelationshipName}'"); - var relationshipName = attr.PublicRelationshipName; if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData)) @@ -255,9 +249,9 @@ private object SetHasManyRelationship(object entity, var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); - // var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type); - attr.SetValue(entity, convertedCollection); + + _jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection); } return entity; diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index a73f0eb53a..132630446d 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -6,6 +6,7 @@ using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Request; namespace JsonApiDotNetCore.Services { @@ -28,6 +29,7 @@ public interface IJsonApiContext Type ControllerType { get; set; } Dictionary DocumentMeta { get; set; } bool IsBulkOperationRequest { get; set; } + HasManyRelationshipPointers HasManyRelationshipPointers { get; } TAttribute GetControllerAttribute() where TAttribute : Attribute; } diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index 2665217fef..0643d494d6 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -6,6 +6,7 @@ using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Internal.Query; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Request; using Microsoft.AspNetCore.Http; namespace JsonApiDotNetCore.Services @@ -51,6 +52,7 @@ public JsonApiContext( public Type ControllerType { get; set; } public Dictionary DocumentMeta { get; set; } public bool IsBulkOperationRequest { get; set; } + public HasManyRelationshipPointers HasManyRelationshipPointers { get; } = new HasManyRelationshipPointers(); public IJsonApiContext ApplyContext(object controller) { From 9ee5a97c11788c763bc262bfff3e5b669d8e58b6 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 07:26:15 -0500 Subject: [PATCH 169/227] ensure pointers are attached prior to adding the entity --- src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index fe85c84049..032fef13c4 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -84,10 +84,9 @@ public virtual async Task GetAndIncludeAsync(TId id, string relationshi public virtual async Task CreateAsync(TEntity entity) { + AttachHasManyPointers(); _dbSet.Add(entity); - DetachHasManyPointers(); - await _context.SaveChangesAsync(); return entity; } @@ -96,7 +95,7 @@ public virtual async Task CreateAsync(TEntity entity) /// This is used to allow creation of HasMany relationships when the /// dependent side of the relationship already exists. /// - private void DetachHasManyPointers() + private void AttachHasManyPointers() { var relationships = _jsonApiContext.HasManyRelationshipPointers.Get(); foreach(var relationship in relationships) From 5fbf2e8a660ee6a3371e22fe69a61a0968a47bbc Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 8 Apr 2018 15:33:58 -0500 Subject: [PATCH 170/227] fix tests --- .../Unit => UnitTests}/Builders/MetaBuilderTests.cs | 6 +++--- .../Extensions/IServiceCollectionExtensionsTests.cs | 7 +++---- .../Unit => UnitTests}/Models/AttributesEqualsTests.cs | 2 +- test/UnitTests/UnitTests.csproj | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Builders/MetaBuilderTests.cs (97%) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Extensions/IServiceCollectionExtensionsTests.cs (92%) rename test/{JsonApiDotNetCoreExampleTests/Unit => UnitTests}/Models/AttributesEqualsTests.cs (97%) diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs b/test/UnitTests/Builders/MetaBuilderTests.cs similarity index 97% rename from test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs rename to test/UnitTests/Builders/MetaBuilderTests.cs index 5cd0b765de..0b784ef5b7 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Builders/MetaBuilderTests.cs +++ b/test/UnitTests/Builders/MetaBuilderTests.cs @@ -1,8 +1,8 @@ -using Xunit; -using JsonApiDotNetCore.Builders; using System.Collections.Generic; +using JsonApiDotNetCore.Builders; +using Xunit; -namespace JsonApiDotNetCoreExampleTests.Unit.Builders +namespace UnitTests.Builders { public class MetaBuilderTests { diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs similarity index 92% rename from test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs rename to test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs index f6772fa22b..4fe2f09ff1 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs @@ -10,12 +10,11 @@ using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; -using UnitTests; using Xunit; +using Microsoft.EntityFrameworkCore; -namespace JsonApiDotNetCoreExampleTests.Unit.Extensions +namespace UnitTests.Extensions { public class IServiceCollectionExtensionsTests { @@ -28,7 +27,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() services.AddDbContext(options => { - options.UseMemoryCache(new MemoryCache(new MemoryCacheOptions())); + options.UseInMemoryDatabase(); }, ServiceLifetime.Transient); // act diff --git a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs b/test/UnitTests/Models/AttributesEqualsTests.cs similarity index 97% rename from test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs rename to test/UnitTests/Models/AttributesEqualsTests.cs index 107dd1d593..0b989169ef 100644 --- a/test/JsonApiDotNetCoreExampleTests/Unit/Models/AttributesEqualsTests.cs +++ b/test/UnitTests/Models/AttributesEqualsTests.cs @@ -1,7 +1,7 @@ using JsonApiDotNetCore.Models; using Xunit; -namespace JsonApiDotNetCoreExampleTests.Unit.Models +namespace UnitTests.Models { public class AttributesEqualsTests { diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index 14a0d30e33..a6ed346e7d 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -12,5 +12,6 @@ + From 46df3b50ad127bdcc330bde5b04b633c03377e4e Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 10 May 2018 14:18:38 -0500 Subject: [PATCH 171/227] add serialization tests --- .../Serialization/JsonApiDeSerializerTests.cs | 261 +++++++++++------- 1 file changed, 163 insertions(+), 98 deletions(-) diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index 1e20c0359e..0b80d3a25a 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Internal.Generics; using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Request; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using Moq; @@ -11,10 +11,13 @@ using Newtonsoft.Json.Serialization; using Xunit; -namespace UnitTests.Serialization { - public class JsonApiDeSerializerTests { +namespace UnitTests.Serialization +{ + public class JsonApiDeSerializerTests + { [Fact] - public void Can_Deserialize_Complex_Types() { + public void Can_Deserialize_Complex_Types() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -29,20 +32,18 @@ public void Can_Deserialize_Complex_Types() { jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); - - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); - var content = new Document { - Data = new DocumentData { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { + var content = new Document + { + Data = new DocumentData { - "complex-member", - new { compoundName = "testName" } - } - } + Type = "test-resource", + Id = "1", + Attributes = new Dictionary + { + { "complex-member", new { compoundName = "testName" } } + } } }; @@ -55,7 +56,8 @@ public void Can_Deserialize_Complex_Types() { } [Fact] - public void Can_Deserialize_Complex_List_Types() { + public void Can_Deserialize_Complex_List_Types() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -69,22 +71,18 @@ public void Can_Deserialize_Complex_List_Types() { jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - - var content = new Document { - Data = new DocumentData { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { + var content = new Document + { + Data = new DocumentData { - "complex-members", - new [] { - new { compoundName = "testName" } - } - } - } + Type = "test-resource", + Id = "1", + Attributes = new Dictionary + { + { "complex-members", new [] { new { compoundName = "testName" } } } + } } }; @@ -98,7 +96,8 @@ public void Can_Deserialize_Complex_List_Types() { } [Fact] - public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() { + public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -113,20 +112,20 @@ public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() { jsonApiOptions.SerializerSettings.ContractResolver = new DasherizedResolver(); // <-- jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - - var content = new Document { - Data = new DocumentData { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { + var content = new Document + { + Data = new DocumentData { - "complex-member", - new Dictionary { { "compound-name", "testName" } } - } - } + Type = "test-resource", + Id = "1", + Attributes = new Dictionary + { + { + "complex-member", new Dictionary { { "compound-name", "testName" } } + } + } } }; @@ -139,7 +138,8 @@ public void Can_Deserialize_Complex_Types_With_Dasherized_Attrs() { } [Fact] - public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() { + public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("test-resource"); @@ -156,22 +156,21 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() { jsonApiOptions.SerializerSettings.ContractResolver = new DasherizedResolver(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); - - var content = new Document { - Data = new DocumentData { - Type = "test-resource", - Id = "1", - Attributes = new Dictionary { + var content = new Document + { + Data = new DocumentData { - "complex-member", - new Dictionary { { "compound-name", "testName" } - } - }, - { "immutable", "value" } - } + Type = "test-resource", + Id = "1", + Attributes = new Dictionary + { + { + "complex-member", new Dictionary { { "compound-name", "testName" } } + }, + { "immutable", "value" } + } } }; @@ -189,7 +188,8 @@ public void Immutable_Attrs_Are_Not_Included_In_AttributesToUpdate() { } [Fact] - public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() { + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("independents"); @@ -204,17 +204,16 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() { var jsonApiOptions = new JsonApiOptions(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); - - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); var property = Guid.NewGuid().ToString(); - var content = new Document { - Data = new DocumentData { - Type = "independents", - Id = "1", - Attributes = new Dictionary { { "property", property } - } + var content = new Document + { + Data = new DocumentData + { + Type = "independents", + Id = "1", + Attributes = new Dictionary { { "property", property } } } }; @@ -229,7 +228,8 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship() { } [Fact] - public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Relationship_Body() { + public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Relationship_Body() + { // arrange var contextGraphBuilder = new ContextGraphBuilder(); contextGraphBuilder.AddResource("independents"); @@ -244,20 +244,18 @@ public void Can_Deserialize_Independent_Side_Of_One_To_One_Relationship_With_Rel var jsonApiOptions = new JsonApiOptions(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); - - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); var property = Guid.NewGuid().ToString(); - var content = new Document { - Data = new DocumentData { - Type = "independents", - Id = "1", - Attributes = new Dictionary { { "property", property } - }, - // a common case for this is deserialization in unit tests - Relationships = new Dictionary { { "dependent", new RelationshipData { } } - } + var content = new Document + { + Data = new DocumentData + { + Type = "independents", + Id = "1", + Attributes = new Dictionary { { "property", property } }, + // a common case for this is deserialization in unit tests + Relationships = new Dictionary { { "dependent", new RelationshipData { } } } } }; @@ -288,24 +286,21 @@ public void Sets_The_DocumentMeta_Property_In_JsonApiContext() var jsonApiOptions = new JsonApiOptions(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); - var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); var property = Guid.NewGuid().ToString(); - + var content = new Document - { - Meta = new Dictionary() { {"foo", "bar"}}, + { + Meta = new Dictionary() { { "foo", "bar" } }, Data = new DocumentData { Type = "independents", Id = "1", - Attributes = new Dictionary { { "property", property } - }, + Attributes = new Dictionary { { "property", property } }, // a common case for this is deserialization in unit tests - Relationships = new Dictionary { { "dependent", new RelationshipData { } } - } + Relationships = new Dictionary { { "dependent", new RelationshipData { } } } } }; @@ -318,32 +313,102 @@ public void Sets_The_DocumentMeta_Property_In_JsonApiContext() jsonApiContextMock.VerifySet(mock => mock.DocumentMeta = content.Meta); } - - private class TestResource : Identifiable { + private class TestResource : Identifiable + { [Attr("complex-member")] public ComplexType ComplexMember { get; set; } - [Attr("immutable", isImmutable : true)] + [Attr("immutable", isImmutable: true)] public string Immutable { get; set; } } - private class TestResourceWithList : Identifiable { + private class TestResourceWithList : Identifiable + { [Attr("complex-members")] public List ComplexMembers { get; set; } } - private class ComplexType { + private class ComplexType + { public string CompoundName { get; set; } } - private class Independent : Identifiable { + private class Independent : Identifiable + { [Attr("property")] public string Property { get; set; } [HasOne("dependent")] public Dependent Dependent { get; set; } } - private class Dependent : Identifiable { + private class Dependent : Identifiable + { [HasOne("independent")] public Independent Independent { get; set; } public int IndependentId { get; set; } } + + + + [Fact] + public void Can_Deserialize_Object_With_HasManyRelationship() + { + // arrange + var contextGraphBuilder = new ContextGraphBuilder(); + contextGraphBuilder.AddResource("independents"); + contextGraphBuilder.AddResource("dependents"); + var contextGraph = contextGraphBuilder.Build(); + + var jsonApiContextMock = new Mock(); + jsonApiContextMock.SetupAllProperties(); + jsonApiContextMock.Setup(m => m.ContextGraph).Returns(contextGraph); + jsonApiContextMock.Setup(m => m.AttributesToUpdate).Returns(new Dictionary()); + jsonApiContextMock.Setup(m => m.HasManyRelationshipPointers).Returns(new HasManyRelationshipPointers()); + + var jsonApiOptions = new JsonApiOptions(); + jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); + + var deserializer = new JsonApiDeSerializer(jsonApiContextMock.Object); + + var contentString = + @"{ + ""data"": { + ""type"": ""independents"", + ""id"": ""1"", + ""attributes"": { }, + ""relationships"": { + ""dependents"": { + ""data"": [ + { + ""type"": ""dependents"", + ""id"": ""2"" + } + ] + } + } + } + }"; + + // act + var result = deserializer.Deserialize(contentString); + + // assert + Assert.NotNull(result); + Assert.Equal(1, result.Id); + Assert.NotNull(result.Dependents); + Assert.NotEmpty(result.Dependents); + Assert.Equal(1, result.Dependents.Count); + + var dependent = result.Dependents[0]; + Assert.Equal(2, dependent.Id); + } + + private class OneToManyDependent : Identifiable + { + [HasOne("independent")] public OneToManyIndependent Independent { get; set; } + public int IndependentId { get; set; } + } + + private class OneToManyIndependent : Identifiable + { + [HasMany("dependents")] public List Dependents { get; set; } + } } } From 846e3fc479e54fca01ebeab2635e0ac7d8370e52 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 10 May 2018 17:00:12 -0500 Subject: [PATCH 172/227] refactor(JsonApiContext): begin interface separation remove redundant IsRelationship property --- .../Builders/DocumentBuilder.cs | 2 +- .../Services/EntityResourceService.cs | 5 +- .../Services/IJsonApiContext.cs | 108 ++++++++++++++++-- 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 088a2bf092..0beb0516c1 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -107,7 +107,7 @@ public DocumentData GetData(ContextEntity contextEntity, IIdentifiable entity) Id = entity.StringId }; - if (_jsonApiContext.IsRelationshipData) + if (_jsonApiContext.IsRelationshipPath) return data; data.Attributes = new Dictionary(); diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index bc7a2adb52..ba9d6b987e 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -80,10 +80,7 @@ private async Task GetWithRelationshipsAsync(TId id) } public virtual async Task GetRelationshipsAsync(TId id, string relationshipName) - { - _jsonApiContext.IsRelationshipData = true; - return await GetRelationshipAsync(id, relationshipName); - } + => await GetRelationshipAsync(id, relationshipName); public virtual async Task GetRelationshipAsync(TId id, string relationshipName) { diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 132630446d..6a358f4732 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -10,27 +10,113 @@ namespace JsonApiDotNetCore.Services { - public interface IJsonApiContext + public interface IJsonApiApplication { JsonApiOptions Options { get; set; } - IJsonApiContext ApplyContext(object controller); IContextGraph ContextGraph { get; set; } - ContextEntity RequestEntity { get; set; } - string BasePath { get; set; } - QuerySet QuerySet { get; set; } - bool IsRelationshipData { get; set; } + } + + public interface IQueryRequest + { List IncludedRelationships { get; set; } - bool IsRelationshipPath { get; } + QuerySet QuerySet { get; set; } PageManager PageManager { get; set; } - IMetaBuilder MetaBuilder { get; set; } - IGenericProcessorFactory GenericProcessorFactory { get; set; } + } + + public interface IUpdateRequest + { Dictionary AttributesToUpdate { get; set; } Dictionary RelationshipsToUpdate { get; set; } + } + + public interface IJsonApiRequest : IJsonApiApplication, IUpdateRequest, IQueryRequest + { + /// + /// The request namespace. This may be an absolute or relative path + /// depending upon the configuration. + /// + /// + /// Absolute: https://example.com/api/v1 + /// + /// Relative: /api/v1 + /// + string BasePath { get; set; } + + /// + /// Stores information to set relationships for the request resource. + /// These relationships must already exist and should not be re-created. + /// By default, it is the responsibility of the repository to use the + /// relationship pointers to persist the relationship. + /// + /// The expected use case is POST-ing or PATCH-ing an entity with HasMany + /// relaitonships: + /// + /// { + /// "data": { + /// "type": "photos", + /// "attributes": { + /// "title": "Ember Hamster", + /// "src": "http://example.com/images/productivity.png" + /// }, + /// "relationships": { + /// "tags": { + /// "data": [ + /// { "type": "tags", "id": "2" }, + /// { "type": "tags", "id": "3" } + /// ] + /// } + /// } + /// } + /// } + /// + /// + HasManyRelationshipPointers HasManyRelationshipPointers { get; } + + /// + /// If the request is a bulk json:api v1.1 operations request. + /// This is determined by the ` + /// ` class. + /// + /// See [json-api/1254](https://github.com/json-api/json-api/pull/1254) for details. + /// + bool IsBulkOperationRequest { get; set; } + + /// + /// The ``for the target route. + /// + /// + /// + /// For a `GET /articles` request, `RequestEntity` will be set + /// to the `Article` resource representation on the `JsonApiContext`. + /// + ContextEntity RequestEntity { get; set; } + + /// + /// The concrete type of the controller that was activated by the MVC routing middleware + /// Type ControllerType { get; set; } + + /// + /// The json:api meta data at the document level + /// Dictionary DocumentMeta { get; set; } - bool IsBulkOperationRequest { get; set; } - HasManyRelationshipPointers HasManyRelationshipPointers { get; } + /// + /// If the request is on the `{id}/relationships/{relationshipName}` route + /// + bool IsRelationshipPath { get; } + + [Obsolete("Use `IsRelationshipPath` instead.")] + bool IsRelationshipData { get; set; } + } + + public interface IJsonApiContext : IJsonApiRequest + { + IJsonApiContext ApplyContext(object controller); + IMetaBuilder MetaBuilder { get; set; } + IGenericProcessorFactory GenericProcessorFactory { get; set; } + + [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] TAttribute GetControllerAttribute() where TAttribute : Attribute; } } From 48c6b5a586a96cfca80994e538976ebfcf75819a Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Tue, 5 Jun 2018 07:01:18 -0500 Subject: [PATCH 173/227] document(IUpdateRequest) --- src/JsonApiDotNetCore/Services/IJsonApiContext.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index 6a358f4732..52036f21af 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -25,7 +25,16 @@ public interface IQueryRequest public interface IUpdateRequest { + /// + /// The attributes that were included in a PATCH request. + /// Only the attributes in this dictionary should be updated. + /// Dictionary AttributesToUpdate { get; set; } + + /// + /// Any relationships that were included in a PATCH request. + /// Only the relationships in this dictionary should be updated. + /// Dictionary RelationshipsToUpdate { get; set; } } From 4ac550e296da13537ba33d9f6d865a6d58670d2b Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 8 Jun 2018 23:01:42 -0500 Subject: [PATCH 174/227] fix(JsonApiDeserializer): if hasOne is nullable allow it to be set null --- .../Models/HasOneAttribute.cs | 7 +- .../Models/RelationshipAttribute.cs | 22 + .../Serialization/JsonApiDeSerializer.cs | 10 +- .../Services/EntityResourceService.cs | 2 +- .../Spec/UpdatingRelationshipsTests.cs | 95 ++++ .../Builders/DocumentBuilder_Tests.cs | 529 +++++++++--------- .../IServiceCollectionExtensionsTests.cs | 5 +- 7 files changed, 395 insertions(+), 275 deletions(-) diff --git a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs index 03fdb200fc..77422027a7 100644 --- a/src/JsonApiDotNetCore/Models/HasOneAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasOneAttribute.cs @@ -39,9 +39,14 @@ public HasOneAttribute(string publicName, Link documentLinks = Link.All, bool ca ? $"{InternalRelationshipName}Id" : _explicitIdentifiablePropertyName; + /// + /// Sets the value of the property identified by this attribute + /// + /// The target object + /// The new property value public override void SetValue(object entity, object newValue) { - var propertyName = (newValue.GetType() == Type) + var propertyName = (newValue?.GetType() == Type) ? InternalRelationshipName : IdentifiablePropertyName; diff --git a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs index 2781ecfb53..3e66bdc8aa 100644 --- a/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs +++ b/src/JsonApiDotNetCore/Models/RelationshipAttribute.cs @@ -19,6 +19,28 @@ protected RelationshipAttribute(string publicName, Link documentLinks, bool canI public Link DocumentLinks { get; } = Link.All; public bool CanInclude { get; } + public bool TryGetHasOne(out HasOneAttribute result) + { + if (IsHasOne) + { + result = (HasOneAttribute)this; + return true; + } + result = null; + return false; + } + + public bool TryGetHasMany(out HasManyAttribute result) + { + if (IsHasMany) + { + result = (HasManyAttribute)this; + return true; + } + result = null; + return false; + } + public abstract void SetValue(object entity, object newValue); public override string ToString() diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 5ef13609d6..da206e4930 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -207,15 +207,17 @@ private object SetHasOneRelationship(object entity, var rio = (ResourceIdentifierObject)relationshipData.ExposedData; - if (rio == null) return entity; - - var newValue = rio.Id; - var foreignKey = attr.IdentifiablePropertyName; var entityProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); if (entityProperty == null) throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a foreign key property '{foreignKey}' for has one relationship '{attr.InternalRelationshipName}'"); + // e.g. PATCH /articles + // {... { "relationships":{ "Owner": { "data" :null } } } } + if (rio == null && Nullable.GetUnderlyingType(entityProperty.PropertyType) == null) + throw new JsonApiException(400, $"Cannot set required relationship identifier '{attr.IdentifiablePropertyName}' to null."); + + var newValue = rio?.Id ?? null; var convertedValue = TypeHelper.ConvertType(newValue, entityProperty.PropertyType); _jsonApiContext.RelationshipsToUpdate[relationshipAttr] = convertedValue; diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index ba9d6b987e..642ee00a57 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -133,7 +133,7 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa .Relationships .FirstOrDefault(r => r.InternalRelationshipName == relationshipName); - var relationshipIds = relationships.Select(r => r.Id?.ToString()); + var relationshipIds = relationships.Select(r => r?.Id?.ToString()); await _entities.UpdateRelationshipsAsync(entity, relationship, relationshipIds); } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs index 1dffa6ce87..067483a1b3 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs @@ -127,5 +127,100 @@ public async Task Can_Update_ToOne_Relationship_ThroughLink() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(todoItemsOwner); } + + [Fact] + public async Task Can_Delete_Relationship_By_Patching_Resource() + { + // arrange + var person = _personFaker.Generate(); + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = person; + + _context.People.Add(person); + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var builder = new WebHostBuilder() + .UseStartup(); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var content = new + { + data = new + { + type = "todo-items", + relationships = new + { + owner = new + { + data = (object)null + } + } + } + }; + + var httpMethod = new HttpMethod("PATCH"); + var route = $"/api/v1/todo-items/{todoItem.Id}"; + var request = new HttpRequestMessage(httpMethod, route); + request.Content = new StringContent(JsonConvert.SerializeObject(content)); + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + + // Act + var response = await client.SendAsync(request); + + // Assert + var todoItemResult = _context.TodoItems + .AsNoTracking() + .Include(t => t.Owner) + .Single(t => t.Id == todoItem.Id); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Null(todoItemResult.Owner); + } + + [Fact] + public async Task Can_Delete_Relationship_By_Patching_Relationship() + { + // arrange + var person = _personFaker.Generate(); + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = person; + + _context.People.Add(person); + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var builder = new WebHostBuilder() + .UseStartup(); + + var server = new TestServer(builder); + var client = server.CreateClient(); + + var content = new + { + data = (object)null + }; + + var httpMethod = new HttpMethod("PATCH"); + var route = $"/api/v1/todo-items/{todoItem.Id}/relationships/owner"; + var request = new HttpRequestMessage(httpMethod, route); + + request.Content = new StringContent(JsonConvert.SerializeObject(content)); + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + + // Act + var response = await client.SendAsync(request); + + // Assert + var todoItemResult = _context.TodoItems + .AsNoTracking() + .Include(t => t.Owner) + .Single(t => t.Id == todoItem.Id); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Null(todoItemResult.Owner); + } } } diff --git a/test/UnitTests/Builders/DocumentBuilder_Tests.cs b/test/UnitTests/Builders/DocumentBuilder_Tests.cs index dbca1bebb4..fc816765eb 100644 --- a/test/UnitTests/Builders/DocumentBuilder_Tests.cs +++ b/test/UnitTests/Builders/DocumentBuilder_Tests.cs @@ -1,268 +1,267 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using JsonApiDotNetCore.Builders; -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Services; -using Moq; -using Xunit; - -namespace UnitTests -{ - public class DocumentBuilder_Tests - { - private readonly Mock _jsonApiContextMock; - private readonly PageManager _pageManager; - private readonly JsonApiOptions _options; - private readonly Mock _requestMetaMock; - - public DocumentBuilder_Tests() - { - _jsonApiContextMock = new Mock(); - _requestMetaMock = new Mock(); - - _options = new JsonApiOptions(); - - _options.BuildContextGraph(builder => - { - builder.AddResource("models"); - builder.AddResource("related-models"); - }); - - _jsonApiContextMock - .Setup(m => m.Options) - .Returns(_options); - - _jsonApiContextMock - .Setup(m => m.ContextGraph) - .Returns(_options.ContextGraph); - - _jsonApiContextMock - .Setup(m => m.MetaBuilder) - .Returns(new MetaBuilder()); - - _pageManager = new PageManager(); - _jsonApiContextMock - .Setup(m => m.PageManager) - .Returns(_pageManager); - - _jsonApiContextMock - .Setup(m => m.BasePath) - .Returns("localhost"); - - _jsonApiContextMock - .Setup(m => m.RequestEntity) - .Returns(_options.ContextGraph.GetContextEntity(typeof(Model))); - } - - [Fact] - public void Includes_Paging_Links_By_Default() - { - // arrange - _pageManager.PageSize = 1; - _pageManager.TotalRecords = 1; - _pageManager.CurrentPage = 1; - - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - var entity = new Model(); - - // act - var document = documentBuilder.Build(entity); - - // assert - Assert.NotNull(document.Links); - Assert.NotNull(document.Links.Last); - } - - [Fact] - public void Page_Links_Can_Be_Disabled_Globally() - { - // arrange - _pageManager.PageSize = 1; - _pageManager.TotalRecords = 1; - _pageManager.CurrentPage = 1; - - _options.BuildContextGraph(builder => builder.DocumentLinks = Link.None); - - _jsonApiContextMock - .Setup(m => m.ContextGraph) - .Returns(_options.ContextGraph); - - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - var entity = new Model(); - - // act - var document = documentBuilder.Build(entity); - - // assert - Assert.Null(document.Links); - } - - [Fact] - public void Related_Links_Can_Be_Disabled() - { - // arrange - _pageManager.PageSize = 1; - _pageManager.TotalRecords = 1; - _pageManager.CurrentPage = 1; - - _jsonApiContextMock - .Setup(m => m.ContextGraph) - .Returns(_options.ContextGraph); - - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - var entity = new Model(); - - // act - var document = documentBuilder.Build(entity); - - // assert - Assert.Null(document.Data.Relationships["related-model"].Links); - } - - [Fact] - public void Related_Data_Included_In_Relationships_By_Default() - { - // arrange - const string relatedTypeName = "related-models"; - const string relationshipName = "related-model"; - const int relatedId = 1; - _jsonApiContextMock - .Setup(m => m.ContextGraph) - .Returns(_options.ContextGraph); - - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - var entity = new Model - { - RelatedModel = new RelatedModel - { - Id = relatedId - } - }; - - // act - var document = documentBuilder.Build(entity); - - // assert - var relationshipData = document.Data.Relationships[relationshipName]; - Assert.NotNull(relationshipData); - Assert.NotNull(relationshipData.SingleData); - Assert.NotNull(relationshipData.SingleData); - Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); - Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); +using System.Collections; +using System.Collections.Generic; +using JsonApiDotNetCore.Builders; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; +using JsonApiDotNetCore.Services; +using Moq; +using Xunit; + +namespace UnitTests +{ + public class DocumentBuilder_Tests + { + private readonly Mock _jsonApiContextMock; + private readonly PageManager _pageManager; + private readonly JsonApiOptions _options; + private readonly Mock _requestMetaMock; + + public DocumentBuilder_Tests() + { + _jsonApiContextMock = new Mock(); + _requestMetaMock = new Mock(); + + _options = new JsonApiOptions(); + + _options.BuildContextGraph(builder => + { + builder.AddResource("models"); + builder.AddResource("related-models"); + }); + + _jsonApiContextMock + .Setup(m => m.Options) + .Returns(_options); + + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + _jsonApiContextMock + .Setup(m => m.MetaBuilder) + .Returns(new MetaBuilder()); + + _pageManager = new PageManager(); + _jsonApiContextMock + .Setup(m => m.PageManager) + .Returns(_pageManager); + + _jsonApiContextMock + .Setup(m => m.BasePath) + .Returns("localhost"); + + _jsonApiContextMock + .Setup(m => m.RequestEntity) + .Returns(_options.ContextGraph.GetContextEntity(typeof(Model))); + } + + [Fact] + public void Includes_Paging_Links_By_Default() + { + // arrange + _pageManager.PageSize = 1; + _pageManager.TotalRecords = 1; + _pageManager.CurrentPage = 1; + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model(); + + // act + var document = documentBuilder.Build(entity); + + // assert + Assert.NotNull(document.Links); + Assert.NotNull(document.Links.Last); } - [Fact] - public void IndependentIdentifier__Included_In_HasOne_Relationships_By_Default() - { - // arrange - const string relatedTypeName = "related-models"; - const string relationshipName = "related-model"; - const int relatedId = 1; - _jsonApiContextMock - .Setup(m => m.ContextGraph) - .Returns(_options.ContextGraph); - - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - var entity = new Model + [Fact] + public void Page_Links_Can_Be_Disabled_Globally() + { + // arrange + _pageManager.PageSize = 1; + _pageManager.TotalRecords = 1; + _pageManager.CurrentPage = 1; + + _options.BuildContextGraph(builder => builder.DocumentLinks = Link.None); + + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model(); + + // act + var document = documentBuilder.Build(entity); + + // assert + Assert.Null(document.Links); + } + + [Fact] + public void Related_Links_Can_Be_Disabled() + { + // arrange + _pageManager.PageSize = 1; + _pageManager.TotalRecords = 1; + _pageManager.CurrentPage = 1; + + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model(); + + // act + var document = documentBuilder.Build(entity); + + // assert + Assert.Null(document.Data.Relationships["related-model"].Links); + } + + [Fact] + public void Related_Data_Included_In_Relationships_By_Default() + { + // arrange + const string relatedTypeName = "related-models"; + const string relationshipName = "related-model"; + const int relatedId = 1; + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model { - RelatedModelId = relatedId - }; - - // act - var document = documentBuilder.Build(entity); - - // assert - var relationshipData = document.Data.Relationships[relationshipName]; - Assert.NotNull(relationshipData); - Assert.NotNull(relationshipData.SingleData); - Assert.NotNull(relationshipData.SingleData); - Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); - Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); - } - - [Fact] - public void Build_Can_Build_Arrays() - { - var entities = new[] { new Model() }; - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - - var documents = documentBuilder.Build(entities); - - Assert.Equal(1, documents.Data.Count); - } - - [Fact] - public void Build_Can_Build_CustomIEnumerables() - { - var entities = new Models(new[] { new Model() }); - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); - - var documents = documentBuilder.Build(entities); - - Assert.Equal(1, documents.Data.Count); - } - - - [Theory] - [InlineData(null, null, true)] - [InlineData(false, null, true)] - [InlineData(true, null, false)] - [InlineData(null, "foo", true)] - [InlineData(false, "foo", true)] - [InlineData(true, "foo", true)] - public void DocumentBuilderOptions(bool? omitNullValuedAttributes, - string attributeValue, - bool resultContainsAttribute) - { - var documentBuilderBehaviourMock = new Mock(); - if (omitNullValuedAttributes.HasValue) - { - documentBuilderBehaviourMock.Setup(m => m.GetDocumentBuilderOptions()) - .Returns(new DocumentBuilderOptions(omitNullValuedAttributes.Value)); - } - var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object, null, omitNullValuedAttributes.HasValue ? documentBuilderBehaviourMock.Object : null); - var document = documentBuilder.Build(new Model() { StringProperty = attributeValue }); - - Assert.Equal(resultContainsAttribute, document.Data.Attributes.ContainsKey("StringProperty")); - } - - private class Model : Identifiable - { - [HasOne("related-model", Link.None)] - public RelatedModel RelatedModel { get; set; } - public int RelatedModelId { get; set; } - [Attr("StringProperty")] - public string StringProperty { get; set; } - - } - - private class RelatedModel : Identifiable - { - [HasMany("models")] - public List Models { get; set; } - } - - private class Models : IEnumerable - { - private readonly IEnumerable models; - - public Models(IEnumerable models) - { - this.models = models; - } - - public IEnumerator GetEnumerator() - { - return models.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return models.GetEnumerator(); - } - } - } -} + RelatedModel = new RelatedModel + { + Id = relatedId + } + }; + + // act + var document = documentBuilder.Build(entity); + + // assert + var relationshipData = document.Data.Relationships[relationshipName]; + Assert.NotNull(relationshipData); + Assert.NotNull(relationshipData.SingleData); + Assert.NotNull(relationshipData.SingleData); + Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); + Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); + } + + [Fact] + public void IndependentIdentifier__Included_In_HasOne_Relationships_By_Default() + { + // arrange + const string relatedTypeName = "related-models"; + const string relationshipName = "related-model"; + const int relatedId = 1; + _jsonApiContextMock + .Setup(m => m.ContextGraph) + .Returns(_options.ContextGraph); + + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + var entity = new Model + { + RelatedModelId = relatedId + }; + + // act + var document = documentBuilder.Build(entity); + + // assert + var relationshipData = document.Data.Relationships[relationshipName]; + Assert.NotNull(relationshipData); + Assert.NotNull(relationshipData.SingleData); + Assert.NotNull(relationshipData.SingleData); + Assert.Equal(relatedId.ToString(), relationshipData.SingleData.Id); + Assert.Equal(relatedTypeName, relationshipData.SingleData.Type); + } + + [Fact] + public void Build_Can_Build_Arrays() + { + var entities = new[] { new Model() }; + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + + var documents = documentBuilder.Build(entities); + + Assert.Equal(1, documents.Data.Count); + } + + [Fact] + public void Build_Can_Build_CustomIEnumerables() + { + var entities = new Models(new[] { new Model() }); + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object); + + var documents = documentBuilder.Build(entities); + + Assert.Equal(1, documents.Data.Count); + } + + + [Theory] + [InlineData(null, null, true)] + [InlineData(false, null, true)] + [InlineData(true, null, false)] + [InlineData(null, "foo", true)] + [InlineData(false, "foo", true)] + [InlineData(true, "foo", true)] + public void DocumentBuilderOptions(bool? omitNullValuedAttributes, + string attributeValue, + bool resultContainsAttribute) + { + var documentBuilderBehaviourMock = new Mock(); + if (omitNullValuedAttributes.HasValue) + { + documentBuilderBehaviourMock.Setup(m => m.GetDocumentBuilderOptions()) + .Returns(new DocumentBuilderOptions(omitNullValuedAttributes.Value)); + } + var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object, null, omitNullValuedAttributes.HasValue ? documentBuilderBehaviourMock.Object : null); + var document = documentBuilder.Build(new Model() { StringProperty = attributeValue }); + + Assert.Equal(resultContainsAttribute, document.Data.Attributes.ContainsKey("StringProperty")); + } + + private class Model : Identifiable + { + [HasOne("related-model", Link.None)] + public RelatedModel RelatedModel { get; set; } + public int RelatedModelId { get; set; } + [Attr("StringProperty")] + public string StringProperty { get; set; } + + } + + private class RelatedModel : Identifiable + { + [HasMany("models")] + public List Models { get; set; } + } + + private class Models : IEnumerable + { + private readonly IEnumerable models; + + public Models(IEnumerable models) + { + this.models = models; + } + + public IEnumerator GetEnumerator() + { + return models.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return models.GetEnumerator(); + } + } + } +} diff --git a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs index 4fe2f09ff1..1b00c5aaa1 100644 --- a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs @@ -25,10 +25,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() var services = new ServiceCollection(); var jsonApiOptions = new JsonApiOptions(); - services.AddDbContext(options => - { - options.UseInMemoryDatabase(); - }, ServiceLifetime.Transient); + services.AddDbContext(options => options.UseInMemoryDatabase("UnitTestDb"), ServiceLifetime.Transient); // act services.AddJsonApiInternals(jsonApiOptions); From 49468edc4866875bba6c41e39fb92f509c59514c Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 8 Jun 2018 23:14:35 -0500 Subject: [PATCH 175/227] fix(JsonApiDeSerializer): null refs --- .../Serialization/JsonApiDeSerializer.cs | 21 +++++++++++-------- .../Serialization/JsonApiDeSerializerTests.cs | 2 -- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index da206e4930..45d77c0f77 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -209,20 +209,23 @@ private object SetHasOneRelationship(object entity, var foreignKey = attr.IdentifiablePropertyName; var entityProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); - if (entityProperty == null) + if (entityProperty == null && rio != null) throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a foreign key property '{foreignKey}' for has one relationship '{attr.InternalRelationshipName}'"); - // e.g. PATCH /articles - // {... { "relationships":{ "Owner": { "data" :null } } } } - if (rio == null && Nullable.GetUnderlyingType(entityProperty.PropertyType) == null) - throw new JsonApiException(400, $"Cannot set required relationship identifier '{attr.IdentifiablePropertyName}' to null."); + if (entityProperty != null) + { + // e.g. PATCH /articles + // {... { "relationships":{ "Owner": { "data" :null } } } } + if (rio == null && Nullable.GetUnderlyingType(entityProperty.PropertyType) == null) + throw new JsonApiException(400, $"Cannot set required relationship identifier '{attr.IdentifiablePropertyName}' to null."); - var newValue = rio?.Id ?? null; - var convertedValue = TypeHelper.ConvertType(newValue, entityProperty.PropertyType); + var newValue = rio?.Id ?? null; + var convertedValue = TypeHelper.ConvertType(newValue, entityProperty.PropertyType); - _jsonApiContext.RelationshipsToUpdate[relationshipAttr] = convertedValue; + _jsonApiContext.RelationshipsToUpdate[relationshipAttr] = convertedValue; - entityProperty.SetValue(entity, convertedValue); + entityProperty.SetValue(entity, convertedValue); + } } return entity; diff --git a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs index 0b80d3a25a..ec34d87d24 100644 --- a/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs +++ b/test/UnitTests/Serialization/JsonApiDeSerializerTests.cs @@ -345,8 +345,6 @@ private class Dependent : Identifiable public int IndependentId { get; set; } } - - [Fact] public void Can_Deserialize_Object_With_HasManyRelationship() { From 013197a7060e46789e4cfd042844ad101f3fcfa0 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 8 Jun 2018 23:16:16 -0500 Subject: [PATCH 176/227] chore(csproj): bump package version --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index eb649ed5dc..f296ef318f 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.2.4 + 2.2.5/VersionPrefix> $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore From d76c6000fffdb384a510233206e4136d4e4bc68b Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Fri, 8 Jun 2018 23:21:02 -0500 Subject: [PATCH 177/227] fix(csproj): syntax error --- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index f296ef318f..4f52a23002 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@  - 2.2.5/VersionPrefix> + 2.2.5 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore From 22e742de2f66524b03a5e29edf0638935fe57189 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Sun, 10 Jun 2018 12:38:43 -0500 Subject: [PATCH 178/227] test(spec): can create hasOne relationship with resource --- .../Acceptance/Spec/CreatingDataTests.cs | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs index 2c71275473..015d79cdbd 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/CreatingDataTests.cs @@ -106,7 +106,7 @@ public async Task Cannot_Create_Entity_With_Client_Generate_Id() attributes = new { description = todoItem.Description, - ordinal = todoItem.Ordinal, + ordinal = todoItem.Ordinal, createdDate = DateTime.Now } } @@ -174,7 +174,7 @@ public async Task Can_Create_Guid_Identifiable_Entity_With_Client_Defined_Id_If_ var httpMethod = new HttpMethod("POST"); var server = new TestServer(builder); var client = server.CreateClient(); - + var context = _fixture.GetService(); var owner = new JsonApiDotNetCoreExample.Models.Person(); @@ -285,6 +285,63 @@ public async Task Can_Create_And_Set_HasMany_Relationships() Assert.NotEmpty(contextCollection.TodoItems); } + [Fact] + public async Task Can_Create_And_Set_HasOne_Relationships() + { + // arrange + var builder = new WebHostBuilder() + .UseStartup(); + var httpMethod = new HttpMethod("POST"); + var server = new TestServer(builder); + var client = server.CreateClient(); + + var context = _fixture.GetService(); + + var todoItem = new TodoItem(); + var owner = new JsonApiDotNetCoreExample.Models.Person(); + context.People.Add(owner); + await context.SaveChangesAsync(); + + var route = "/api/v1/todo-items"; + var request = new HttpRequestMessage(httpMethod, route); + var content = new + { + data = new + { + type = "todo-items", + relationships = new Dictionary + { + { "owner", new { + data = new + { + type = "people", + id = owner.Id.ToString() + } + } } + } + } + }; + + request.Content = new StringContent(JsonConvert.SerializeObject(content)); + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + + // act + var response = await client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + + // assert + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + var deserializedBody = (TodoItem)_fixture.GetService().Deserialize(body); + var newId = deserializedBody.Id; + + context = _fixture.GetService(); + var todoItemResult = context.TodoItems + .Include(c => c.Owner) + .SingleOrDefault(c => c.Id == newId); + + Assert.Equal(owner.Id, todoItemResult.OwnerId); + } + [Fact] public async Task ShouldReceiveLocationHeader_InResponse() { From df7cc0f04924c4933df8d4bcc742f099a4baae29 Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Mon, 11 Jun 2018 21:33:09 -0500 Subject: [PATCH 179/227] docs(*): add xml comments --- .../IDocumentBuilderOptionsProvider.cs | 6 +-- .../NullAttributeResponseBehavior.cs | 25 +++++++-- src/JsonApiDotNetCore/Models/AttrAttribute.cs | 53 ++++++++++++++++++- .../Models/HasManyAttribute.cs | 26 ++++++++- .../Services/QueryComposer.cs | 5 +- 5 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs index d8effd4fe3..fe014bced5 100644 --- a/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs +++ b/src/JsonApiDotNetCore/Builders/IDocumentBuilderOptionsProvider.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace JsonApiDotNetCore.Builders { public interface IDocumentBuilderOptionsProvider { - DocumentBuilderOptions GetDocumentBuilderOptions(); + DocumentBuilderOptions GetDocumentBuilderOptions(); } } diff --git a/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs index 1b10140f5e..125d38b5fc 100644 --- a/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs +++ b/src/JsonApiDotNetCore/Configuration/NullAttributeResponseBehavior.cs @@ -1,19 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace JsonApiDotNetCore.Configuration { + /// + /// Allows null attributes to be ommitted from the response payload + /// public struct NullAttributeResponseBehavior { + /// Do not serialize null attributes + /// + /// Allow clients to override the serialization behavior through a query parmeter. + /// + /// ``` + /// GET /articles?omitNullValuedAttributes=true + /// ``` + /// + /// public NullAttributeResponseBehavior(bool omitNullValuedAttributes = false, bool allowClientOverride = false) { OmitNullValuedAttributes = omitNullValuedAttributes; AllowClientOverride = allowClientOverride; } + /// + /// Do not include null attributes in the response payload. + /// public bool OmitNullValuedAttributes { get; } + + /// + /// Allows clients to specify a `omitNullValuedAttributes` boolean query param to control + /// serialization behavior. + /// public bool AllowClientOverride { get; } - // ... } } diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs index db61cb56ea..e38b47abec 100644 --- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs +++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs @@ -5,6 +5,26 @@ namespace JsonApiDotNetCore.Models { public class AttrAttribute : Attribute { + /// + /// Defines a public attribute exposed by the API + /// + /// + /// How this attribute is exposed through the API + /// Prevent PATCH requests from updating the value + /// Prevent filters on this attribute + /// Prevent this attribute from being sorted by + /// + /// + /// + /// + /// public class Author : Identifiable + /// { + /// [Attr("name")] + /// public string Name { get; set; } + /// } + /// + /// + /// public AttrAttribute(string publicName, bool isImmutable = false, bool isFilterable = true, bool isSortable = true) { PublicAttributeName = publicName; @@ -20,20 +40,51 @@ internal AttrAttribute(string publicName, string internalName, bool isImmutable IsImmutable = isImmutable; } + /// + /// How this attribute is exposed through the API + /// public string PublicAttributeName { get; } + + /// + /// The internal property name this attribute belongs to. + /// public string InternalAttributeName { get; internal set; } + + /// + /// Prevents PATCH requests from updating the value. + /// public bool IsImmutable { get; } + + /// + /// Whether or not this attribute can be filtered on via a query string filters. + /// Attempts to filter on an attribute with `IsFilterable == false` will return + /// an HTTP 400 response. + /// public bool IsFilterable { get; } + + /// + /// Whether or not this attribute can be sorted on via a query string sort. + /// Attempts to filter on an attribute with `IsSortable == false` will return + /// an HTTP 400 response. + /// public bool IsSortable { get; } + /// + /// Get the value of the attribute for the given object. + /// Returns null if the attribute does not belong to the + /// provided object. + /// public object GetValue(object entity) { return entity .GetType() .GetProperty(InternalAttributeName) - .GetValue(entity); + ?.GetValue(entity); } + /// + /// Sets the value of the attribute on the given object. + /// public void SetValue(object entity, object newValue) { var propertyInfo = entity diff --git a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs index c2d7594400..877df29146 100644 --- a/src/JsonApiDotNetCore/Models/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Models/HasManyAttribute.cs @@ -2,16 +2,40 @@ namespace JsonApiDotNetCore.Models { public class HasManyAttribute : RelationshipAttribute { + /// + /// Create a HasMany relational link to another entity + /// + /// + /// The relationship name as exposed by the API + /// Which links are available. Defaults to + /// Whether or not this relationship can be included using the ?include=public-name query string + /// + /// + /// + /// + /// public class Author : Identifiable + /// { + /// [HasMany("articles"] + /// public virtual List
Articles { get; set; } + /// } + /// + /// + /// public HasManyAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true) : base(publicName, documentLinks, canInclude) { } + /// + /// Sets the value of the property identified by this attribute + /// + /// The target object + /// The new property value public override void SetValue(object entity, object newValue) { var propertyInfo = entity .GetType() .GetProperty(InternalRelationshipName); - + propertyInfo.SetValue(entity, newValue); } } diff --git a/src/JsonApiDotNetCore/Services/QueryComposer.cs b/src/JsonApiDotNetCore/Services/QueryComposer.cs index 8e0819a438..e365811704 100644 --- a/src/JsonApiDotNetCore/Services/QueryComposer.cs +++ b/src/JsonApiDotNetCore/Services/QueryComposer.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using JsonApiDotNetCore.Internal.Query; -using Microsoft.Extensions.Logging; namespace JsonApiDotNetCore.Services { @@ -14,8 +13,8 @@ public class QueryComposer : IQueryComposer public string Compose(IJsonApiContext jsonApiContext) { string result = ""; - if(jsonApiContext != null && jsonApiContext.QuerySet != null) - { + if (jsonApiContext != null && jsonApiContext.QuerySet != null) + { List filterQueries = jsonApiContext.QuerySet.Filters; if (filterQueries.Count > 0) { From 67c310299d0088f4dde87f86e9564afede850bc1 Mon Sep 17 00:00:00 2001 From: Bj Date: Mon, 11 Jun 2018 23:07:19 -0400 Subject: [PATCH 180/227] Make `AddJsonApi` chainable --- .../JsonApiDotNetCoreExample/Startup.cs | 23 ++++++-------- .../IServiceCollectionExtensions.cs | 14 +++++---- .../Helpers/Startups/MetaStartup.cs | 31 +++++++------------ 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs index 1388004a55..378a948a61 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -29,19 +29,16 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services) { var loggerFactory = new LoggerFactory(); loggerFactory.AddConsole(LogLevel.Trace); - services.AddSingleton(loggerFactory); - services.AddDbContext(options => - { - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); - - services.AddJsonApi(opt => - { - opt.Namespace = "api/v1"; - opt.DefaultPageSize = 5; - opt.IncludeTotalRecordCount = true; - }); + services + .AddSingleton(loggerFactory) + .AddDbContext(options => + options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Transient) + .AddJsonApi(options => { + options.Namespace = "api/v1"; + options.DefaultPageSize = 5; + options.IncludeTotalRecordCount = true; + }); var provider = services.BuildServiceProvider(); var appContext = provider.GetRequiredService(); @@ -67,4 +64,4 @@ public virtual void Configure( public string GetDbConnectionString() => Config["Data:DefaultConnection"]; } -} \ No newline at end of file +} diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 807d21c018..217b5f077b 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -20,21 +20,21 @@ namespace JsonApiDotNetCore.Extensions // ReSharper disable once InconsistentNaming public static class IServiceCollectionExtensions { - public static void AddJsonApi(this IServiceCollection services) + public static IServiceCollection AddJsonApi(this IServiceCollection services) where TContext : DbContext { var mvcBuilder = services.AddMvc(); - AddJsonApi(services, (opt) => { }, mvcBuilder); + return AddJsonApi(services, (opt) => { }, mvcBuilder); } - public static void AddJsonApi(this IServiceCollection services, Action options) + public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options) where TContext : DbContext { var mvcBuilder = services.AddMvc(); - AddJsonApi(services, options, mvcBuilder); + return AddJsonApi(services, options, mvcBuilder); } - public static void AddJsonApi(this IServiceCollection services, + public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options, IMvcBuilder mvcBuilder) where TContext : DbContext { @@ -52,9 +52,10 @@ public static void AddJsonApi(this IServiceCollection services, }); AddJsonApiInternals(services, config); + return services; } - public static void AddJsonApi(this IServiceCollection services, + public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options, IMvcBuilder mvcBuilder) { @@ -70,6 +71,7 @@ public static void AddJsonApi(this IServiceCollection services, }); AddJsonApiInternals(services, config); + return services; } public static void AddJsonApiInternals( diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/MetaStartup.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/MetaStartup.cs index 0001878a50..df32a1223a 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/MetaStartup.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Startups/MetaStartup.cs @@ -20,25 +20,18 @@ public MetaStartup(IHostingEnvironment env) public override IServiceProvider ConfigureServices(IServiceCollection services) { var loggerFactory = new LoggerFactory(); - - loggerFactory - .AddConsole(LogLevel.Trace); - - services.AddSingleton(loggerFactory); - - services.AddDbContext(options => - { - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); - - services.AddJsonApi(opt => - { - opt.Namespace = "api/v1"; - opt.DefaultPageSize = 5; - opt.IncludeTotalRecordCount = true; - }); - - services.AddScoped(); + loggerFactory.AddConsole(LogLevel.Trace); + + services + .AddSingleton(loggerFactory) + .AddDbContext(options => + options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Transient) + .AddJsonApi(options => { + options.Namespace = "api/v1"; + options.DefaultPageSize = 5; + options.IncludeTotalRecordCount = true; + }) + .AddScoped(); return services.BuildServiceProvider(); } From a3f6d5fbd4c7fe3f6bf56a90c9975ccaea44a2d2 Mon Sep 17 00:00:00 2001 From: Bj Date: Mon, 11 Jun 2018 23:10:35 -0400 Subject: [PATCH 181/227] Use `MvcCore` instead of `Mvc` --- .travis.yml | 4 ++-- .../Controllers/Restricted/ReadOnlyController.cs | 8 ++++---- .../Controllers/TestValuesController.cs | 2 +- .../Controllers/TodoItemsCustomController.cs | 2 +- src/Examples/NoEntityFrameworkExample/Startup.cs | 4 ++-- src/Examples/ReportsExample/ReportsExample.csproj | 2 +- src/Examples/ReportsExample/Startup.cs | 2 +- .../Controllers/JsonApiControllerMixin.cs | 2 +- .../Controllers/JsonApiOperationsController.cs | 2 +- .../Extensions/IServiceCollectionExtensions.cs | 10 +++++----- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 3 ++- 11 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7ac38bba9f..9c5e937589 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: csharp dist: trusty sudo: required -services: +services: - postgresql before_script: - psql -c 'create database JsonApiDotNetCoreExample;' -U postgres mono: none -dotnet: 2.1.105 # https://www.microsoft.com/net/download/linux +dotnet: 2.1.300 # https://www.microsoft.com/net/download/linux branches: only: - master diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs index 57fafc8fc6..2515b1ea7a 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/Restricted/ReadOnlyController.cs @@ -5,7 +5,7 @@ namespace JsonApiDotNetCoreExample.Controllers.Restricted { [Route("[controller]")] [HttpReadOnly] - public class ReadOnlyController : Controller + public class ReadOnlyController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); @@ -22,7 +22,7 @@ public class ReadOnlyController : Controller [Route("[controller]")] [NoHttpPost] - public class NoHttpPostController : Controller + public class NoHttpPostController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); @@ -39,7 +39,7 @@ public class NoHttpPostController : Controller [Route("[controller]")] [NoHttpPatch] - public class NoHttpPatchController : Controller + public class NoHttpPatchController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); @@ -56,7 +56,7 @@ public class NoHttpPatchController : Controller [Route("[controller]")] [NoHttpDelete] - public class NoHttpDeleteController : Controller + public class NoHttpDeleteController : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs index 3443d34b74..a29295c426 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/TestValuesController.cs @@ -3,7 +3,7 @@ namespace JsonApiDotNetCoreExample.Controllers { [Route("[controller]")] - public class TestValuesController : Controller + public class TestValuesController : ControllerBase { [HttpGet] public IActionResult Get() diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs index de784c129a..fc25f8396e 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsCustomController.cs @@ -33,7 +33,7 @@ public CustomJsonApiController( } public class CustomJsonApiController - : Controller where T : class, IIdentifiable + : ControllerBase where T : class, IIdentifiable { private readonly ILogger _logger; private readonly IResourceService _resourceService; diff --git a/src/Examples/NoEntityFrameworkExample/Startup.cs b/src/Examples/NoEntityFrameworkExample/Startup.cs index dfba27ddd9..86eee500c9 100755 --- a/src/Examples/NoEntityFrameworkExample/Startup.cs +++ b/src/Examples/NoEntityFrameworkExample/Startup.cs @@ -1,4 +1,4 @@ -using JsonApiDotNetCore.Extensions; +using JsonApiDotNetCore.Extensions; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; @@ -31,7 +31,7 @@ public Startup(IHostingEnvironment env) public virtual IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. - var mvcBuilder = services.AddMvc(); + var mvcBuilder = services.AddMvcCore(); services.AddJsonApi(options => { options.Namespace = "api/v1"; diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj index bd4b402071..48df3ea2c8 100644 --- a/src/Examples/ReportsExample/ReportsExample.csproj +++ b/src/Examples/ReportsExample/ReportsExample.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Examples/ReportsExample/Startup.cs b/src/Examples/ReportsExample/Startup.cs index 72710681b9..fe476c0406 100644 --- a/src/Examples/ReportsExample/Startup.cs +++ b/src/Examples/ReportsExample/Startup.cs @@ -25,7 +25,7 @@ public Startup(IHostingEnvironment env) public virtual void ConfigureServices(IServiceCollection services) { - var mvcBuilder = services.AddMvc(); + var mvcBuilder = services.AddMvcCore(); services.AddJsonApi(opt => { opt.BuildContextGraph(builder => diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs index 6fff3a22c8..840422eb6c 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiControllerMixin.cs @@ -5,7 +5,7 @@ namespace JsonApiDotNetCore.Controllers { - public abstract class JsonApiControllerMixin : Controller + public abstract class JsonApiControllerMixin : ControllerBase { protected IActionResult UnprocessableEntity() { diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs index c3b667bc7d..f6db9f0d06 100644 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs @@ -8,7 +8,7 @@ namespace JsonApiDotNetCore.Controllers /// /// A controller to be used for bulk operations as defined in the json:api 1.1 specification /// - public class JsonApiOperationsController : Controller + public class JsonApiOperationsController : ControllerBase { private readonly IOperationsProcessor _operationsProcessor; diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 217b5f077b..5e8eeefdd1 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -23,20 +23,20 @@ public static class IServiceCollectionExtensions public static IServiceCollection AddJsonApi(this IServiceCollection services) where TContext : DbContext { - var mvcBuilder = services.AddMvc(); - return AddJsonApi(services, (opt) => { }, mvcBuilder); + var mvcBuilder = services.AddMvcCore(); + return AddJsonApi(services, opt => { }, mvcBuilder); } public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options) where TContext : DbContext { - var mvcBuilder = services.AddMvc(); + var mvcBuilder = services.AddMvcCore(); return AddJsonApi(services, options, mvcBuilder); } public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options, - IMvcBuilder mvcBuilder) where TContext : DbContext + IMvcCoreBuilder mvcBuilder) where TContext : DbContext { var config = new JsonApiOptions(); @@ -57,7 +57,7 @@ public static IServiceCollection AddJsonApi(this IServiceCollection se public static IServiceCollection AddJsonApi(this IServiceCollection services, Action options, - IMvcBuilder mvcBuilder) + IMvcCoreBuilder mvcBuilder) { var config = new JsonApiOptions(); diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 4f52a23002..960f0f84ea 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -19,11 +19,12 @@ - + + - 15.3.0-preview-20170427-09 - 1.1.2 - 2.3.0-beta3-build3705 - 15.0.3 - 4.7.99 + 15.7.2 + 2.3.1 + 22.1.2 + 4.8.3 diff --git a/benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj index 1e8b227f3c..21de8e1aa2 100644 --- a/benchmarks/Benchmarks.csproj +++ b/benchmarks/Benchmarks.csproj @@ -5,7 +5,7 @@ Benchmarks - + diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs index c86425b00c..c9788bf82f 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.Designer.cs @@ -1,4 +1,4 @@ -// +// using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage.Internal; using System; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace JsonApiDotNetCoreExample.Migrations { diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs index ba19b62ef6..cc696f54bf 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/20180327120810_initial.cs @@ -1,7 +1,8 @@ -using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using System; using System.Collections.Generic; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace JsonApiDotNetCoreExample.Migrations { diff --git a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs index c0794103fe..08c284393e 100755 --- a/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs @@ -1,4 +1,4 @@ -// +// using JsonApiDotNetCoreExample.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage.Internal; using System; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace JsonApiDotNetCoreExample.Migrations { diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj index eed5f1b09e..efdaa68e5b 100755 --- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj +++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj index 48df3ea2c8..24c01b9a8d 100644 --- a/src/Examples/ReportsExample/ReportsExample.csproj +++ b/src/Examples/ReportsExample/ReportsExample.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 960f0f84ea..b8af04e278 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -17,14 +17,14 @@ - + - - + +