@@ -24,22 +24,27 @@ internal class RazorComponentEndpointDataSource<[DynamicallyAccessedMembers(Comp
24
24
private readonly IApplicationBuilder _applicationBuilder ;
25
25
private readonly RenderModeEndpointProvider [ ] _renderModeEndpointProviders ;
26
26
private readonly RazorComponentEndpointFactory _factory ;
27
-
27
+ private readonly HotReloadService _hotReloadService ;
28
28
private List < Endpoint > ? _endpoints ;
29
- // TODO: Implement endpoint data source updates https://github.com/dotnet/aspnetcore/issues/47026
30
- private readonly CancellationTokenSource _cancellationTokenSource ;
31
- private readonly IChangeToken _changeToken ;
29
+ private CancellationTokenSource _cancellationTokenSource ;
30
+ private IChangeToken _changeToken ;
31
+
32
+ // Internal for testing.
33
+ internal ComponentApplicationBuilder Builder => _builder ;
34
+ internal List < Action < EndpointBuilder > > Conventions => _conventions ;
32
35
33
36
public RazorComponentEndpointDataSource (
34
37
ComponentApplicationBuilder builder ,
35
38
IEnumerable < RenderModeEndpointProvider > renderModeEndpointProviders ,
36
39
IApplicationBuilder applicationBuilder ,
37
- RazorComponentEndpointFactory factory )
40
+ RazorComponentEndpointFactory factory ,
41
+ HotReloadService hotReloadService )
38
42
{
39
43
_builder = builder ;
40
44
_applicationBuilder = applicationBuilder ;
41
45
_renderModeEndpointProviders = renderModeEndpointProviders . ToArray ( ) ;
42
46
_factory = factory ;
47
+ _hotReloadService = hotReloadService ;
43
48
DefaultBuilder = new RazorComponentsEndpointConventionBuilder (
44
49
_lock ,
45
50
builder ,
@@ -62,7 +67,7 @@ public override IReadOnlyList<Endpoint> Endpoints
62
67
// The order is as follows:
63
68
// * MapRazorComponents gets called and the data source gets created.
64
69
// * The RazorComponentEndpointConventionBuilder is returned and the user gets a chance to call on it to add conventions.
65
- // * The first request arrives and the DfaMatcherBuilder acesses the data sources to get the endpoints.
70
+ // * The first request arrives and the DfaMatcherBuilder accesses the data sources to get the endpoints.
66
71
// * The endpoints get created and the conventions get applied.
67
72
Initialize ( ) ;
68
73
Debug . Assert ( _changeToken != null ) ;
@@ -89,47 +94,61 @@ private void Initialize()
89
94
90
95
private void UpdateEndpoints ( )
91
96
{
92
- var endpoints = new List < Endpoint > ( ) ;
93
- var context = _builder . Build ( ) ;
94
-
95
- foreach ( var definition in context . Pages )
97
+ lock ( _lock )
96
98
{
97
- _factory . AddEndpoints ( endpoints , typeof ( TRootComponent ) , definition , _conventions , _finallyConventions ) ;
98
- }
99
+ var endpoints = new List < Endpoint > ( ) ;
100
+ var context = _builder . Build ( ) ;
99
101
100
- ICollection < IComponentRenderMode > renderModes = Options . ConfiguredRenderModes ;
102
+ foreach ( var definition in context . Pages )
103
+ {
104
+ _factory . AddEndpoints ( endpoints , typeof ( TRootComponent ) , definition , _conventions , _finallyConventions ) ;
105
+ }
101
106
102
- foreach ( var renderMode in renderModes )
103
- {
104
- var found = false ;
105
- foreach ( var provider in _renderModeEndpointProviders )
107
+ ICollection < IComponentRenderMode > renderModes = Options . ConfiguredRenderModes ;
108
+
109
+ foreach ( var renderMode in renderModes )
106
110
{
107
- if ( provider . Supports ( renderMode ) )
111
+ var found = false ;
112
+ foreach ( var provider in _renderModeEndpointProviders )
113
+ {
114
+ if ( provider . Supports ( renderMode ) )
115
+ {
116
+ found = true ;
117
+ RenderModeEndpointProvider . AddEndpoints (
118
+ endpoints ,
119
+ typeof ( TRootComponent ) ,
120
+ provider . GetEndpointBuilders ( renderMode , _applicationBuilder . New ( ) ) ,
121
+ renderMode ,
122
+ _conventions ,
123
+ _finallyConventions ) ;
124
+ }
125
+ }
126
+
127
+ if ( ! found )
108
128
{
109
- found = true ;
110
- RenderModeEndpointProvider . AddEndpoints (
111
- endpoints ,
112
- typeof ( TRootComponent ) ,
113
- provider . GetEndpointBuilders ( renderMode , _applicationBuilder . New ( ) ) ,
114
- renderMode ,
115
- _conventions ,
116
- _finallyConventions ) ;
129
+ throw new InvalidOperationException ( $ "Unable to find a provider for the render mode: { renderMode . GetType ( ) . FullName } . This generally " +
130
+ $ "means that a call to 'AddWebAssemblyComponents' or 'AddServerComponents' is missing. " +
131
+ $ "Alternatively call 'AddWebAssemblyRenderMode', 'AddServerRenderMode' might be missing if you have set UseDeclaredRenderModes = false.") ;
117
132
}
118
133
}
119
134
120
- if ( ! found )
135
+ var oldCancellationTokenSource = _cancellationTokenSource ;
136
+ _endpoints = endpoints ;
137
+ _cancellationTokenSource = new CancellationTokenSource ( ) ;
138
+ _changeToken = new CancellationChangeToken ( _cancellationTokenSource . Token ) ;
139
+ oldCancellationTokenSource ? . Cancel ( ) ;
140
+ if ( _hotReloadService . MetadataUpdateSupported )
121
141
{
122
- throw new InvalidOperationException ( $ "Unable to find a provider for the render mode: { renderMode . GetType ( ) . FullName } . This generally " +
123
- $ "means that a call to 'AddWebAssemblyComponents' or 'AddServerComponents' is missing. " +
124
- $ "Alternatively call 'AddWebAssemblyRenderMode', 'AddServerRenderMode' might be missing if you have set UseDeclaredRenderModes = false.") ;
142
+ ChangeToken . OnChange ( _hotReloadService . GetChangeToken , UpdateEndpoints ) ;
125
143
}
126
144
}
127
-
128
- _endpoints = endpoints ;
129
145
}
146
+
130
147
public override IChangeToken GetChangeToken ( )
131
148
{
132
- // TODO: Handle updates if necessary (for hot reload).
149
+ Initialize ( ) ;
150
+ Debug . Assert ( _changeToken != null ) ;
151
+ Debug . Assert ( _endpoints != null ) ;
133
152
return _changeToken ;
134
153
}
135
154
}
0 commit comments