Skip to content

Commit 977346d

Browse files
authored
Merge pull request #1583 from json-api-dotnet/use-disallownull-in-pipeline
Add [DisallowNull] on TId in pipeline parameters
2 parents ae5d0d1 + 3897ebd commit 977346d

26 files changed

+128
-95
lines changed

src/Examples/DapperExample/Repositories/DapperRepository.cs

+4-3
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

+7-6
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

+1-1
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

+1-1
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

+1-1
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

+1-1
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

+1-1
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

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using JsonApiDotNetCore.Configuration;
23
using JsonApiDotNetCore.Errors;
34
using JsonApiDotNetCore.Middleware;
@@ -108,7 +109,7 @@ public virtual async Task<IActionResult> GetAsync(CancellationToken cancellation
108109
/// GET /articles/1 HTTP/1.1
109110
/// ]]></code>
110111
/// </summary>
111-
public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken cancellationToken)
112+
public virtual async Task<IActionResult> GetAsync([DisallowNull] TId id, CancellationToken cancellationToken)
112113
{
113114
_traceWriter.LogMethodStart(new
114115
{
@@ -133,7 +134,7 @@ public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken canc
133134
/// GET /articles/1/revisions HTTP/1.1
134135
/// ]]></code>
135136
/// </summary>
136-
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)
137138
{
138139
_traceWriter.LogMethodStart(new
139140
{
@@ -162,7 +163,7 @@ public virtual async Task<IActionResult> GetSecondaryAsync(TId id, string relati
162163
/// GET /articles/1/relationships/revisions HTTP/1.1
163164
/// ]]></code>
164165
/// </summary>
165-
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)
166167
{
167168
_traceWriter.LogMethodStart(new
168169
{
@@ -246,8 +247,8 @@ private string GetLocationUrl(string resourceId)
246247
/// <param name="cancellationToken">
247248
/// Propagates notification that request handling should be canceled.
248249
/// </param>
249-
public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
250-
CancellationToken cancellationToken)
250+
public virtual async Task<IActionResult> PostRelationshipAsync([DisallowNull] TId id, string relationshipName,
251+
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
251252
{
252253
_traceWriter.LogMethodStart(new
253254
{
@@ -275,7 +276,7 @@ public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string re
275276
/// PATCH /articles/1 HTTP/1.1
276277
/// ]]></code>
277278
/// </summary>
278-
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)
279280
{
280281
_traceWriter.LogMethodStart(new
281282
{
@@ -321,7 +322,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource
321322
/// <param name="cancellationToken">
322323
/// Propagates notification that request handling should be canceled.
323324
/// </param>
324-
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,
325326
CancellationToken cancellationToken)
326327
{
327328
_traceWriter.LogMethodStart(new
@@ -348,7 +349,7 @@ public virtual async Task<IActionResult> PatchRelationshipAsync(TId id, string r
348349
/// DELETE /articles/1 HTTP/1.1
349350
/// ]]></code>
350351
/// </summary>
351-
public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken cancellationToken)
352+
public virtual async Task<IActionResult> DeleteAsync([DisallowNull] TId id, CancellationToken cancellationToken)
352353
{
353354
_traceWriter.LogMethodStart(new
354355
{
@@ -382,8 +383,8 @@ public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken c
382383
/// <param name="cancellationToken">
383384
/// Propagates notification that request handling should be canceled.
384385
/// </param>
385-
public virtual async Task<IActionResult> DeleteRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
386-
CancellationToken cancellationToken)
386+
public virtual async Task<IActionResult> DeleteRelationshipAsync([DisallowNull] TId id, string relationshipName,
387+
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
387388
{
388389
_traceWriter.LogMethodStart(new
389390
{

src/JsonApiDotNetCore/Controllers/JsonApiController.cs

+12-9
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);

src/JsonApiDotNetCore/Queries/IQueryLayerComposer.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using JsonApiDotNetCore.Configuration;
23
using JsonApiDotNetCore.Queries.Expressions;
34
using JsonApiDotNetCore.Resources;
@@ -18,7 +19,7 @@ public interface IQueryLayerComposer
1819
/// <summary>
1920
/// Builds a filter from constraints, used to determine total resource count on a secondary collection endpoint.
2021
/// </summary>
21-
FilterExpression? GetSecondaryFilterFromConstraints<TId>(TId primaryId, HasManyAttribute hasManyRelationship);
22+
FilterExpression? GetSecondaryFilterFromConstraints<TId>([DisallowNull] TId primaryId, HasManyAttribute hasManyRelationship);
2223

2324
/// <summary>
2425
/// Collects constraints and builds a <see cref="QueryLayer" /> out of them, used to retrieve the actual resources.
@@ -28,7 +29,7 @@ public interface IQueryLayerComposer
2829
/// <summary>
2930
/// Collects constraints and builds a <see cref="QueryLayer" /> out of them, used to retrieve one resource.
3031
/// </summary>
31-
QueryLayer ComposeForGetById<TId>(TId id, ResourceType primaryResourceType, TopFieldSelection fieldSelection);
32+
QueryLayer ComposeForGetById<TId>([DisallowNull] TId id, ResourceType primaryResourceType, TopFieldSelection fieldSelection);
3233

3334
/// <summary>
3435
/// Collects constraints and builds the secondary layer for a relationship endpoint.
@@ -38,14 +39,14 @@ public interface IQueryLayerComposer
3839
/// <summary>
3940
/// Wraps a layer for a secondary endpoint into a primary layer, rewriting top-level includes.
4041
/// </summary>
41-
QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, ResourceType primaryResourceType, TId primaryId,
42+
QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, ResourceType primaryResourceType, [DisallowNull] TId primaryId,
4243
RelationshipAttribute relationship);
4344

4445
/// <summary>
4546
/// Builds a query that retrieves the primary resource, including all of its attributes and all targeted relationships, during a create/update/delete
4647
/// request.
4748
/// </summary>
48-
QueryLayer ComposeForUpdate<TId>(TId id, ResourceType primaryResourceType);
49+
QueryLayer ComposeForUpdate<TId>([DisallowNull] TId id, ResourceType primaryResourceType);
4950

5051
/// <summary>
5152
/// Builds a query for each targeted relationship with a filter to match on its right resource IDs.
@@ -60,5 +61,5 @@ QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, Resourc
6061
/// <summary>
6162
/// Builds a query for a to-many relationship with a filter to match on its left and right resource IDs.
6263
/// </summary>
63-
QueryLayer ComposeForHasMany<TId>(HasManyAttribute hasManyRelationship, TId leftId, ICollection<IIdentifiable> rightResourceIds);
64+
QueryLayer ComposeForHasMany<TId>(HasManyAttribute hasManyRelationship, [DisallowNull] TId leftId, ICollection<IIdentifiable> rightResourceIds);
6465
}

0 commit comments

Comments
 (0)