Skip to content

Commit 3a387cb

Browse files
author
Bart Koelman
committed
Enhanced rendering of error.source.pointer on ModelState validation errors
1 parent 4c9d0f9 commit 3a387cb

File tree

104 files changed

+777
-362
lines changed

Some content is hidden

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

104 files changed

+777
-362
lines changed

CSharpGuidelinesAnalyzer.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<cSharpGuidelinesAnalyzerSettings>
33
<setting rule="AV1561" name="MaxParameterCount" value="6" />
4-
<setting rule="AV1561" name="MaxConstructorParameterCount" value="12" />
4+
<setting rule="AV1561" name="MaxConstructorParameterCount" value="13" />
55
</cSharpGuidelinesAnalyzerSettings>

docs/getting-started/step-by-step.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ where `TResource` is the model that inherits from `Identifiable<TId>`.
6969
```c#
7070
public class PeopleController : JsonApiController<Person, int>
7171
{
72-
public PeopleController(IJsonApiOptions options, ILoggerFactory loggerFactory,
73-
IResourceService<Person, int> resourceService)
74-
: base(options, loggerFactory, resourceService)
72+
public PeopleController(IJsonApiOptions options, IResourceGraph resourceGraph,
73+
ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
74+
: base(options, resourceGraph, loggerFactory, resourceService)
7575
{
7676
}
7777
}

docs/usage/extensibility/controllers.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ You need to create controllers that inherit from `JsonApiController<TResource, T
55
```c#
66
public class ArticlesController : JsonApiController<Article, Guid>
77
{
8-
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
9-
IResourceService<Article, Guid> resourceService)
10-
: base(options, loggerFactory, resourceService)
8+
public ArticlesController(IJsonApiOptions options, IResourceGraph resourceGraph,
9+
ILoggerFactory loggerFactory, IResourceService<Article, Guid> resourceService)
10+
: base(options, resourceGraph, loggerFactory, resourceService)
1111
{
1212
}
1313
}
@@ -24,9 +24,9 @@ This approach is ok, but introduces some boilerplate that can easily be avoided.
2424
```c#
2525
public class ArticlesController : BaseJsonApiController<Article, int>
2626
{
27-
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
28-
IResourceService<Article, int> resourceService)
29-
: base(options, loggerFactory, resourceService)
27+
public ArticlesController(IJsonApiOptions options, IResourceGraph resourceGraph,
28+
ILoggerFactory loggerFactory, IResourceService<Article, int> resourceService)
29+
: base(options, resourceGraph, loggerFactory, resourceService)
3030
{
3131
}
3232

