Skip to content

Commit 779be27

Browse files
authored
Merge pull request #52055 from vseanreesermsft/internal-merge-8.0-2023-11-14-1317
Merging internal commits for release/8.0
2 parents 068e593 + 19176d1 commit 779be27

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1003
-833
lines changed

NuGet.config

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
<!-- Begin: Package sources from dotnet-extensions -->
77
<!-- End: Package sources from dotnet-extensions -->
88
<!-- Begin: Package sources from dotnet-efcore -->
9-
<add key="darc-pub-dotnet-efcore-e8d9247" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-efcore-e8d92476/nuget/v3/index.json" />
9+
<add key="darc-int-dotnet-efcore-e017dc1" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-e017dc12/nuget/v3/index.json" />
1010
<!-- End: Package sources from dotnet-efcore -->
1111
<!-- Begin: Package sources from dotnet-runtime -->
12-
<add key="darc-pub-dotnet-runtime-488a8a3" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-runtime-488a8a35/nuget/v3/index.json" />
12+
<add key="darc-int-dotnet-runtime-5535e31" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-5535e31a/nuget/v3/index.json" />
1313
<!-- End: Package sources from dotnet-runtime -->
1414
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
1515
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
@@ -28,5 +28,13 @@
2828
</packageSources>
2929
<disabledPackageSources>
3030
<clear />
31+
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
32+
<!-- Begin: Package sources from dotnet-efcore -->
33+
<add key="darc-int-dotnet-efcore-e017dc1" value="true" />
34+
<!-- End: Package sources from dotnet-efcore -->
35+
<!-- Begin: Package sources from dotnet-runtime -->
36+
<add key="darc-int-dotnet-runtime-5535e31" value="true" />
37+
<!-- End: Package sources from dotnet-runtime -->
38+
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
3139
</disabledPackageSources>
3240
</configuration>

eng/Baseline.Designer.props

Lines changed: 513 additions & 483 deletions
Large diffs are not rendered by default.

eng/Baseline.xml

Lines changed: 106 additions & 103 deletions
Large diffs are not rendered by default.

eng/Version.Details.xml

Lines changed: 163 additions & 163 deletions
Large diffs are not rendered by default.

