Skip to content

Commit e03329a

Browse files
author
Bart Koelman
authored
Merge pull request #1088 from json-api-dotnet/merge-master-into-openapi
Merge master into openapi (retry)
2 parents 362bf5f + 4f5ee42 commit e03329a

File tree

330 files changed

+6223
-6917
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

330 files changed

+6223
-6917
lines changed

Directory.Build.props

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
<SwashbuckleVersion>6.2.*</SwashbuckleVersion>
88
<JsonApiDotNetCoreVersionPrefix>4.2.0</JsonApiDotNetCoreVersionPrefix>
99
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodingGuidelines.ruleset</CodeAnalysisRuleSet>
10+
<WarningLevel>9999</WarningLevel>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
1314
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" PrivateAssets="All" />
14-
<PackageReference Include="CSharpGuidelinesAnalyzer" Version="3.6.0" PrivateAssets="All" />
15+
<PackageReference Include="CSharpGuidelinesAnalyzer" Version="3.7.0" PrivateAssets="All" />
1516
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CSharpGuidelinesAnalyzer.config" Visible="False" />
1617
</ItemGroup>
1718

@@ -23,11 +24,11 @@
2324

2425
<!-- Test Project Dependencies -->
2526
<PropertyGroup>
26-
<BogusVersion>33.0.2</BogusVersion>
27+
<BogusVersion>33.1.1</BogusVersion>
2728
<CoverletVersion>3.1.0</CoverletVersion>
28-
<FluentAssertionsVersion>5.10.3</FluentAssertionsVersion>
29+
<FluentAssertionsVersion>6.1.0</FluentAssertionsVersion>
2930
<MoqVersion>4.16.1</MoqVersion>
3031
<XUnitVersion>2.4.*</XUnitVersion>
31-
<TestSdkVersion>16.10.0</TestSdkVersion>
32+
<TestSdkVersion>16.11.0</TestSdkVersion>
3233
</PropertyGroup>
3334
</Project>

