Skip to content

Commit d04febe

Browse files
committed
Undo the IsFixed change
1 parent dbbee36 commit d04febe

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

src/Components/Components/src/Binding/CascadingModelBinder.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ public sealed class CascadingModelBinder : IComponent, ICascadingValueComponent,
2323
/// </summary>
2424
[Parameter] public string Name { get; set; } = "";
2525

26+
/// <summary>
27+
/// If true, indicates that <see cref="ModelBindingContext.BindingContextId"/> will not change.
28+
/// This is a performance optimization that allows the framework to skip setting up
29+
/// change notifications. Set this flag only if you will not change
30+
/// <see cref="Name"/> of this context or its parents' context during the component's lifetime.
31+
/// </summary>
32+
[Parameter] public bool IsFixed { get; set; }
33+
2634
/// <summary>
2735
/// Specifies the content to be rendered inside this <see cref="CascadingModelBinder"/>.
2836
/// </summary>
@@ -70,7 +78,7 @@ private void Render()
7078
{
7179
_hasPendingQueuedRender = false;
7280
builder.OpenComponent<CascadingValue<ModelBindingContext>>(0);
73-
builder.AddComponentParameter(1, nameof(CascadingValue<ModelBindingContext>.IsFixed), true);
81+
builder.AddComponentParameter(1, nameof(CascadingValue<ModelBindingContext>.IsFixed), IsFixed);
7482
builder.AddComponentParameter(2, nameof(CascadingValue<ModelBindingContext>.Value), _bindingContext);
7583
builder.AddComponentParameter(3, nameof(CascadingValue<ModelBindingContext>.ChildContent), ChildContent?.Invoke(_bindingContext!));
7684
builder.CloseComponent();
@@ -109,7 +117,7 @@ internal void UpdateBindingInformation(string url)
109117
_bindingContext : new ModelBindingContext(name, bindingId);
110118

111119
// It doesn't matter that we don't check IsFixed, since the CascadingValue we are setting up will throw if the app changes.
112-
if (_bindingContext != null && _bindingContext != bindingContext)
120+
if (IsFixed && _bindingContext != null && _bindingContext != bindingContext)
113121
{
114122
// Throw an exception if either the Name or the BindingContextId changed. Once a CascadingModelBinder has been initialized
115123
// as fixed, it can't change it's name nor its BindingContextId. This can happen in several situations:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Microsoft.AspNetCore.Components.CascadingModelBinder
77
Microsoft.AspNetCore.Components.CascadingModelBinder.CascadingModelBinder() -> void
88
Microsoft.AspNetCore.Components.CascadingModelBinder.ChildContent.get -> Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.ModelBindingContext!>!
99
Microsoft.AspNetCore.Components.CascadingModelBinder.ChildContent.set -> void
10+
Microsoft.AspNetCore.Components.CascadingModelBinder.IsFixed.get -> bool
11+
Microsoft.AspNetCore.Components.CascadingModelBinder.IsFixed.set -> void
1012
Microsoft.AspNetCore.Components.CascadingModelBinder.Name.get -> string!
1113
Microsoft.AspNetCore.Components.CascadingModelBinder.Name.set -> void
1214
Microsoft.AspNetCore.Components.ComponentBase.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task!

src/Components/Components/test/CascadingModelBinderTest.cs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ public void Throws_WhenIsFixedAndNameChanges()
200200
{
201201
builder.OpenComponent<CascadingModelBinder>(0);
202202
builder.AddAttribute(1, nameof(CascadingModelBinder.Name), contextName);
203+
builder.AddAttribute(2, nameof(CascadingModelBinder.IsFixed), true);
203204
builder.AddAttribute(3, nameof(CascadingModelBinder.ChildContent), contents);
204205
builder.CloseComponent();
205206
});
@@ -213,6 +214,85 @@ public void Throws_WhenIsFixedAndNameChanges()
213214
Assert.Equal("'CascadingModelBinder' 'Name' can't change after initialized.", exception.Message);
214215
}
215216