eng/Versions.props

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<AspNetCorePatchVersion>1</AspNetCorePatchVersion>
1212
<PreReleaseVersionIteration>
1313
</PreReleaseVersionIteration>
14-
<ValidateBaseline>false</ValidateBaseline>
14+
<ValidateBaseline>true</ValidateBaseline>
1515
<IdentityModelVersion>7.0.3</IdentityModelVersion>
1616
<!--
1717
When StabilizePackageVersion is set to 'true', this branch will produce stable outputs for 'Shipping' packages
@@ -71,7 +71,7 @@
7171
<MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>8.0.0</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>
7272
<MicrosoftNETRuntimeWebAssemblySdkVersion>8.0.0</MicrosoftNETRuntimeWebAssemblySdkVersion>
7373
<MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>8.0.0</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>
74-
<MicrosoftNETCoreBrowserDebugHostTransportVersion>8.0.0-rtm.23523.12</MicrosoftNETCoreBrowserDebugHostTransportVersion>
74+
<MicrosoftNETCoreBrowserDebugHostTransportVersion>8.0.0-rtm.23531.3</MicrosoftNETCoreBrowserDebugHostTransportVersion>
7575
<MicrosoftExtensionsCachingAbstractionsVersion>8.0.0</MicrosoftExtensionsCachingAbstractionsVersion>
7676
<MicrosoftExtensionsCachingMemoryVersion>8.0.0</MicrosoftExtensionsCachingMemoryVersion>
7777
<MicrosoftExtensionsConfigurationAbstractionsVersion>8.0.0</MicrosoftExtensionsConfigurationAbstractionsVersion>
@@ -92,7 +92,7 @@
9292
<MicrosoftExtensionsFileProvidersCompositeVersion>8.0.0</MicrosoftExtensionsFileProvidersCompositeVersion>
9393
<MicrosoftExtensionsFileProvidersPhysicalVersion>8.0.0</MicrosoftExtensionsFileProvidersPhysicalVersion>
9494
<MicrosoftExtensionsFileSystemGlobbingVersion>8.0.0</MicrosoftExtensionsFileSystemGlobbingVersion>
95-
<MicrosoftExtensionsHostFactoryResolverSourcesVersion>8.0.0-rtm.23523.12</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
95+
<MicrosoftExtensionsHostFactoryResolverSourcesVersion>8.0.0-rtm.23531.3</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
9696
<MicrosoftExtensionsHostingAbstractionsVersion>8.0.0</MicrosoftExtensionsHostingAbstractionsVersion>
9797
<MicrosoftExtensionsHostingVersion>8.0.0</MicrosoftExtensionsHostingVersion>
9898
<MicrosoftExtensionsHttpVersion>8.0.0</MicrosoftExtensionsHttpVersion>
@@ -108,7 +108,7 @@
108108
<MicrosoftExtensionsOptionsDataAnnotationsVersion>8.0.0</MicrosoftExtensionsOptionsDataAnnotationsVersion>
109109
<MicrosoftExtensionsOptionsVersion>8.0.0</MicrosoftExtensionsOptionsVersion>
110110
<MicrosoftExtensionsPrimitivesVersion>8.0.0</MicrosoftExtensionsPrimitivesVersion>
111-
<MicrosoftInternalRuntimeAspNetCoreTransportVersion>8.0.0-rtm.23523.12</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
111+
<MicrosoftInternalRuntimeAspNetCoreTransportVersion>8.0.0-rtm.23531.3</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
112112
<SystemConfigurationConfigurationManagerVersion>8.0.0</SystemConfigurationConfigurationManagerVersion>
113113
<SystemDiagnosticsDiagnosticSourceVersion>8.0.0</SystemDiagnosticsDiagnosticSourceVersion>
114114
<SystemDiagnosticsEventLogVersion>8.0.0</SystemDiagnosticsEventLogVersion>
@@ -128,9 +128,9 @@
128128
<SystemThreadingAccessControlVersion>8.0.0</SystemThreadingAccessControlVersion>
129129
<SystemThreadingChannelsVersion>8.0.0</SystemThreadingChannelsVersion>
130130
<SystemThreadingRateLimitingVersion>8.0.0</SystemThreadingRateLimitingVersion>
131-
<MicrosoftSourceBuildIntermediateruntimelinuxx64Version>8.0.0-rtm.23523.12</MicrosoftSourceBuildIntermediateruntimelinuxx64Version>
131+
<MicrosoftSourceBuildIntermediateruntimelinuxx64Version>8.0.0-rtm.23531.3</MicrosoftSourceBuildIntermediateruntimelinuxx64Version>
132132
<!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
133-
<MicrosoftNETCorePlatformsVersion>8.0.0-rtm.23523.12</MicrosoftNETCorePlatformsVersion>
133+
<MicrosoftNETCorePlatformsVersion>8.0.0-rtm.23531.3</MicrosoftNETCorePlatformsVersion>
134134
<MicrosoftBclAsyncInterfacesVersion>8.0.0</MicrosoftBclAsyncInterfacesVersion>
135135
<!-- Transitive package to provide coherency in dotnet/extensions -->
136136
<MicrosoftBclTimeProviderVersion>8.0.0</MicrosoftBclTimeProviderVersion>
@@ -278,10 +278,10 @@
278278
<MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version>5.0.17-servicing-22215-7</MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version>
279279
<MicrosoftAspNetCoreAzureAppServicesSiteExtension50x64Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension50x64Version>
280280
<MicrosoftAspNetCoreAzureAppServicesSiteExtension50x86Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension50x86Version>
281-
<MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version>6.0.20-servicing-23321-6</MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version>
281+
<MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version>6.0.25-servicing-23523-15</MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version>
282282
<MicrosoftAspNetCoreAzureAppServicesSiteExtension60x64Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension60x64Version>
283283
<MicrosoftAspNetCoreAzureAppServicesSiteExtension60x86Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension60Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension60x86Version>
284-
<MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version>7.0.9-servicing-23321-10</MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version>
284+
<MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version>7.0.14-servicing-23523-16</MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version>
285285
<MicrosoftAspNetCoreAzureAppServicesSiteExtension70x64Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension70x64Version>
286286
<MicrosoftAspNetCoreAzureAppServicesSiteExtension70x86Version>$(MicrosoftAspNetCoreAzureAppServicesSiteExtension70Version)</MicrosoftAspNetCoreAzureAppServicesSiteExtension70x86Version>
287287
<!-- 3rd party dependencies -->