ROADMAP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ The need for breaking changes has blocked several efforts in the v4.x release, s
1919
- [x] Tweak trace logging [#1033](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1033)
2020
- [x] Instrumentation [#1032](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1032)
2121
- [x] Optimized delete to-many [#1030](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1030)
22-
- [ ] Support System.Text.Json [#664](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/664) [#999](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/999) [#233](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/233)
23-
- [ ] Optimize IIdentifiable to ResourceObject conversion [#1028](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1028) [#1024](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1024)
22+
- [x] Support System.Text.Json [#664](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/664) [#999](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/999) [1077](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1077) [1078](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1078)
23+
- [ ] Optimize IIdentifiable to ResourceObject conversion [#1028](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1028) [#1024](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1024) [#233](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/233)
2424
- [ ] Nullable reference types [#1029](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1029)
2525

2626
Aside from the list above, we have interest in the following topics. It's too soon yet to decide whether they'll make it into v5.x or in a later major version.

appveyor.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ for:
3535
only:
3636
- image: Visual Studio 2019
3737
services:
38-
- postgresql134
39-
# https://help.appveyor.com/discussions/problems/30239-postgres-fails-to-connect-after-version-change
40-
init:
41-
- net start postgresql-x64-13
38+
- postgresql13
4239
# REF: https://github.com/docascode/docfx-seed/blob/master/appveyor.yml
4340
before_build:
4441
- pwsh: |

benchmarks/DependencyFactory.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ internal sealed class DependencyFactory
88
public IResourceGraph CreateResourceGraph(IJsonApiOptions options)
99
{
1010
var builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
11+
1112
builder.Add<BenchmarkResource>(BenchmarkResourcePublicNames.Type);
13+
builder.Add<SubResource>();
14+
1215
return builder.Build();
1316
}
1417
}

benchmarks/Query/QueryParserBenchmarks.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,9 @@ private static QueryStringReader CreateQueryParameterDiscoveryForAll(IResourceGr
6464
var sortReader = new SortQueryStringParameterReader(request, resourceGraph);
6565
var sparseFieldSetReader = new SparseFieldSetQueryStringParameterReader(request, resourceGraph);
6666
var paginationReader = new PaginationQueryStringParameterReader(request, resourceGraph, options);
67-
var defaultsReader = new DefaultsQueryStringParameterReader(options);
68-
var nullsReader = new NullsQueryStringParameterReader(options);
6967

7068
IQueryStringParameterReader[] readers = ArrayFactory.Create<IQueryStringParameterReader>(includeReader, filterReader, sortReader,
71-
sparseFieldSetReader, paginationReader, defaultsReader, nullsReader);
69+
sparseFieldSetReader, paginationReader);
7270

7371
return new QueryStringReader(options, queryStringAccessor, readers, NullLoggerFactory.Instance);
7472
}

benchmarks/Serialization/JsonApiDeserializerBenchmarks.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
1-
using System;
2-
using System.Collections.Generic;
31
using System.ComponentModel.Design;
2+
using System.Text.Json;
43
using BenchmarkDotNet.Attributes;
54
using JsonApiDotNetCore.Configuration;
65
using JsonApiDotNetCore.Middleware;
76
using JsonApiDotNetCore.Resources;
87
using JsonApiDotNetCore.Serialization;
9-
using JsonApiDotNetCore.Serialization.Objects;
108
using Microsoft.AspNetCore.Http;
11-
using Newtonsoft.Json;
129

1310
namespace Benchmarks.Serialization
1411
{
1512
// ReSharper disable once ClassCanBeSealed.Global
1613
[MarkdownExporter]
1714
public class JsonApiDeserializerBenchmarks
1815
{
19-
private static readonly string Content = JsonConvert.SerializeObject(new Document
16+
private static readonly string RequestBody = JsonSerializer.Serialize(new
2017
{
21-
Data = new ResourceObject
18+
data = new
2219
{
23-
Type = BenchmarkResourcePublicNames.Type,
24-
Id = "1",
25-
Attributes = new Dictionary<string, object>
20+
type = BenchmarkResourcePublicNames.Type,
21+
id = "1",
22+
attributes = new
2623
{
27-
["name"] = Guid.NewGuid().ToString()
2824
}
2925
}
3026
});
@@ -55,7 +51,7 @@ public JsonApiDeserializerBenchmarks()
5551
[Benchmark]
5652
public object DeserializeSimpleObject()
5753
{
58-
return _jsonApiDeserializer.Deserialize(Content);
54+
return _jsonApiDeserializer.Deserialize(RequestBody);
5955
}
6056
}
6157
}

benchmarks/Serialization/JsonApiSerializerBenchmarks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public JsonApiSerializerBenchmarks()
3434
ILinkBuilder linkBuilder = new Mock<ILinkBuilder>().Object;
3535
IIncludedResourceObjectBuilder includeBuilder = new Mock<IIncludedResourceObjectBuilder>().Object;
3636

37-
var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, new ResourceObjectBuilderSettings());
37+
var resourceObjectBuilder = new ResourceObjectBuilder(resourceGraph, options);
3838

3939
IResourceDefinitionAccessor resourceDefinitionAccessor = new Mock<IResourceDefinitionAccessor>().Object;
4040

docs/request-examples/012_PATCH_Book.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ curl -s -f http://localhost:14141/api/books/1 `
44
-d '{
55
\"data\": {
66
\"type\": \"books\",
7-
\"id\": "1",
7+
\"id\": \"1\",
88
\"attributes\": {
99
\"publishYear\": 1820
1010
}

docs/usage/options.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,27 +78,26 @@ To limit the maximum depth of nested includes, use `MaximumIncludeDepth`. This i
7878
options.MaximumIncludeDepth = 1;
7979
```
8080

81-
## Custom Serializer Settings
81+
## Customize Serializer options
8282

83-
We use [Newtonsoft.Json](https://www.newtonsoft.com/json) for all serialization needs.
84-
If you want to change the default serializer settings, you can:
83+
We use [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) for all serialization needs.
84+
If you want to change the default serializer options, you can:
8585

8686
```c#
87-
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
88-
options.SerializerSettings.Converters.Add(new StringEnumConverter());
89-
options.SerializerSettings.Formatting = Formatting.Indented;
87+
options.SerializerOptions.WriteIndented = true;
88+
options.SerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
89+
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
9090
```
9191

9292
The default naming convention (as used in the routes and resource/attribute/relationship names) is also determined here, and can be changed (default is camel-case):
9393

9494
```c#
95-
options.SerializerSettings.ContractResolver = new DefaultContractResolver
96-
{
97-
NamingStrategy = new KebabCaseNamingStrategy()
98-
};
95+
// Use Pascal case
96+
options.SerializerOptions.PropertyNamingPolicy = null;
97+
options.SerializerOptions.DictionaryKeyPolicy = null;
9998
```
10099

101-
Because we copy resource properties into an intermediate object before serialization, Newtonsoft.Json annotations on properties are ignored.
100+
Because we copy resource properties into an intermediate object before serialization, JSON annotations such as `[JsonPropertyName]` and `[JsonIgnore]` on `[Attr]` properties are ignored.
102101

103102

104103
## Enable ModelState Validation

docs/usage/resource-graph.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,4 @@ public class MyModel : Identifiable
9898
}
9999
```
100100

101-
The default naming convention can be changed in [options](~/usage/options.md#custom-serializer-settings).
101+
The default naming convention can be changed in [options](~/usage/options.md#customize-serializer-options).

docs/usage/resources/attributes.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class Person : Identifiable
1414

1515
There are two ways the exposed attribute name is determined:
1616

17-
1. Using the configured [naming convention](~/usage/options.md#custom-serializer-settings).
17+
1. Using the configured [naming convention](~/usage/options.md#customize-serializer-options).
1818

1919
2. Individually using the attribute's constructor.
2020
```c#
@@ -88,9 +88,9 @@ public class Person : Identifiable
8888
## Complex Attributes
8989

9090
Models may contain complex attributes.
91-
Serialization of these types is done by [Newtonsoft.Json](https://www.newtonsoft.com/json),
92-
so you should use their APIs to specify serialization formats.
93-
You can also use global options to specify `JsonSerializer` configuration.
91+
Serialization of these types is done by [System.Text.Json](https://www.nuget.org/packages/System.Text.Json),
92+
so you should use their APIs to specify serialization format.
93+
You can also use [global options](~/usage/options.md#customize-serializer-options) to control the `JsonSerializer` behavior.
9494

9595
```c#
9696
public class Foo : Identifiable
@@ -101,7 +101,8 @@ public class Foo : Identifiable
101101

102102
public class Bar
103103
{
104-
[JsonProperty("compound-member")]
104+
[JsonPropertyName("compound-member")]
105+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
105106
public string CompoundMember { get; set; }
106107
}
107108
```
@@ -121,13 +122,13 @@ public class Foo : Identifiable
121122
{
122123
get
123124
{
124-
return Bar == null ? "{}" : JsonConvert.SerializeObject(Bar);
125+
return Bar == null ? "{}" : JsonSerializer.Serialize(Bar);
125126
}
126127
set
127128
{
128129
Bar = string.IsNullOrWhiteSpace(value)
129130
? null
130-
: JsonConvert.DeserializeObject<Bar>(value);
131+
: JsonSerializer.Deserialize<Bar>(value);
131132
}
132133
}
133134
}

docs/usage/resources/relationships.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,37 @@ public class Person : Identifiable
3434

3535
The left side of this relationship is of type `Person` (public name: "persons") and the right side is of type `TodoItem` (public name: "todoItems").
3636

37+
## HasManyThrough
38+
39+
_removed since v5.0_
40+
41+
Earlier versions of Entity Framework Core (up to v5) [did not support](https://github.com/aspnet/EntityFrameworkCore/issues/1368) many-to-many relationships without a join entity.
42+
For this reason, earlier versions of JsonApiDotNetCore filled this gap by allowing applications to declare a relationship as `HasManyThrough`,
43+
which would expose the relationship to the client the same way as any other `HasMany` relationship.
44+
However, under the covers it would use the join type and Entity Framework Core's APIs to get and set the relationship.
45+
46+
```c#
47+
public class Article : Identifiable
48+
{
49+
// tells Entity Framework Core to ignore this property
50+
[NotMapped]
51+
52+
// tells JsonApiDotNetCore to use the join table below
53+
[HasManyThrough(nameof(ArticleTags))]
54+
public ICollection<Tag> Tags { get; set; }
55+
56+
// this is the Entity Framework Core navigation to the join table
57+
public ICollection<ArticleTag> ArticleTags { get; set; }
58+
}
59+
```
60+
61+
The left side of this relationship is of type `Article` (public name: "articles") and the right side is of type `Tag` (public name: "tags").
62+
3763
## Name
3864

3965
There are two ways the exposed relationship name is determined:
4066

41-
1. Using the configured [naming convention](~/usage/options.md#custom-serializer-settings).
67+
1. Using the configured [naming convention](~/usage/options.md#customize-serializer-options).
4268

4369
2. Individually using the attribute's constructor.
4470
```c#

docs/usage/routing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The exposed name of the resource ([which can be customized](~/usage/resource-gra
4545

4646
### Non-JSON:API controllers
4747

48-
If a controller does not inherit from `JsonApiController<TResource>`, the [configured naming convention](~/usage/options.md#custom-serializer-settings) is applied to the name of the controller.
48+
If a controller does not inherit from `JsonApiController<TResource>`, the [configured naming convention](~/usage/options.md#customize-serializer-options) is applied to the name of the controller.
4949

5050
```c#
5151
public class OrderLineController : ControllerBase

src/Examples/GettingStarted/Properties/launchSettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
"profiles": {
1111
"IIS Express": {
1212
"commandName": "IISExpress",
13-
"launchBrowser": false,
13+
"launchBrowser": true,
1414
"launchUrl": "api/people",
1515
"environmentVariables": {
1616
"ASPNETCORE_ENVIRONMENT": "Development"
1717
}
1818
},
1919
"Kestrel": {
2020
"commandName": "Project",
21-
"launchBrowser": false,
21+
"launchBrowser": true,
2222
"launchUrl": "api/people",
2323
"applicationUrl": "http://localhost:14141",
2424
"environmentVariables": {

src/Examples/GettingStarted/Startup.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Microsoft.AspNetCore.Builder;
66
using Microsoft.EntityFrameworkCore;
77
using Microsoft.Extensions.DependencyInjection;
8-
using Newtonsoft.Json;
98

109
namespace GettingStarted
1110
{
@@ -21,7 +20,7 @@ public void ConfigureServices(IServiceCollection services)
2120
options.Namespace = "api";
2221
options.UseRelativeLinks = true;
2322
options.IncludeTotalResourceCount = true;
24-
options.SerializerSettings.Formatting = Formatting.Indented;
23+
options.SerializerOptions.WriteIndented = true;
2524
});
2625
}
2726

src/Examples/JsonApiDotNetCoreExample/Controllers/NonJsonApiController.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,21 @@ public async Task<IActionResult> PostAsync()
2828
return BadRequest("Please send your name.");
2929
}
3030

31-
string result = "Hello, " + name;
31+
string result = $"Hello, {name}";
3232
return Ok(result);
3333
}
3434

3535
[HttpPut]
3636
public IActionResult Put([FromBody] string name)
3737
{
38-
string result = "Hi, " + name;
38+
string result = $"Hi, {name}";
3939
return Ok(result);
4040
}
4141

4242
[HttpPatch]
4343
public IActionResult Patch(string name)
4444
{
45-
string result = "Good day, " + name;
45+
string result = $"Good day, {name}";
4646
return Ok(result);
4747
}
4848

src/Examples/JsonApiDotNetCoreExample/Startup.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Text.Json.Serialization;
23
using JsonApiDotNetCore.Configuration;
34
using JsonApiDotNetCore.Diagnostics;
45
using JsonApiDotNetCore.OpenApi;
@@ -10,8 +11,6 @@
1011
using Microsoft.Extensions.Configuration;
1112
using Microsoft.Extensions.DependencyInjection;
1213
using Microsoft.Extensions.Logging;
13-
using Newtonsoft.Json;
14-
using Newtonsoft.Json.Converters;
1514

1615
namespace JsonApiDotNetCoreExample
1716
{
@@ -55,8 +54,8 @@ public void ConfigureServices(IServiceCollection services)
5554
options.UseRelativeLinks = true;
5655
options.ValidateModelState = true;
5756
options.IncludeTotalResourceCount = true;
58-
options.SerializerSettings.Formatting = Formatting.Indented;
59-
options.SerializerSettings.Converters.Add(new StringEnumConverter());
57+
options.SerializerOptions.WriteIndented = true;
58+
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
6059
#if DEBUG
6160
options.IncludeExceptionStackTraceInErrors = true;
6261
#endif

src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@
2828
</PackageReference>
2929
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(SwashbuckleVersion)" />
3030
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="$(SwashbuckleVersion)" />
31-
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="$(SwashbuckleVersion)" />
3231
</ItemGroup>
3332
</Project>

0 commit comments

Comments
 (0)