Skip to content

Commit d8510aa

Browse files
author
Bart Koelman
committed
Rewrite of rendering the response body from models
- Added temporary bridge class to toggle between old/new code - Fixed: Missing top-level link in error- and operations response - Fixed: `ILinkBuilder.GetResourceLinks` was also used to render relationship links - IJsonApiRequest management: restore backup after processing operations - Refreshed serialization benchmarks Measurement results for GET http://localhost:14140/api/v1/todoItems?include=owner,assignee,tags: Write response body ............................ 0:00:00:00.0010385 -> 0:00:00:00.0013343 = 130% Measurement results for GET http://localhost:14140/api/v1/todoItems?filter=and(startsWith(description,'T'),equals(priority,'Low'),not(equals(owner,null)),not(equals(assignee,null))): Write response body ............................ 0:00:00:00.0006601 -> 0:00:00:00.0004624 = 70% Measurement results for POST http://localhost:14140/api/v1/operations (10x add-resource): Write response body ............................ 0:00:00:00.0003432 -> 0:00:00:00.0003289 = 95% | Method | Mean | Error | StdDev | |---------------------------------- |---------:|--------:|--------:| | SerializeOperationsResponse | 153.8 us | 0.72 us | 0.60 us | | LegacySerializeOperationsResponse | 239.0 us | 3.17 us | 2.81 us | | Method | Mean | Error | StdDev | |-------------------------------- |---------:|--------:|--------:| | SerializeResourceResponse | 101.3 us | 0.31 us | 0.29 us | | LegacySerializeResourceResponse | 177.6 us | 0.56 us | 0.50 us |
1 parent cab3dc6 commit d8510aa

24 files changed

+1194
-124
lines changed

benchmarks/LinkBuilder/LinkBuilderGetNamespaceFromPathBenchmarks.cs renamed to benchmarks/LinkBuilding/LinkBuilderGetNamespaceFromPathBenchmarks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Text;
33
using BenchmarkDotNet.Attributes;
44

5-
namespace Benchmarks.LinkBuilder
5+
namespace Benchmarks.LinkBuilding
66
{
77
// ReSharper disable once ClassCanBeSealed.Global
88
[MarkdownExporter]

benchmarks/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using BenchmarkDotNet.Running;
22
using Benchmarks.Deserialization;
3-
using Benchmarks.LinkBuilder;
3+
using Benchmarks.LinkBuilding;
44
using Benchmarks.Query;
55
using Benchmarks.Serialization;
66

@@ -14,7 +14,8 @@ private static void Main(string[] args)
1414
{
1515
typeof(ResourceDeserializationBenchmarks),
1616
typeof(OperationsDeserializationBenchmarks),
17-
typeof(JsonApiSerializerBenchmarks),
17+
typeof(ResourceSerializationBenchmarks),
18+
typeof(OperationsSerializationBenchmarks),
1819
typeof(QueryParserBenchmarks),
1920
typeof(LinkBuilderGetNamespaceFromPathBenchmarks)
2021
});

