Skip to content

Commit 45bf8bc

Browse files
Copilotjaviercn
andcommitted
Remove InternalsVisibleTo from Components to Components.Server
Co-authored-by: javiercn <6995051+javiercn@users.noreply.github.com>
1 parent 4abc68c commit 45bf8bc

9 files changed

+178
-67
lines changed

src/Components/Components/src/ComponentsActivitySource.cs

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,28 @@ namespace Microsoft.AspNetCore.Components;
1111
internal class ComponentsActivitySource
1212
{
1313
internal const string Name = "Microsoft.AspNetCore.Components";
14-
internal const string OnCircuitName = $"{Name}.CircuitStart";
1514
internal const string OnRouteName = $"{Name}.RouteChange";
1615
internal const string OnEventName = $"{Name}.HandleEvent";
1716

1817
private ActivityContext _httpContext;
19-
private ActivityContext _circuitContext;
20-
private string? _circuitId;
2118
private ActivityContext _routeContext;
19+
private Activity? _capturedActivity;
2220

2321
private ActivitySource ActivitySource { get; } = new ActivitySource(Name);
2422

23+
/// <summary>
24+
/// Initializes the ComponentsActivitySource with a captured activity for linking.
25+
/// </summary>
26+
/// <param name="capturedActivity">Activity to link with component activities.</param>
27+
public void Initialize(Activity? capturedActivity)
28+
{
29+
_capturedActivity = capturedActivity;
30+
_httpContext = CaptureHttpContext();
31+
}
32+
33+
/// <summary>
34+
/// Captures the current HTTP context activity.
35+
/// </summary>
2536
public static ActivityContext CaptureHttpContext()
2637
{
2738
var parentActivity = Activity.Current;
@@ -32,58 +43,19 @@ public static ActivityContext CaptureHttpContext()
3243
return default;
3344
}
3445

35-
public Activity? StartCircuitActivity(string circuitId, ActivityContext httpContext)
36-
{
37-
_circuitId = circuitId;
38-
39-
var activity = ActivitySource.CreateActivity(OnCircuitName, ActivityKind.Internal, parentId: null, null, null);
40-
if (activity is not null)
41-
{
42-
if (activity.IsAllDataRequested)
43-
{
44-
if (_circuitId != null)
45-
{
46-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
47-
}
48-
if (httpContext != default)
49-
{
50-
activity.AddLink(new ActivityLink(httpContext));
51-
}
52-
}
53-
activity.DisplayName = $"Circuit {circuitId ?? ""}";
54-
activity.Start();
55-
_circuitContext = activity.Context;
56-
}
57-
return activity;
58-
}
59-
60-
public void FailCircuitActivity(Activity? activity, Exception ex)
61-
{
62-
_circuitContext = default;
63-
if (activity != null && !activity.IsStopped)
64-
{
65-
activity.SetTag("error.type", ex.GetType().FullName);
66-
activity.SetStatus(ActivityStatusCode.Error);
67-
activity.Stop();
68-
}
69-
}
70-
7146
public Activity? StartRouteActivity(string componentType, string route)
7247
{
73-
if (_httpContext == default)
74-
{
75-
_httpContext = CaptureHttpContext();
76-
}
77-
7848
var activity = ActivitySource.CreateActivity(OnRouteName, ActivityKind.Internal, parentId: null, null, null);
7949
if (activity is not null)
8050
{
8151
if (activity.IsAllDataRequested)
8252
{
83-
if (_circuitId != null)
53+
// Copy any circuit ID from captured activity if present
54+
if (_capturedActivity != null && _capturedActivity.GetTagItem("aspnetcore.components.circuit.id") is string circuitId)
8455
{
85-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
56+
activity.SetTag("aspnetcore.components.circuit.id", circuitId);
8657
}
58+
8759
if (componentType != null)
8860
{
8961
activity.SetTag("aspnetcore.components.type", componentType);
@@ -96,9 +68,9 @@ public void FailCircuitActivity(Activity? activity, Exception ex)
9668
{
9769
activity.AddLink(new ActivityLink(_httpContext));
9870
}
99-
if (_circuitContext != default)
71+
if (_capturedActivity != null)
10072
{
101-
activity.AddLink(new ActivityLink(_circuitContext));
73+
activity.AddLink(new ActivityLink(_capturedActivity.Context));
10274
}
10375
}
10476

@@ -116,10 +88,12 @@ public void FailCircuitActivity(Activity? activity, Exception ex)
11688
{
11789
if (activity.IsAllDataRequested)
11890
{
119-
if (_circuitId != null)
91+
// Copy any circuit ID from captured activity if present
92+
if (_capturedActivity != null && _capturedActivity.GetTagItem("aspnetcore.components.circuit.id") is string circuitId)
12093
{
121-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
94+
activity.SetTag("aspnetcore.components.circuit.id", circuitId);
12295
}
96+
12397
if (componentType != null)
12498
{
12599
activity.SetTag("aspnetcore.components.type", componentType);
@@ -136,9 +110,9 @@ public void FailCircuitActivity(Activity? activity, Exception ex)
136110
{
137111
activity.AddLink(new ActivityLink(_httpContext));
138112
}
139-
if (_circuitContext != default)
113+
if (_capturedActivity != null)
140114
{
141-
activity.AddLink(new ActivityLink(_circuitContext));
115+
activity.AddLink(new ActivityLink(_capturedActivity.Context));
142116
}
143117
if (_routeContext != default)
144118
{

src/Components/Components/src/Microsoft.AspNetCore.Components.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979

8080
<ItemGroup>
8181
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Web" />
82-
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Server" />
8382
<InternalsVisibleTo Include="Microsoft.AspNetCore.Blazor.Build.Tests" />
8483
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Authorization.Tests" />
8584
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Forms.Tests" />
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
6+
namespace Microsoft.AspNetCore.Components.Server.Circuits;
7+
8+
/// <summary>
9+
/// Activity source for circuit-related activities.
10+
/// </summary>
11+
public class CircuitActivitySource
12+
{
13+
internal const string Name = "Microsoft.AspNetCore.Components.Server";
14+
internal const string OnCircuitName = $"{Name}.CircuitStart";
15+
16+
private ActivitySource ActivitySource { get; } = new ActivitySource(Name);
17+
18+
/// <summary>
19+
/// Creates and starts a new activity for circuit initialization.
20+
/// </summary>
21+
/// <param name="circuitId">The ID of the circuit being initialized.</param>
22+
/// <param name="httpContext">The HTTP context associated with the request that created the circuit.</param>
23+
/// <returns>The created activity.</returns>
24+
public Activity? StartCircuitActivity(string circuitId, ActivityContext httpContext)
25+
{
26+
var activity = ActivitySource.CreateActivity(OnCircuitName, ActivityKind.Internal, parentId: null, null, null);
27+
if (activity is not null)
28+
{
29+
if (activity.IsAllDataRequested)
30+
{
31+
if (circuitId != null)
32+
{
33+
activity.SetTag("aspnetcore.components.circuit.id", circuitId);
34+
}
35+
if (httpContext != default)
36+
{
37+
activity.AddLink(new ActivityLink(httpContext));
38+
}
39+
}
40+
activity.DisplayName = $"Circuit {circuitId ?? ""}";
41+
activity.Start();
42+
}
43+
return activity;
44+
}
45+
46+
/// <summary>
47+
/// Stops a circuit activity that was previously started.
48+
/// </summary>
49+
/// <param name="activity">The activity to stop.</param>
50+
public void StopCircuitActivity(Activity? activity)
51+
{
52+
if (activity != null && !activity.IsStopped)
53+
{
54+
activity.Stop();
55+
}
56+
}
57+
58+
/// <summary>
59+
/// Marks a circuit activity as failed and stops it.
60+
/// </summary>
61+
/// <param name="activity">The activity to mark as failed.</param>
62+
/// <param name="ex">The exception that caused the failure.</param>
63+
public void FailCircuitActivity(Activity? activity, Exception ex)
64+
{
65+
if (activity != null && !activity.IsStopped)
66+
{
67+
activity.SetTag("error.type", ex.GetType().FullName);
68+
activity.SetStatus(ActivityStatusCode.Error);
69+
activity.Stop();
70+
}
71+
}
72+
73+
/// <summary>
74+
/// Captures the current HTTP context activity.
75+
/// </summary>
76+
/// <returns>The captured HTTP context activity.</returns>
77+
public static ActivityContext CaptureHttpContext()
78+
{
79+
var parentActivity = Activity.Current;
80+
if (parentActivity is not null && parentActivity.OperationName == "Microsoft.AspNetCore.Hosting.HttpRequestIn" && parentActivity.Recorded)
81+
{
82+
return parentActivity.Context;
83+
}
84+
return default;
85+
}
86+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.Components.Server.Circuits;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
6+
7+
namespace Microsoft.Extensions.DependencyInjection;
8+
9+
/// <summary>
10+
/// Extension methods for adding <see cref="CircuitActivitySource"/> to the service collection.
11+
/// </summary>
12+
internal static class CircuitActivitySourceServiceCollectionExtensions
13+
{
14+
/// <summary>
15+
/// Adds <see cref="CircuitActivitySource"/> to the service collection.
16+
/// </summary>
17+
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
18+
/// <returns>The <see cref="IServiceCollection"/>.</returns>
19+
public static IServiceCollection AddCircuitActivitySource(this IServiceCollection services)
20+
{
21+
services.TryAddSingleton<CircuitActivitySource>();
22+
return services;
23+
}
24+
}

src/Components/Server/src/Circuits/CircuitFactory.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Linq;
56
using System.Security.Claims;
67
using Microsoft.AspNetCore.Components.Infrastructure;
@@ -45,7 +46,8 @@ public async ValueTask<CircuitHost> CreateCircuitHostAsync(
4546
string uri,
4647
ClaimsPrincipal user,
4748
IPersistentComponentStateStore store,
48-
ResourceAssetCollection resourceCollection)
49+
ResourceAssetCollection resourceCollection,
50+
Activity? circuitActivity = null)
4951
{
5052
var scope = _scopeFactory.CreateAsyncScope();
5153
var jsRuntime = (RemoteJSRuntime)scope.ServiceProvider.GetRequiredService<IJSRuntime>();
@@ -67,6 +69,11 @@ public async ValueTask<CircuitHost> CreateCircuitHostAsync(
6769
navigationManager.Initialize(baseUri, uri);
6870
}
6971
var componentsActivitySource = scope.ServiceProvider.GetService<ComponentsActivitySource>();
72+
73+
// Initialize the components activity source with the circuit activity if available
74+
componentsActivitySource?.Initialize(circuitActivity);
75+
76+
var circuitActivitySource = scope.ServiceProvider.GetService<CircuitActivitySource>();
7077

7178
if (components.Count > 0)
7279
{
@@ -99,8 +106,10 @@ public async ValueTask<CircuitHost> CreateCircuitHostAsync(
99106
.OrderBy(h => h.Order)
100107
.ToArray();
101108

109+
var circuitId = _circuitIdFactory.CreateCircuitId();
110+
102111
var circuitHost = new CircuitHost(
103-
_circuitIdFactory.CreateCircuitId(),
112+
circuitId,
104113
scope,
105114
_options,
106115
client,
@@ -110,7 +119,8 @@ public async ValueTask<CircuitHost> CreateCircuitHostAsync(
110119
navigationManager,
111120
circuitHandlers,
112121
_circuitMetrics,
113-
componentsActivitySource,
122+
circuitActivitySource,
123+
circuitActivity,
114124
_loggerFactory.CreateLogger<CircuitHost>());
115125
Log.CreatedCircuit(_logger, circuitHost);
116126

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ internal partial class CircuitHost : IAsyncDisposable
2525
private readonly RemoteNavigationManager _navigationManager;
2626
private readonly ILogger _logger;
2727
private readonly CircuitMetrics? _circuitMetrics;
28-
private readonly ComponentsActivitySource? _componentsActivitySource;
28+
private readonly CircuitActivitySource? _circuitActivitySource;
29+
private readonly Activity? _circuitActivity;
2930
private Func<Func<Task>, Task> _dispatchInboundActivity;
3031
private CircuitHandler[] _circuitHandlers;
3132
private bool _initialized;
@@ -52,7 +53,8 @@ public CircuitHost(
5253
RemoteNavigationManager navigationManager,
5354
CircuitHandler[] circuitHandlers,
5455
CircuitMetrics? circuitMetrics,
55-
ComponentsActivitySource? componentsActivitySource,
56+
CircuitActivitySource? circuitActivitySource,
57+
Activity? circuitActivity,
5658
ILogger logger)
5759
{
5860
CircuitId = circuitId;
@@ -71,7 +73,8 @@ public CircuitHost(
7173
_navigationManager = navigationManager ?? throw new ArgumentNullException(nameof(navigationManager));
7274
_circuitHandlers = circuitHandlers ?? throw new ArgumentNullException(nameof(circuitHandlers));
7375
_circuitMetrics = circuitMetrics;
74-
_componentsActivitySource = componentsActivitySource;
76+
_circuitActivitySource = circuitActivitySource;
77+
_circuitActivity = circuitActivity;
7578
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
7679

7780
Services = scope.ServiceProvider;
@@ -124,7 +127,6 @@ public Task InitializeAsync(ProtectedPrerenderComponentApplicationStore store, A
124127
{
125128
_initialized = true; // We're ready to accept incoming JSInterop calls from here on
126129

127-
activity = _componentsActivitySource?.StartCircuitActivity(CircuitId.Id, httpContext);
128130
_startTime = (_circuitMetrics != null && _circuitMetrics.IsDurationEnabled()) ? Stopwatch.GetTimestamp() : 0;
129131

130132
// We only run the handlers in case we are in a Blazor Server scenario, which renders
@@ -169,12 +171,10 @@ public Task InitializeAsync(ProtectedPrerenderComponentApplicationStore store, A
169171
_isFirstUpdate = Descriptors.Count == 0;
170172

171173
Log.InitializationSucceeded(_logger);
172-
173-
activity?.Stop();
174174
}
175175
catch (Exception ex)
176176
{
177-
_componentsActivitySource?.FailCircuitActivity(activity, ex);
177+
_circuitActivitySource?.FailCircuitActivity(_circuitActivity, ex);
178178

179179
// Report errors asynchronously. InitializeAsync is designed not to throw.
180180
Log.InitializationFailed(_logger, ex);
@@ -337,6 +337,9 @@ private async Task OnCircuitDownAsync(CancellationToken cancellationToken)
337337
{
338338
Log.CircuitClosed(_logger, CircuitId);
339339
_circuitMetrics?.OnCircuitDown(_startTime, Stopwatch.GetTimestamp());
340+
341+
// Stop the circuit activity when the circuit is closed
342+
_circuitActivitySource?.StopCircuitActivity(_circuitActivity);
340343

341344
List<Exception> exceptions = null;
342345

src/Components/Server/src/Circuits/ICircuitFactory.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Security.Claims;
56

67
namespace Microsoft.AspNetCore.Components.Server.Circuits;
@@ -14,5 +15,6 @@ ValueTask<CircuitHost> CreateCircuitHostAsync(
1415
string uri,
1516
ClaimsPrincipal user,
1617
IPersistentComponentStateStore store,
17-
ResourceAssetCollection resourceCollection);
18+
ResourceAssetCollection resourceCollection,
19+
Activity? circuitActivity = null);
1820
}

0 commit comments

Comments
 (0)