Skip to content

Commit 39e741f

Browse files
committed
No .NET->JS web root component sync anymore
1 parent 67b5257 commit 39e741f

20 files changed

+199
-239
lines changed

src/Components/Server/src/Circuits/CircuitHost.cs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -785,12 +785,11 @@ internal Task UpdateRootComponents(
785785
{
786786
case RootComponentOperationType.Add:
787787
{
788-
var selectorId = operation.SelectorId.Value.ToString(CultureInfo.InvariantCulture);
789788
var task = webRootComponentManager.AddRootComponentAsync(
789+
operation.SsrComponentId,
790790
descriptor.ComponentType,
791791
descriptor.Parameters,
792-
descriptor.Key,
793-
selectorId);
792+
descriptor.Key);
794793
if (pendingTasks != null)
795794
{
796795
pendingTasks[i] = task;
@@ -799,25 +798,15 @@ internal Task UpdateRootComponents(
799798
break;
800799
case RootComponentOperationType.Update:
801800
{
802-
var componentType = Renderer.GetExistingComponentType(operation.ComponentId.Value);
803-
if (descriptor.ComponentType != componentType)
804-
{
805-
Log.InvalidComponentTypeForUpdate(_logger, message: "Component type mismatch.");
806-
throw new InvalidOperationException($"Incorrect type for descriptor '{descriptor.ComponentType.FullName}'");
807-
}
808-
809801
// We don't need to await component updates as any unhandled exception will be reported and terminate the circuit.
810-
var selectorId = operation.SelectorId.Value.ToString(CultureInfo.InvariantCulture);
811802
_ = webRootComponentManager.UpdateRootComponentAsync(
812-
operation.ComponentId.Value,
813-
componentType,
803+
operation.SsrComponentId,
814804
descriptor.Parameters,
815-
descriptor.Key,
816-
selectorId);
805+
descriptor.Key);
817806
}
818807
break;
819808
case RootComponentOperationType.Remove:
820-
webRootComponentManager.RemoveRootComponent(operation.ComponentId.Value);
809+
webRootComponentManager.RemoveRootComponent(operation.SsrComponentId);
821810
break;
822811
}
823812
}

src/Components/Server/src/Circuits/ServerComponentDeserializer.cs

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -292,44 +292,21 @@ public bool TryDeserializeRootComponentOperations(string serializedComponentOper
292292
for (var i = 0; i < result.Length; i++)
293293
{
294294
var operation = result[i];
295-
if (operation.Type == RootComponentOperationType.Remove ||
296-
operation.Type == RootComponentOperationType.Update)
295+
if (seenComponentIds[0..currentComponentIdIndex].Contains(operation.SsrComponentId))
297296
{
298-
if (operation.ComponentId == null)
299-
{
300-
Log.InvalidRootComponentOperation(_logger, operation.Type, message: "Missing component ID.");
301-
operations = null;
302-
return false;
303-
}
304-
305-
if (seenComponentIds[0..currentComponentIdIndex]
306-
.Contains(operation.ComponentId.Value))
307-
{
308-
Log.InvalidRootComponentOperation(_logger, operation.Type, message: "Duplicate component ID.");
309-
operations = null;
310-
return false;
311-
}
312-
313-
seenComponentIds[currentComponentIdIndex++] = operation.ComponentId.Value;
297+
Log.InvalidRootComponentOperation(_logger, operation.Type, message: "Duplicate component ID.");
298+
operations = null;
299+
return false;
314300
}
315301

302+
seenComponentIds[currentComponentIdIndex++] = operation.SsrComponentId;
303+
316304
if (operation.Type == RootComponentOperationType.Remove)
317305
{
318306
operations[i] = (operation, null);
319307
continue;
320308
}
321309

322-
if (operation.Type == RootComponentOperationType.Add ||
323-
operation.Type == RootComponentOperationType.Update)
324-
{
325-
if (operation.SelectorId is not { } selectorId)
326-
{
327-
Log.InvalidRootComponentOperation(_logger, operation.Type, message: "Missing selector ID.");
328-
operations = null;
329-
return false;
330-
}
331-
}
332-
333310
if (operation.Marker == null)
334311
{
335312
Log.InvalidRootComponentOperation(_logger, operation.Type, message: "Missing marker.");

src/Components/Server/test/Circuits/CircuitHostTest.cs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,15 @@ public async Task UpdateRootComponents_CanAddNewRootComponent()
426426
var operation = new RootComponentOperation
427427
{
428428
Type = RootComponentOperationType.Add,
429-
SelectorId = 1,
429+
SsrComponentId = 1,
430430
Marker = CreateMarker(typeof(DynamicallyAddedComponent), parameters),
431431
};
432432
var descriptor = new ComponentDescriptor()
433433
{
434434
ComponentType = typeof(DynamicallyAddedComponent),
435435
Parameters = ParameterView.FromDictionary(parameters),
436436
Sequence = 0,
437+
Key = operation.Marker.Value.Key,
437438
};
438439

439440
// Act
@@ -454,27 +455,29 @@ public async Task UpdateRootComponents_CanUpdateExistingRootComponent()
454455
remoteRenderer: GetRemoteRenderer(),
455456
serviceScope: new ServiceCollection().BuildServiceProvider().CreateAsyncScope());
456457
var expectedMessage = "Updated message";
458+
var componentKey = "mykey";
457459

458460
Dictionary<string, object> parameters = new()
459461
{
460462
[nameof(DynamicallyAddedComponent.Message)] = expectedMessage,
461463
};
462-
await AddComponent<DynamicallyAddedComponent>(circuitHost, parameters);
464+
await AddComponent<DynamicallyAddedComponent>(circuitHost, parameters, componentKey);
463465

464466
var operation = new RootComponentOperation
465467
{
466468
Type = RootComponentOperationType.Update,
467-
ComponentId = 0,
469+
SsrComponentId = 1,
468470
Marker = CreateMarker(typeof(DynamicallyAddedComponent), new()
469471
{
470472
[nameof(DynamicallyAddedComponent.Message)] = expectedMessage,
471-
}),
473+
}, componentKey),
472474
};
473475
var descriptor = new ComponentDescriptor()
474476
{
475477
ComponentType = typeof(DynamicallyAddedComponent),
476478
Parameters = ParameterView.FromDictionary(new Dictionary<string, object>()),
477479
Sequence = 0,
480+
Key = operation.Marker.Value.Key,
478481
};
479482

480483
// Act
@@ -493,6 +496,7 @@ public async Task UpdateRootComponents_DoesNotUpdateExistingRootComponent_WhenDe
493496
var circuitHost = TestCircuitHost.Create(
494497
remoteRenderer: GetRemoteRenderer(),
495498
serviceScope: new ServiceCollection().BuildServiceProvider().CreateAsyncScope());
499+
var componentKey = "mykey";
496500

497501
// Arrange
498502
var expectedMessage = "Existing message";
@@ -501,7 +505,7 @@ public async Task UpdateRootComponents_DoesNotUpdateExistingRootComponent_WhenDe
501505
[nameof(DynamicallyAddedComponent.Message)] = expectedMessage,
502506
});
503507