benchmarks/Serialization/JsonApiSerializerBenchmarks.cs

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.Json;
4+
using BenchmarkDotNet.Attributes;
5+
using JsonApiDotNetCore.Configuration;
6+
using JsonApiDotNetCore.Middleware;
7+
using JsonApiDotNetCore.Queries.Internal;
8+
using JsonApiDotNetCore.Resources;
9+
using JsonApiDotNetCore.Serialization.Objects;
10+
11+
namespace Benchmarks.Serialization
12+
{
13+
[MarkdownExporter]
14+
// ReSharper disable once ClassCanBeSealed.Global
15+
public class OperationsSerializationBenchmarks : SerializationBenchmarkBase
16+
{
17+
private readonly IEnumerable<OperationContainer> _responseOperations;
18+
19+
public OperationsSerializationBenchmarks()
20+
{
21+
// ReSharper disable once VirtualMemberCallInConstructor
22+
JsonApiRequest request = CreateJsonApiRequest(ResourceGraph);
23+
24+
_responseOperations = CreateResponseOperations(request);
25+
}
26+
27+
private static IEnumerable<OperationContainer> CreateResponseOperations(IJsonApiRequest request)
28+
{
29+
var resource1 = new ResourceA
30+
{
31+
Id = 1,
32+
Attribute01 = true,
33+
Attribute02 = 'A',
34+
Attribute03 = 100UL,
35+
Attribute04 = 100.001m,
36+
Attribute05 = 100.002f,
37+
Attribute06 = "text1",
38+
Attribute07 = new DateTime(2001, 1, 1),
39+
Attribute08 = new DateTimeOffset(2001, 1, 1, 0, 0, 0, TimeSpan.FromHours(1)),
40+
Attribute09 = new TimeSpan(1, 0, 0),
41+
Attribute10 = DayOfWeek.Sunday
42+
};
43+
44+
var resource2 = new ResourceA
45+
{
46+
Id = 2,
47+
Attribute01 = false,
48+
Attribute02 = 'B',
49+
Attribute03 = 200UL,
50+
Attribute04 = 200.001m,
51+
Attribute05 = 200.002f,
52+
Attribute06 = "text2",
53+
Attribute07 = new DateTime(2002, 2, 2),
54+
Attribute08 = new DateTimeOffset(2002, 2, 2, 0, 0, 0, TimeSpan.FromHours(2)),
55+
Attribute09 = new TimeSpan(2, 0, 0),
56+
Attribute10 = DayOfWeek.Monday
57+
};
58+
59+
var resource3 = new ResourceA
60+
{
61+
Id = 3,
62+
Attribute01 = true,
63+
Attribute02 = 'C',
64+
Attribute03 = 300UL,
65+
Attribute04 = 300.001m,
66+
Attribute05 = 300.002f,
67+
Attribute06 = "text3",
68+
Attribute07 = new DateTime(2003, 3, 3),
69+
Attribute08 = new DateTimeOffset(2003, 3, 3, 0, 0, 0, TimeSpan.FromHours(3)),
70+
Attribute09 = new TimeSpan(3, 0, 0),
71+
Attribute10 = DayOfWeek.Tuesday
72+
};
73+
74+
var resource4 = new ResourceA
75+
{
76+
Id = 4,
77+
Attribute01 = false,
78+
Attribute02 = 'D',
79+
Attribute03 = 400UL,
80+
Attribute04 = 400.001m,
81+
Attribute05 = 400.002f,
82+
Attribute06 = "text4",
83+
Attribute07 = new DateTime(2004, 4, 4),
84+
Attribute08 = new DateTimeOffset(2004, 4, 4, 0, 0, 0, TimeSpan.FromHours(4)),
85+
Attribute09 = new TimeSpan(4, 0, 0),
86+
Attribute10 = DayOfWeek.Wednesday
87+
};
88+
89+
var resource5 = new ResourceA
90+
{
91+
Id = 5,
92+
Attribute01 = true,
93+
Attribute02 = 'E',
94+
Attribute03 = 500UL,
95+
Attribute04 = 500.001m,
96+
Attribute05 = 500.002f,
97+
Attribute06 = "text5",
98+
Attribute07 = new DateTime(2005, 5, 5),
99+
Attribute08 = new DateTimeOffset(2005, 5, 5, 0, 0, 0, TimeSpan.FromHours(5)),
100+
Attribute09 = new TimeSpan(5, 0, 0),
101+
Attribute10 = DayOfWeek.Thursday
102+
};
103+
104+
var targetedFields = new TargetedFields();
105+
106+
return new List<OperationContainer>
107+
{
108+
new(resource1, targetedFields, request),
109+
new(resource2, targetedFields, request),
110+
new(resource3, targetedFields, request),
111+
new(resource4, targetedFields, request),
112+
new(resource5, targetedFields, request)
113+
};
114+
}
115+
116+
[Benchmark]
117+
public string SerializeOperationsResponse()
118+
{
119+
(Document responseDocument, _) = ResponseModelAdapter.Convert(_responseOperations);
120+
return JsonSerializer.Serialize(responseDocument, SerializerWriteOptions);
121+
}
122+
123+
[Benchmark]
124+
public string LegacySerializeOperationsResponse()
125+
{
126+
return JsonApiOperationsSerializer.Serialize(_responseOperations);
127+
}
128+
129+
protected override JsonApiRequest CreateJsonApiRequest(IResourceGraph resourceGraph)
130+
{
131+
return new JsonApiRequest
132+
{
133+
Kind = EndpointKind.AtomicOperations,
134+
PrimaryResource = resourceGraph.GetResourceContext<ResourceA>()
135+
};
136+
}
137+
138+
protected override IEvaluatedIncludeCache CreateEvaluatedIncludeCache(IResourceGraph resourceGraph)
139+
{
140+
return new EvaluatedIncludeCache();
141+
}
142+
}
143+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.Immutable;
4+
using System.Text.Json;
5+
using BenchmarkDotNet.Attributes;
6+
using JsonApiDotNetCore;
7+
using JsonApiDotNetCore.Configuration;
8+
using JsonApiDotNetCore.Middleware;
9+
using JsonApiDotNetCore.Queries.Expressions;
10+
using JsonApiDotNetCore.Queries.Internal;
11+
using JsonApiDotNetCore.Resources.Annotations;
12+
using JsonApiDotNetCore.Serialization.Objects;
13+
14+
namespace Benchmarks.Serialization
15+
{
16+
[MarkdownExporter]
17+
// ReSharper disable once ClassCanBeSealed.Global
18+
public class ResourceSerializationBenchmarks : SerializationBenchmarkBase
19+
{
20+
private static readonly ResourceA ResponseResource = CreateResponseResource();
21+
22+
private static ResourceA CreateResponseResource()
23+
{
24+
var resource1 = new ResourceA
25+
{
26+
Id = 1,
27+
Attribute01 = true,
28+
Attribute02 = 'A',
29+
Attribute03 = 100UL,
30+
Attribute04 = 100.001m,
31+
Attribute05 = 100.002f,
32+
Attribute06 = "text1",
33+
Attribute07 = new DateTime(2001, 1, 1),
34+
Attribute08 = new DateTimeOffset(2001, 1, 1, 0, 0, 0, TimeSpan.FromHours(1)),
35+
Attribute09 = new TimeSpan(1, 0, 0),
36+
Attribute10 = DayOfWeek.Sunday
37+
};
38+
39+
var resource2 = new ResourceA
40+
{
41+
Id = 2,
42+
Attribute01 = false,
43+
Attribute02 = 'B',
44+
Attribute03 = 200UL,
45+
Attribute04 = 200.001m,
46+
Attribute05 = 200.002f,
47+
Attribute06 = "text2",
48+
Attribute07 = new DateTime(2002, 2, 2),
49+
Attribute08 = new DateTimeOffset(2002, 2, 2, 0, 0, 0, TimeSpan.FromHours(2)),
50+
Attribute09 = new TimeSpan(2, 0, 0),
51+
Attribute10 = DayOfWeek.Monday
52+
};
53+
54+
var resource3 = new ResourceA
55+
{
56+
Id = 3,
57+
Attribute01 = true,
58+
Attribute02 = 'C',
59+
Attribute03 = 300UL,
60+
Attribute04 = 300.001m,
61+
Attribute05 = 300.002f,
62+
Attribute06 = "text3",
63+
Attribute07 = new DateTime(2003, 3, 3),
64+
Attribute08 = new DateTimeOffset(2003, 3, 3, 0, 0, 0, TimeSpan.FromHours(3)),
65+
Attribute09 = new TimeSpan(3, 0, 0),
66+
Attribute10 = DayOfWeek.Tuesday
67+
};
68+
69+
var resource4 = new ResourceA
70+
{
71+
Id = 4,
72+
Attribute01 = false,
73+
Attribute02 = 'D',
74+
Attribute03 = 400UL,
75+
Attribute04 = 400.001m,
76+
Attribute05 = 400.002f,
77+
Attribute06 = "text4",
78+
Attribute07 = new DateTime(2004, 4, 4),
79+
Attribute08 = new DateTimeOffset(2004, 4, 4, 0, 0, 0, TimeSpan.FromHours(4)),
80+
Attribute09 = new TimeSpan(4, 0, 0),
81+
Attribute10 = DayOfWeek.Wednesday
82+
};
83+
84+
var resource5 = new ResourceA
85+
{
86+
Id = 5,
87+
Attribute01 = true,
88+
Attribute02 = 'E',
89+
Attribute03 = 500UL,
90+
Attribute04 = 500.001m,
91+
Attribute05 = 500.002f,
92+
Attribute06 = "text5",
93+
Attribute07 = new DateTime(2005, 5, 5),
94+
Attribute08 = new DateTimeOffset(2005, 5, 5, 0, 0, 0, TimeSpan.FromHours(5)),
95+
Attribute09 = new TimeSpan(5, 0, 0),
96+
Attribute10 = DayOfWeek.Thursday
97+
};
98+
99+
resource1.Single2 = resource2;
100+
resource2.Single3 = resource3;
101+
resource3.Multi4 = resource4.AsHashSet();
102+
resource4.Multi5 = resource5.AsHashSet();
103+
104+
return resource1;
105+
}
106+
107+
[Benchmark]
108+
public string SerializeResourceResponse()
109+
{
110+
(Document responseDocument, _) = ResponseModelAdapter.Convert(ResponseResource);
111+
return JsonSerializer.Serialize(responseDocument, SerializerWriteOptions);
112+
}
113+
114+
[Benchmark]
115+
public string LegacySerializeResourceResponse()
116+
{
117+
return JsonApiResourceSerializer.Serialize(ResponseResource);
118+
}
119+
120+
protected override JsonApiRequest CreateJsonApiRequest(IResourceGraph resourceGraph)
121+
{
122+
return new JsonApiRequest
123+
{
124+
Kind = EndpointKind.Primary,
125+
PrimaryResource = resourceGraph.GetResourceContext<ResourceA>()
126+
};
127+
}
128+
129+
protected override IEvaluatedIncludeCache CreateEvaluatedIncludeCache(IResourceGraph resourceGraph)
130+
{
131+
ResourceContext resourceContext = resourceGraph.GetResourceContext<ResourceA>();
132+
133+
RelationshipAttribute single2 = resourceContext.GetRelationshipByPropertyName(nameof(ResourceA.Single2));
134+
RelationshipAttribute single3 = resourceContext.GetRelationshipByPropertyName(nameof(ResourceA.Single3));
135+
RelationshipAttribute multi4 = resourceContext.GetRelationshipByPropertyName(nameof(ResourceA.Multi4));
136+
RelationshipAttribute multi5 = resourceContext.GetRelationshipByPropertyName(nameof(ResourceA.Multi5));
137+
138+
ImmutableArray<ResourceFieldAttribute> chain = ArrayFactory.Create<ResourceFieldAttribute>(single2, single3, multi4, multi5).ToImmutableArray();
139+
IEnumerable<ResourceFieldChainExpression> chains = new ResourceFieldChainExpression(chain).AsEnumerable();
140+
141+
var converter = new IncludeChainConverter();
142+
IncludeExpression include = converter.FromRelationshipChains(chains);
143+
144+
var cache = new EvaluatedIncludeCache();
145+
cache.Set(include);
146+
return cache;
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)