global.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"sdk": {
3-
"version": "8.0.100-rtm.23506.1"
3+
"version": "8.0.100"
44
},
55
"tools": {
6-
"dotnet": "8.0.100-rtm.23506.1",
6+
"dotnet": "8.0.100",
77
"runtimes": {
88
"dotnet/x86": [
99
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"

src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ private static void InitializeNewAttributeFrame(ref DiffContext diffContext, ref
978978
newFrame.AttributeNameField.Length >= 3 &&
979979
newFrame.AttributeNameField.StartsWith("on", StringComparison.Ordinal))
980980
{
981-
diffContext.Renderer.AssignEventHandlerId(ref newFrame);
981+
diffContext.Renderer.AssignEventHandlerId(diffContext.ComponentId, ref newFrame);
982982
}
983983
}
984984

src/Components/Components/src/RenderTree/Renderer.Log.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,16 @@ public static void HandlingEvent(ILogger logger, ulong eventHandlerId, EventArgs
6363
HandlingEvent(logger, eventHandlerId, eventArgs?.GetType().Name ?? "null");
6464
}
6565
}
66+
67+
[LoggerMessage(6, LogLevel.Debug, "Skipping attempt to raise event {EventId} of type '{EventType}' because the component ID {ComponentId} was already disposed", EventName = "SkippingEventOnDisposedComponent", SkipEnabledCheck = true)]
68+
public static partial void SkippingEventOnDisposedComponent(ILogger logger, int componentId, ulong eventId, string eventType);
69+
70+
public static void SkippingEventOnDisposedComponent(ILogger logger, int componentId, ulong eventHandlerId, EventArgs? eventArgs)
71+
{
72+
if (logger.IsEnabled(LogLevel.Debug)) // This is almost always false, so skip the evaluations
73+
{
74+
SkippingEventOnDisposedComponent(logger, componentId, eventHandlerId, eventArgs?.GetType().Name ?? "null");
75+
}
76+
}
6677
}
6778
}

src/Components/Components/src/RenderTree/Renderer.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public abstract partial class Renderer : IDisposable, IAsyncDisposable
2828
private readonly Dictionary<int, ComponentState> _componentStateById = new Dictionary<int, ComponentState>();
2929
private readonly Dictionary<IComponent, ComponentState> _componentStateByComponent = new Dictionary<IComponent, ComponentState>();
3030
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
31-
private readonly Dictionary<ulong, EventCallback> _eventBindings = new Dictionary<ulong, EventCallback>();
31+
private readonly Dictionary<ulong, (int RenderedByComponentId, EventCallback Callback)> _eventBindings = new();
3232
private readonly Dictionary<ulong, ulong> _eventHandlerIdReplacements = new Dictionary<ulong, ulong>();
3333
private readonly ILogger _logger;
3434
private readonly ComponentFactory _componentFactory;
@@ -416,7 +416,22 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
416416
_pendingTasks ??= new();
417417
}
418418

419-
var callback = GetRequiredEventCallback(eventHandlerId);
419+
var (renderedByComponentId, callback) = GetRequiredEventBindingEntry(eventHandlerId);
420+
421+
// If this event attribute was rendered by a component that's since been disposed, don't dispatch the event at all.
422+
// This can occur because event handler disposal is deferred, so event handler IDs can outlive their components.
423+
// The reason the following check is based on "which component rendered this frame" and not on "which component
424+
// receives the callback" (i.e., callback.Receiver) is that if parent A passes a RenderFragment with events to child B,
425+
// and then child B is disposed, we don't want to dispatch the events (because the developer considers them removed
426+
// from the UI) even though the receiver A is still alive.
427+
if (!_componentStateById.ContainsKey(renderedByComponentId))
428+
{
429+
// This is not an error since it can happen legitimately (in Blazor Server, the user might click a button at the same
430+
// moment that the component is disposed remotely, and then the click event will arrive after disposal).
431+
Log.SkippingEventOnDisposedComponent(_logger, renderedByComponentId, eventHandlerId, eventArgs);
432+
return Task.CompletedTask;
433+
}
434+
420435
Log.HandlingEvent(_logger, eventHandlerId, eventArgs);
421436

422437
// Try to match it up with a receiver so that, if the event handler later throws, we can route the error to the
@@ -480,7 +495,7 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
480495
/// <returns>The parameter type expected by the event handler. Normally this is a subclass of <see cref="EventArgs"/>.</returns>
481496
public Type GetEventArgsType(ulong eventHandlerId)
482497
{
483-
var methodInfo = GetRequiredEventCallback(eventHandlerId).Delegate?.Method;
498+
var methodInfo = GetRequiredEventBindingEntry(eventHandlerId).Callback.Delegate?.Method;
484499

485500
// The DispatchEventAsync code paths allow for the case where Delegate or its method
486501
// is null, and in this case the event receiver just receives null. This won't happen
@@ -581,7 +596,7 @@ protected virtual void AddPendingTask(ComponentState? componentState, Task task)
581596
_pendingTasks?.Add(task);
582597
}
583598

584-
internal void AssignEventHandlerId(ref RenderTreeFrame frame)
599+
internal void AssignEventHandlerId(int renderedByComponentId, ref RenderTreeFrame frame)
585600
{
586601
var id = ++_lastEventHandlerId;
587602

@@ -593,15 +608,15 @@ internal void AssignEventHandlerId(ref RenderTreeFrame frame)
593608
//
594609
// When that happens we intentionally box the EventCallback because we need to hold on to
595610
// the receiver.
596-
_eventBindings.Add(id, callback);
611+
_eventBindings.Add(id, (renderedByComponentId, callback));
597612
}
598613
else if (frame.AttributeValueField is MulticastDelegate @delegate)
599614
{
600615
// This is the common case for a delegate, where the receiver of the event
601616
// is the same as delegate.Target. In this case since the receiver is implicit we can
602617
// avoid boxing the EventCallback object and just re-hydrate it on the other side of the
603618
// render tree.
604-
_eventBindings.Add(id, new EventCallback(@delegate.Target as IHandleEvent, @delegate));
619+
_eventBindings.Add(id, (renderedByComponentId, new EventCallback(@delegate.Target as IHandleEvent, @delegate)));
605620
}
606621