217+
[Theory]
218+
[InlineData(true)]
219+
[InlineData(false)]
220+
public void Throws_WhenIsFixed_Changes(bool isFixed)
221+
{
222+
ModelBindingContext capturedContext = null;
223+
RenderFragment<ModelBindingContext> contents = (ctx) => b => { capturedContext = ctx; };
224+
var testComponent = new TestComponent(builder =>
225+
{
226+
builder.OpenComponent<CascadingModelBinder>(0);
227+
builder.AddAttribute(1, nameof(CascadingModelBinder.IsFixed), isFixed);
228+
builder.AddAttribute(2, nameof(CascadingModelBinder.ChildContent), contents);
229+
builder.CloseComponent();
230+
});
231+
var id = _renderer.AssignRootComponentId(testComponent);
232+
_renderer.RenderRootComponent(id);
233+
234+
// Act
235+
isFixed = !isFixed;
236+
var exception = Assert.Throws<InvalidOperationException>(testComponent.TriggerRender);
237+
238+
Assert.Equal("The value of IsFixed cannot be changed dynamically.", exception.Message);
239+
}
240+
241+
[Fact]
242+
public void CanChange_Name_WhenNotFixed()
243+
{
244+
ModelBindingContext capturedContext = null;
245+
ModelBindingContext originalContext = null;
246+
RenderFragment<ModelBindingContext> contents = (ctx) => b => { capturedContext = ctx; };
247+
var contextName = "parent-context";
248+
249+
var testComponent = new TestComponent(builder =>
250+
{
251+
builder.OpenComponent<CascadingModelBinder>(0);
252+
builder.AddAttribute(1, nameof(CascadingModelBinder.Name), contextName);
253+
builder.AddAttribute(3, nameof(CascadingModelBinder.ChildContent), contents);
254+
builder.CloseComponent();
255+
});
256+
var id = _renderer.AssignRootComponentId(testComponent);
257+
_renderer.RenderRootComponent(id);
258+
259+
originalContext = capturedContext;
260+
contextName = "changed";
261+
262+
// Act
263+
testComponent.TriggerRender();
264+
265+
Assert.NotSame(capturedContext, originalContext);
266+
Assert.Equal("changed", capturedContext.Name);
267+
}
268+
269+
[Fact]
270+
public void CanChange_BindingContextId_WhenNotFixed()
271+
{
272+
ModelBindingContext capturedContext = null;
273+
ModelBindingContext originalContext = null;
274+
RenderFragment<ModelBindingContext> contents = (ctx) => b => { capturedContext = ctx; };
275+
276+
var testComponent = new TestComponent(builder =>
277+
{
278+
builder.OpenComponent<CascadingModelBinder>(0);
279+
builder.AddComponentParameter(1, nameof(CascadingModelBinder.Name), "context-name");
280+
builder.AddComponentParameter(2, nameof(CascadingModelBinder.ChildContent), contents);
281+
builder.CloseComponent();
282+
});
283+
var id = _renderer.AssignRootComponentId(testComponent);
284+
_renderer.RenderRootComponent(id);
285+
286+
originalContext = capturedContext;
287+
288+
// Act
289+
_navigationManager.NavigateTo(_navigationManager.ToAbsoluteUri("fetch-data/6").ToString());
290+
testComponent.TriggerRender();
291+
292+
Assert.NotSame(capturedContext, originalContext);
293+
Assert.Equal("fetch-data/6?handler=context-name", capturedContext.BindingContextId);
294+
}
295+
216296
private class RouteViewTestNavigationManager : NavigationManager
217297
{
218298
public RouteViewTestNavigationManager() =>

src/Components/Components/test/RouteViewTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public void RendersPageInsideLayoutView()
8989
var cascadingModelBinderFrames = _renderer.GetCurrentRenderTreeFrames(cascadingModelBinderComponentId).AsEnumerable();
9090
Assert.Collection(cascadingModelBinderFrames,
9191
frame => AssertFrame.Component<CascadingValue<ModelBindingContext>>(frame, sequence: 0, subtreeLength: 4),
92-
frame => AssertFrame.Attribute(frame, nameof(CascadingValue<ModelBindingContext>.IsFixed), true, sequence: 1),
92+
frame => AssertFrame.Attribute(frame, nameof(CascadingValue<ModelBindingContext>.IsFixed), false, sequence: 1),
9393
frame => AssertFrame.Attribute(frame, nameof(CascadingValue<ModelBindingContext>.Value), typeof(ModelBindingContext), sequence: 2),
9494
frame => AssertFrame.Attribute(frame, nameof(CascadingValue<ModelBindingContext>.ChildContent), typeof(RenderFragment), sequence: 3));
9595

0 commit comments

Comments
 (0)