504-
await AddComponent<TestComponent>(circuitHost, []);
508+
await AddComponent<TestComponent>(circuitHost, [], componentKey);
505509

506510
Dictionary<string, object> parameters = new()
507511
{
@@ -510,14 +514,15 @@ public async Task UpdateRootComponents_DoesNotUpdateExistingRootComponent_WhenDe
510514
var operation = new RootComponentOperation
511515
{
512516
Type = RootComponentOperationType.Update,
513-
ComponentId = 0,
514-
Marker = CreateMarker(typeof(TestComponent) /* Note the incorrect component type */, parameters),
517+
SsrComponentId = 0,
518+
Marker = CreateMarker(typeof(TestComponent) /* Note the incorrect component type */, parameters, componentKey),
515519
};
516520
var descriptor = new ComponentDescriptor()
517521
{
518522
ComponentType = typeof(TestComponent),
519523
Parameters = ParameterView.FromDictionary(parameters),
520524
Sequence = 0,
525+
Key = operation.Marker.Value.Key,
521526
};
522527
var operationsJson = JsonSerializer.Serialize(
523528
new[] { operation },
@@ -557,7 +562,7 @@ public async Task UpdateRootComponents_CanRemoveExistingRootComponent()
557562
var operation = new RootComponentOperation
558563
{
559564
Type = RootComponentOperationType.Remove,
560-
ComponentId = 0,
565+
SsrComponentId = 1,
561566
};
562567

563568
// Act
@@ -568,20 +573,21 @@ public async Task UpdateRootComponents_CanRemoveExistingRootComponent()
568573
((TestRemoteRenderer)circuitHost.Renderer).GetTestComponentState(0));
569574
}
570575

