3
3
using System . IO ;
4
4
using System . Threading . Tasks ;
5
5
using JsonApiDotNetCore . Exceptions ;
6
+ using JsonApiDotNetCore . Managers . Contracts ;
6
7
using JsonApiDotNetCore . Models ;
7
8
using JsonApiDotNetCore . Serialization . Server ;
8
9
using Microsoft . AspNetCore . Http . Extensions ;
@@ -15,12 +16,15 @@ namespace JsonApiDotNetCore.Formatters
15
16
public class JsonApiReader : IJsonApiReader
16
17
{
17
18
private readonly IJsonApiDeserializer _deserializer ;
19
+ private readonly ICurrentRequest _currentRequest ;
18
20
private readonly ILogger < JsonApiReader > _logger ;
19
21
20
22
public JsonApiReader ( IJsonApiDeserializer deserializer ,
21
- ILoggerFactory loggerFactory )
23
+ ICurrentRequest currentRequest ,
24
+ ILoggerFactory loggerFactory )
22
25
{
23
26
_deserializer = deserializer ;
27
+ _currentRequest = currentRequest ;
24
28
_logger = loggerFactory . CreateLogger < JsonApiReader > ( ) ;
25
29
}
26
30
@@ -57,46 +61,56 @@ public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
57
61
58
62
if ( context . HttpContext . Request . Method == "PATCH" )
59
63
{
60
- var hasMissingId = model is IList list ? CheckForId ( list ) : CheckForId ( model ) ;
64
+ bool hasMissingId = model is IList list ? HasMissingId ( list ) : HasMissingId ( model ) ;
61
65
if ( hasMissingId )
62
66
{
63
67
throw new InvalidRequestBodyException ( "Payload must include id attribute." , null , body ) ;
64
68
}
69
+
70
+ if ( ! _currentRequest . IsRelationshipPath && TryGetId ( model , out var bodyId ) && bodyId != _currentRequest . BaseId )
71
+ {
72
+ throw new ResourceIdMismatchException ( bodyId , _currentRequest . BaseId , context . HttpContext . Request . GetDisplayUrl ( ) ) ;
73
+ }
65
74
}
66
75
67
76
return await InputFormatterResult . SuccessAsync ( model ) ;
68
77
}
69
78
70
79
/// <summary> Checks if the deserialized payload has an ID included </summary>
71
- private bool CheckForId ( object model )
80
+ private bool HasMissingId ( object model )
72
81
{
73
- if ( model == null ) return false ;
74
- if ( model is ResourceObject ro )
75
- {
76
- if ( string . IsNullOrEmpty ( ro . Id ) ) return true ;
77
- }
78
- else if ( model is IIdentifiable identifiable )
82
+ return TryGetId ( model , out string id ) && string . IsNullOrEmpty ( id ) ;
83
+ }
84
+
85
+ /// <summary> Checks if all elements in the deserialized payload have an ID included </summary>
86
+ private bool HasMissingId ( IEnumerable models )
87
+ {
88
+ foreach ( var model in models )
79
89
{
80
- if ( string . IsNullOrEmpty ( identifiable . StringId ) ) return true ;
90
+ if ( TryGetId ( model , out string id ) && string . IsNullOrEmpty ( id ) )
91
+ {
92
+ return true ;
93
+ }
81
94
}
95
+
82
96
return false ;
83
97
}
84
98
85
- /// <summary> Checks if the elements in the deserialized payload have an ID included </summary>
86
- private bool CheckForId ( IList modelList )
99
+ private static bool TryGetId ( object model , out string id )
87
100
{
88
- foreach ( var model in modelList )
101
+ if ( model is ResourceObject resourceObject )
89
102
{
90
- if ( model == null ) continue ;
91
- if ( model is ResourceObject ro )
92
- {
93
- if ( string . IsNullOrEmpty ( ro . Id ) ) return true ;
94
- }
95
- else if ( model is IIdentifiable identifiable )
96
- {
97
- if ( string . IsNullOrEmpty ( identifiable . StringId ) ) return true ;
98
- }
103
+ id = resourceObject . Id ;
104
+ return true ;
99
105
}
106
+
107
+ if ( model is IIdentifiable identifiable )
108
+ {
109
+ id = identifiable . StringId ;
110
+ return true ;
111
+ }
112
+
113
+ id = null ;
100
114
return false ;
101
115
}
102
116
0 commit comments