8
8
using CommunityToolkit . Datasync . Client . Threading ;
9
9
using Microsoft . EntityFrameworkCore ;
10
10
using Microsoft . EntityFrameworkCore . ChangeTracking ;
11
+ using System . Net ;
11
12
using System . Reflection ;
12
13
using System . Text . Json ;
13
14
@@ -77,7 +78,7 @@ internal List<EntityEntry> GetChangedEntitiesInScope()
77
78
/// </summary>
78
79
/// <remarks>
79
80
/// An entity is "synchronization ready" if:
80
- ///
81
+ ///
81
82
/// * It is a property on this context
82
83
/// * The property is public and a <see cref="DbSet{TEntity}"/>.
83
84
/// * The property does not have a <see cref="DoNotSynchronizeAttribute"/> specified.
@@ -215,7 +216,7 @@ internal IEnumerable<Type> GetSynchronizableEntityTypes(IEnumerable<Type> allowe
215
216
/// </summary>
216
217
/// <remarks>
217
218
/// An entity is "synchronization ready" if:
218
- ///
219
+ ///
219
220
/// * It is a property on this context
220
221
/// * The property is public and a <see cref="DbSet{TEntity}"/>.
221
222
/// * The property does not have a <see cref="DoNotSynchronizeAttribute"/> specified.
@@ -299,7 +300,40 @@ internal async Task<PushResult> PushAsync(IEnumerable<Type> entityTypes, PushOpt
299
300
ExecutableOperation op = await ExecutableOperation . CreateAsync ( operation , cancellationToken ) . ConfigureAwait ( false ) ;
300
301
ServiceResponse response = await op . ExecuteAsync ( options , cancellationToken ) . ConfigureAwait ( false ) ;
301
302
302
- if ( ! response . IsSuccessful )
303
+ bool isSuccessful = response . IsSuccessful ;
304
+ if ( response . IsConflictStatusCode && options . ConflictResolver is not null )
305
+ {
306
+ object ? serverEntity = JsonSerializer . Deserialize ( response . ContentStream , entityType , DatasyncSerializer . JsonSerializerOptions ) ;
307
+ object ? clientEntity = JsonSerializer . Deserialize ( operation . Item , entityType , DatasyncSerializer . JsonSerializerOptions ) ;
308
+ ConflictResolution resolution = await options . ConflictResolver . ResolveConflictAsync ( clientEntity , serverEntity , cancellationToken ) . ConfigureAwait ( false ) ;
309
+
310
+ if ( resolution . Result is ConflictResolutionResult . Client )
311
+ {
312
+ operation . Item = JsonSerializer . Serialize ( resolution . Entity , entityType , DatasyncSerializer . JsonSerializerOptions ) ;
313
+ operation . State = OperationState . Pending ;
314
+ operation . LastAttempt = DateTimeOffset . UtcNow ;
315
+ operation . HttpStatusCode = response . StatusCode ;
316
+ operation . EntityVersion = string . Empty ; // Force the push
317
+ operation . Version ++ ;
318
+ _ = this . _context . Update ( operation ) ;
319
+ ExecutableOperation resolvedOp = await ExecutableOperation . CreateAsync ( operation , cancellationToken ) . ConfigureAwait ( false ) ;
320
+ response = await resolvedOp . ExecuteAsync ( options , cancellationToken ) . ConfigureAwait ( false ) ;
321
+ isSuccessful = response . IsSuccessful ;
322
+ }
323
+ else if ( resolution . Result is ConflictResolutionResult . Server )
324
+ {
325
+ lock ( this . pushlock )
326
+ {
327
+ operation . State = OperationState . Completed ; // Make it successful
328
+ operation . LastAttempt = DateTimeOffset . UtcNow ;
329
+ operation . HttpStatusCode = 200 ;
330
+ isSuccessful = true ;
331
+ _ = this . _context . Update ( operation ) ;
332
+ }
333
+ }
334
+ }
335
+
336
+ if ( ! isSuccessful )
303
337
{
304
338
lock ( this . pushlock )
305
339
{
@@ -315,6 +349,7 @@ internal async Task<PushResult> PushAsync(IEnumerable<Type> entityTypes, PushOpt
315
349
// If the operation is a success, then the content may need to be updated.
316
350
if ( operation . Kind != OperationKind . Delete )
317
351
{
352
+ _ = response . ContentStream . Seek ( 0L , SeekOrigin . Begin ) ; // Reset the memory stream to the beginning.
318
353
object ? newValue = JsonSerializer . Deserialize ( response . ContentStream , entityType , DatasyncSerializer . JsonSerializerOptions ) ;
319
354
object ? oldValue = await this . _context . FindAsync ( entityType , [ operation . ItemId ] , cancellationToken ) . ConfigureAwait ( false ) ;
320
355
ReplaceDatabaseValue ( oldValue , newValue ) ;
0 commit comments