Skip to content

Commit f7e68a8

Browse files
authored
Add SectionName to SectionOutlet and SectionContent (#47221)
* Added SectionName to SectionOutlet and SectionContent
1 parent 7264c87 commit f7e68a8

File tree

6 files changed

+364
-84
lines changed

6 files changed

+364
-84
lines changed

src/Components/Components/src/PublicAPI.Unshipped.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ Microsoft.AspNetCore.Components.Sections.SectionContent.ChildContent.get -> Micr
99
Microsoft.AspNetCore.Components.Sections.SectionContent.ChildContent.set -> void
1010
Microsoft.AspNetCore.Components.Sections.SectionContent.Dispose() -> void
1111
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionContent() -> void
12-
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionId.get -> object!
12+
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionId.get -> object?
1313
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionId.set -> void
14+
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionName.get -> string?
15+
Microsoft.AspNetCore.Components.Sections.SectionContent.SectionName.set -> void
1416
Microsoft.AspNetCore.Components.Sections.SectionOutlet
1517
Microsoft.AspNetCore.Components.Sections.SectionOutlet.Dispose() -> void
16-
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionId.get -> object!
18+
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionId.get -> object?
1719
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionId.set -> void
20+
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionName.get -> string?
21+
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionName.set -> void
1822
Microsoft.AspNetCore.Components.Sections.SectionOutlet.SectionOutlet() -> void
1923
Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, object? value) -> void
2024
override Microsoft.AspNetCore.Components.EventCallback.GetHashCode() -> int

src/Components/Components/src/Sections/SectionContent.cs

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ namespace Microsoft.AspNetCore.Components.Sections;
88
/// </summary>
99
public sealed class SectionContent : ISectionContentProvider, IComponent, IDisposable
1010
{
11-
private object? _registeredSectionId;
11+
private object? _registeredIdentifier;
1212
private bool? _registeredIsDefaultContent;
1313
private SectionRegistry _registry = default!;
1414

1515
/// <summary>
16-
/// Gets or sets the ID that determines which <see cref="SectionOutlet"/> instance will render
16+
/// Gets or sets the <see cref="string"/> ID that determines which <see cref="SectionOutlet"/> instance will render
1717
/// the content of this instance.
1818
/// </summary>
19-
[Parameter, EditorRequired] public object SectionId { get; set; } = default!;
19+
[Parameter] public string? SectionName { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the <see cref="object"/> ID that determines which <see cref="SectionOutlet"/> instance will render
23+
/// the content of this instance.
24+
/// </summary>
25+
[Parameter] public object? SectionId { get; set; }
2026

2127
/// <summary>
2228
/// Gets or sets whether this component should provide the default content for the target
@@ -37,11 +43,56 @@ void IComponent.Attach(RenderHandle renderHandle)
3743
}
3844

3945
Task IComponent.SetParametersAsync(ParameterView parameters)
46+
{
47+
// We are not using parameters.SetParameterProperties(this)
48+
// because IsDefaultContent is internal property and not a parameter
49+
SetParameterValues(parameters);
50+
51+
object? identifier;
52+
53+
if (SectionName is not null && SectionId is not null)
54+
{
55+
throw new InvalidOperationException($"{nameof(SectionContent)} requires that '{nameof(SectionName)}' and '{nameof(SectionId)}' cannot both have non-null values.");
56+
}
57+
else if (SectionName is not null)
58+
{
59+
identifier = SectionName;
60+
}
61+
else if (SectionId is not null)
62+
{
63+
identifier = SectionId;
64+
}
65+
else
66+
{
67+
throw new InvalidOperationException($"{nameof(SectionContent)} requires a non-null value either for '{nameof(SectionName)}' or '{nameof(SectionId)}'.");
68+
}
69+
70+
if (!object.Equals(identifier, _registeredIdentifier) || IsDefaultContent != _registeredIsDefaultContent)
71+
{
72+
if (_registeredIdentifier is not null)
73+
{
74+
_registry.RemoveProvider(_registeredIdentifier, this);
75+
}
76+
77+
_registry.AddProvider(identifier, this, IsDefaultContent);
78+
_registeredIdentifier = SectionId;
79+
_registeredIsDefaultContent = IsDefaultContent;
80+
}
81+
82+
_registry.NotifyContentChanged(identifier, this);
83+
84+
return Task.CompletedTask;
85+
}
86+
87+
private void SetParameterValues(in ParameterView parameters)
4088
{
4189
foreach (var param in parameters)
4290
{
4391
switch (param.Name)
4492
{
93+
case nameof(SectionContent.SectionName):
94+
SectionName = (string)param.Value;
95+
break;
4596
case nameof(SectionContent.SectionId):
4697
SectionId = param.Value;
4798
break;
@@ -55,35 +106,14 @@ Task IComponent.SetParametersAsync(ParameterView parameters)
55106
throw new ArgumentException($"Unknown parameter '{param.Name}'");
56107
}
57108
}
58-
59-
if (SectionId is null)
60-
{
61-
throw new InvalidOperationException($"{nameof(SectionContent)} requires a non-null value for the parameter '{nameof(SectionId)}'.");
62-
}
63-
64-
if (!object.Equals(SectionId, _registeredSectionId) || IsDefaultContent != _registeredIsDefaultContent)
65-
{
66-
if (_registeredSectionId is not null)
67-
{
68-
_registry.RemoveProvider(_registeredSectionId, this);
69-
}
70-
71-
_registry.AddProvider(SectionId, this, IsDefaultContent);
72-
_registeredSectionId = SectionId;
73-
_registeredIsDefaultContent = IsDefaultContent;
74-
}
75-
76-
_registry.NotifyContentChanged(SectionId, this);
77-
78-
return Task.CompletedTask;
79109
}
80110

81111
/// <inheritdoc/>
82112
public void Dispose()
83113
{
84-
if (_registeredSectionId is not null)
114+
if (_registeredIdentifier is not null)
85115
{
86-
_registry.RemoveProvider(_registeredSectionId, this);
116+
_registry.RemoveProvider(_registeredIdentifier, this);
87117
}
88118
}
89119
}