571-
private async Task AddComponent<TComponent>(CircuitHost circuitHost, Dictionary<string, object> parameters)
576+
private async Task AddComponent<TComponent>(CircuitHost circuitHost, Dictionary<string, object> parameters, string componentKey = "")
572577
where TComponent : IComponent
573578
{
574579
var addOperation = new RootComponentOperation
575580
{
576581
Type = RootComponentOperationType.Add,
577-
SelectorId = 1,
578-
Marker = CreateMarker(typeof(TComponent), parameters),
582+
SsrComponentId = 1,
583+
Marker = CreateMarker(typeof(TComponent), parameters, componentKey),
579584
};
580585
var addDescriptor = new ComponentDescriptor()
581586
{
582587
ComponentType = typeof(TComponent),
583588
Parameters = ParameterView.FromDictionary(parameters),
584589
Sequence = 0,
590+
Key = addOperation.Marker.Value.Key,
585591
};
586592

587593
// Add component
@@ -628,10 +634,11 @@ private static void SetupMockInboundActivityHandler(Mock<CircuitHandler> circuit
628634
.Verifiable();
629635
}
630636

631-
private ComponentMarker CreateMarker(Type type, Dictionary<string, object> parameters = null)
637+
private ComponentMarker CreateMarker(Type type, Dictionary<string, object> parameters = null, string componentKey = "")
632638
{
633639
var serializer = new ServerComponentSerializer(_ephemeralDataProtectionProvider);
634-
var marker = ComponentMarker.Create(ComponentMarker.ServerMarkerType, false, null);
640+
var key = new BoundaryMarkerKey(type.FullName.AsMemory(), "0".AsMemory(), componentKey.AsMemory());
641+
var marker = ComponentMarker.Create(ComponentMarker.ServerMarkerType, false, key.ToString());
635642
serializer.SerializeInvocation(
636643
ref marker,
637644
_invocationSequence,

src/Components/Server/test/Circuits/ServerComponentDeserializerTest.cs

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -394,32 +394,6 @@ public void TryDeserializeSingleComponentDescriptor_DoesNotParseMarkerFromOldInv
394394
Assert.False(serverComponentDeserializer.TryDeserializeSingleComponentDescriptor(firstInvocationMarkers[0], out _));
395395
}
396396

397-
[Fact]
398-
public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFalse_WhenAddOperationIsMissingSelectorId()
399-
{
400-
// Arrange
401-
var operation = new RootComponentOperation
402-
{
403-
Type = RootComponentOperationType.Add,
404-
SelectorId = 1,
405-
Marker = new ComponentMarker()
406-
{
407-
Descriptor = "some random text",
408-
},
409-
};
410-
var operationsJson = JsonSerializer.Serialize(
411-
new[] { operation },
412-
ServerComponentSerializationSettings.JsonSerializationOptions);
413-
var deserializer = CreateServerComponentDeserializer();
414-
415-
// Act
416-
var result = deserializer.TryDeserializeRootComponentOperations(operationsJson, out var parsed);
417-
418-
// Assert
419-
Assert.False(result);
420-
Assert.Null(parsed);
421-
}
422-
423397
[Fact]
424398
public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFalse_WhenComponentIdIsMissing()
425399
{
@@ -447,13 +421,13 @@ public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFal
447421
}
448422

449423
[Fact]
450-
public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFalse_WhenComponentIdIsRepeated()
424+
public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFalse_WhenSsrComponentIdIsRepeated()
451425
{
452426
// Arrange
453427
var operation = new RootComponentOperation
454428
{
455429
Type = RootComponentOperationType.Update,
456-
ComponentId = 1,
430+
SsrComponentId = 1,
457431
Marker = CreateMarker(typeof(DynamicallyAddedComponent), new()
458432
{
459433
["Message"] = "Some other message",
@@ -463,7 +437,7 @@ public void UpdateRootComponents_TryDeserializeRootComponentOperationsReturnsFal
463437
var other = new RootComponentOperation
464438
{
465439
Type = RootComponentOperationType.Remove,
466-
ComponentId = 1,
440+
SsrComponentId = 1,
467441
Marker = CreateMarker(typeof(DynamicallyAddedComponent)),
468442
};
469443

@@ -501,7 +475,8 @@ private string SerializeMarkers(ComponentMarker[] markers) =>
501475
private ComponentMarker CreateMarker(Type type, Dictionary<string, object> parameters = null)
502476
{
503477
var serializer = new ServerComponentSerializer(_ephemeralDataProtectionProvider);
504-
var marker = ComponentMarker.Create(ComponentMarker.ServerMarkerType, false, null);
478+
var key = new BoundaryMarkerKey(type.FullName.AsMemory(), "0".AsMemory(), Memory<char>.Empty);
479+
var marker = ComponentMarker.Create(ComponentMarker.ServerMarkerType, false, key.ToString());
505480
serializer.SerializeInvocation(
506481
ref marker,
507482
_invocationSequence,

src/Components/Shared/src/RootComponentOperation.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@ internal sealed class RootComponentOperation
88
// Represents the type of root component operation to perform.
99
public RootComponentOperationType Type { get; set; }
1010

11-
// When adding a root component, this is the selector ID
12-
// to round-trip back to the client so it knows which DOM
13-
// element the component should be attached to.
14-
public int? SelectorId { get; set; }
15-
16-
// The ID of the component to use during an update or remove
17-
// operation.
18-
public int? ComponentId { get; set; }
11+
// The client side ID of the component to perform the operation on.
12+
public int SsrComponentId { get; set; }
1913

2014
// The marker that was initially rendered to the page.
2115
public ComponentMarker? Marker { get; set; }

0 commit comments

Comments
 (0)