@@ -61,9 +61,9 @@ An attempt to use one of the blacklisted methods will result in a HTTP 405 Metho
6161
[HttpReadOnly]
6262
public class ArticlesController : BaseJsonApiController<Article, int>
6363
{
64-
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
65-
IResourceService<Article, int> resourceService)
66-
: base(options, loggerFactory, resourceService)
64+
public ArticlesController(IJsonApiOptions options, IResourceGraph resourceGraph,
65+
ILoggerFactory loggerFactory, IResourceService<Article, int> resourceService)
66+
: base(options, resourceGraph, loggerFactory, resourceService)
6767
{
6868
}
6969
}
@@ -80,9 +80,9 @@ For more information about resource service injection, see [Replacing injected s
8080
```c#
8181
public class ReportsController : BaseJsonApiController<Report, int>
8282
{
83-
public ReportsController(IJsonApiOptions options, ILoggerFactory loggerFactory,
84-
IGetAllService<Report, int> getAllService)
85-
: base(options, loggerFactory, getAllService)
83+
public ReportsController(IJsonApiOptions options, IResourceGraph resourceGraph,
84+
ILoggerFactory loggerFactory, IGetAllService<Report, int> getAllService)
85+
: base(options, resourceGraph, loggerFactory, getAllService)
8686
{
8787
}
8888

docs/usage/extensibility/services.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,10 @@ Then in the controller, you should inherit from the base controller and pass the
156156
```c#
157157
public class ArticlesController : BaseJsonApiController<Article, int>
158158
{
159-
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
160-
ICreateService<Article, int> create, IDeleteService<Article, int> delete)
161-
: base(options, loggerFactory, create: create, delete: delete)
159+
public ArticlesController(IJsonApiOptions options, IResourceGraph resourceGraph,
160+
ILoggerFactory loggerFactory, ICreateService<Article, int> create,
161+
IDeleteService<Article, int> delete)
162+
: base(options, resourceGraph, loggerFactory, create: create, delete: delete)
162163
{
163164
}
164165

docs/usage/routing.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public class OrderLine : Identifiable<int>
2929

3030
public class OrderLineController : JsonApiController<OrderLine, int>
3131
{
32-
public OrderLineController(IJsonApiOptions options, ILoggerFactory loggerFactory,
33-
IResourceService<OrderLine, int> resourceService)
34-
: base(options, loggerFactory, resourceService)
32+
public OrderLineController(IJsonApiOptions options, IResourceGraph resourceGraph,
33+
ILoggerFactory loggerFactory, IResourceService<OrderLine, int> resourceService)
34+
: base(options, resourceGraph, loggerFactory, resourceService)
3535
{
3636
}
3737
}
@@ -65,9 +65,9 @@ It is possible to bypass the default routing convention for a controller.
6565
[Route("v1/custom/route/lines-in-order"), DisableRoutingConvention]
6666
public class OrderLineController : JsonApiController<OrderLine, int>
6767
{
68-
public OrderLineController(IJsonApiOptions options, ILoggerFactory loggerFactory,
69-
IResourceService<OrderLine, int> resourceService)
70-
: base(options, loggerFactory, resourceService)
68+
public OrderLineController(IJsonApiOptions options, IResourceGraph resourceGraph,
69+
ILoggerFactory loggerFactory, IResourceService<OrderLine, int> resourceService)
70+
: base(options, resourceGraph, loggerFactory, resourceService)
7171
{
7272
}
7373
}

docs/usage/writing/bulk-batch-operations.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ To enable operations, add a controller to your project that inherits from `JsonA
1717
```c#
1818
public sealed class OperationsController : JsonApiOperationsController
1919
{
20-
public OperationsController(IJsonApiOptions options, ILoggerFactory loggerFactory,
21-
IOperationsProcessor processor, IJsonApiRequest request,
22-
ITargetedFields targetedFields)
23-
: base(options, loggerFactory, processor, request, targetedFields)
20+
public OperationsController(IJsonApiOptions options, IResourceGraph resourceGraph,
21+
ILoggerFactory loggerFactory, IOperationsProcessor processor,
22+
IJsonApiRequest request, ITargetedFields targetedFields)
23+
: base(options, resourceGraph, loggerFactory, processor, request, targetedFields)
2424
{
2525
}
2626
}

src/Examples/GettingStarted/Controllers/BooksController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace GettingStarted.Controllers
88
{
99
public sealed class BooksController : JsonApiController<Book, int>
1010
{
11-
public BooksController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<Book, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public BooksController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<Book, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/GettingStarted/Controllers/PeopleController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace GettingStarted.Controllers
88
{
99
public sealed class PeopleController : JsonApiController<Person, int>
1010
{
11-
public PeopleController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public PeopleController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/JsonApiDotNetCoreExample/Controllers/OperationsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ namespace JsonApiDotNetCoreExample.Controllers
99
{
1010
public sealed class OperationsController : JsonApiOperationsController
1111
{
12-
public OperationsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
12+
public OperationsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
1313
ITargetedFields targetedFields)
14-
: base(options, loggerFactory, processor, request, targetedFields)
14+
: base(options, resourceGraph, loggerFactory, processor, request, targetedFields)
1515
{
1616
}
1717
}

src/Examples/JsonApiDotNetCoreExample/Controllers/PeopleController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace JsonApiDotNetCoreExample.Controllers
88
{
99
public sealed class PeopleController : JsonApiController<Person, int>
1010
{
11-
public PeopleController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public PeopleController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/JsonApiDotNetCoreExample/Controllers/TagsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace JsonApiDotNetCoreExample.Controllers
88
{
99
public sealed class TagsController : JsonApiController<Tag, int>
1010
{
11-
public TagsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<Tag, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public TagsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<Tag, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/JsonApiDotNetCoreExample/Controllers/TodoItemsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace JsonApiDotNetCoreExample.Controllers
88
{
99
public sealed class TodoItemsController : JsonApiController<TodoItem, int>
1010
{
11-
public TodoItemsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<TodoItem, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public TodoItemsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<TodoItem, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/MultiDbContextExample/Controllers/ResourceAsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace MultiDbContextExample.Controllers
88
{
99
public sealed class ResourceAsController : JsonApiController<ResourceA, int>
1010
{
11-
public ResourceAsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<ResourceA, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public ResourceAsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<ResourceA, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/MultiDbContextExample/Controllers/ResourceBsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace MultiDbContextExample.Controllers
88
{
99
public sealed class ResourceBsController : JsonApiController<ResourceB, int>
1010
{
11-
public ResourceBsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<ResourceB, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public ResourceBsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<ResourceB, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/NoEntityFrameworkExample/Controllers/WorkItemsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace NoEntityFrameworkExample.Controllers
88
{
99
public sealed class WorkItemsController : JsonApiController<WorkItem, int>
1010
{
11-
public WorkItemsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<WorkItem, int> resourceService)
12-
: base(options, loggerFactory, resourceService)
11+
public WorkItemsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<WorkItem, int> resourceService)
12+
: base(options, resourceGraph, loggerFactory, resourceService)
1313
{
1414
}
1515
}

src/Examples/ReportsExample/Controllers/ReportsController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ namespace ReportsExample.Controllers
1212
[Route("api/[controller]")]
1313
public class ReportsController : BaseJsonApiController<Report, int>
1414
{
15-
public ReportsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IGetAllService<Report, int> getAllService)
16-
: base(options, loggerFactory, getAllService)
15+
public ReportsController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IGetAllService<Report, int> getAllService)
16+
: base(options, resourceGraph, loggerFactory, getAllService)
1717
{
1818
}
1919

src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public abstract class BaseJsonApiController<TResource, TId> : CoreJsonApiControl
2525
where TResource : class, IIdentifiable<TId>
2626
{
2727
private readonly IJsonApiOptions _options;
28+
private readonly IResourceGraph _resourceGraph;
2829
private readonly IGetAllService<TResource, TId>? _getAll;
2930
private readonly IGetByIdService<TResource, TId>? _getById;
3031
private readonly IGetSecondaryService<TResource, TId>? _getSecondary;
@@ -40,35 +41,37 @@ public abstract class BaseJsonApiController<TResource, TId> : CoreJsonApiControl
4041
/// <summary>
4142
/// Creates an instance from a read/write service.
4243
/// </summary>
43-
protected BaseJsonApiController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService<TResource, TId> resourceService)
44-
: this(options, loggerFactory, resourceService, resourceService)
44+
protected BaseJsonApiController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<TResource, TId> resourceService)
45+
: this(options, resourceGraph, loggerFactory, resourceService, resourceService)
4546
{
4647
}
4748

4849
/// <summary>
4950
/// Creates an instance from separate services for reading and writing.
5051
/// </summary>
51-
protected BaseJsonApiController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceQueryService<TResource, TId>? queryService = null,
52+
protected BaseJsonApiController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceQueryService<TResource, TId>? queryService = null,
5253
IResourceCommandService<TResource, TId>? commandService = null)
53-
: this(options, loggerFactory, queryService, queryService, queryService, queryService, commandService, commandService, commandService,
54+
: this(options, resourceGraph, loggerFactory, queryService, queryService, queryService, queryService, commandService, commandService, commandService,
5455
commandService, commandService, commandService)
5556
{
5657
}
5758

5859
/// <summary>
5960
/// Creates an instance from separate services for the various individual read and write methods.
6061
/// </summary>
61-
protected BaseJsonApiController(IJsonApiOptions options, ILoggerFactory loggerFactory, IGetAllService<TResource, TId>? getAll = null,
62+
protected BaseJsonApiController(IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IGetAllService<TResource, TId>? getAll = null,
6263
IGetByIdService<TResource, TId>? getById = null, IGetSecondaryService<TResource, TId>? getSecondary = null,
6364
IGetRelationshipService<TResource, TId>? getRelationship = null, ICreateService<TResource, TId>? create = null,
6465
IAddToRelationshipService<TResource, TId>? addToRelationship = null, IUpdateService<TResource, TId>? update = null,
6566
ISetRelationshipService<TResource, TId>? setRelationship = null, IDeleteService<TResource, TId>? delete = null,
6667
IRemoveFromRelationshipService<TResource, TId>? removeFromRelationship = null)
6768
{
6869
ArgumentGuard.NotNull(options, nameof(options));
70+
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
6971
ArgumentGuard.NotNull(loggerFactory, nameof(loggerFactory));
7072

7173
_options = options;
74+
_resourceGraph = resourceGraph;
7275
_traceWriter = new TraceLogWriter<BaseJsonApiController<TResource, TId>>(loggerFactory);
7376
_getAll = getAll;
7477
_getById = getById;
@@ -184,8 +187,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] TResource resource
184187

185188
if (_options.ValidateModelState && !ModelState.IsValid)
186189
{
187-
throw new InvalidModelStateException(ModelState, typeof(TResource), _options.IncludeExceptionStackTraceInErrors,
188-
_options.SerializerOptions.PropertyNamingPolicy);
190+
throw new InvalidModelStateException(ModelState, typeof(TResource), _options.IncludeExceptionStackTraceInErrors, _resourceGraph);
189191
}
190192

191193
TResource? newResource = await _create.CreateAsync(resource, cancellationToken);
@@ -261,8 +263,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource
261263

262264
if (_options.ValidateModelState && !ModelState.IsValid)
263265
{
264-
throw new InvalidModelStateException(ModelState, typeof(TResource), _options.IncludeExceptionStackTraceInErrors,
265-
_options.SerializerOptions.PropertyNamingPolicy);
266+
throw new InvalidModelStateException(ModelState, typeof(TResource), _options.IncludeExceptionStackTraceInErrors, _resourceGraph);
266267
}
267268

268269
TResource? updated = await _update.UpdateAsync(id, resource, cancellationToken);

0 commit comments

Comments
 (0)