From dc8fb6ffe5b6f104bd0893c6f02944c6c74e82bd Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Mon, 28 Sep 2020 14:37:58 +0200 Subject: [PATCH 1/7] Replaced calls to serviceProvider.GetService with GetRequiredService where possible. --- .../Startups/Startup.cs | 2 +- .../JsonApiApplicationBuilder.cs | 36 +++++++-------- .../ServiceCollectionExtensions.cs | 2 +- .../Middleware/JsonApiInputFormatter.cs | 2 +- .../Middleware/JsonApiOutputFormatter.cs | 2 +- .../Annotations/IsRequiredAttribute.cs | 1 - .../Building/ResourceObjectBuilder.cs | 8 ++-- .../ResponseSerializerFactory.cs | 3 +- .../ServiceDiscoveryFacadeTests.cs | 9 ++-- .../Extensibility/CustomControllerTests.cs | 4 +- .../Extensibility/IgnoreDefaultValuesTests.cs | 5 +- .../Extensibility/IgnoreNullValuesTests.cs | 5 +- .../Acceptance/InjectableResourceTests.cs | 2 +- .../Acceptance/ManyToManyTests.cs | 20 ++++---- .../Acceptance/Spec/DeletingDataTests.cs | 2 +- .../DocumentTests/LinksWithNamespaceTests.cs | 4 +- .../Acceptance/Spec/DocumentTests/Meta.cs | 5 +- .../Spec/DocumentTests/Relationships.cs | 2 +- .../Acceptance/Spec/EndToEndTest.cs | 2 +- .../Acceptance/Spec/FetchingDataTests.cs | 8 ++-- .../Spec/FetchingRelationshipsTests.cs | 16 +++---- .../Spec/FunctionalTestCollection.cs | 4 +- .../Acceptance/Spec/UpdatingDataTests.cs | 2 +- .../Spec/UpdatingRelationshipsTests.cs | 20 ++++---- .../Acceptance/TestFixture.cs | 16 +++---- .../Acceptance/TodoItemControllerTests.cs | 4 +- .../ClientGeneratedIdsApplicationFactory.cs | 4 +- .../Factories/CustomApplicationFactoryBase.cs | 4 +- .../ResourceHooksApplicationFactory.cs | 4 +- .../Extensions/TestServerExtensions.cs | 7 +-- .../IServiceCollectionExtensionsTests.cs | 46 +++++++++---------- 31 files changed, 126 insertions(+), 125 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs index b41e501b54..85116981ba 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs @@ -29,7 +29,7 @@ public override void ConfigureServices(IServiceCollection services) ConfigureClock(services); services.AddScoped(); - services.AddScoped(sp => sp.GetService()); + services.AddScoped(sp => sp.GetRequiredService()); services.AddDbContext(options => { diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs b/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs index 9f3db2ce18..a30f236526 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs @@ -43,7 +43,7 @@ public JsonApiApplicationBuilder(IServiceCollection services, IMvcCoreBuilder mv _mvcBuilder = mvcBuilder ?? throw new ArgumentNullException(nameof(mvcBuilder)); _intermediateProvider = services.BuildServiceProvider(); - var loggerFactory = _intermediateProvider.GetService(); + var loggerFactory = _intermediateProvider.GetRequiredService(); _resourceGraphBuilder = new ResourceGraphBuilder(_options, loggerFactory); _serviceDiscoveryFacade = new ServiceDiscoveryFacade(_services, _resourceGraphBuilder, _options, loggerFactory); @@ -74,7 +74,7 @@ public void AddResourceGraph(Type dbContextType, Action co if (dbContextType != null) { - AddResourcesFromDbContext((DbContext)_intermediateProvider.GetService(dbContextType), _resourceGraphBuilder); + AddResourcesFromDbContext((DbContext)_intermediateProvider.GetRequiredService(dbContextType), _resourceGraphBuilder); } configureResourceGraph?.Invoke(_resourceGraphBuilder); @@ -158,7 +158,7 @@ private void AddMiddlewareLayer() _services.TryAddSingleton(); _services.TryAddSingleton(); _services.TryAddSingleton(); - _services.AddSingleton(sp => sp.GetService()); + _services.AddSingleton(sp => sp.GetRequiredService()); _services.AddSingleton(); _services.AddScoped(); _services.AddScoped(); @@ -232,21 +232,21 @@ private void AddQueryStringLayer() _services.AddScoped(); _services.AddScoped(); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); - _services.AddScoped(sp => sp.GetService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); + _services.AddScoped(sp => sp.GetRequiredService()); _services.AddScoped(); _services.AddSingleton(); diff --git a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs index 55e1b52028..ef2e865e76 100644 --- a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs @@ -71,7 +71,7 @@ public static IServiceCollection AddClientSerialization(this IServiceCollection services.AddScoped(); services.AddScoped(sp => { - var graph = sp.GetService(); + var graph = sp.GetRequiredService(); return new RequestSerializer(graph, new ResourceObjectBuilder(graph, new ResourceObjectBuilderSettings())); }); return services; diff --git a/src/JsonApiDotNetCore/Middleware/JsonApiInputFormatter.cs b/src/JsonApiDotNetCore/Middleware/JsonApiInputFormatter.cs index 044431b8a5..ebab9cc134 100644 --- a/src/JsonApiDotNetCore/Middleware/JsonApiInputFormatter.cs +++ b/src/JsonApiDotNetCore/Middleware/JsonApiInputFormatter.cs @@ -22,7 +22,7 @@ public async Task ReadAsync(InputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); - var reader = context.HttpContext.RequestServices.GetService(); + var reader = context.HttpContext.RequestServices.GetRequiredService(); return await reader.ReadAsync(context); } } diff --git a/src/JsonApiDotNetCore/Middleware/JsonApiOutputFormatter.cs b/src/JsonApiDotNetCore/Middleware/JsonApiOutputFormatter.cs index 644e829538..9f77fc58e7 100644 --- a/src/JsonApiDotNetCore/Middleware/JsonApiOutputFormatter.cs +++ b/src/JsonApiDotNetCore/Middleware/JsonApiOutputFormatter.cs @@ -22,7 +22,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); - var writer = context.HttpContext.RequestServices.GetService(); + var writer = context.HttpContext.RequestServices.GetRequiredService(); await writer.WriteAsync(context); } } diff --git a/src/JsonApiDotNetCore/Resources/Annotations/IsRequiredAttribute.cs b/src/JsonApiDotNetCore/Resources/Annotations/IsRequiredAttribute.cs index 8a2b0dc37b..0d031aa7d2 100644 --- a/src/JsonApiDotNetCore/Resources/Annotations/IsRequiredAttribute.cs +++ b/src/JsonApiDotNetCore/Resources/Annotations/IsRequiredAttribute.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using JsonApiDotNetCore.Configuration; diff --git a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs index bb4453d64e..3267ce7595 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs @@ -30,17 +30,17 @@ public ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attr.Property.Name != nameof(Identifiable.Id)).ToArray()).Any()) - ProcessAttributes(resource, attributes, ro); + ProcessAttributes(resource, attributes, resourceObject); // populating the top-level "relationship" member of a resource object. if (relationships != null) - ProcessRelationships(resource, relationships, ro); + ProcessRelationships(resource, relationships, resourceObject); - return ro; + return resourceObject; } /// diff --git a/src/JsonApiDotNetCore/Serialization/ResponseSerializerFactory.cs b/src/JsonApiDotNetCore/Serialization/ResponseSerializerFactory.cs index 356c606833..0232eec083 100644 --- a/src/JsonApiDotNetCore/Serialization/ResponseSerializerFactory.cs +++ b/src/JsonApiDotNetCore/Serialization/ResponseSerializerFactory.cs @@ -1,6 +1,7 @@ using System; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Middleware; +using Microsoft.Extensions.DependencyInjection; namespace JsonApiDotNetCore.Serialization { @@ -28,7 +29,7 @@ public IJsonApiSerializer GetSerializer() var targetType = GetDocumentType(); var serializerType = typeof(ResponseSerializer<>).MakeGenericType(targetType); - var serializer = (IResponseSerializer)_provider.GetService(serializerType); + var serializer = (IResponseSerializer)_provider.GetRequiredService(serializerType); if (_request.Kind == EndpointKind.Relationship && _request.Relationship != null) serializer.RequestRelationship = _request.Relationship; diff --git a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs index c370354a60..5a7a67c000 100644 --- a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs +++ b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs @@ -5,7 +5,6 @@ using JsonApiDotNetCore.Queries; using JsonApiDotNetCore.Repositories; using JsonApiDotNetCore.Resources; -using JsonApiDotNetCore.Serialization.Building; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Models; using Microsoft.EntityFrameworkCore; @@ -90,7 +89,7 @@ public void DiscoverInjectables_Adds_Resource_Services_From_Current_Assembly_To_ // Assert var services = _services.BuildServiceProvider(); - var service = services.GetService>(); + var service = services.GetRequiredService>(); Assert.IsType(service); } @@ -106,7 +105,7 @@ public void DiscoverInjectables_Adds_Resource_Repositories_From_Current_Assembly // Assert var services = _services.BuildServiceProvider(); - Assert.IsType(services.GetService>()); + Assert.IsType(services.GetRequiredService>()); } [Fact] @@ -121,7 +120,7 @@ public void AddCurrentAssembly_Adds_Resource_Definitions_From_Current_Assembly_T // Assert var services = _services.BuildServiceProvider(); - Assert.IsType(services.GetService>()); + Assert.IsType(services.GetRequiredService>()); } [Fact] @@ -138,7 +137,7 @@ public void AddCurrentAssembly_Adds_Resource_Hooks_Definitions_From_Current_Asse // Assert var services = _services.BuildServiceProvider(); - Assert.IsType(services.GetService>()); + Assert.IsType(services.GetRequiredService>()); } public sealed class TestModel : Identifiable { } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs index cdd5d448e4..86c021e86d 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/CustomControllerTests.cs @@ -81,7 +81,7 @@ public async Task CustomRouteControllers_Uses_Dasherized_Collection_Route() public async Task CustomRouteControllers_Uses_Dasherized_Item_Route() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var todoItem = _todoItemFaker.Generate(); var person = _personFaker.Generate(); todoItem.Owner = person; @@ -108,7 +108,7 @@ public async Task CustomRouteControllers_Uses_Dasherized_Item_Route() public async Task CustomRouteControllers_Creates_Proper_Relationship_Links() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var todoItem = _todoItemFaker.Generate(); var person = _personFaker.Generate(); todoItem.Owner = person; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreDefaultValuesTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreDefaultValuesTests.cs index bc4400b7c1..144bc9218c 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreDefaultValuesTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreDefaultValuesTests.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Xunit; @@ -23,7 +24,7 @@ public sealed class IgnoreDefaultValuesTests : IAsyncLifetime public IgnoreDefaultValuesTests(TestFixture fixture) { - _dbContext = fixture.GetService(); + _dbContext = fixture.GetRequiredService(); _todoItem = new TodoItem { CreatedDate = default, @@ -95,7 +96,7 @@ public async Task CheckBehaviorCombination(DefaultValueHandling? defaultValue, b var services = server.Host.Services; var client = server.CreateClient(); - var options = (JsonApiOptions)services.GetService(typeof(IJsonApiOptions)); + var options = (JsonApiOptions)services.GetRequiredService(typeof(IJsonApiOptions)); if (defaultValue != null) { diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreNullValuesTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreNullValuesTests.cs index f6a03bf098..e4ac1e61cc 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreNullValuesTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/IgnoreNullValuesTests.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Xunit; @@ -23,7 +24,7 @@ public sealed class IgnoreNullValuesTests : IAsyncLifetime public IgnoreNullValuesTests(TestFixture fixture) { - _dbContext = fixture.GetService(); + _dbContext = fixture.GetRequiredService(); _todoItem = new TodoItem { Description = null, @@ -98,7 +99,7 @@ public async Task CheckBehaviorCombination(NullValueHandling? defaultValue, bool var services = server.Host.Services; var client = server.CreateClient(); - var options = (JsonApiOptions)services.GetService(typeof(IJsonApiOptions)); + var options = (JsonApiOptions)services.GetRequiredService(typeof(IJsonApiOptions)); if (defaultValue != null) { diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/InjectableResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/InjectableResourceTests.cs index 1af223de4a..4d6dc63aaa 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/InjectableResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/InjectableResourceTests.cs @@ -27,7 +27,7 @@ public class InjectableResourceTests public InjectableResourceTests(TestFixture fixture) { _fixture = fixture; - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); _todoItemFaker = new Faker() .RuleFor(t => t.Description, f => f.Lorem.Sentence()) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/ManyToManyTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/ManyToManyTests.cs index 76d18461b7..eda2dcdd4d 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/ManyToManyTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/ManyToManyTests.cs @@ -31,7 +31,7 @@ public sealed class ManyToManyTests public ManyToManyTests(TestFixture fixture) { _fixture = fixture; - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); _authorFaker = new Faker() .RuleFor(a => a.LastName, f => f.Random.Words(2)); @@ -49,7 +49,7 @@ public ManyToManyTests(TestFixture fixture) public async Task Can_Fetch_Many_To_Many_Through_Id() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var article = _articleFaker.Generate(); var tag = _tagFaker.Generate(); var articleTag = new ArticleTag @@ -88,7 +88,7 @@ public async Task Can_Fetch_Many_To_Many_Through_Id() public async Task Can_Fetch_Many_To_Many_Through_GetById_Relationship_Link() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var article = _articleFaker.Generate(); var tag = _tagFaker.Generate(); var articleTag = new ArticleTag @@ -126,7 +126,7 @@ public async Task Can_Fetch_Many_To_Many_Through_GetById_Relationship_Link() public async Task Can_Fetch_Many_To_Many_Through_Relationship_Link() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var article = _articleFaker.Generate(); var tag = _tagFaker.Generate(); var articleTag = new ArticleTag @@ -164,7 +164,7 @@ public async Task Can_Fetch_Many_To_Many_Through_Relationship_Link() public async Task Can_Fetch_Many_To_Many_Without_Include() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var article = _articleFaker.Generate(); var tag = _tagFaker.Generate(); var articleTag = new ArticleTag @@ -197,7 +197,7 @@ public async Task Can_Fetch_Many_To_Many_Without_Include() public async Task Can_Create_Many_To_Many() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var tag = _tagFaker.Generate(); var author = _authorFaker.Generate(); context.Tags.Add(tag); @@ -267,7 +267,7 @@ public async Task Can_Create_Many_To_Many() public async Task Can_Update_Many_To_Many() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var tag = _tagFaker.Generate(); var article = _articleFaker.Generate(); context.Tags.Add(tag); @@ -327,7 +327,7 @@ public async Task Can_Update_Many_To_Many() public async Task Can_Update_Many_To_Many_With_Complete_Replacement() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var firstTag = _tagFaker.Generate(); var article = _articleFaker.Generate(); var articleTag = new ArticleTag @@ -391,7 +391,7 @@ public async Task Can_Update_Many_To_Many_With_Complete_Replacement() public async Task Can_Update_Many_To_Many_With_Complete_Replacement_With_Overlap() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var firstTag = _tagFaker.Generate(); var article = _articleFaker.Generate(); var articleTag = new ArticleTag @@ -459,7 +459,7 @@ public async Task Can_Update_Many_To_Many_With_Complete_Replacement_With_Overlap public async Task Can_Update_Many_To_Many_Through_Relationship_Link() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var tag = _tagFaker.Generate(); var article = _articleFaker.Generate(); context.Tags.Add(tag); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs index 2a434f8508..3b74dd7502 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DeletingDataTests.cs @@ -20,7 +20,7 @@ public sealed class DeletingDataTests public DeletingDataTests(TestFixture fixture) { - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); } [Fact] diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/LinksWithNamespaceTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/LinksWithNamespaceTests.cs index e347d8097f..25bc0d8a80 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/LinksWithNamespaceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/LinksWithNamespaceTests.cs @@ -27,7 +27,7 @@ public async Task GET_RelativeLinks_True_With_Namespace_Returns_RelativeLinks() var route = "/api/v1/people/" + person.StringId; var request = new HttpRequestMessage(HttpMethod.Get, route); - var options = (JsonApiOptions) _factory.GetService(); + var options = (JsonApiOptions) _factory.GetRequiredService(); options.UseRelativeLinks = true; // Act @@ -52,7 +52,7 @@ public async Task GET_RelativeLinks_False_With_Namespace_Returns_AbsoluteLinks() var route = "/api/v1/people/" + person.StringId; var request = new HttpRequestMessage(HttpMethod.Get, route); - var options = (JsonApiOptions) _factory.GetService(); + var options = (JsonApiOptions) _factory.GetRequiredService(); options.UseRelativeLinks = false; // Act diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs index 422af54634..f3964a786e 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs @@ -8,7 +8,6 @@ using JsonApiDotNetCore.Serialization.Objects; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; -using JsonApiDotNetCoreExample.Definitions; using JsonApiDotNetCoreExample.Models; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; @@ -26,7 +25,7 @@ public sealed class Meta public Meta(TestFixture fixture) { _fixture = fixture; - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); } [Fact] @@ -181,7 +180,7 @@ public async Task ResourceThatImplements_IHasMeta_Contains_MetaData() var server = new TestServer(builder); var client = server.CreateClient(); var request = new HttpRequestMessage(httpMethod, route); - var expectedMeta = _fixture.GetService>().GetMeta(); + var expectedMeta = _fixture.GetRequiredService>().GetMeta(); // Act var response = await client.SendAsync(request); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs index cf183eb641..dacac855a8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Relationships.cs @@ -24,7 +24,7 @@ public sealed class Relationships public Relationships(TestFixture fixture) { - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); _todoItemFaker = new Faker() .RuleFor(t => t.Description, f => f.Lorem.Sentence()) .RuleFor(t => t.Ordinal, f => f.Random.Number()) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/EndToEndTest.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/EndToEndTest.cs index bdaf4ee109..701235ba41 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/EndToEndTest.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/EndToEndTest.cs @@ -51,7 +51,7 @@ public AppDbContext PrepareTest() where TStartup : class public AppDbContext GetDbContext() { - return _fixture.GetService(); + return _fixture.GetRequiredService(); } public async Task<(string, HttpResponseMessage)> SendRequest(string method, string route, string content = null) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs index 8a1ba5b09b..d80be3aba0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingDataTests.cs @@ -41,7 +41,7 @@ public FetchingDataTests(TestFixture fixture) public async Task Request_ForEmptyCollection_Returns_EmptyDataCollection() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); await context.ClearTableAsync(); await context.SaveChangesAsync(); @@ -72,7 +72,7 @@ public async Task Request_ForEmptyCollection_Returns_EmptyDataCollection() public async Task Included_Resources_Contain_Relationship_Links() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var todoItem = _todoItemFaker.Generate(); var person = _personFaker.Generate(); todoItem.Owner = person; @@ -105,7 +105,7 @@ public async Task Included_Resources_Contain_Relationship_Links() public async Task GetResources_NoDefaultPageSize_ReturnsResources() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); await context.ClearTableAsync(); await context.SaveChangesAsync(); @@ -138,7 +138,7 @@ public async Task GetResources_NoDefaultPageSize_ReturnsResources() public async Task GetSingleResource_ResourceDoesNotExist_ReturnsNotFound() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); await context.ClearTableAsync(); await context.SaveChangesAsync(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs index 152bc31d82..37031e19b6 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs @@ -40,7 +40,7 @@ public async Task When_getting_existing_ToOne_relationship_it_should_succeed() var todoItem = _todoItemFaker.Generate(); todoItem.Owner = new Person(); - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -93,7 +93,7 @@ public async Task When_getting_existing_ToMany_relationship_it_should_succeed() } }; - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.AuthorDifferentDbContextName.Add(author); await context.SaveChangesAsync(); @@ -140,7 +140,7 @@ public async Task When_getting_related_missing_to_one_resource_it_should_succeed var todoItem = _todoItemFaker.Generate(); todoItem.Owner = null; - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -187,7 +187,7 @@ public async Task When_getting_relationship_for_missing_to_one_resource_it_shoul var todoItem = _todoItemFaker.Generate(); todoItem.Owner = null; - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -217,7 +217,7 @@ public async Task When_getting_related_missing_to_many_resource_it_should_succee var todoItem = _todoItemFaker.Generate(); todoItem.ChildrenTodos = new List(); - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -247,7 +247,7 @@ public async Task When_getting_relationship_for_missing_to_many_resource_it_shou var todoItem = _todoItemFaker.Generate(); todoItem.ChildrenTodos = new List(); - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -324,7 +324,7 @@ public async Task When_getting_unknown_related_resource_it_should_fail() // Arrange var todoItem = _todoItemFaker.Generate(); - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); @@ -354,7 +354,7 @@ public async Task When_getting_unknown_relationship_for_resource_it_should_fail( // Arrange var todoItem = _todoItemFaker.Generate(); - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); context.TodoItems.Add(todoItem); await context.SaveChangesAsync(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FunctionalTestCollection.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FunctionalTestCollection.cs index 18fdf77398..7e4a14b094 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FunctionalTestCollection.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FunctionalTestCollection.cs @@ -28,7 +28,7 @@ public FunctionalTestCollection(TFactory factory) { _factory = factory; _client = _factory.CreateClient(); - _dbContext = _factory.GetService(); + _dbContext = _factory.GetRequiredService(); _deserializer = GetDeserializer(); ClearDbContext(); } @@ -83,7 +83,7 @@ protected IResponseDeserializer GetDeserializer() protected AppDbContext GetDbContext() => GetService(); - protected T GetService() => _factory.GetService(); + protected T GetService() => _factory.GetRequiredService(); protected void AssertEqualStatusCode(HttpStatusCode expected, HttpResponseMessage response) { diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs index b575c4a890..ad62bb6b6e 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs @@ -34,7 +34,7 @@ public sealed class UpdatingDataTests : EndToEndTest public UpdatingDataTests(TestFixture fixture) : base(fixture) { - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); _todoItemFaker = new Faker() .RuleFor(t => t.Description, f => f.Lorem.Sentence()) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs index 52cda9df1b..5764b77542 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingRelationshipsTests.cs @@ -31,7 +31,7 @@ public sealed class UpdatingRelationshipsTests public UpdatingRelationshipsTests(TestFixture fixture) { _fixture = fixture; - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); _personFaker = new Faker() .RuleFor(t => t.FirstName, f => f.Name.FirstName()) .RuleFor(t => t.LastName, f => f.Name.LastName()); @@ -92,7 +92,7 @@ public async Task Can_Update_Cyclic_ToMany_Relationship_By_Patching_Resource() // Act await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItem = _context.TodoItems.AsNoTracking() .Where(ti => ti.Id == todoItem.Id) @@ -144,7 +144,7 @@ public async Task Can_Update_Cyclic_ToOne_Relationship_By_Patching_Resource() // Act await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItem = _context.TodoItems.AsNoTracking() .Where(ti => ti.Id == todoItem.Id) @@ -207,7 +207,7 @@ public async Task Can_Update_Both_Cyclic_ToOne_And_ToMany_Relationship_By_Patchi // Act await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItem = _context.TodoItems.AsNoTracking() .Where(ti => ti.Id == todoItem.Id) @@ -271,7 +271,7 @@ public async Task Can_Update_ToMany_Relationship_By_Patching_Resource() // Act var response = await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItems = _context.TodoItemCollections.AsNoTracking() .Where(tic => tic.Id == todoCollection.Id) .Include(tdc => tdc.TodoItems).SingleOrDefault().TodoItems; @@ -349,7 +349,7 @@ public async Task Can_Update_ToMany_Relationship_By_Patching_Resource_When_Targe // Act var response = await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItems = _context.TodoItemCollections.AsNoTracking() .Where(tic => tic.Id == todoCollection.Id) .Include(tdc => tdc.TodoItems).SingleOrDefault().TodoItems; @@ -415,7 +415,7 @@ public async Task Can_Update_ToMany_Relationship_By_Patching_Resource_With_Overl var response = await client.SendAsync(request); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var updatedTodoItems = _context.TodoItemCollections.AsNoTracking() .Where(tic => tic.Id == todoCollection.Id) .Include(tdc => tdc.TodoItems).SingleOrDefault().TodoItems; @@ -470,7 +470,7 @@ public async Task Can_Update_ToMany_Relationship_ThroughLink() var body = response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - _context = _fixture.GetService(); + _context = _fixture.GetRequiredService(); var personsTodoItems = _context.People.Include(p => p.TodoItems).Single(p => p.Id == person.Id).TodoItems; Assert.NotEmpty(personsTodoItems); @@ -664,7 +664,7 @@ public async Task Can_Delete_Relationship_By_Patching_Relationship() public async Task Updating_ToOne_Relationship_With_Implicit_Remove() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var passport = new Passport(context); var person1 = _personFaker.Generate(); person1.Passport = passport; @@ -712,7 +712,7 @@ public async Task Updating_ToOne_Relationship_With_Implicit_Remove() public async Task Updating_ToMany_Relationship_With_Implicit_Remove() { // Arrange - var context = _fixture.GetService(); + var context = _fixture.GetRequiredService(); var person1 = _personFaker.Generate(); person1.TodoItems = _todoItemFaker.Generate(3).ToHashSet(); var person2 = _personFaker.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs index b9e35a4ca2..5868e34fc0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs @@ -31,7 +31,7 @@ public TestFixture() ServiceProvider = _server.Host.Services; Client = _server.CreateClient(); - Context = GetService().GetContext() as AppDbContext; + Context = GetRequiredService().GetContext() as AppDbContext; } public HttpClient Client { get; set; } @@ -39,8 +39,8 @@ public TestFixture() public static IRequestSerializer GetSerializer(IServiceProvider serviceProvider, Expression> attributes = null, Expression> relationships = null) where TResource : class, IIdentifiable { - var serializer = (IRequestSerializer)serviceProvider.GetService(typeof(IRequestSerializer)); - var graph = (IResourceGraph)serviceProvider.GetService(typeof(IResourceGraph)); + var serializer = (IRequestSerializer)serviceProvider.GetRequiredService(typeof(IRequestSerializer)); + var graph = (IResourceGraph)serviceProvider.GetRequiredService(typeof(IResourceGraph)); serializer.AttributesToSerialize = attributes != null ? graph.GetAttributes(attributes) : null; serializer.RelationshipsToSerialize = relationships != null ? graph.GetRelationships(relationships) : null; return serializer; @@ -48,8 +48,8 @@ public static IRequestSerializer GetSerializer(IServiceProvider servi public IRequestSerializer GetSerializer(Expression> attributes = null, Expression> relationships = null) where TResource : class, IIdentifiable { - var serializer = GetService(); - var graph = GetService(); + var serializer = GetRequiredService(); + var graph = GetRequiredService(); serializer.AttributesToSerialize = attributes != null ? graph.GetAttributes(attributes) : null; serializer.RelationshipsToSerialize = relationships != null ? graph.GetRelationships(relationships) : null; return serializer; @@ -57,7 +57,7 @@ public IRequestSerializer GetSerializer(Expression(); + var options = GetRequiredService(); var resourceGraph = new ResourceGraphBuilder(options, NullLoggerFactory.Instance) .Add() @@ -74,12 +74,12 @@ public IResponseDeserializer GetDeserializer() return new ResponseDeserializer(resourceGraph, new ResourceFactory(ServiceProvider)); } - public T GetService() => (T)ServiceProvider.GetService(typeof(T)); + public T GetRequiredService() => (T)ServiceProvider.GetRequiredService(typeof(T)); public void ReloadDbContext() { ISystemClock systemClock = ServiceProvider.GetRequiredService(); - DbContextOptions options = GetService>(); + DbContextOptions options = GetRequiredService>(); Context = new AppDbContext(options, systemClock); } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemControllerTests.cs index b4b03d5a65..9a75fcbb82 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemControllerTests.cs @@ -31,7 +31,7 @@ public sealed class TodoItemControllerTests public TodoItemControllerTests(TestFixture fixture) { _fixture = fixture; - _context = fixture.GetService(); + _context = fixture.GetRequiredService(); _todoItemFaker = new Faker() .RuleFor(t => t.Description, f => f.Lorem.Sentence()) .RuleFor(t => t.Ordinal, f => f.Random.Number()) @@ -49,7 +49,7 @@ public async Task Can_Get_TodoItems_Paginate_Check() // Arrange await _context.ClearTableAsync(); await _context.SaveChangesAsync(); - var expectedResourcesPerPage = _fixture.GetService().DefaultPageSize.Value; + var expectedResourcesPerPage = _fixture.GetRequiredService().DefaultPageSize.Value; var person = new Person(); var todoItems = _todoItemFaker.Generate(expectedResourcesPerPage + 1); diff --git a/test/JsonApiDotNetCoreExampleTests/Factories/ClientGeneratedIdsApplicationFactory.cs b/test/JsonApiDotNetCoreExampleTests/Factories/ClientGeneratedIdsApplicationFactory.cs index 9496c0394b..570e479b16 100644 --- a/test/JsonApiDotNetCoreExampleTests/Factories/ClientGeneratedIdsApplicationFactory.cs +++ b/test/JsonApiDotNetCoreExampleTests/Factories/ClientGeneratedIdsApplicationFactory.cs @@ -1,4 +1,3 @@ -using System.Reflection; using JsonApiDotNetCore.Configuration; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; @@ -24,8 +23,9 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) options.DefaultPageSize = new PageSize(5); options.IncludeTotalResourceCount = true; options.AllowClientGeneratedIds = true; + options.IncludeExceptionStackTraceInErrors = true; }, - discovery => discovery.AddAssembly(Assembly.Load(nameof(JsonApiDotNetCoreExample)))); + discovery => discovery.AddAssembly(typeof(JsonApiDotNetCoreExample.Program).Assembly)); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/Factories/CustomApplicationFactoryBase.cs b/test/JsonApiDotNetCoreExampleTests/Factories/CustomApplicationFactoryBase.cs index d9d1fb8fb5..04e237acb8 100644 --- a/test/JsonApiDotNetCoreExampleTests/Factories/CustomApplicationFactoryBase.cs +++ b/test/JsonApiDotNetCoreExampleTests/Factories/CustomApplicationFactoryBase.cs @@ -20,7 +20,7 @@ public CustomApplicationFactoryBase() _scope = Services.CreateScope(); } - public T GetService() => (T)_scope.ServiceProvider.GetService(typeof(T)); + public T GetRequiredService() => (T)_scope.ServiceProvider.GetRequiredService(typeof(T)); protected override void ConfigureWebHost(IWebHostBuilder builder) { @@ -32,7 +32,7 @@ public interface IApplicationFactory { IServiceProvider ServiceProvider { get; } - T GetService(); + T GetRequiredService(); HttpClient CreateClient(); } } diff --git a/test/JsonApiDotNetCoreExampleTests/Factories/ResourceHooksApplicationFactory.cs b/test/JsonApiDotNetCoreExampleTests/Factories/ResourceHooksApplicationFactory.cs index b38c58be59..72f879054b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Factories/ResourceHooksApplicationFactory.cs +++ b/test/JsonApiDotNetCoreExampleTests/Factories/ResourceHooksApplicationFactory.cs @@ -1,4 +1,3 @@ -using System.Reflection; using JsonApiDotNetCore.Configuration; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; @@ -25,8 +24,9 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) options.IncludeTotalResourceCount = true; options.EnableResourceHooks = true; options.LoadDatabaseValues = true; + options.IncludeExceptionStackTraceInErrors = true; }, - discovery => discovery.AddAssembly(Assembly.Load(nameof(JsonApiDotNetCoreExample)))); + discovery => discovery.AddAssembly(typeof(JsonApiDotNetCoreExample.Program).Assembly)); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/TestServerExtensions.cs b/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/TestServerExtensions.cs index a7363e7b32..a15ad59bb4 100644 --- a/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/TestServerExtensions.cs +++ b/test/JsonApiDotNetCoreExampleTests/Helpers/Extensions/TestServerExtensions.cs @@ -1,12 +1,13 @@ using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; namespace JsonApiDotNetCoreExampleTests.Helpers.Extensions { public static class TestServerExtensions { - public static T GetService(this TestServer server) + public static T GetRequiredService(this TestServer server) { - return (T)server.Host.Services.GetService(typeof(T)); + return (T)server.Host.Services.GetRequiredService(typeof(T)); } } -} \ No newline at end of file +} diff --git a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs index ccddd24f1f..1e9b24197c 100644 --- a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs @@ -38,7 +38,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() var provider = services.BuildServiceProvider(); // Assert - var request = provider.GetService() as JsonApiRequest; + var request = provider.GetRequiredService() as JsonApiRequest; Assert.NotNull(request); var resourceGraph = provider.GetService(); Assert.NotNull(resourceGraph); @@ -72,7 +72,7 @@ public void RegisterResource_DeviatingDbContextPropertyName_RegistersCorrectly() // to get the request scoped DbContext instance services.AddScoped(); var provider = services.BuildServiceProvider(); - var graph = provider.GetService(); + var graph = provider.GetRequiredService(); var resourceContext = graph.GetResourceContext(); // Assert @@ -90,16 +90,16 @@ public void AddResourceService_Registers_All_Shorthand_Service_Interfaces() // Assert var provider = services.BuildServiceProvider(); - Assert.IsType(provider.GetService(typeof(IResourceService))); - Assert.IsType(provider.GetService(typeof(IResourceCommandService))); - Assert.IsType(provider.GetService(typeof(IResourceQueryService))); - Assert.IsType(provider.GetService(typeof(IGetAllService))); - Assert.IsType(provider.GetService(typeof(IGetByIdService))); - Assert.IsType(provider.GetService(typeof(IGetSecondaryService))); - Assert.IsType(provider.GetService(typeof(IGetRelationshipService))); - Assert.IsType(provider.GetService(typeof(ICreateService))); - Assert.IsType(provider.GetService(typeof(IUpdateService))); - Assert.IsType(provider.GetService(typeof(IDeleteService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceCommandService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceQueryService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetAllService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetByIdService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetSecondaryService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetRelationshipService))); + Assert.IsType(provider.GetRequiredService(typeof(ICreateService))); + Assert.IsType(provider.GetRequiredService(typeof(IUpdateService))); + Assert.IsType(provider.GetRequiredService(typeof(IDeleteService))); } [Fact] @@ -113,16 +113,16 @@ public void AddResourceService_Registers_All_LongForm_Service_Interfaces() // Assert var provider = services.BuildServiceProvider(); - Assert.IsType(provider.GetService(typeof(IResourceService))); - Assert.IsType(provider.GetService(typeof(IResourceCommandService))); - Assert.IsType(provider.GetService(typeof(IResourceQueryService))); - Assert.IsType(provider.GetService(typeof(IGetAllService))); - Assert.IsType(provider.GetService(typeof(IGetByIdService))); - Assert.IsType(provider.GetService(typeof(IGetSecondaryService))); - Assert.IsType(provider.GetService(typeof(IGetRelationshipService))); - Assert.IsType(provider.GetService(typeof(ICreateService))); - Assert.IsType(provider.GetService(typeof(IUpdateService))); - Assert.IsType(provider.GetService(typeof(IDeleteService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceCommandService))); + Assert.IsType(provider.GetRequiredService(typeof(IResourceQueryService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetAllService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetByIdService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetSecondaryService))); + Assert.IsType(provider.GetRequiredService(typeof(IGetRelationshipService))); + Assert.IsType(provider.GetRequiredService(typeof(ICreateService))); + Assert.IsType(provider.GetRequiredService(typeof(IUpdateService))); + Assert.IsType(provider.GetRequiredService(typeof(IDeleteService))); } [Fact] @@ -150,7 +150,7 @@ public void AddJsonApi_With_Context_Uses_Resource_Type_Name_If_NoOtherSpecified( // Assert var provider = services.BuildServiceProvider(); - var resourceGraph = provider.GetService(); + var resourceGraph = provider.GetRequiredService(); var resource = resourceGraph.GetResourceContext(typeof(IntResource)); Assert.Equal("intResources", resource.PublicName); } From a811cd3b5105df802d60dc1262a1a3e9b72dde15 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Mon, 28 Sep 2020 14:45:52 +0200 Subject: [PATCH 2/7] Fixed invalid test name --- .../{RequestMetaTests.cs => ResponseMetaTests.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/{RequestMetaTests.cs => ResponseMetaTests.cs} (89%) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs similarity index 89% rename from test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs rename to test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs index 326240b6cc..09046c3dc3 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/RequestMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs @@ -11,11 +11,11 @@ namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility { - public sealed class RequestMetaTests : IClassFixture> + public sealed class ResponseMetaTests : IClassFixture> { private readonly IntegrationTestContext _testContext; - public RequestMetaTests(IntegrationTestContext testContext) + public ResponseMetaTests(IntegrationTestContext testContext) { _testContext = testContext; From d93a1f82a9f591f2fa8b31693cfb24d83dacda12 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Mon, 28 Sep 2020 14:58:35 +0200 Subject: [PATCH 3/7] Improved top-level meta test --- .../Extensibility/ResponseMetaTests.cs | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs index 09046c3dc3..5fd5b8b338 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs @@ -2,11 +2,14 @@ using System.Net; using System.Threading.Tasks; using FluentAssertions; +using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Objects; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; +using JsonApiDotNetCoreExample.Models; +using JsonApiDotNetCoreExampleTests.Helpers.Extensions; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; using Xunit; namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility @@ -23,23 +26,46 @@ public ResponseMetaTests(IntegrationTestContext testConte { services.AddScoped(); }); + + var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); + options.IncludeTotalResourceCount = false; } [Fact] public async Task Injecting_IResponseMeta_Adds_Meta_Data() { // Arrange + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + }); + var route = "/api/v1/people"; // Act - var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); + var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); - responseDocument.Meta.Should().NotBeNull(); - responseDocument.Meta.ContainsKey("request-meta").Should().BeTrue(); - responseDocument.Meta["request-meta"].Should().Be("request-meta-value"); + var expected = @"{ + ""meta"": { + ""license"": ""MIT"", + ""projectUrl"": ""https://github.com/json-api-dotnet/JsonApiDotNetCore/"", + ""versions"": [ + ""v4.0.0"", + ""v3.1.0"", + ""v2.5.2"", + ""v1.3.1"" + ] + }, + ""links"": { + ""self"": ""http://localhost/api/v1/people"" + }, + ""data"": [] +}"; + + responseDocument.ToString().NormalizeLineEndings().Should().Be(expected.NormalizeLineEndings()); } } @@ -49,7 +75,15 @@ public IReadOnlyDictionary GetMeta() { return new Dictionary { - {"request-meta", "request-meta-value"} + ["license"] = "MIT", + ["projectUrl"] = "https://github.com/json-api-dotnet/JsonApiDotNetCore/", + ["versions"] = new[] + { + "v4.0.0", + "v3.1.0", + "v2.5.2", + "v1.3.1" + } }; } } From 0ca476a922dc3770707dd25853db3cb786a30099 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Mon, 28 Sep 2020 17:34:12 +0200 Subject: [PATCH 4/7] Added resource-specific meta; converted tests --- .../JsonApiSerializerBenchmarks.cs | 13 +- docs/usage/meta.md | 56 ++--- .../Definitions/PersonDefinition.cs | 30 --- .../Definitions/TodoItemDefinition.cs | 27 +++ .../JsonApiApplicationBuilder.cs | 3 +- .../ServiceCollectionExtensions.cs | 5 +- .../Resources/IResourceDefinition.cs | 4 +- .../Resources/IResourceDefinitionAccessor.cs | 4 +- .../Resources/JsonApiResourceDefinition.cs | 2 +- .../Resources/ResourceDefinitionAccessor.cs | 4 +- .../Serialization/BaseSerializer.cs | 10 +- .../Serialization/Building/IMetaBuilder.cs | 20 +- .../Building/IResourceObjectBuilder.cs | 3 +- .../Building/IncludedResourceObjectBuilder.cs | 5 +- .../Serialization/Building/MetaBuilder.cs | 34 +-- .../Building/ResourceObjectBuilder.cs | 11 +- .../Building/ResponseResourceObjectBuilder.cs | 3 +- .../Client/Internal/RequestSerializer.cs | 8 +- .../Serialization/EmptyResponseMeta.cs | 14 ++ .../Serialization/IResponseMeta.cs | 7 +- .../Serialization/Objects/ResourceObject.cs | 3 + .../Serialization/ResponseSerializer.cs | 10 +- .../Acceptance/SerializationTests.cs | 10 - .../Acceptance/Spec/DocumentTests/Meta.cs | 209 ------------------ .../Spec/FetchingRelationshipsTests.cs | 10 - .../IntegrationTests/Meta/ResourceTests.cs | 87 ++++++++ .../Meta}/ResponseMetaTests.cs | 17 +- .../Meta/TopLevelCountTests.cs | 133 +++++++++++ .../IServiceCollectionExtensionsTests.cs | 2 +- .../Client/RequestSerializerTests.cs | 4 +- .../Common/DocumentBuilderTests.cs | 10 +- .../Common/ResourceObjectBuilderTests.cs | 27 ++- .../Serialization/SerializerTestsSetup.cs | 28 ++- .../IncludedResourceObjectBuilderTests.cs | 7 +- .../ResponseResourceObjectBuilderTests.cs | 8 +- 35 files changed, 424 insertions(+), 404 deletions(-) delete mode 100644 src/Examples/JsonApiDotNetCoreExample/Definitions/PersonDefinition.cs create mode 100644 src/Examples/JsonApiDotNetCoreExample/Definitions/TodoItemDefinition.cs create mode 100644 src/JsonApiDotNetCore/Serialization/EmptyResponseMeta.cs delete mode 100644 test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs create mode 100644 test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResourceTests.cs rename test/JsonApiDotNetCoreExampleTests/{Acceptance/Extensibility => IntegrationTests/Meta}/ResponseMetaTests.cs (82%) create mode 100644 test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/TopLevelCountTests.cs diff --git a/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs b/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs index bd11dbbbd7..5bdc150b8f 100644 --- a/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs +++ b/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs @@ -28,14 +28,15 @@ public JsonApiSerializerBenchmarks() IResourceGraph resourceGraph = DependencyFactory.CreateResourceGraph(options); IFieldsToSerialize fieldsToSerialize = CreateFieldsToSerialize(resourceGraph); - var metaBuilderMock = new Mock>(); - var linkBuilderMock = new Mock(); - var includeBuilderMock = new Mock(); + var metaBuilder = new Mock().Object; + var linkBuilder = new Mock().Object; + var includeBuilder = new Mock().Object; + var accessor = new Mock().Object; - var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, new ResourceObjectBuilderSettings()); + var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, accessor, new ResourceObjectBuilderSettings()); - _jsonApiSerializer = new ResponseSerializer(metaBuilderMock.Object, linkBuilderMock.Object, - includeBuilderMock.Object, fieldsToSerialize, resourceObjectBuilder, options); + _jsonApiSerializer = new ResponseSerializer(metaBuilder, linkBuilder, + includeBuilder, fieldsToSerialize, resourceObjectBuilder, options); } private static FieldsToSerialize CreateFieldsToSerialize(IResourceGraph resourceGraph) diff --git a/docs/usage/meta.md b/docs/usage/meta.md index 2cefca3858..17d28f80b3 100644 --- a/docs/usage/meta.md +++ b/docs/usage/meta.md @@ -1,25 +1,21 @@ # Metadata -Top-level metadata can be added to your API responses in two ways: globally and per resource type. In the event of a key collision, the resource meta will take precendence. +We support two ways to add json:api meta to your responses: global and per resource. ## Global Meta -Global metadata can be added by registering a service that implements `IResponseMeta`. +Global metadata can be added to the root of the response document by registering a service that implements `IResponseMeta`. This is useful if you need access to other registered services to build the meta object. ```c# -public class ResponseMetaService : IResponseMeta +public sealed class CopyrightResponseMeta : IResponseMeta { - public ResponseMetaService(/*...other dependencies here */) { - // ... - } - - public Dictionary GetMeta() + public IReadOnlyDictionary GetMeta() { return new Dictionary { - {"copyright", "Copyright 2018 Example Corp."}, - {"authors", new string[] {"John Doe"}} + ["copyright"] = "Copyright (C) 2002 Umbrella Corporation.", + ["authors"] = new[] {"Alice", "Red Queen"} }; } } @@ -28,14 +24,13 @@ public class ResponseMetaService : IResponseMeta ```json { "meta": { - "copyright": "Copyright 2018 Example Corp.", + "copyright": "Copyright (C) 2002 Umbrella Corporation.", "authors": [ - "John Doe" + "Alice", + "Red Queen" ] }, - "data": { - // ... - } + "data": [] } ``` @@ -50,23 +45,34 @@ public class PersonDefinition : JsonApiResourceDefinition { } - public override IReadOnlyDictionary GetMeta() + public override IReadOnlyDictionary GetMeta(Person person) { - return new Dictionary + if (person.IsEmployee) { - ["notice"] = "Check our intranet at http://www.example.com for personal details." - }; + return new Dictionary + { + ["notice"] = "Check our intranet at http://www.example.com/employees/" + person.StringId + " for personal details." + }; + } + + return null; } } ``` ```json { - "meta": { - "notice": "Check our intranet at http://www.example.com for personal details." - }, - "data": { - // ... - } + "data": [ + { + "type": "people", + "id": "1", + "attributes": { + ... + }, + "meta": { + "notice": "Check our intranet at http://www.example.com/employees/1 for personal details." + } + } + ] } ``` diff --git a/src/Examples/JsonApiDotNetCoreExample/Definitions/PersonDefinition.cs b/src/Examples/JsonApiDotNetCoreExample/Definitions/PersonDefinition.cs deleted file mode 100644 index aaa45b75a7..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Definitions/PersonDefinition.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Resources; -using JsonApiDotNetCoreExample.Models; - -namespace JsonApiDotNetCoreExample.Definitions -{ - public class PersonDefinition : JsonApiResourceDefinition - { - public PersonDefinition(IResourceGraph resourceGraph) : base(resourceGraph) - { - } - - public override IReadOnlyDictionary GetMeta() - { - return new Dictionary - { - ["license"] = "MIT", - ["projectUrl"] = "https://github.com/json-api-dotnet/JsonApiDotNetCore/", - ["versions"] = new[] - { - "v4.0.0", - "v3.1.0", - "v2.5.2", - "v1.3.1" - } - }; - } - } -} diff --git a/src/Examples/JsonApiDotNetCoreExample/Definitions/TodoItemDefinition.cs b/src/Examples/JsonApiDotNetCoreExample/Definitions/TodoItemDefinition.cs new file mode 100644 index 0000000000..5d0dc01cf5 --- /dev/null +++ b/src/Examples/JsonApiDotNetCoreExample/Definitions/TodoItemDefinition.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCoreExample.Models; + +namespace JsonApiDotNetCoreExample.Definitions +{ + public sealed class TodoItemDefinition : JsonApiResourceDefinition + { + public TodoItemDefinition(IResourceGraph resourceGraph) : base(resourceGraph) + { + } + + public override IDictionary GetMeta(TodoItem resource) + { + if (resource.Description != null && resource.Description.StartsWith("Important:")) + { + return new Dictionary + { + ["hasHighPriority"] = true + }; + } + + return base.GetMeta(resource); + } + } +} diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs b/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs index a30f236526..e24d2fbe36 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs @@ -268,7 +268,8 @@ private void AddSerializationLayer() _services.AddScoped(); _services.AddScoped(); _services.AddScoped(); - _services.AddScoped(typeof(IMetaBuilder<>), typeof(MetaBuilder<>)); + _services.AddScoped(); + _services.AddScoped(); _services.AddScoped(typeof(ResponseSerializer<>)); _services.AddScoped(sp => sp.GetRequiredService().GetSerializer()); _services.AddScoped(); diff --git a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs index ef2e865e76..de8787a8c5 100644 --- a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.ComponentModel.Design; using System.Linq; using System.Reflection; using JsonApiDotNetCore.Errors; +using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Serialization.Building; using JsonApiDotNetCore.Serialization.Client.Internal; using Microsoft.EntityFrameworkCore; @@ -72,7 +74,8 @@ public static IServiceCollection AddClientSerialization(this IServiceCollection services.AddScoped(sp => { var graph = sp.GetRequiredService(); - return new RequestSerializer(graph, new ResourceObjectBuilder(graph, new ResourceObjectBuilderSettings())); + var accessor = new ResourceDefinitionAccessor(graph, new ServiceContainer()); + return new RequestSerializer(graph, new ResourceObjectBuilder(graph, accessor, new ResourceObjectBuilderSettings())); }); return services; } diff --git a/src/JsonApiDotNetCore/Resources/IResourceDefinition.cs b/src/JsonApiDotNetCore/Resources/IResourceDefinition.cs index ab246ceb1f..b5708436f9 100644 --- a/src/JsonApiDotNetCore/Resources/IResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Resources/IResourceDefinition.cs @@ -115,8 +115,8 @@ public interface IResourceDefinition QueryStringParameterHandlers OnRegisterQueryableHandlersForQueryStringParameters(); /// - /// Enables to add json:api meta information, specific to this resource type. + /// Enables to add json:api meta information, specific to this resource. /// - IReadOnlyDictionary GetMeta(); + IDictionary GetMeta(TResource resource); } } diff --git a/src/JsonApiDotNetCore/Resources/IResourceDefinitionAccessor.cs b/src/JsonApiDotNetCore/Resources/IResourceDefinitionAccessor.cs index 7dac3e616c..2f7a5837ee 100644 --- a/src/JsonApiDotNetCore/Resources/IResourceDefinitionAccessor.cs +++ b/src/JsonApiDotNetCore/Resources/IResourceDefinitionAccessor.cs @@ -42,8 +42,8 @@ public interface IResourceDefinitionAccessor object GetQueryableHandlerForQueryStringParameter(Type resourceType, string parameterName); /// - /// Invokes for the specified resource type. + /// Invokes for the specified resource. /// - IReadOnlyDictionary GetMeta(Type resourceType); + IDictionary GetMeta(Type resourceType, IIdentifiable resourceInstance); } } diff --git a/src/JsonApiDotNetCore/Resources/JsonApiResourceDefinition.cs b/src/JsonApiDotNetCore/Resources/JsonApiResourceDefinition.cs index 37c9d6e761..282ec058ef 100644 --- a/src/JsonApiDotNetCore/Resources/JsonApiResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Resources/JsonApiResourceDefinition.cs @@ -103,7 +103,7 @@ public virtual QueryStringParameterHandlers OnRegisterQueryableHandle } /// - public virtual IReadOnlyDictionary GetMeta() + public virtual IDictionary GetMeta(TResource resource) { return null; } diff --git a/src/JsonApiDotNetCore/Resources/ResourceDefinitionAccessor.cs b/src/JsonApiDotNetCore/Resources/ResourceDefinitionAccessor.cs index 7318e82236..ed9b2ea1dd 100644 --- a/src/JsonApiDotNetCore/Resources/ResourceDefinitionAccessor.cs +++ b/src/JsonApiDotNetCore/Resources/ResourceDefinitionAccessor.cs @@ -76,12 +76,12 @@ public object GetQueryableHandlerForQueryStringParameter(Type resourceType, stri } /// - public IReadOnlyDictionary GetMeta(Type resourceType) + public IDictionary GetMeta(Type resourceType, IIdentifiable resourceInstance) { if (resourceType == null) throw new ArgumentNullException(nameof(resourceType)); dynamic resourceDefinition = GetResourceDefinition(resourceType); - return resourceDefinition.GetMeta(); + return resourceDefinition.GetMeta((dynamic) resourceInstance); } protected object GetResourceDefinition(Type resourceType) diff --git a/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs b/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs index da61a4b188..17c613dfe7 100644 --- a/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs @@ -27,15 +27,16 @@ protected BaseSerializer(IResourceObjectBuilder resourceObjectBuilder) /// Adds the attributes and relationships that are enlisted in and . /// /// Resource to build a for. + /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - protected Document Build(IIdentifiable resource, IReadOnlyCollection attributes, IReadOnlyCollection relationships) + protected Document Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships) { if (resource == null) return new Document(); - return new Document { Data = ResourceObjectBuilder.Build(resource, attributes, relationships) }; + return new Document { Data = ResourceObjectBuilder.Build(resource, includeResourceMeta, attributes, relationships) }; } /// @@ -43,16 +44,17 @@ protected Document Build(IIdentifiable resource, IReadOnlyCollection and . /// /// Resource to build a for. + /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - protected Document Build(IReadOnlyCollection resources, IReadOnlyCollection attributes, IReadOnlyCollection relationships) + protected Document Build(IReadOnlyCollection resources, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships) { if (resources == null) throw new ArgumentNullException(nameof(resources)); var data = new List(); foreach (IIdentifiable resource in resources) - data.Add(ResourceObjectBuilder.Build(resource, attributes, relationships)); + data.Add(ResourceObjectBuilder.Build(resource, includeResourceMeta, attributes, relationships)); return new Document { Data = data }; } diff --git a/src/JsonApiDotNetCore/Serialization/Building/IMetaBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/IMetaBuilder.cs index c939d9d139..c56607db75 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/IMetaBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/IMetaBuilder.cs @@ -1,27 +1,21 @@ using System.Collections.Generic; -using JsonApiDotNetCore.Resources; namespace JsonApiDotNetCore.Serialization.Building { /// - /// Builds the top-level meta object. This builder is generic to allow for - /// different top-level meta objects depending on the associated resource of the request. + /// Builds the top-level meta object. /// - /// Associated resource for which to build the meta element. - public interface IMetaBuilder where TResource : class, IIdentifiable + public interface IMetaBuilder { /// - /// Adds a key-value pair to the top-level meta object. + /// Merges the specified dictionary with existing key/value pairs. In the event of a key collision, + /// the value from the specified dictionary will overwrite the existing one. /// - void Add(string key, object value); - /// - /// Joins the new dictionary with the current one. In the event of a key collision, - /// the new value will overwrite the old one. - /// - void Add(IReadOnlyDictionary values); + void Add(IReadOnlyDictionary values); + /// /// Builds the top-level meta data object. /// - IDictionary GetMeta(); + IDictionary Build(); } } diff --git a/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs index 4dea18abdb..a20fa4df73 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs @@ -16,9 +16,10 @@ public interface IResourceObjectBuilder /// Adds the attributes and relationships that are enlisted in and . /// /// Resource to build a for. + /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes, IReadOnlyCollection relationships); + ResourceObject Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships); } } diff --git a/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs index 8ff303c40c..45047cb4e2 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs @@ -18,8 +18,9 @@ public class IncludedResourceObjectBuilder : ResourceObjectBuilder, IIncludedRes public IncludedResourceObjectBuilder(IFieldsToSerialize fieldsToSerialize, ILinkBuilder linkBuilder, IResourceContextProvider resourceContextProvider, + IResourceDefinitionAccessor resourceDefinitionAccessor, IResourceObjectBuilderSettingsProvider settingsProvider) - : base(resourceContextProvider, settingsProvider.Get()) + : base(resourceContextProvider, resourceDefinitionAccessor, settingsProvider.Get()) { _included = new HashSet(ResourceIdentifierObjectComparer.Instance); _fieldsToSerialize = fieldsToSerialize ?? throw new ArgumentNullException(nameof(fieldsToSerialize)); @@ -126,7 +127,7 @@ private ResourceObject GetOrBuildResourceObject(IIdentifiable parent, Relationsh var entry = _included.SingleOrDefault(ro => ro.Type == resourceName && ro.Id == parent.StringId); if (entry == null) { - entry = Build(parent, _fieldsToSerialize.GetAttributes(type, relationship), _fieldsToSerialize.GetRelationships(type)); + entry = Build(parent, true, _fieldsToSerialize.GetAttributes(type, relationship), _fieldsToSerialize.GetRelationships(type)); _included.Add(entry); } return entry; diff --git a/src/JsonApiDotNetCore/Serialization/Building/MetaBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/MetaBuilder.cs index b9837ac7ba..dc455fe50c 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/MetaBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/MetaBuilder.cs @@ -3,48 +3,37 @@ using System.Linq; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Queries; -using JsonApiDotNetCore.Resources; namespace JsonApiDotNetCore.Serialization.Building { /// - public class MetaBuilder : IMetaBuilder where TResource : class, IIdentifiable + public class MetaBuilder : IMetaBuilder { private readonly IPaginationContext _paginationContext; private readonly IJsonApiOptions _options; - private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor; private readonly IResponseMeta _responseMeta; private Dictionary _meta = new Dictionary(); - public MetaBuilder(IPaginationContext paginationContext, IJsonApiOptions options, IResourceDefinitionAccessor resourceDefinitionAccessor, IResponseMeta responseMeta = null) + public MetaBuilder(IPaginationContext paginationContext, IJsonApiOptions options, IResponseMeta responseMeta) { _paginationContext = paginationContext ?? throw new ArgumentNullException(nameof(paginationContext)); _options = options ?? throw new ArgumentNullException(nameof(options)); - _resourceDefinitionAccessor = resourceDefinitionAccessor ?? throw new ArgumentNullException(nameof(resourceDefinitionAccessor)); - _responseMeta = responseMeta; + _responseMeta = responseMeta ?? throw new ArgumentNullException(nameof(responseMeta)); } /// - public void Add(string key, object value) - { - if (key == null) throw new ArgumentNullException(nameof(key)); - - _meta[key] = value ?? throw new ArgumentNullException(nameof(value)); - } - - /// - public void Add(IReadOnlyDictionary values) + public void Add(IReadOnlyDictionary values) { if (values == null) throw new ArgumentNullException(nameof(values)); _meta = values.Keys.Union(_meta.Keys) - .ToDictionary(key => key, + .ToDictionary(key => key, key => values.ContainsKey(key) ? values[key] : _meta[key]); } /// - public IDictionary GetMeta() + public IDictionary Build() { if (_paginationContext.TotalResourceCount != null) { @@ -54,15 +43,10 @@ public IDictionary GetMeta() _meta.Add(key, _paginationContext.TotalResourceCount); } - if (_responseMeta != null) - { - Add(_responseMeta.GetMeta()); - } - - var resourceMeta = _resourceDefinitionAccessor.GetMeta(typeof(TResource)); - if (resourceMeta != null) + var extraMeta = _responseMeta.GetMeta(); + if (extraMeta != null) { - Add(resourceMeta); + Add(extraMeta); } return _meta.Any() ? _meta : null; diff --git a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs index 3267ce7595..6602d0529c 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs @@ -14,16 +14,18 @@ namespace JsonApiDotNetCore.Serialization.Building public class ResourceObjectBuilder : IResourceObjectBuilder { protected IResourceContextProvider ResourceContextProvider { get; } + private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor; private readonly ResourceObjectBuilderSettings _settings; - public ResourceObjectBuilder(IResourceContextProvider resourceContextProvider, ResourceObjectBuilderSettings settings) + public ResourceObjectBuilder(IResourceContextProvider resourceContextProvider, IResourceDefinitionAccessor resourceDefinitionAccessor, ResourceObjectBuilderSettings settings) { ResourceContextProvider = resourceContextProvider ?? throw new ArgumentNullException(nameof(resourceContextProvider)); + _resourceDefinitionAccessor = resourceDefinitionAccessor ?? throw new ArgumentNullException(nameof(resourceDefinitionAccessor)); _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } /// - public ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public ResourceObject Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { if (resource == null) throw new ArgumentNullException(nameof(resource)); @@ -40,6 +42,11 @@ public ResourceObject Build(IIdentifiable resource, IReadOnlyCollection constraintProviders, IResourceContextProvider resourceContextProvider, + IResourceDefinitionAccessor resourceDefinitionAccessor, IResourceObjectBuilderSettingsProvider settingsProvider) - : base(resourceContextProvider, settingsProvider.Get()) + : base(resourceContextProvider, resourceDefinitionAccessor, settingsProvider.Get()) { _linkBuilder = linkBuilder ?? throw new ArgumentNullException(nameof(linkBuilder)); _includedBuilder = includedBuilder ?? throw new ArgumentNullException(nameof(includedBuilder)); diff --git a/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs b/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs index 2e0cf5f461..05ed84f60d 100644 --- a/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs @@ -31,12 +31,12 @@ public string Serialize(IIdentifiable resource) { if (resource == null) { - var empty = Build((IIdentifiable) null, Array.Empty(), Array.Empty()); + var empty = Build((IIdentifiable) null, false, Array.Empty(), Array.Empty()); return SerializeObject(empty, _jsonSerializerSettings); } _currentTargetedResource = resource.GetType(); - var document = Build(resource, GetAttributesToSerialize(resource), GetRelationshipsToSerialize(resource)); + var document = Build(resource, false, GetAttributesToSerialize(resource), GetRelationshipsToSerialize(resource)); _currentTargetedResource = null; return SerializeObject(document, _jsonSerializerSettings); @@ -52,7 +52,7 @@ public string Serialize(IReadOnlyCollection resources) Document document; if (firstResource == null) { - document = Build(resources, Array.Empty(), Array.Empty()); + document = Build(resources, false, Array.Empty(), Array.Empty()); } else { @@ -60,7 +60,7 @@ public string Serialize(IReadOnlyCollection resources) var attributes = GetAttributesToSerialize(firstResource); var relationships = GetRelationshipsToSerialize(firstResource); - document = Build(resources, attributes, relationships); + document = Build(resources, false, attributes, relationships); _currentTargetedResource = null; } diff --git a/src/JsonApiDotNetCore/Serialization/EmptyResponseMeta.cs b/src/JsonApiDotNetCore/Serialization/EmptyResponseMeta.cs new file mode 100644 index 0000000000..592a752926 --- /dev/null +++ b/src/JsonApiDotNetCore/Serialization/EmptyResponseMeta.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace JsonApiDotNetCore.Serialization +{ + /// + public sealed class EmptyResponseMeta : IResponseMeta + { + /// + public IReadOnlyDictionary GetMeta() + { + return null; + } + } +} diff --git a/src/JsonApiDotNetCore/Serialization/IResponseMeta.cs b/src/JsonApiDotNetCore/Serialization/IResponseMeta.cs index 2c423ed74e..85db12b6e9 100644 --- a/src/JsonApiDotNetCore/Serialization/IResponseMeta.cs +++ b/src/JsonApiDotNetCore/Serialization/IResponseMeta.cs @@ -5,11 +5,14 @@ namespace JsonApiDotNetCore.Serialization { /// - /// Service to add global top-level json:api meta to a response . - /// Use to specify top-level metadata per resource type. + /// Provides a method to obtain global json:api meta, which is added at top-level to a response . + /// Use to specify nested metadata per individual resource. /// public interface IResponseMeta { + /// + /// Gets the global top-level json:api meta information to add to the response. + /// IReadOnlyDictionary GetMeta(); } } diff --git a/src/JsonApiDotNetCore/Serialization/Objects/ResourceObject.cs b/src/JsonApiDotNetCore/Serialization/Objects/ResourceObject.cs index 787bfe292e..c3ae877787 100644 --- a/src/JsonApiDotNetCore/Serialization/Objects/ResourceObject.cs +++ b/src/JsonApiDotNetCore/Serialization/Objects/ResourceObject.cs @@ -13,5 +13,8 @@ public sealed class ResourceObject : ResourceIdentifierObject [JsonProperty("links", NullValueHandling = NullValueHandling.Ignore)] public ResourceLinks Links { get; set; } + + [JsonProperty("meta", NullValueHandling = NullValueHandling.Ignore)] + public IDictionary Meta { get; set; } } } diff --git a/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs b/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs index 5639ed5a77..2b5c230004 100644 --- a/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs @@ -29,12 +29,12 @@ public class ResponseSerializer : BaseSerializer, IJsonApiSerializer, private readonly IFieldsToSerialize _fieldsToSerialize; private readonly IJsonApiOptions _options; - private readonly IMetaBuilder _metaBuilder; + private readonly IMetaBuilder _metaBuilder; private readonly Type _primaryResourceType; private readonly ILinkBuilder _linkBuilder; private readonly IIncludedResourceObjectBuilder _includedBuilder; - public ResponseSerializer(IMetaBuilder metaBuilder, + public ResponseSerializer(IMetaBuilder metaBuilder, ILinkBuilder linkBuilder, IIncludedResourceObjectBuilder includedBuilder, IFieldsToSerialize fieldsToSerialize, @@ -91,7 +91,7 @@ internal string SerializeSingle(IIdentifiable resource) } var (attributes, relationships) = GetFieldsToSerialize(); - var document = Build(resource, attributes, relationships); + var document = Build(resource, true, attributes, relationships); var resourceObject = document.SingleData; if (resourceObject != null) resourceObject.Links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id); @@ -115,7 +115,7 @@ internal string SerializeSingle(IIdentifiable resource) internal string SerializeMany(IReadOnlyCollection resources) { var (attributes, relationships) = GetFieldsToSerialize(); - var document = Build(resources, attributes, relationships); + var document = Build(resources, true, attributes, relationships); foreach (ResourceObject resourceObject in document.ManyData) { var links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id); @@ -137,7 +137,7 @@ internal string SerializeMany(IReadOnlyCollection resources) private void AddTopLevelObjects(Document document) { document.Links = _linkBuilder.GetTopLevelLinks(); - document.Meta = _metaBuilder.GetMeta(); + document.Meta = _metaBuilder.Build(); document.Included = _includedBuilder.Build(); } } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/SerializationTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/SerializationTests.cs index 7b5f67905f..214f8adbda 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/SerializationTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/SerializationTests.cs @@ -47,16 +47,6 @@ public async Task When_getting_person_it_must_match_JSON_text() var json = JsonConvert.DeserializeObject(bodyText).ToString(); var expected = @"{ - ""meta"": { - ""license"": ""MIT"", - ""projectUrl"": ""https://github.com/json-api-dotnet/JsonApiDotNetCore/"", - ""versions"": [ - ""v4.0.0"", - ""v3.1.0"", - ""v2.5.2"", - ""v1.3.1"" - ] - }, ""links"": { ""self"": ""http://localhost/api/v1/people/123"" }, diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs deleted file mode 100644 index f3964a786e..0000000000 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Meta.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System.Collections; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using JsonApiDotNetCore.Middleware; -using JsonApiDotNetCore.Resources; -using JsonApiDotNetCore.Serialization.Objects; -using JsonApiDotNetCoreExample; -using JsonApiDotNetCoreExample.Data; -using JsonApiDotNetCoreExample.Models; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Newtonsoft.Json; -using Xunit; - -namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec.DocumentTests -{ - [Collection("WebHostCollection")] - public sealed class Meta - { - private readonly TestFixture _fixture; - private readonly AppDbContext _context; - public Meta(TestFixture fixture) - { - _fixture = fixture; - _context = fixture.GetRequiredService(); - } - - [Fact] - public async Task Total_Resource_Count_Included() - { - // Arrange - await _context.ClearTableAsync(); - _context.TodoItems.Add(new TodoItem()); - await _context.SaveChangesAsync(); - var expectedCount = 1; - var builder = WebHost.CreateDefaultBuilder() - .UseStartup(); - - var httpMethod = new HttpMethod("GET"); - var route = "/api/v1/todoItems"; - - var server = new TestServer(builder); - var client = server.CreateClient(); - var request = new HttpRequestMessage(httpMethod, route); - - // Act - var response = await client.SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var documents = JsonConvert.DeserializeObject(responseBody); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(documents.Meta); - Assert.Equal(expectedCount, (long)documents.Meta["totalResources"]); - } - - [Fact] - public async Task Total_Resource_Count_Included_When_None() - { - // Arrange - await _context.ClearTableAsync(); - await _context.SaveChangesAsync(); - var builder = WebHost.CreateDefaultBuilder() - .UseStartup(); - - var httpMethod = new HttpMethod("GET"); - var route = "/api/v1/todoItems"; - - var server = new TestServer(builder); - var client = server.CreateClient(); - var request = new HttpRequestMessage(httpMethod, route); - - // Act - var response = await client.SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var documents = JsonConvert.DeserializeObject(responseBody); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(documents.Meta); - Assert.Equal(0, (long)documents.Meta["totalResources"]); - } - - [Fact] - public async Task Total_Resource_Count_Not_Included_In_POST_Response() - { - // Arrange - await _context.ClearTableAsync(); - await _context.SaveChangesAsync(); - var builder = WebHost.CreateDefaultBuilder() - .UseStartup(); - - var httpMethod = new HttpMethod("POST"); - var route = "/api/v1/todoItems"; - - var server = new TestServer(builder); - var client = server.CreateClient(); - var request = new HttpRequestMessage(httpMethod, route); - var content = new - { - data = new - { - type = "todoItems", - attributes = new - { - description = "New Description" - } - } - }; - - request.Content = new StringContent(JsonConvert.SerializeObject(content)); - request.Content.Headers.ContentType = new MediaTypeHeaderValue(HeaderConstants.MediaType); - - // Act - var response = await client.SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var documents = JsonConvert.DeserializeObject(responseBody); - - // Assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.True(documents.Meta == null || !documents.Meta.ContainsKey("totalResources")); - } - - [Fact] - public async Task Total_Resource_Count_Not_Included_In_PATCH_Response() - { - // Arrange - await _context.ClearTableAsync(); - TodoItem todoItem = new TodoItem(); - _context.TodoItems.Add(todoItem); - await _context.SaveChangesAsync(); - var builder = WebHost.CreateDefaultBuilder() - .UseStartup(); - - var httpMethod = new HttpMethod("PATCH"); - var route = $"/api/v1/todoItems/{todoItem.Id}"; - - var server = new TestServer(builder); - var client = server.CreateClient(); - var request = new HttpRequestMessage(httpMethod, route); - var content = new - { - data = new - { - type = "todoItems", - id = todoItem.Id, - attributes = new - { - description = "New Description" - } - } - }; - - request.Content = new StringContent(JsonConvert.SerializeObject(content)); - request.Content.Headers.ContentType = new MediaTypeHeaderValue(HeaderConstants.MediaType); - - // Act - var response = await client.SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var documents = JsonConvert.DeserializeObject(responseBody); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(documents.Meta == null || !documents.Meta.ContainsKey("totalResources")); - } - - [Fact] - public async Task ResourceThatImplements_IHasMeta_Contains_MetaData() - { - // Arrange - var builder = WebHost.CreateDefaultBuilder() - .UseStartup(); - - var httpMethod = new HttpMethod("GET"); - var route = "/api/v1/people"; - - var server = new TestServer(builder); - var client = server.CreateClient(); - var request = new HttpRequestMessage(httpMethod, route); - var expectedMeta = _fixture.GetRequiredService>().GetMeta(); - - // Act - var response = await client.SendAsync(request); - var documents = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(documents.Meta); - Assert.NotNull(expectedMeta); - Assert.NotEmpty(expectedMeta); - - foreach (var hash in expectedMeta) - { - if (hash.Value is IList listValue) - { - for (var i = 0; i < listValue.Count; i++) - Assert.Equal(listValue[i].ToString(), ((IList)documents.Meta[hash.Key])[i].ToString()); - } - else - { - Assert.Equal(hash.Value, documents.Meta[hash.Key]); - } - } - } - } -} diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs index 37031e19b6..3c65dec700 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs @@ -161,16 +161,6 @@ public async Task When_getting_related_missing_to_one_resource_it_should_succeed var json = JsonConvert.DeserializeObject(body).ToString(); var expected = @"{ - ""meta"": { - ""license"": ""MIT"", - ""projectUrl"": ""https://github.com/json-api-dotnet/JsonApiDotNetCore/"", - ""versions"": [ - ""v4.0.0"", - ""v3.1.0"", - ""v2.5.2"", - ""v1.3.1"" - ] - }, ""links"": { ""self"": ""http://localhost/api/v1/todoItems/" + todoItem.StringId + @"/owner"" }, diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResourceTests.cs new file mode 100644 index 0000000000..60690f1758 --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResourceTests.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using FluentAssertions; +using JsonApiDotNetCore.Serialization.Objects; +using JsonApiDotNetCoreExample; +using JsonApiDotNetCoreExample.Data; +using JsonApiDotNetCoreExample.Models; +using Xunit; + +namespace JsonApiDotNetCoreExampleTests.IntegrationTests.Meta +{ + public sealed class ResourceTests : IClassFixture> + { + private readonly IntegrationTestContext _testContext; + + public ResourceTests(IntegrationTestContext testContext) + { + _testContext = testContext; + } + + [Fact] + public async Task ResourceDefinition_That_Implements_GetMeta_Contains_Resource_Meta() + { + // Arrange + var todoItems = new[] + { + new TodoItem {Id = 1, Description = "Important: Pay the bills"}, + new TodoItem {Id = 2, Description = "Plan my birthday party"}, + new TodoItem {Id = 3, Description = "Important: Call mom"} + }; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TodoItems.AddRange(todoItems); + + await dbContext.SaveChangesAsync(); + }); + + var route = "/api/v1/todoItems"; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); + + responseDocument.ManyData.Should().HaveCount(3); + responseDocument.ManyData[0].Meta.Should().ContainKey("hasHighPriority"); + responseDocument.ManyData[1].Meta.Should().BeNull(); + responseDocument.ManyData[2].Meta.Should().ContainKey("hasHighPriority"); + } + + [Fact] + public async Task ResourceDefinition_That_Implements_GetMeta_Contains_Include_Meta() + { + // Arrange + var person = new Person + { + TodoItems = new HashSet + { + new TodoItem {Id = 1, Description = "Important: Pay the bills"}, + } + }; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.People.Add(person); + await dbContext.SaveChangesAsync(); + }); + + var route = $"/api/v1/people/{person.StringId}?include=todoItems"; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); + + responseDocument.SingleData.Should().NotBeNull(); + responseDocument.Included.Should().HaveCount(1); + responseDocument.Included[0].Meta.Should().ContainKey("hasHighPriority"); + } + } +} diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs similarity index 82% rename from test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs rename to test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs index 5fd5b8b338..bdd3323f18 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/ResponseMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs @@ -12,7 +12,7 @@ using Newtonsoft.Json.Linq; using Xunit; -namespace JsonApiDotNetCoreExampleTests.Acceptance.Extensibility +namespace JsonApiDotNetCoreExampleTests.IntegrationTests.Meta { public sealed class ResponseMetaTests : IClassFixture> { @@ -22,24 +22,21 @@ public ResponseMetaTests(IntegrationTestContext testConte { _testContext = testContext; - testContext.ConfigureServicesBeforeStartup(services => + testContext.ConfigureServicesAfterStartup(services => { - services.AddScoped(); + services.AddSingleton(); }); - var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService(); + var options = (JsonApiOptions) testContext.Factory.Services.GetRequiredService(); options.IncludeTotalResourceCount = false; } [Fact] - public async Task Injecting_IResponseMeta_Adds_Meta_Data() + public async Task Registered_IResponseMeta_Adds_TopLevel_Meta() { // Arrange - await _testContext.RunOnDatabaseAsync(async dbContext => - { - await dbContext.ClearTableAsync(); - }); - + await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync(); }); + var route = "/api/v1/people"; // Act diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/TopLevelCountTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/TopLevelCountTests.cs new file mode 100644 index 0000000000..ce5c9f0577 --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/TopLevelCountTests.cs @@ -0,0 +1,133 @@ +using System.Net; +using System.Threading.Tasks; +using FluentAssertions; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Serialization.Objects; +using JsonApiDotNetCoreExample; +using JsonApiDotNetCoreExample.Data; +using JsonApiDotNetCoreExample.Models; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace JsonApiDotNetCoreExampleTests.IntegrationTests.Meta +{ + public sealed class TopLevelCountTests : IClassFixture> + { + private readonly IntegrationTestContext _testContext; + + public TopLevelCountTests(IntegrationTestContext testContext) + { + _testContext = testContext; + + var options = (JsonApiOptions) testContext.Factory.Services.GetRequiredService(); + options.IncludeTotalResourceCount = true; + } + + [Fact] + public async Task Total_Resource_Count_Included_For_Collection() + { + // Arrange + var todoItem = new TodoItem(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TodoItems.Add(todoItem); + + await dbContext.SaveChangesAsync(); + }); + + var route = "/api/v1/todoItems"; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); + + responseDocument.Meta.Should().NotBeNull(); + responseDocument.Meta["totalResources"].Should().Be(1); + } + + [Fact] + public async Task Total_Resource_Count_Included_For_Empty_Collection() + { + // Arrange + await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync(); }); + + var route = "/api/v1/todoItems"; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync(route); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); + + responseDocument.Meta.Should().NotBeNull(); + responseDocument.Meta["totalResources"].Should().Be(0); + } + + [Fact] + public async Task Total_Resource_Count_Excluded_From_POST_Response() + { + // Arrange + var requestBody = new + { + data = new + { + type = "todoItems", + attributes = new + { + description = "Something" + } + } + }; + + var route = "/api/v1/todoItems"; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecutePostAsync(route, requestBody); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); + + responseDocument.Meta.Should().BeNull(); + } + + [Fact] + public async Task Total_Resource_Count_Excluded_From_PATCH_Response() + { + // Arrange + var todoItem = new TodoItem(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TodoItems.Add(todoItem); + await dbContext.SaveChangesAsync(); + }); + + var requestBody = new + { + data = new + { + type = "todoItems", + id = todoItem.Id, + attributes = new + { + description = "Something else" + } + } + }; + + var route = "/api/v1/todoItems/" + todoItem.StringId; + + // Act + var (httpResponse, responseDocument) = await _testContext.ExecutePatchAsync(route, requestBody); + + // Assert + httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); + + responseDocument.Meta.Should().BeNull(); + } + } +} diff --git a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs index 1e9b24197c..dc3931d429 100644 --- a/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs +++ b/test/UnitTests/Extensions/IServiceCollectionExtensionsTests.cs @@ -48,7 +48,7 @@ public void AddJsonApiInternals_Adds_All_Required_Services() Assert.NotNull(provider.GetService(typeof(IResourceRepository))); Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); - Assert.NotNull(provider.GetService>()); + Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); Assert.NotNull(provider.GetService()); diff --git a/test/UnitTests/Serialization/Client/RequestSerializerTests.cs b/test/UnitTests/Serialization/Client/RequestSerializerTests.cs index e5a2d696ce..27979a7d91 100644 --- a/test/UnitTests/Serialization/Client/RequestSerializerTests.cs +++ b/test/UnitTests/Serialization/Client/RequestSerializerTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.Design; using System.Text.RegularExpressions; using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Serialization.Building; @@ -14,7 +15,8 @@ public sealed class RequestSerializerTests : SerializerTestsSetup public RequestSerializerTests() { - var builder = new ResourceObjectBuilder(_resourceGraph, new ResourceObjectBuilderSettings()); + var accessor = new ResourceDefinitionAccessor(_resourceGraph, new ServiceContainer()); + var builder = new ResourceObjectBuilder(_resourceGraph, accessor, new ResourceObjectBuilderSettings()); _serializer = new RequestSerializer(_resourceGraph, builder); } diff --git a/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs b/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs index 1023998c15..b802970661 100644 --- a/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs +++ b/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs @@ -16,7 +16,7 @@ public sealed class BaseDocumentBuilderTests : SerializerTestsSetup public BaseDocumentBuilderTests() { var mock = new Mock(); - mock.Setup(m => m.Build(It.IsAny(), It.IsAny>(), It.IsAny>())).Returns(new ResourceObject()); + mock.Setup(m => m.Build(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>())).Returns(new ResourceObject()); _builder = new TestSerializer(mock.Object); } @@ -25,7 +25,7 @@ public BaseDocumentBuilderTests() public void ResourceToDocument_NullResource_CanBuild() { // Act - var document = _builder.Build((TestResource) null); + var document = _builder.Build((TestResource) null, false); // Assert Assert.Null(document.Data); @@ -40,7 +40,7 @@ public void ResourceToDocument_EmptyList_CanBuild() var resources = new List(); // Act - var document = _builder.Build(resources); + var document = _builder.Build(resources, false); // Assert Assert.NotNull(document.Data); @@ -55,7 +55,7 @@ public void ResourceToDocument_SingleResource_CanBuild() IIdentifiable dummy = new DummyResource(); // Act - var document = _builder.Build(dummy); + var document = _builder.Build(dummy, false); // Assert Assert.NotNull(document.Data); @@ -69,7 +69,7 @@ public void ResourceToDocument_ResourceList_CanBuild() var resources = new List { new DummyResource(), new DummyResource() }; // Act - var document = _builder.Build(resources); + var document = _builder.Build(resources, false); var data = (List)document.Data; // Assert diff --git a/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs b/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs index 58d380cee9..7c142ed1fb 100644 --- a/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs +++ b/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs @@ -1,7 +1,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel.Design; using System.Linq; +using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Serialization.Building; using JsonApiDotNetCore.Serialization.Objects; using UnitTests.TestModels; @@ -15,7 +17,8 @@ public sealed class ResourceObjectBuilderTests : SerializerTestsSetup public ResourceObjectBuilderTests() { - _builder = new ResourceObjectBuilder(_resourceGraph, new ResourceObjectBuilderSettings()); + var accessor = new ResourceDefinitionAccessor(_resourceGraph, new ServiceContainer()); + _builder = new ResourceObjectBuilder(_resourceGraph, accessor, new ResourceObjectBuilderSettings()); } [Fact] @@ -25,7 +28,7 @@ public void ResourceToResourceObject_EmptyResource_CanBuild() var resource = new TestResource(); // Act - var resourceObject = _builder.Build(resource); + var resourceObject = _builder.Build(resource, false); // Assert Assert.Null(resourceObject.Attributes); @@ -41,7 +44,7 @@ public void ResourceToResourceObject_ResourceWithId_CanBuild() var resource = new TestResource { Id = 1 }; // Act - var resourceObject = _builder.Build(resource); + var resourceObject = _builder.Build(resource, false); // Assert Assert.Equal("1", resourceObject.Id); @@ -60,7 +63,7 @@ public void ResourceToResourceObject_ResourceWithIncludedAttrs_CanBuild(string s var attrs = _resourceGraph.GetAttributes(tr => new { tr.StringField, tr.NullableIntField }); // Act - var resourceObject = _builder.Build(resource, attrs); + var resourceObject = _builder.Build(resource, false, attrs); // Assert Assert.NotNull(resourceObject.Attributes); @@ -76,7 +79,7 @@ public void ResourceWithRelationshipsToResourceObject_EmptyResource_CanBuild() var resource = new MultipleRelationshipsPrincipalPart(); // Act - var resourceObject = _builder.Build(resource); + var resourceObject = _builder.Build(resource, false); // Assert Assert.Null(resourceObject.Attributes); @@ -95,7 +98,7 @@ public void ResourceWithRelationshipsToResourceObject_ResourceWithId_CanBuild() }; // Act - var resourceObject = _builder.Build(resource); + var resourceObject = _builder.Build(resource, false); // Assert Assert.Null(resourceObject.Attributes); @@ -116,7 +119,7 @@ public void ResourceWithRelationshipsToResourceObject_WithIncludedRelationshipsA var relationships = _resourceGraph.GetRelationships(tr => new { tr.PopulatedToManies, tr.PopulatedToOne, tr.EmptyToOne, tr.EmptyToManies }); // Act - var resourceObject = _builder.Build(resource, relationships: relationships); + var resourceObject = _builder.Build(resource, false, relationships: relationships); // Assert Assert.Equal(4, resourceObject.Relationships.Count); @@ -140,7 +143,7 @@ public void ResourceWithRelationshipsToResourceObject_DeviatingForeignKeyWhileRe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, relationships: relationships); + var resourceObject = _builder.Build(resource, false, relationships: relationships); // Assert Assert.Single(resourceObject.Relationships); @@ -157,7 +160,7 @@ public void ResourceWithRelationshipsToResourceObject_DeviatingForeignKeyAndNoNa var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, relationships: relationships); + var resourceObject = _builder.Build(resource, false, relationships: relationships); // Assert Assert.Null(resourceObject.Relationships["principal"].Data); @@ -171,7 +174,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_DeviatingForeignKe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, relationships: relationships); + var resourceObject = _builder.Build(resource, false, relationships: relationships); // Assert Assert.Single(resourceObject.Relationships); @@ -188,7 +191,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_DeviatingForeignKe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act & assert - Assert.ThrowsAny(() => _builder.Build(resource, relationships: relationships)); + Assert.ThrowsAny(() => _builder.Build(resource, false, relationships: relationships)); } [Fact] @@ -199,7 +202,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_EmptyResourceWhile var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act & assert - Assert.ThrowsAny(() => _builder.Build(resource, relationships: relationships)); + Assert.ThrowsAny(() => _builder.Build(resource, false, relationships: relationships)); } } } diff --git a/test/UnitTests/Serialization/SerializerTestsSetup.cs b/test/UnitTests/Serialization/SerializerTestsSetup.cs index 840250f799..aeec4a4afe 100644 --- a/test/UnitTests/Serialization/SerializerTestsSetup.cs +++ b/test/UnitTests/Serialization/SerializerTestsSetup.cs @@ -41,12 +41,12 @@ public SerializerTestsSetup() protected ResponseSerializer GetResponseSerializer(List> inclusionChains = null, Dictionary metaDict = null, TopLevelLinks topLinks = null, ResourceLinks resourceLinks = null, RelationshipLinks relationshipLinks = null) where T : class, IIdentifiable { - var meta = GetMetaBuilder(metaDict); + var meta = GetMetaBuilder(metaDict); var link = GetLinkBuilder(topLinks, resourceLinks, relationshipLinks); var includeConstraints = GetIncludeConstraints(inclusionChains); var includedBuilder = GetIncludedBuilder(); var fieldsToSerialize = GetSerializableFields(); - ResponseResourceObjectBuilder resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, _resourceGraph, GetSerializerSettingsProvider()); + ResponseResourceObjectBuilder resourceObjectBuilder = new ResponseResourceObjectBuilder(link, includedBuilder, includeConstraints, _resourceGraph, GetResourceDefinitionAccessor(), GetSerializerSettingsProvider()); return new ResponseSerializer(meta, link, includedBuilder, fieldsToSerialize, resourceObjectBuilder, new JsonApiOptions()); } @@ -55,12 +55,12 @@ protected ResponseResourceObjectBuilder GetResponseResourceObjectBuilder(List
  • GetMetaBuilder(Dictionary meta = null) where T : class, IIdentifiable + protected IResourceDefinitionAccessor GetResourceDefinitionAccessor() { - var mock = new Mock>(); - mock.Setup(m => m.GetMeta()).Returns(meta); + var mock = new Mock(); + return mock.Object; + } + + protected IMetaBuilder GetMetaBuilder(Dictionary meta = null) + { + var mock = new Mock(); + mock.Setup(m => m.Build()).Returns(meta); return mock.Object; } @@ -120,14 +126,14 @@ protected sealed class TestSerializer : BaseSerializer { public TestSerializer(IResourceObjectBuilder resourceObjectBuilder) : base(resourceObjectBuilder) { } - public new Document Build(IIdentifiable resource, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public new Document Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { - return base.Build(resource, attributes, relationships); + return base.Build(resource, true, attributes, relationships); } - public new Document Build(IReadOnlyCollection resources, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public new Document Build(IReadOnlyCollection resources, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { - return base.Build(resources, attributes, relationships); + return base.Build(resources, true, attributes, relationships); } } } diff --git a/test/UnitTests/Serialization/Server/IncludedResourceObjectBuilderTests.cs b/test/UnitTests/Serialization/Server/IncludedResourceObjectBuilderTests.cs index 798f3b4f79..e6f43b0919 100644 --- a/test/UnitTests/Serialization/Server/IncludedResourceObjectBuilderTests.cs +++ b/test/UnitTests/Serialization/Server/IncludedResourceObjectBuilderTests.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using System.Linq; +using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; using JsonApiDotNetCore.Serialization.Building; +using Moq; using UnitTests.TestModels; using Xunit; @@ -167,8 +169,9 @@ private IncludedResourceObjectBuilder GetBuilder() { var fields = GetSerializableFields(); var links = GetLinkBuilder(); - return new IncludedResourceObjectBuilder(fields, links, _resourceGraph, GetSerializerSettingsProvider()); - } + var accessor = new Mock().Object; + return new IncludedResourceObjectBuilder(fields, links, _resourceGraph, accessor, GetSerializerSettingsProvider()); + } } } diff --git a/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs b/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs index bc50c2ec93..8c8ba13eec 100644 --- a/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs +++ b/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs @@ -24,7 +24,7 @@ public void Build_RelationshipNotIncludedAndLinksEnabled_RelationshipEntryWithLi var builder = GetResponseResourceObjectBuilder(relationshipLinks: _dummyRelationshipLinks); // Act - var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); @@ -41,7 +41,7 @@ public void Build_RelationshipNotIncludedAndLinksDisabled_NoRelationshipObject() var builder = GetResponseResourceObjectBuilder(); // Act - var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); // Assert Assert.Null(resourceObject.Relationships); @@ -55,7 +55,7 @@ public void Build_RelationshipIncludedAndLinksDisabled_RelationshipEntryWithData var builder = GetResponseResourceObjectBuilder(inclusionChains: new List> { _relationshipsForBuild } ); // Act - var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); @@ -72,7 +72,7 @@ public void Build_RelationshipIncludedAndLinksEnabled_RelationshipEntryWithDataA var builder = GetResponseResourceObjectBuilder(inclusionChains: new List> { _relationshipsForBuild }, relationshipLinks: _dummyRelationshipLinks); // Act - var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); From cfc20e0939cb0f028a15fab2e6a5b575fd735444 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Tue, 29 Sep 2020 17:28:32 +0200 Subject: [PATCH 5/7] Post-merge fixes --- .../IntegrationTests/Meta/ResponseMetaTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs index bdd3323f18..353ae641de 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/Meta/ResponseMetaTests.cs @@ -57,7 +57,8 @@ public async Task Registered_IResponseMeta_Adds_TopLevel_Meta() ] }, ""links"": { - ""self"": ""http://localhost/api/v1/people"" + ""self"": ""http://localhost/api/v1/people"", + ""first"": ""http://localhost/api/v1/people"" }, ""data"": [] }"; From f8e3908265d312dfba80780bd19a065adebfc045 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Thu, 1 Oct 2020 10:31:42 +0200 Subject: [PATCH 6/7] Review: use overridden ResourceObjectBuilder.Build method instead of passing a boolean flag --- .../JsonApiSerializerBenchmarks.cs | 3 +-- .../ServiceCollectionExtensions.cs | 3 +-- .../Serialization/BaseSerializer.cs | 10 +++----- .../Building/IResourceObjectBuilder.cs | 3 +-- .../Building/IncludedResourceObjectBuilder.cs | 17 +++++++++++-- .../Building/ResourceObjectBuilder.cs | 11 ++------ .../Building/ResponseResourceObjectBuilder.cs | 15 ++++++++++- .../Client/Internal/RequestSerializer.cs | 8 +++--- .../Serialization/ResponseSerializer.cs | 4 +-- .../Client/RequestSerializerTests.cs | 3 +-- .../Common/DocumentBuilderTests.cs | 10 ++++---- .../Common/ResourceObjectBuilderTests.cs | 25 +++++++++---------- .../Serialization/SerializerTestsSetup.cs | 8 +++--- .../ResponseResourceObjectBuilderTests.cs | 8 +++--- 14 files changed, 70 insertions(+), 58 deletions(-) diff --git a/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs b/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs index 5bdc150b8f..da0fa71ca1 100644 --- a/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs +++ b/benchmarks/Serialization/JsonApiSerializerBenchmarks.cs @@ -31,9 +31,8 @@ public JsonApiSerializerBenchmarks() var metaBuilder = new Mock().Object; var linkBuilder = new Mock().Object; var includeBuilder = new Mock().Object; - var accessor = new Mock().Object; - var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, accessor, new ResourceObjectBuilderSettings()); + var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, new ResourceObjectBuilderSettings()); _jsonApiSerializer = new ResponseSerializer(metaBuilder, linkBuilder, includeBuilder, fieldsToSerialize, resourceObjectBuilder, options); diff --git a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs index 4f14981e2e..ffa5fd340e 100644 --- a/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Configuration/ServiceCollectionExtensions.cs @@ -73,8 +73,7 @@ public static IServiceCollection AddClientSerialization(this IServiceCollection services.AddScoped(sp => { var graph = sp.GetRequiredService(); - var accessor = new ResourceDefinitionAccessor(graph, new ServiceContainer()); - return new RequestSerializer(graph, new ResourceObjectBuilder(graph, accessor, new ResourceObjectBuilderSettings())); + return new RequestSerializer(graph, new ResourceObjectBuilder(graph, new ResourceObjectBuilderSettings())); }); return services; } diff --git a/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs b/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs index 17c613dfe7..da61a4b188 100644 --- a/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/BaseSerializer.cs @@ -27,16 +27,15 @@ protected BaseSerializer(IResourceObjectBuilder resourceObjectBuilder) /// Adds the attributes and relationships that are enlisted in and . /// /// Resource to build a for. - /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - protected Document Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships) + protected Document Build(IIdentifiable resource, IReadOnlyCollection attributes, IReadOnlyCollection relationships) { if (resource == null) return new Document(); - return new Document { Data = ResourceObjectBuilder.Build(resource, includeResourceMeta, attributes, relationships) }; + return new Document { Data = ResourceObjectBuilder.Build(resource, attributes, relationships) }; } /// @@ -44,17 +43,16 @@ protected Document Build(IIdentifiable resource, bool includeResourceMeta, IRead /// Adds the attributes and relationships that are enlisted in and . /// /// Resource to build a for. - /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - protected Document Build(IReadOnlyCollection resources, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships) + protected Document Build(IReadOnlyCollection resources, IReadOnlyCollection attributes, IReadOnlyCollection relationships) { if (resources == null) throw new ArgumentNullException(nameof(resources)); var data = new List(); foreach (IIdentifiable resource in resources) - data.Add(ResourceObjectBuilder.Build(resource, includeResourceMeta, attributes, relationships)); + data.Add(ResourceObjectBuilder.Build(resource, attributes, relationships)); return new Document { Data = data }; } diff --git a/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs index a20fa4df73..4dea18abdb 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/IResourceObjectBuilder.cs @@ -16,10 +16,9 @@ public interface IResourceObjectBuilder /// Adds the attributes and relationships that are enlisted in and . /// /// Resource to build a for. - /// When true, retrieves resource-specific meta from . /// Attributes to include in the building process. /// Relationships to include in the building process. /// The resource object that was built. - ResourceObject Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes, IReadOnlyCollection relationships); + ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes, IReadOnlyCollection relationships); } } diff --git a/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs index 45047cb4e2..0b81bf3553 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/IncludedResourceObjectBuilder.cs @@ -14,17 +14,19 @@ public class IncludedResourceObjectBuilder : ResourceObjectBuilder, IIncludedRes private readonly HashSet _included; private readonly IFieldsToSerialize _fieldsToSerialize; private readonly ILinkBuilder _linkBuilder; + private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor; public IncludedResourceObjectBuilder(IFieldsToSerialize fieldsToSerialize, ILinkBuilder linkBuilder, IResourceContextProvider resourceContextProvider, IResourceDefinitionAccessor resourceDefinitionAccessor, IResourceObjectBuilderSettingsProvider settingsProvider) - : base(resourceContextProvider, resourceDefinitionAccessor, settingsProvider.Get()) + : base(resourceContextProvider, settingsProvider.Get()) { _included = new HashSet(ResourceIdentifierObjectComparer.Instance); _fieldsToSerialize = fieldsToSerialize ?? throw new ArgumentNullException(nameof(fieldsToSerialize)); _linkBuilder = linkBuilder ?? throw new ArgumentNullException(nameof(linkBuilder)); + _resourceDefinitionAccessor = resourceDefinitionAccessor ?? throw new ArgumentNullException(nameof(resourceDefinitionAccessor)); } /// @@ -48,6 +50,17 @@ public IList Build() return null; } + /// + public override ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes = null, + IReadOnlyCollection relationships = null) + { + var resourceObject = base.Build(resource, attributes, relationships); + + resourceObject.Meta = _resourceDefinitionAccessor.GetMeta(resource.GetType(), resource); + + return resourceObject; + } + /// public void IncludeRelationshipChain(IReadOnlyCollection inclusionChain, IIdentifiable rootResource) { @@ -127,7 +140,7 @@ private ResourceObject GetOrBuildResourceObject(IIdentifiable parent, Relationsh var entry = _included.SingleOrDefault(ro => ro.Type == resourceName && ro.Id == parent.StringId); if (entry == null) { - entry = Build(parent, true, _fieldsToSerialize.GetAttributes(type, relationship), _fieldsToSerialize.GetRelationships(type)); + entry = Build(parent, _fieldsToSerialize.GetAttributes(type, relationship), _fieldsToSerialize.GetRelationships(type)); _included.Add(entry); } return entry; diff --git a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs index 6602d0529c..071fc73e30 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/ResourceObjectBuilder.cs @@ -14,18 +14,16 @@ namespace JsonApiDotNetCore.Serialization.Building public class ResourceObjectBuilder : IResourceObjectBuilder { protected IResourceContextProvider ResourceContextProvider { get; } - private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor; private readonly ResourceObjectBuilderSettings _settings; - public ResourceObjectBuilder(IResourceContextProvider resourceContextProvider, IResourceDefinitionAccessor resourceDefinitionAccessor, ResourceObjectBuilderSettings settings) + public ResourceObjectBuilder(IResourceContextProvider resourceContextProvider, ResourceObjectBuilderSettings settings) { ResourceContextProvider = resourceContextProvider ?? throw new ArgumentNullException(nameof(resourceContextProvider)); - _resourceDefinitionAccessor = resourceDefinitionAccessor ?? throw new ArgumentNullException(nameof(resourceDefinitionAccessor)); _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } /// - public ResourceObject Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public virtual ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { if (resource == null) throw new ArgumentNullException(nameof(resource)); @@ -42,11 +40,6 @@ public ResourceObject Build(IIdentifiable resource, bool includeResourceMeta, IR if (relationships != null) ProcessRelationships(resource, relationships, resourceObject); - if (includeResourceMeta) - { - resourceObject.Meta = _resourceDefinitionAccessor.GetMeta(resource.GetType(), resource); - } - return resourceObject; } diff --git a/src/JsonApiDotNetCore/Serialization/Building/ResponseResourceObjectBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/ResponseResourceObjectBuilder.cs index 8c9945073b..6daae945ec 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/ResponseResourceObjectBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/ResponseResourceObjectBuilder.cs @@ -15,6 +15,7 @@ public class ResponseResourceObjectBuilder : ResourceObjectBuilder { private readonly IIncludedResourceObjectBuilder _includedBuilder; private readonly IEnumerable _constraintProviders; + private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor; private readonly ILinkBuilder _linkBuilder; private RelationshipAttribute _requestRelationship; @@ -24,11 +25,12 @@ public ResponseResourceObjectBuilder(ILinkBuilder linkBuilder, IResourceContextProvider resourceContextProvider, IResourceDefinitionAccessor resourceDefinitionAccessor, IResourceObjectBuilderSettingsProvider settingsProvider) - : base(resourceContextProvider, resourceDefinitionAccessor, settingsProvider.Get()) + : base(resourceContextProvider, settingsProvider.Get()) { _linkBuilder = linkBuilder ?? throw new ArgumentNullException(nameof(linkBuilder)); _includedBuilder = includedBuilder ?? throw new ArgumentNullException(nameof(includedBuilder)); _constraintProviders = constraintProviders ?? throw new ArgumentNullException(nameof(constraintProviders)); + _resourceDefinitionAccessor = resourceDefinitionAccessor ?? throw new ArgumentNullException(nameof(resourceDefinitionAccessor)); } public RelationshipEntry Build(IIdentifiable resource, RelationshipAttribute requestRelationship) @@ -39,6 +41,17 @@ public RelationshipEntry Build(IIdentifiable resource, RelationshipAttribute req return GetRelationshipData(requestRelationship, resource); } + /// + public override ResourceObject Build(IIdentifiable resource, IReadOnlyCollection attributes = null, + IReadOnlyCollection relationships = null) + { + var resourceObject = base.Build(resource, attributes, relationships); + + resourceObject.Meta = _resourceDefinitionAccessor.GetMeta(resource.GetType(), resource); + + return resourceObject; + } + /// /// Builds the values of the relationships object on a resource object. /// The server serializer only populates the "data" member when the relationship is included, diff --git a/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs b/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs index 05ed84f60d..d216db5818 100644 --- a/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/Client/Internal/RequestSerializer.cs @@ -31,12 +31,12 @@ public string Serialize(IIdentifiable resource) { if (resource == null) { - var empty = Build((IIdentifiable) null, false, Array.Empty(), Array.Empty()); + var empty = Build((IIdentifiable) null, Array.Empty(), Array.Empty()); return SerializeObject(empty, _jsonSerializerSettings); } _currentTargetedResource = resource.GetType(); - var document = Build(resource, false, GetAttributesToSerialize(resource), GetRelationshipsToSerialize(resource)); + var document = Build(resource, GetAttributesToSerialize(resource), GetRelationshipsToSerialize(resource)); _currentTargetedResource = null; return SerializeObject(document, _jsonSerializerSettings); @@ -52,7 +52,7 @@ public string Serialize(IReadOnlyCollection resources) Document document; if (firstResource == null) { - document = Build(resources, false, Array.Empty(), Array.Empty()); + document = Build(resources, Array.Empty(), Array.Empty()); } else { @@ -60,7 +60,7 @@ public string Serialize(IReadOnlyCollection resources) var attributes = GetAttributesToSerialize(firstResource); var relationships = GetRelationshipsToSerialize(firstResource); - document = Build(resources, false, attributes, relationships); + document = Build(resources, attributes, relationships); _currentTargetedResource = null; } diff --git a/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs b/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs index 2b5c230004..2e5b0a4afc 100644 --- a/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/ResponseSerializer.cs @@ -91,7 +91,7 @@ internal string SerializeSingle(IIdentifiable resource) } var (attributes, relationships) = GetFieldsToSerialize(); - var document = Build(resource, true, attributes, relationships); + var document = Build(resource, attributes, relationships); var resourceObject = document.SingleData; if (resourceObject != null) resourceObject.Links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id); @@ -115,7 +115,7 @@ internal string SerializeSingle(IIdentifiable resource) internal string SerializeMany(IReadOnlyCollection resources) { var (attributes, relationships) = GetFieldsToSerialize(); - var document = Build(resources, true, attributes, relationships); + var document = Build(resources, attributes, relationships); foreach (ResourceObject resourceObject in document.ManyData) { var links = _linkBuilder.GetResourceLinks(resourceObject.Type, resourceObject.Id); diff --git a/test/UnitTests/Serialization/Client/RequestSerializerTests.cs b/test/UnitTests/Serialization/Client/RequestSerializerTests.cs index 27979a7d91..0089f70262 100644 --- a/test/UnitTests/Serialization/Client/RequestSerializerTests.cs +++ b/test/UnitTests/Serialization/Client/RequestSerializerTests.cs @@ -15,8 +15,7 @@ public sealed class RequestSerializerTests : SerializerTestsSetup public RequestSerializerTests() { - var accessor = new ResourceDefinitionAccessor(_resourceGraph, new ServiceContainer()); - var builder = new ResourceObjectBuilder(_resourceGraph, accessor, new ResourceObjectBuilderSettings()); + var builder = new ResourceObjectBuilder(_resourceGraph, new ResourceObjectBuilderSettings()); _serializer = new RequestSerializer(_resourceGraph, builder); } diff --git a/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs b/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs index b802970661..1023998c15 100644 --- a/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs +++ b/test/UnitTests/Serialization/Common/DocumentBuilderTests.cs @@ -16,7 +16,7 @@ public sealed class BaseDocumentBuilderTests : SerializerTestsSetup public BaseDocumentBuilderTests() { var mock = new Mock(); - mock.Setup(m => m.Build(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>())).Returns(new ResourceObject()); + mock.Setup(m => m.Build(It.IsAny(), It.IsAny>(), It.IsAny>())).Returns(new ResourceObject()); _builder = new TestSerializer(mock.Object); } @@ -25,7 +25,7 @@ public BaseDocumentBuilderTests() public void ResourceToDocument_NullResource_CanBuild() { // Act - var document = _builder.Build((TestResource) null, false); + var document = _builder.Build((TestResource) null); // Assert Assert.Null(document.Data); @@ -40,7 +40,7 @@ public void ResourceToDocument_EmptyList_CanBuild() var resources = new List(); // Act - var document = _builder.Build(resources, false); + var document = _builder.Build(resources); // Assert Assert.NotNull(document.Data); @@ -55,7 +55,7 @@ public void ResourceToDocument_SingleResource_CanBuild() IIdentifiable dummy = new DummyResource(); // Act - var document = _builder.Build(dummy, false); + var document = _builder.Build(dummy); // Assert Assert.NotNull(document.Data); @@ -69,7 +69,7 @@ public void ResourceToDocument_ResourceList_CanBuild() var resources = new List { new DummyResource(), new DummyResource() }; // Act - var document = _builder.Build(resources, false); + var document = _builder.Build(resources); var data = (List)document.Data; // Assert diff --git a/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs b/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs index 7c142ed1fb..1e884c28f1 100644 --- a/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs +++ b/test/UnitTests/Serialization/Common/ResourceObjectBuilderTests.cs @@ -17,8 +17,7 @@ public sealed class ResourceObjectBuilderTests : SerializerTestsSetup public ResourceObjectBuilderTests() { - var accessor = new ResourceDefinitionAccessor(_resourceGraph, new ServiceContainer()); - _builder = new ResourceObjectBuilder(_resourceGraph, accessor, new ResourceObjectBuilderSettings()); + _builder = new ResourceObjectBuilder(_resourceGraph, new ResourceObjectBuilderSettings()); } [Fact] @@ -28,7 +27,7 @@ public void ResourceToResourceObject_EmptyResource_CanBuild() var resource = new TestResource(); // Act - var resourceObject = _builder.Build(resource, false); + var resourceObject = _builder.Build(resource); // Assert Assert.Null(resourceObject.Attributes); @@ -44,7 +43,7 @@ public void ResourceToResourceObject_ResourceWithId_CanBuild() var resource = new TestResource { Id = 1 }; // Act - var resourceObject = _builder.Build(resource, false); + var resourceObject = _builder.Build(resource); // Assert Assert.Equal("1", resourceObject.Id); @@ -63,7 +62,7 @@ public void ResourceToResourceObject_ResourceWithIncludedAttrs_CanBuild(string s var attrs = _resourceGraph.GetAttributes(tr => new { tr.StringField, tr.NullableIntField }); // Act - var resourceObject = _builder.Build(resource, false, attrs); + var resourceObject = _builder.Build(resource, attrs); // Assert Assert.NotNull(resourceObject.Attributes); @@ -79,7 +78,7 @@ public void ResourceWithRelationshipsToResourceObject_EmptyResource_CanBuild() var resource = new MultipleRelationshipsPrincipalPart(); // Act - var resourceObject = _builder.Build(resource, false); + var resourceObject = _builder.Build(resource); // Assert Assert.Null(resourceObject.Attributes); @@ -98,7 +97,7 @@ public void ResourceWithRelationshipsToResourceObject_ResourceWithId_CanBuild() }; // Act - var resourceObject = _builder.Build(resource, false); + var resourceObject = _builder.Build(resource); // Assert Assert.Null(resourceObject.Attributes); @@ -119,7 +118,7 @@ public void ResourceWithRelationshipsToResourceObject_WithIncludedRelationshipsA var relationships = _resourceGraph.GetRelationships(tr => new { tr.PopulatedToManies, tr.PopulatedToOne, tr.EmptyToOne, tr.EmptyToManies }); // Act - var resourceObject = _builder.Build(resource, false, relationships: relationships); + var resourceObject = _builder.Build(resource, relationships: relationships); // Assert Assert.Equal(4, resourceObject.Relationships.Count); @@ -143,7 +142,7 @@ public void ResourceWithRelationshipsToResourceObject_DeviatingForeignKeyWhileRe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, false, relationships: relationships); + var resourceObject = _builder.Build(resource, relationships: relationships); // Assert Assert.Single(resourceObject.Relationships); @@ -160,7 +159,7 @@ public void ResourceWithRelationshipsToResourceObject_DeviatingForeignKeyAndNoNa var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, false, relationships: relationships); + var resourceObject = _builder.Build(resource, relationships: relationships); // Assert Assert.Null(resourceObject.Relationships["principal"].Data); @@ -174,7 +173,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_DeviatingForeignKe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act - var resourceObject = _builder.Build(resource, false, relationships: relationships); + var resourceObject = _builder.Build(resource, relationships: relationships); // Assert Assert.Single(resourceObject.Relationships); @@ -191,7 +190,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_DeviatingForeignKe var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act & assert - Assert.ThrowsAny(() => _builder.Build(resource, false, relationships: relationships)); + Assert.ThrowsAny(() => _builder.Build(resource, relationships: relationships)); } [Fact] @@ -202,7 +201,7 @@ public void ResourceWithRequiredRelationshipsToResourceObject_EmptyResourceWhile var relationships = _resourceGraph.GetRelationships(tr => tr.Principal); // Act & assert - Assert.ThrowsAny(() => _builder.Build(resource, false, relationships: relationships)); + Assert.ThrowsAny(() => _builder.Build(resource, relationships: relationships)); } } } diff --git a/test/UnitTests/Serialization/SerializerTestsSetup.cs b/test/UnitTests/Serialization/SerializerTestsSetup.cs index aeec4a4afe..233e5568ec 100644 --- a/test/UnitTests/Serialization/SerializerTestsSetup.cs +++ b/test/UnitTests/Serialization/SerializerTestsSetup.cs @@ -126,14 +126,14 @@ protected sealed class TestSerializer : BaseSerializer { public TestSerializer(IResourceObjectBuilder resourceObjectBuilder) : base(resourceObjectBuilder) { } - public new Document Build(IIdentifiable resource, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public new Document Build(IIdentifiable resource, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { - return base.Build(resource, true, attributes, relationships); + return base.Build(resource, attributes, relationships); } - public new Document Build(IReadOnlyCollection resources, bool includeResourceMeta, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) + public new Document Build(IReadOnlyCollection resources, IReadOnlyCollection attributes = null, IReadOnlyCollection relationships = null) { - return base.Build(resources, true, attributes, relationships); + return base.Build(resources, attributes, relationships); } } } diff --git a/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs b/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs index 8c8ba13eec..bc50c2ec93 100644 --- a/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs +++ b/test/UnitTests/Serialization/Server/ResponseResourceObjectBuilderTests.cs @@ -24,7 +24,7 @@ public void Build_RelationshipNotIncludedAndLinksEnabled_RelationshipEntryWithLi var builder = GetResponseResourceObjectBuilder(relationshipLinks: _dummyRelationshipLinks); // Act - var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); @@ -41,7 +41,7 @@ public void Build_RelationshipNotIncludedAndLinksDisabled_NoRelationshipObject() var builder = GetResponseResourceObjectBuilder(); // Act - var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); // Assert Assert.Null(resourceObject.Relationships); @@ -55,7 +55,7 @@ public void Build_RelationshipIncludedAndLinksDisabled_RelationshipEntryWithData var builder = GetResponseResourceObjectBuilder(inclusionChains: new List> { _relationshipsForBuild } ); // Act - var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); @@ -72,7 +72,7 @@ public void Build_RelationshipIncludedAndLinksEnabled_RelationshipEntryWithDataA var builder = GetResponseResourceObjectBuilder(inclusionChains: new List> { _relationshipsForBuild }, relationshipLinks: _dummyRelationshipLinks); // Act - var resourceObject = builder.Build(resource, false, relationships: _relationshipsForBuild); + var resourceObject = builder.Build(resource, relationships: _relationshipsForBuild); // Assert Assert.True(resourceObject.Relationships.TryGetValue(_relationshipName, out var entry)); From ede2e93334e34b3a4b4eca2a69ec55d5638cc85e Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Thu, 1 Oct 2020 10:37:56 +0200 Subject: [PATCH 7/7] added registration to docs --- docs/usage/meta.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/usage/meta.md b/docs/usage/meta.md index 17d28f80b3..1bd4678d69 100644 --- a/docs/usage/meta.md +++ b/docs/usage/meta.md @@ -8,6 +8,9 @@ Global metadata can be added to the root of the response document by registering This is useful if you need access to other registered services to build the meta object. ```c# +// In Startup.ConfigureServices +services.AddSingleton(); + public sealed class CopyrightResponseMeta : IResponseMeta { public IReadOnlyDictionary GetMeta()