src/Components/Components/src/Sections/SectionOutlet.cs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,22 @@ public sealed class SectionOutlet : ISectionContentSubscriber, IComponent, IDisp
1010
{
1111
private static readonly RenderFragment _emptyRenderFragment = _ => { };
1212

13-
private object? _subscribedSectionId;
13+
private object? _subscribedIdentifier;
1414
private RenderHandle _renderHandle;
1515
private SectionRegistry _registry = default!;
1616
private RenderFragment? _content;
1717

1818
/// <summary>
19-
/// Gets or sets the ID that determines which <see cref="SectionContent"/> instances will provide
19+
/// Gets or sets the <see cref="string"/> ID that determines which <see cref="SectionContent"/> instances will provide
2020
/// content to this instance.
2121
/// </summary>
22-
[Parameter, EditorRequired] public object SectionId { get; set; } = default!;
22+
[Parameter] public string? SectionName { get; set; }
23+
24+
/// <summary>
25+
/// Gets or sets the <see cref="object"/> ID that determines which <see cref="SectionContent"/> instances will provide
26+
/// content to this instance.
27+
/// </summary>
28+
[Parameter] public object? SectionId { get; set; }
2329

2430
void IComponent.Attach(RenderHandle renderHandle)
2531
{
@@ -31,20 +37,34 @@ Task IComponent.SetParametersAsync(ParameterView parameters)
3137
{
3238
parameters.SetParameterProperties(this);
3339

34-
if (SectionId is null)
40+
object? identifier;
41+
42+
if (SectionName is not null && SectionId is not null)
43+
{
44+
throw new InvalidOperationException($"{nameof(SectionOutlet)} requires that '{nameof(SectionName)}' and '{nameof(SectionId)}' cannot both have non-null values.");
45+
}
46+
else if (SectionName is not null)
47+
{
48+
identifier = SectionName;
49+
}
50+
else if (SectionId is not null)
51+
{
52+
identifier = SectionId;
53+
}
54+
else
3555
{
36-
throw new InvalidOperationException($"{nameof(SectionOutlet)} requires a non-null value for the parameter '{nameof(SectionId)}'.");
56+
throw new InvalidOperationException($"{nameof(SectionOutlet)} requires a non-null value either for '{nameof(SectionName)}' or '{nameof(SectionId)}'.");
3757
}
3858

39-
if (!object.Equals(SectionId, _subscribedSectionId))
59+
if (!object.Equals(identifier, _subscribedIdentifier))
4060
{
41-
if (_subscribedSectionId is not null)
61+
if (_subscribedIdentifier is not null)
4262
{
43-
_registry.Unsubscribe(_subscribedSectionId);
63+
_registry.Unsubscribe(_subscribedIdentifier);
4464
}
4565

46-
_registry.Subscribe(SectionId, this);
47-
_subscribedSectionId = SectionId;
66+
_registry.Subscribe(identifier, this);
67+
_subscribedIdentifier = SectionId;
4868
}
4969

5070
RenderContent();
@@ -74,9 +94,9 @@ private void RenderContent()
7494
/// <inheritdoc/>
7595
public void Dispose()
7696
{
77-
if (_subscribedSectionId is not null)
97+
if (_subscribedIdentifier is not null)
7898
{
79-
_registry.Unsubscribe(_subscribedSectionId);
99+
_registry.Unsubscribe(_subscribedIdentifier);
80100
}
81101
}
82102
}

src/Components/Components/src/Sections/SectionRegistry.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ namespace Microsoft.AspNetCore.Components.Sections;
55

66
internal sealed class SectionRegistry
77
{
8-
private readonly Dictionary<object, ISectionContentSubscriber> _subscribersBySectionId = new();
9-
private readonly Dictionary<object, List<ISectionContentProvider>> _providersBySectionId = new();
8+
private readonly Dictionary<object, ISectionContentSubscriber> _subscribersByIdentifier = new();
9+
private readonly Dictionary<object, List<ISectionContentProvider>> _providersByIdentifier = new();
1010

11-
public void AddProvider(object sectionId, ISectionContentProvider provider, bool isDefaultProvider)
11+
public void AddProvider(object identifier, ISectionContentProvider provider, bool isDefaultProvider)
1212
{
13-
if (!_providersBySectionId.TryGetValue(sectionId, out var providers))
13+
if (!_providersByIdentifier.TryGetValue(identifier, out var providers))
1414
{
1515
providers = new();
16-
_providersBySectionId.Add(sectionId, providers);
16+
_providersByIdentifier.Add(identifier, providers);
1717
}
1818

1919
if (isDefaultProvider)
@@ -26,18 +26,18 @@ public void AddProvider(object sectionId, ISectionContentProvider provider, bool
2626
}
2727
}
2828

29-
public void RemoveProvider(object sectionId, ISectionContentProvider provider)
29+
public void RemoveProvider(object identifier, ISectionContentProvider provider)
3030
{
31-
if (!_providersBySectionId.TryGetValue(sectionId, out var providers))
31+
if (!_providersByIdentifier.TryGetValue(identifier, out var providers))
3232
{
33-
throw new InvalidOperationException($"There are no content providers with the given section ID '{sectionId}'.");
33+
throw new InvalidOperationException($"There are no content providers with the given section ID '{identifier}'.");
3434
}
3535

3636
var index = providers.LastIndexOf(provider);
3737

3838
if (index < 0)
3939
{
40-
throw new InvalidOperationException($"The provider was not found in the providers list of the given section ID '{sectionId}'.");
40+
throw new InvalidOperationException($"The provider was not found in the providers list of the given section ID '{identifier}'.");
4141
}
4242

4343
providers.RemoveAt(index);
@@ -47,44 +47,44 @@ public void RemoveProvider(object sectionId, ISectionContentProvider provider)
4747
// We just removed the most recently added provider, meaning we need to change
4848
// the current content to that of second most recently added provider.
4949
var content = GetCurrentProviderContentOrDefault(providers);
50-
NotifyContentChangedForSubscriber(sectionId, content);
50+
NotifyContentChangedForSubscriber(identifier, content);
5151
}
5252
}
5353

54-
public void Subscribe(object sectionId, ISectionContentSubscriber subscriber)
54+
public void Subscribe(object identifier, ISectionContentSubscriber subscriber)
5555
{
56-
if (_subscribersBySectionId.ContainsKey(sectionId))
56+
if (_subscribersByIdentifier.ContainsKey(identifier))
5757
{
58-
throw new InvalidOperationException($"There is already a subscriber to the content with the given section ID '{sectionId}'.");
58+
throw new InvalidOperationException($"There is already a subscriber to the content with the given section ID '{identifier}'.");
5959
}
6060

6161
// Notify the new subscriber with any existing content.
62-
var content = GetCurrentProviderContentOrDefault(sectionId);
62+
var content = GetCurrentProviderContentOrDefault(identifier);
6363
subscriber.ContentChanged(content);
6464

65-
_subscribersBySectionId.Add(sectionId, subscriber);
65+
_subscribersByIdentifier.Add(identifier, subscriber);
6666
}
6767

68-
public void Unsubscribe(object sectionId)
68+
public void Unsubscribe(object identifier)
6969
{
70-
if (!_subscribersBySectionId.Remove(sectionId))
70+
if (!_subscribersByIdentifier.Remove(identifier))
7171
{
72-
throw new InvalidOperationException($"The subscriber with the given section ID '{sectionId}' is already unsubscribed.");
72+
throw new InvalidOperationException($"The subscriber with the given section ID '{identifier}' is already unsubscribed.");
7373
}
7474
}
7575

76-
public void NotifyContentChanged(object sectionId, ISectionContentProvider provider)
76+
public void NotifyContentChanged(object identifier, ISectionContentProvider provider)
7777
{
78-
if (!_providersBySectionId.TryGetValue(sectionId, out var providers))
78+
if (!_providersByIdentifier.TryGetValue(identifier, out var providers))
7979
{
80-
throw new InvalidOperationException($"There are no content providers with the given section ID '{sectionId}'.");
80+
throw new InvalidOperationException($"There are no content providers with the given section ID '{identifier}'.");
8181
}
8282

8383
// We only notify content changed for subscribers when the content of the
8484
// most recently added provider changes.
8585
if (providers.Count != 0 && providers[^1] == provider)
8686
{
87-
NotifyContentChangedForSubscriber(sectionId, provider.Content);
87+
NotifyContentChangedForSubscriber(identifier, provider.Content);
8888
}
8989
}
9090

@@ -93,14 +93,14 @@ public void NotifyContentChanged(object sectionId, ISectionContentProvider provi
9393
? providers[^1].Content
9494
: null;
9595

96-
private RenderFragment? GetCurrentProviderContentOrDefault(object sectionId)
97-
=> _providersBySectionId.TryGetValue(sectionId, out var existingList)
96+
private RenderFragment? GetCurrentProviderContentOrDefault(object identifier)
97+
=> _providersByIdentifier.TryGetValue(identifier, out var existingList)
9898
? GetCurrentProviderContentOrDefault(existingList)
9999
: null;
100100

101-
private void NotifyContentChangedForSubscriber(object sectionId, RenderFragment? content)
101+
private void NotifyContentChangedForSubscriber(object identifier, RenderFragment? content)
102102
{
103-
if (_subscribersBySectionId.TryGetValue(sectionId, out var subscriber))
103+
if (_subscribersByIdentifier.TryGetValue(identifier, out var subscriber))
104104
{
105105
subscriber.ContentChanged(content);
106106
}

0 commit comments

Comments
 (0)