11using System ;
22using System . Net ;
33using JsonApiDotNetCore . Configuration ;
4- using JsonApiDotNetCore . Errors ;
54using JsonApiDotNetCore . Middleware ;
65using JsonApiDotNetCore . Resources ;
76using JsonApiDotNetCore . Resources . Annotations ;
@@ -34,75 +33,7 @@ protected ResourceIdentityAdapter(IResourceGraph resourceGraph, IResourceFactory
3433 ArgumentGuard . NotNull ( state , nameof ( state ) ) ;
3534
3635 ResourceContext resourceContext = ConvertType ( identity , requirements , state ) ;
37-
38- if ( state . Request . Kind != EndpointKind . AtomicOperations )
39- {
40- AssertHasNoLid ( identity , state ) ;
41- }
42-
43- AssertNoIdWithLid ( identity , state ) ;
44-
45- if ( requirements . IdConstraint == JsonElementConstraint . Required )
46- {
47- AssertHasIdOrLid ( identity , state ) ;
48- }
49- else if ( requirements . IdConstraint == JsonElementConstraint . Forbidden )
50- {
51- AssertHasNoId ( identity , state ) ;
52- }
53-
54- if ( requirements . IdValue != null && identity . Id != null && identity . Id != requirements . IdValue )
55- {
56- using ( state . Position . PushElement ( "id" ) )
57- {
58- if ( state . Request . Kind == EndpointKind . AtomicOperations )
59- {
60- throw new DeserializationException ( state . Position , "Resource ID mismatch between 'ref.id' and 'data.id' element." ,
61- $ "Expected resource with ID '{ requirements . IdValue } ' in 'data.id', instead of '{ identity . Id } '.") ;
62- }
63-
64- throw new JsonApiException ( new ErrorObject ( HttpStatusCode . Conflict )
65- {
66- Title = "Resource ID mismatch between request body and endpoint URL." ,
67- Detail = $ "Expected resource ID '{ requirements . IdValue } ', instead of '{ identity . Id } '.",
68- Source = new ErrorSource
69- {
70- Pointer = state . Position . ToSourcePointer ( )
71- }
72- } ) ;
73- }
74- }
75-
76- if ( requirements . LidValue != null && identity . Lid != null && identity . Lid != requirements . LidValue )
77- {
78- using ( state . Position . PushElement ( "lid" ) )
79- {
80- throw new DeserializationException ( state . Position , "Resource local ID mismatch between 'ref.lid' and 'data.lid' element." ,
81- $ "Expected resource with local ID '{ requirements . LidValue } ' in 'data.lid', instead of '{ identity . Lid } '.") ;
82- }
83- }
84-
85- if ( requirements . IdValue != null && identity . Lid != null )
86- {
87- using ( state . Position . PushElement ( "lid" ) )
88- {
89- throw new DeserializationException ( state . Position , "Resource identity mismatch between 'ref.id' and 'data.lid' element." ,
90- $ "Expected resource with ID '{ requirements . IdValue } ' in 'data.id', instead of '{ identity . Lid } ' in 'data.lid'.") ;
91- }
92- }
93-
94- if ( requirements . LidValue != null && identity . Id != null )
95- {
96- using ( state . Position . PushElement ( "id" ) )
97- {
98- throw new DeserializationException ( state . Position , "Resource identity mismatch between 'ref.lid' and 'data.id' element." ,
99- $ "Expected resource with local ID '{ requirements . LidValue } ' in 'data.lid', instead of '{ identity . Id } ' in 'data.id'.") ;
100- }
101- }
102-
103- IIdentifiable resource = _resourceFactory . CreateInstance ( resourceContext . ResourceType ) ;
104- AssignStringId ( identity , resource , state ) ;
105- resource . LocalId = identity . Lid ;
36+ IIdentifiable resource = CreateResource ( identity , requirements , resourceContext . ResourceType , state ) ;
10637
10738 return ( resource , resourceContext ) ;
10839 }
@@ -148,6 +79,34 @@ private static void AssertIsCompatibleResourceType(ResourceContext actual, Resou
14879 }
14980 }
15081
82+ private IIdentifiable CreateResource ( IResourceIdentity identity , ResourceIdentityRequirements requirements , Type resourceType ,
83+ RequestAdapterState state )
84+ {
85+ if ( state . Request . Kind != EndpointKind . AtomicOperations )
86+ {
87+ AssertHasNoLid ( identity , state ) ;
88+ }
89+
90+ AssertNoIdWithLid ( identity , state ) ;
91+
92+ if ( requirements . IdConstraint == JsonElementConstraint . Required )
93+ {
94+ AssertHasIdOrLid ( identity , requirements , state ) ;
95+ }
96+ else if ( requirements . IdConstraint == JsonElementConstraint . Forbidden )
97+ {
98+ AssertHasNoId ( identity , state ) ;
99+ }
100+
101+ AssertSameIdValue ( identity , requirements . IdValue , state ) ;
102+ AssertSameLidValue ( identity , requirements . LidValue , state ) ;
103+
104+ IIdentifiable resource = _resourceFactory . CreateInstance ( resourceType ) ;
105+ AssignStringId ( identity , resource , state ) ;
106+ resource . LocalId = identity . Lid ;
107+ return resource ;
108+ }
109+
151110 private static void AssertHasNoLid ( IResourceIdentity identity , RequestAdapterState state )
152111 {
153112 if ( identity . Lid != null )
@@ -165,14 +124,25 @@ private static void AssertNoIdWithLid(IResourceIdentity identity, RequestAdapter
165124 }
166125 }
167126
168- private static void AssertHasIdOrLid ( IResourceIdentity identity , RequestAdapterState state )
127+ private static void AssertHasIdOrLid ( IResourceIdentity identity , ResourceIdentityRequirements requirements , RequestAdapterState state )
169128 {
170- if ( identity . Id == null && identity . Lid == null )
129+ string message = null ;
130+
131+ if ( requirements . IdValue != null && identity . Id == null )
132+ {
133+ message = "The 'id' element is required." ;
134+ }
135+ else if ( requirements . LidValue != null && identity . Lid == null )
171136 {
172- string message = state . Request . Kind == EndpointKind . AtomicOperations
173- ? "The 'id' or 'lid' element is required."
174- : "The 'id' element is required." ;
137+ message = "The 'lid' element is required." ;
138+ }
139+ else if ( identity . Id == null && identity . Lid == null )
140+ {
141+ message = state . Request . Kind == EndpointKind . AtomicOperations ? "The 'id' or 'lid' element is required." : "The 'id' element is required." ;
142+ }
175143
144+ if ( message != null )
145+ {
176146 throw new ModelConversionException ( state . Position , message , null ) ;
177147 }
178148 }
@@ -186,18 +156,39 @@ private static void AssertHasNoId(IResourceIdentity identity, RequestAdapterStat
186156 }
187157 }
188158
189- private void AssignStringId ( IResourceIdentity identity , IIdentifiable resource , RequestAdapterState state )
159+ private static void AssertSameIdValue ( IResourceIdentity identity , string expected , RequestAdapterState state )
190160 {
191- if ( identity . Id != null )
161+ if ( expected != null && identity . Id != expected )
192162 {
193163 using IDisposable _ = state . Position . PushElement ( "id" ) ;
194164
165+ throw new ModelConversionException ( state . Position , "Conflicting 'id' values found." , $ "Expected '{ expected } ' instead of '{ identity . Id } '.",
166+ HttpStatusCode . Conflict ) ;
167+ }
168+ }
169+
170+ private static void AssertSameLidValue ( IResourceIdentity identity , string expected , RequestAdapterState state )
171+ {
172+ if ( expected != null && identity . Lid != expected )
173+ {
174+ using IDisposable _ = state . Position . PushElement ( "lid" ) ;
175+
176+ throw new ModelConversionException ( state . Position , "Conflicting 'lid' values found." , $ "Expected '{ expected } ' instead of '{ identity . Lid } '.",
177+ HttpStatusCode . Conflict ) ;
178+ }
179+ }
180+
181+ private void AssignStringId ( IResourceIdentity identity , IIdentifiable resource , RequestAdapterState state )
182+ {
183+ if ( identity . Id != null )
184+ {
195185 try
196186 {
197187 resource . StringId = identity . Id ;
198188 }
199189 catch ( FormatException exception )
200190 {
191+ using IDisposable _ = state . Position . PushElement ( "id" ) ;
201192 throw new DeserializationException ( state . Position , null , exception . Message ) ;
202193 }
203194 }
0 commit comments