Skip to content

Commit 525dac7

Browse files
author
Bart Koelman
committed
Rewrite of reading the request body and converting it into models.
The existing validation logic inside controllers, JsonApiReader and RequestDeserializer/BaseDeserializer has been consolidated into a set of adapters that delegate to each other, passing along the current state. The dependency on `HttpContext` has been removed and similar errors are now grouped, in preparation to unify them. Because in this commit we always track the location of errors and write them to `error.source.pointer`, the error messages can be unified and simplified in future commits. In this commit, I've gone through great lenghts to preserve the existing error messages in our tests as much as possible, while keeping all tests green. All error tests in ReadWrite and Operations now have assertions on the source pointer. Added tests for missing/invalid 'data' in resource requests. Removed outdated unit tests and added new one for handling attributes of various CLR types. Updated benchmark code. The synthetic BenchmarkDotNet reports it has become 3-7% slower (we're talking microseconds here) compared to the old code. But when running full requests with our pipeline-instrumentation turned on, the difference falls in the range of background noise and is thus unmeasurable. ``` BEFORE: Read request body ............................... 0:00:00:00.0000167 ... 1.08% } = 0:00:00:00.0000601 JsonSerializer.Deserialize .................... 0:00:00:00.0000560 ... 3.62% + Deserializer.Build (single) ................... 0:00:00:00.0000434 ... 2.80% } AFTER: Read request body ............................... 0:00:00:00.0000511 ... 3.43% JsonSerializer.Deserialize .................... 0:00:00:00.0000537 ... 3.61% ```
1 parent f773df6 commit 525dac7

File tree

88 files changed

+3091
-2477
lines changed

Some content is hidden

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

88 files changed

+3091
-2477
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.Design;
4+
using System.Text.Json;
5+
using JetBrains.Annotations;
6+
using JsonApiDotNetCore.Configuration;
7+
using JsonApiDotNetCore.Middleware;
8+
using JsonApiDotNetCore.Resources;
9+
using JsonApiDotNetCore.Resources.Annotations;
10+
using JsonApiDotNetCore.Serialization.JsonConverters;
11+
using JsonApiDotNetCore.Serialization.RequestAdapters;
12+
using Microsoft.Extensions.Logging.Abstractions;
13+
14+
namespace Benchmarks.Deserialization
15+
{
16+
public abstract class DeserializationBenchmarkBase
17+
{
18+
protected readonly JsonSerializerOptions SerializerReadOptions;
19+
protected readonly DocumentAdapter DocumentAdapter;
20+
21+
protected DeserializationBenchmarkBase()
22+
{
23+
var options = new JsonApiOptions();
24+
IResourceGraph resourceGraph = new ResourceGraphBuilder(options, NullLoggerFactory.Instance).Add<ResourceA>().Build();
25+
options.SerializerOptions.Converters.Add(new ResourceObjectConverter(resourceGraph));
26+
SerializerReadOptions = ((IJsonApiOptions)options).SerializerReadOptions;
27+
28+
var serviceContainer = new ServiceContainer();
29+
var resourceFactory = new ResourceFactory(serviceContainer);
30+
var resourceDefinitionAccessor = new ResourceDefinitionAccessor(resourceGraph, serviceContainer);
31+
32+
serviceContainer.AddService(typeof(IResourceDefinitionAccessor), resourceDefinitionAccessor);
33+
serviceContainer.AddService(typeof(IResourceDefinition<ResourceA>), new JsonApiResourceDefinition<ResourceA>(resourceGraph));
34+
35+
// ReSharper disable once VirtualMemberCallInConstructor
36+
JsonApiRequest request = CreateJsonApiRequest(resourceGraph);
37+
var targetedFields = new TargetedFields();
38+
39+
var resourceIdentifierObjectAdapter = new ResourceIdentifierObjectAdapter(resourceGraph, resourceFactory);
40+
var relationshipDataAdapter = new RelationshipDataAdapter(resourceGraph, resourceIdentifierObjectAdapter);
41+
var resourceObjectAdapter = new ResourceObjectAdapter(resourceGraph, resourceFactory, options, relationshipDataAdapter);
42+
var resourceDataAdapter = new ResourceDataAdapter(resourceDefinitionAccessor, resourceObjectAdapter);
43+
44+
var atomicReferenceAdapter = new AtomicReferenceAdapter(resourceGraph, resourceFactory);
45+
var atomicOperationResourceDataAdapter = new OperationResourceDataAdapter(resourceDefinitionAccessor, resourceObjectAdapter);
46+
47+
var atomicOperationObjectAdapter = new AtomicOperationObjectAdapter(resourceGraph, options, atomicReferenceAdapter,
48+
atomicOperationResourceDataAdapter, relationshipDataAdapter);
49+
50+
var resourceDocumentAdapter = new ResourceDocumentAdapter(options, resourceDataAdapter, relationshipDataAdapter);
51+
var operationsDocumentAdapter = new OperationsDocumentAdapter(options, atomicOperationObjectAdapter);
52+
53+
DocumentAdapter = new DocumentAdapter(request, targetedFields, resourceDocumentAdapter, operationsDocumentAdapter);
54+
}
55+
56+
protected abstract JsonApiRequest CreateJsonApiRequest(IResourceGraph resourceGraph);
57+
58+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
59+
public sealed class ResourceA : Identifiable
60+
{
61+
[Attr]
62+
public bool Attribute01 { get; set; }
63+
64+
[Attr]
65+
public char Attribute02 { get; set; }
66+
67+
[Attr]
68+
public ulong? Attribute03 { get; set; }
69+
70+
[Attr]
71+
public decimal Attribute04 { get; set; }
72+
73+
[Attr]
74+
public float? Attribute05 { get; set; }
75+
76+
[Attr]
77+
public string Attribute06 { get; set; }
78+
79+
[Attr]
80+
public DateTime? Attribute07 { get; set; }
81+
82+
[Attr]
83+
public DateTimeOffset? Attribute08 { get; set; }
84+
85+
[Attr]
86+
public TimeSpan? Attribute09 { get; set; }
87+
88+
[Attr]
89+
public DayOfWeek Attribute10 { get; set; }
90+
91+
[HasOne]
92+
public ResourceA Single1 { get; set; }
93+
94+
[HasOne]
95+
public ResourceA Single2 { get; set; }
96+
97+
[HasOne]
98+
public ResourceA Single3 { get; set; }
99+
100+
[HasOne]
101+
public ResourceA Single4 { get; set; }
102+
103+
[HasOne]
104+
public ResourceA Single5 { get; set; }
105+
106+
[HasMany]
107+
public ISet<ResourceA> Multi1 { get; set; }
108+
109+
[HasMany]
110+
public ISet<ResourceA> Multi2 { get; set; }
111+
112+
[HasMany]
113+
public ISet<ResourceA> Multi3 { get; set; }
114+
115+
[HasMany]
116+
public ISet<ResourceA> Multi4 { get; set; }
117+
118+
[HasMany]
119+
public ISet<ResourceA> Multi5 { get; set; }
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)