Skip to content

Commit 6ddd7b8

Browse files
authored
Merge pull request #1585 from json-api-dotnet/merge-master-into-openapi
Merge master (v5.6.0) into openapi
2 parents 67924c4 + 72cefc6 commit 6ddd7b8

37 files changed

+225
-108
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
2828
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodingGuidelines.ruleset</CodeAnalysisRuleSet>
2929
<RunSettingsFilePath>$(MSBuildThisFileDirectory)tests.runsettings</RunSettingsFilePath>
30-
<JsonApiDotNetCoreVersionPrefix>5.5.2</JsonApiDotNetCoreVersionPrefix>
30+
<JsonApiDotNetCoreVersionPrefix>5.6.1</JsonApiDotNetCoreVersionPrefix>
3131
</PropertyGroup>
3232
</Project>

src/Examples/DapperExample/Repositories/DapperRepository.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Data.Common;
2+
using System.Diagnostics.CodeAnalysis;
23
using Dapper;
34
using DapperExample.AtomicOperations;
45
using DapperExample.TranslationToSql;
@@ -177,7 +178,7 @@ public async Task<int> CountAsync(FilterExpression? filter, CancellationToken ca
177178
}
178179

179180
/// <inheritdoc />
180-
public Task<TResource> GetForCreateAsync(Type resourceClrType, TId id, CancellationToken cancellationToken)
181+
public Task<TResource> GetForCreateAsync(Type resourceClrType, [DisallowNull] TId id, CancellationToken cancellationToken)
181182
{
182183
ArgumentGuard.NotNull(resourceClrType);
183184

@@ -355,7 +356,7 @@ await ExecuteInTransactionAsync(async transaction =>
355356
}
356357

357358
/// <inheritdoc />
358-
public async Task DeleteAsync(TResource? resourceFromDatabase, TId id, CancellationToken cancellationToken)
359+
public async Task DeleteAsync(TResource? resourceFromDatabase, [DisallowNull] TId id, CancellationToken cancellationToken)
359360
{
360361
TResource placeholderResource = resourceFromDatabase ?? _resourceFactory.CreateInstance<TResource>();
361362
placeholderResource.Id = id;
@@ -451,7 +452,7 @@ await ExecuteInTransactionAsync(async transaction =>
451452
}
452453

453454
/// <inheritdoc />
454-
public async Task AddToToManyRelationshipAsync(TResource? leftResource, TId leftId, ISet<IIdentifiable> rightResourceIds,
455+
public async Task AddToToManyRelationshipAsync(TResource? leftResource, [DisallowNull] TId leftId, ISet<IIdentifiable> rightResourceIds,
455456
CancellationToken cancellationToken)
456457
{
457458
ArgumentGuard.NotNull(rightResourceIds);

src/Examples/NoEntityFrameworkExample/Services/InMemoryResourceService.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections;
2+
using System.Diagnostics.CodeAnalysis;
23
using JsonApiDotNetCore.Configuration;
34
using JsonApiDotNetCore.Errors;
45
using JsonApiDotNetCore.Queries;
@@ -114,7 +115,7 @@ private bool SetPrimaryTotalCountIsZero()
114115
}
115116

116117
/// <inheritdoc />
117-
public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
118+
public Task<TResource> GetAsync([DisallowNull] TId id, CancellationToken cancellationToken)
118119
{
119120
QueryLayer queryLayer = _queryLayerComposer.ComposeForGetById(id, _resourceType, TopFieldSelection.PreserveExisting);
120121

@@ -124,14 +125,14 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
124125

125126
if (resource == null)
126127
{
127-
throw new ResourceNotFoundException(id!.ToString()!, _resourceType.PublicName);
128+
throw new ResourceNotFoundException(id.ToString()!, _resourceType.PublicName);
128129
}
129130

130131
return Task.FromResult(resource);
131132
}
132133

133134
/// <inheritdoc />
134-
public Task<object?> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
135+
public Task<object?> GetSecondaryAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
135136
{
136137
RelationshipAttribute? relationship = _resourceType.FindRelationshipByPublicName(relationshipName);
137138

@@ -151,7 +152,7 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
151152

152153
if (primaryResource == null)
153154
{
154-
throw new ResourceNotFoundException(id!.ToString()!, _resourceType.PublicName);
155+
throw new ResourceNotFoundException(id.ToString()!, _resourceType.PublicName);
155156
}
156157

157158
object? rightValue = relationship.GetValue(primaryResource);
@@ -164,7 +165,7 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
164165
return Task.FromResult(rightValue);
165166
}
166167

167-
private void SetNonPrimaryTotalCount(TId id, RelationshipAttribute relationship)
168+
private void SetNonPrimaryTotalCount([DisallowNull] TId id, RelationshipAttribute relationship)
168169
{
169170
if (_options.IncludeTotalResourceCount && relationship is HasManyAttribute hasManyRelationship)
170171
{
@@ -188,7 +189,7 @@ private void SetNonPrimaryTotalCount(TId id, RelationshipAttribute relationship)
188189
}
189190

190191
/// <inheritdoc />
191-
public Task<object?> GetRelationshipAsync(TId id, string relationshipName, CancellationToken cancellationToken)
192+
public Task<object?> GetRelationshipAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
192193
{
193194
return GetSecondaryAsync(id, relationshipName, cancellationToken);
194195
}

src/JsonApiDotNetCore/AtomicOperations/Processors/AddToRelationshipProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public AddToRelationshipProcessor(IAddToRelationshipService<TResource, TId> serv
2626
var leftId = (TId)operation.Resource.GetTypedId();
2727
ISet<IIdentifiable> rightResourceIds = operation.GetSecondaryResources();
2828

29-
await _service.AddToToManyRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
29+
await _service.AddToToManyRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
3030

3131
return null;
3232
}

src/JsonApiDotNetCore/AtomicOperations/Processors/DeleteProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public DeleteProcessor(IDeleteService<TResource, TId> service)
2424
ArgumentGuard.NotNull(operation);
2525

2626
var id = (TId)operation.Resource.GetTypedId();
27-
await _service.DeleteAsync(id, cancellationToken);
27+
await _service.DeleteAsync(id!, cancellationToken);
2828

2929
return null;
3030
}

src/JsonApiDotNetCore/AtomicOperations/Processors/RemoveFromRelationshipProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public RemoveFromRelationshipProcessor(IRemoveFromRelationshipService<TResource,
2626
var leftId = (TId)operation.Resource.GetTypedId();
2727
ISet<IIdentifiable> rightResourceIds = operation.GetSecondaryResources();
2828

29-
await _service.RemoveFromToManyRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
29+
await _service.RemoveFromToManyRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
3030

3131
return null;
3232
}

src/JsonApiDotNetCore/AtomicOperations/Processors/SetRelationshipProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public SetRelationshipProcessor(ISetRelationshipService<TResource, TId> service)
2828
var leftId = (TId)operation.Resource.GetTypedId();
2929
object? rightValue = GetRelationshipRightValue(operation);
3030

31-
await _service.SetRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightValue, cancellationToken);
31+
await _service.SetRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightValue, cancellationToken);
3232

3333
return null;
3434
}