607622
// NOTE: we do not to handle EventCallback<T> here. EventCallback<T> is only used when passing
@@ -645,14 +660,14 @@ internal void TrackReplacedEventHandlerId(ulong oldEventHandlerId, ulong newEven
645660
_eventHandlerIdReplacements.Add(oldEventHandlerId, newEventHandlerId);
646661
}
647662

648-
private EventCallback GetRequiredEventCallback(ulong eventHandlerId)
663+
private (int RenderedByComponentId, EventCallback Callback) GetRequiredEventBindingEntry(ulong eventHandlerId)
649664
{
650-
if (!_eventBindings.TryGetValue(eventHandlerId, out var callback))
665+
if (!_eventBindings.TryGetValue(eventHandlerId, out var entry))
651666
{
652667
throw new ArgumentException($"There is no event handler associated with this event. EventId: '{eventHandlerId}'.", nameof(eventHandlerId));
653668
}
654669

655-
return callback;
670+
return entry;
656671
}
657672

658673
private ulong FindLatestEventHandlerIdInChain(ulong eventHandlerId)

src/Components/Components/test/RendererTest.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,6 +2619,56 @@ public void RenderBatch_DoesNotDisposeComponentMultipleTimes()
26192619
Assert.True(component.Disposed);
26202620
}
26212621

2622+
[Fact]
2623+
public async Task DoesNotDispatchEventsAfterOwnerComponentIsDisposed()
2624+
{
2625+
// Arrange
2626+
var renderer = new TestRenderer();
2627+
var eventCount = 0;
2628+
Action<EventArgs> origEventHandler = args => { eventCount++; };
2629+
var component = new ConditionalParentComponent<EventComponent>
2630+
{
2631+
IncludeChild = true,
2632+
ChildParameters = new Dictionary<string, object>
2633+
{
2634+
{ nameof(EventComponent.OnTest), origEventHandler }
2635+
}
2636+
};
2637+
var rootComponentId = renderer.AssignRootComponentId(component);
2638+
component.TriggerRender();
2639+
var batch = renderer.Batches.Single();
2640+
var rootComponentDiff = batch.DiffsByComponentId[rootComponentId].Single();
2641+
var rootComponentFrame = batch.ReferenceFrames[0];
2642+
var childComponentFrame = rootComponentDiff.Edits
2643+
.Select(e => batch.ReferenceFrames[e.ReferenceFrameIndex])
2644+
.Where(f => f.FrameType == RenderTreeFrameType.Component)
2645+
.Single();
2646+
var childComponentId = childComponentFrame.ComponentId;
2647+
var childComponentDiff = batch.DiffsByComponentId[childComponentFrame.ComponentId].Single();
2648+
var eventHandlerId = batch.ReferenceFrames
2649+
.Skip(childComponentDiff.Edits[0].ReferenceFrameIndex) // Search from where the child component frames start
2650+
.Where(f => f.FrameType == RenderTreeFrameType.Attribute)
2651+
.Single(f => f.AttributeEventHandlerId != 0)
2652+
.AttributeEventHandlerId;
2653+
2654+
// Act/Assert 1: Event handler fires when we trigger it
2655+
Assert.Equal(0, eventCount);
2656+
var renderTask = renderer.DispatchEventAsync(eventHandlerId, args: null);
2657+
Assert.True(renderTask.IsCompletedSuccessfully);
2658+
Assert.Equal(1, eventCount);
2659+
await renderTask;
2660+
2661+
// Now remove the EventComponent, but without ever acknowledging the renderbatch, so the event handler doesn't get disposed
2662+
var disposalBatchAcknowledgementTcs = new TaskCompletionSource();
2663+
component.IncludeChild = false;
2664+
renderer.NextRenderResultTask = disposalBatchAcknowledgementTcs.Task;
2665+
component.TriggerRender();
2666+
2667+
// Act/Assert 2: Can no longer fire the original event. It's not an error but the delegate was not invoked.
2668+
await renderer.DispatchEventAsync(eventHandlerId, args: null);
2669+
Assert.Equal(1, eventCount);
2670+
}
2671+
26222672
[Fact]
26232673
public async Task DisposesEventHandlersWhenAttributeValueChanged()
26242674
{

0 commit comments

Comments
 (0)