src/JsonApiDotNetCore/AtomicOperations/Processors/UpdateProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public UpdateProcessor(IUpdateService<TResource, TId> service)
2424
ArgumentGuard.NotNull(operation);
2525

2626
var resource = (TResource)operation.Resource;
27-
TResource? updated = await _service.UpdateAsync(resource.Id, resource, cancellationToken);
27+
TResource? updated = await _service.UpdateAsync(resource.Id!, resource, cancellationToken);
2828

2929
return updated == null ? null : operation.WithResource(updated);
3030
}

src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using JsonApiDotNetCore.Configuration;
23
using JsonApiDotNetCore.Errors;
34
using JsonApiDotNetCore.Middleware;
45
using JsonApiDotNetCore.Resources;
56
using JsonApiDotNetCore.Services;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Http.Extensions;
69
using Microsoft.AspNetCore.Mvc;
710
using Microsoft.Extensions.Logging;
811

@@ -106,7 +109,7 @@ public virtual async Task<IActionResult> GetAsync(CancellationToken cancellation
106109
/// GET /articles/1 HTTP/1.1
107110
/// ]]></code>
108111
/// </summary>
109-
public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken cancellationToken)
112+
public virtual async Task<IActionResult> GetAsync([DisallowNull] TId id, CancellationToken cancellationToken)
110113
{
111114
_traceWriter.LogMethodStart(new
112115
{
@@ -131,7 +134,7 @@ public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken canc
131134
/// GET /articles/1/revisions HTTP/1.1
132135
/// ]]></code>
133136
/// </summary>
134-
public virtual async Task<IActionResult> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
137+
public virtual async Task<IActionResult> GetSecondaryAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
135138
{
136139
_traceWriter.LogMethodStart(new
137140
{
@@ -160,7 +163,7 @@ public virtual async Task<IActionResult> GetSecondaryAsync(TId id, string relati
160163
/// GET /articles/1/relationships/revisions HTTP/1.1
161164
/// ]]></code>
162165
/// </summary>
163-
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName, CancellationToken cancellationToken)
166+
public virtual async Task<IActionResult> GetRelationshipAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
164167
{
165168
_traceWriter.LogMethodStart(new
166169
{
@@ -207,7 +210,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] TResource resource
207210
TResource? newResource = await _create.CreateAsync(resource, cancellationToken);
208211

209212
string resourceId = (newResource ?? resource).StringId!;
210-
string locationUrl = HttpContext.Request.Path.Add($"/{resourceId}");
213+
string locationUrl = GetLocationUrl(resourceId);
211214

212215
if (newResource == null)
213216
{
@@ -218,6 +221,15 @@ public virtual async Task<IActionResult> PostAsync([FromBody] TResource resource
218221
return Created(locationUrl, newResource);
219222
}
220223

224+
private string GetLocationUrl(string resourceId)
225+
{
226+
PathString locationPath = HttpContext.Request.Path.Add($"/{resourceId}");
227+
228+
return _options.UseRelativeLinks
229+
? UriHelper.BuildRelative(HttpContext.Request.PathBase, locationPath)
230+
: UriHelper.BuildAbsolute(HttpContext.Request.Scheme, HttpContext.Request.Host, HttpContext.Request.PathBase, locationPath);
231+
}
232+
221233
/// <summary>
222234
/// Adds resources to a to-many relationship. Example: <code><![CDATA[
223235
/// POST /articles/1/revisions HTTP/1.1
@@ -235,8 +247,8 @@ public virtual async Task<IActionResult> PostAsync([FromBody] TResource resource
235247
/// <param name="cancellationToken">
236248
/// Propagates notification that request handling should be canceled.
237249
/// </param>
238-
public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
239-
CancellationToken cancellationToken)
250+
public virtual async Task<IActionResult> PostRelationshipAsync([DisallowNull] TId id, string relationshipName,
251+
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
240252
{
241253
_traceWriter.LogMethodStart(new
242254
{
@@ -264,7 +276,7 @@ public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string re
264276
/// PATCH /articles/1 HTTP/1.1
265277
/// ]]></code>
266278
/// </summary>
267-
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource resource, CancellationToken cancellationToken)
279+
public virtual async Task<IActionResult> PatchAsync([DisallowNull] TId id, [FromBody] TResource resource, CancellationToken cancellationToken)
268280
{
269281
_traceWriter.LogMethodStart(new
270282
{
@@ -310,7 +322,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource
310322
/// <param name="cancellationToken">
311323
/// Propagates notification that request handling should be canceled.
312324
/// </param>
313-
public virtual async Task<IActionResult> PatchRelationshipAsync(TId id, string relationshipName, [FromBody] object? rightValue,
325+
public virtual async Task<IActionResult> PatchRelationshipAsync([DisallowNull] TId id, string relationshipName, [FromBody] object? rightValue,
314326
CancellationToken cancellationToken)
315327
{
316328
_traceWriter.LogMethodStart(new
@@ -337,7 +349,7 @@ public virtual async Task<IActionResult> PatchRelationshipAsync(TId id, string r
337349
/// DELETE /articles/1 HTTP/1.1
338350
/// ]]></code>
339351
/// </summary>
340-
public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken cancellationToken)
352+
public virtual async Task<IActionResult> DeleteAsync([DisallowNull] TId id, CancellationToken cancellationToken)
341353
{
342354
_traceWriter.LogMethodStart(new
343355
{
@@ -371,8 +383,8 @@ public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken c
371383
/// <param name="cancellationToken">
372384
/// Propagates notification that request handling should be canceled.
373385
/// </param>
374-
public virtual async Task<IActionResult> DeleteRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
375-
CancellationToken cancellationToken)
386+
public virtual async Task<IActionResult> DeleteRelationshipAsync([DisallowNull] TId id, string relationshipName,
387+
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
376388
{
377389
_traceWriter.LogMethodStart(new
378390
{

src/JsonApiDotNetCore/Controllers/JsonApiController.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.ComponentModel.DataAnnotations;
2+
using System.Diagnostics.CodeAnalysis;
23
using JsonApiDotNetCore.Configuration;
34
using JsonApiDotNetCore.Resources;
45
using JsonApiDotNetCore.Services;
@@ -50,23 +51,25 @@ public override async Task<IActionResult> GetAsync(CancellationToken cancellatio
5051
/// <inheritdoc />
5152
[HttpGet("{id}")]
5253
[HttpHead("{id}")]
53-
public override async Task<IActionResult> GetAsync([Required] TId id, CancellationToken cancellationToken)
54+
public override async Task<IActionResult> GetAsync([Required] [DisallowNull] TId id, CancellationToken cancellationToken)
5455
{
5556
return await base.GetAsync(id, cancellationToken);
5657
}
5758

5859
/// <inheritdoc />
5960
[HttpGet("{id}/{relationshipName}")]
6061
[HttpHead("{id}/{relationshipName}")]
61-
public override async Task<IActionResult> GetSecondaryAsync([Required] TId id, [Required] string relationshipName, CancellationToken cancellationToken)
62+
public override async Task<IActionResult> GetSecondaryAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
63+
CancellationToken cancellationToken)
6264
{
6365
return await base.GetSecondaryAsync(id, relationshipName, cancellationToken);
6466
}
6567

6668
/// <inheritdoc />
6769
[HttpGet("{id}/relationships/{relationshipName}")]
6870
[HttpHead("{id}/relationships/{relationshipName}")]
69-
public override async Task<IActionResult> GetRelationshipAsync([Required] TId id, [Required] string relationshipName, CancellationToken cancellationToken)
71+
public override async Task<IActionResult> GetRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
72+
CancellationToken cancellationToken)
7073
{
7174
return await base.GetRelationshipAsync(id, relationshipName, cancellationToken);
7275
}
@@ -80,38 +83,38 @@ public override async Task<IActionResult> PostAsync([Required] TResource resourc
8083

8184
/// <inheritdoc />
8285
[HttpPost("{id}/relationships/{relationshipName}")]
83-
public override async Task<IActionResult> PostRelationshipAsync([Required] TId id, [Required] string relationshipName,
86+
public override async Task<IActionResult> PostRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
8487
[Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
8588
{
8689
return await base.PostRelationshipAsync(id, relationshipName, rightResourceIds, cancellationToken);
8790
}
8891

8992
/// <inheritdoc />
9093
[HttpPatch("{id}")]
91-
public override async Task<IActionResult> PatchAsync([Required] TId id, [Required] TResource resource, CancellationToken cancellationToken)
94+
public override async Task<IActionResult> PatchAsync([Required] [DisallowNull] TId id, [Required] TResource resource, CancellationToken cancellationToken)
9295
{
9396
return await base.PatchAsync(id, resource, cancellationToken);
9497
}
9598

9699
/// <inheritdoc />
97100
[HttpPatch("{id}/relationships/{relationshipName}")]
98101
// Parameter `[Required] object? rightValue` makes Swashbuckle generate the OpenAPI request body as required. We don't actually validate ModelState, so it doesn't hurt.
99-
public override async Task<IActionResult> PatchRelationshipAsync([Required] TId id, [Required] string relationshipName, [Required] object? rightValue,
100-
CancellationToken cancellationToken)
102+
public override async Task<IActionResult> PatchRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
103+
[Required] object? rightValue, CancellationToken cancellationToken)
101104
{
102105
return await base.PatchRelationshipAsync(id, relationshipName, rightValue, cancellationToken);
103106
}
104107

105108
/// <inheritdoc />
106109
[HttpDelete("{id}")]
107-
public override async Task<IActionResult> DeleteAsync([Required] TId id, CancellationToken cancellationToken)
110+
public override async Task<IActionResult> DeleteAsync([Required] [DisallowNull] TId id, CancellationToken cancellationToken)
108111
{
109112
return await base.DeleteAsync(id, cancellationToken);
110113
}
111114

112115
/// <inheritdoc />
113116
[HttpDelete("{id}/relationships/{relationshipName}")]
114-
public override async Task<IActionResult> DeleteRelationshipAsync([Required] TId id, [Required] string relationshipName,
117+
public override async Task<IActionResult> DeleteRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
115118
[Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
116119
{
117120
return await base.DeleteRelationshipAsync(id, relationshipName, rightResourceIds, cancellationToken);

0 commit comments

Comments
 (0)