Skip to content

Commit 1def9b7

Browse files
committed
Make binders handle exceptions during conversion
1 parent 7780b9e commit 1def9b7

File tree

3 files changed

+70
-8
lines changed

3 files changed

+70
-8
lines changed

src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,22 @@ public static EventCallback<UIChangeEventArgs> CreateBinder(
330330
// when a format is used.
331331
Action<UIChangeEventArgs> callback = (e) =>
332332
{
333-
setter(ConvertDateTime(e.Value, format: null));
333+
DateTime value = default;
334+
var converted = false;
335+
try
336+
{
337+
value = ConvertDateTime(e.Value, format: null);
338+
converted = true;
339+
}
340+
catch
341+
{
342+
}
343+
344+
// See comments in CreateBinderCore
345+
if (converted)
346+
{
347+
setter(value);
348+
}
334349
};
335350
return factory.Create<UIChangeEventArgs>(receiver, callback);
336351
}
@@ -355,7 +370,22 @@ public static EventCallback<UIChangeEventArgs> CreateBinder(
355370
// when a format is used.
356371
Action<UIChangeEventArgs> callback = (e) =>
357372
{
358-
setter(ConvertDateTime(e.Value, format));
373+
DateTime value = default;
374+
var converted = false;
375+
try
376+
{
377+
value = ConvertDateTime(e.Value, format);
378+
converted = true;
379+
}
380+
catch
381+
{
382+
}
383+
384+
// See comments in CreateBinderCore
385+
if (converted)
386+
{
387+
setter(value);
388+
}
359389
};
360390
return factory.Create<UIChangeEventArgs>(receiver, callback);
361391
}
@@ -403,7 +433,24 @@ private static EventCallback<UIChangeEventArgs> CreateBinderCore<T>(
403433
{
404434
Action<UIChangeEventArgs> callback = e =>
405435
{
406-
setter(converter(e.Value));
436+
T value = default;
437+
var converted = false;
438+
try
439+
{
440+
value = converter(e.Value);
441+
converted = true;
442+
}
443+
catch
444+
{
445+
}
446+
447+
// We only invoke the setter if the conversion didn't throw. This is valuable because it allows us to attempt
448+
// to process invalid input but avoid dirtying the state of the component if can't be converted. Imagine if
449+
// we assigned default(T) on failure - this would result in trouncing the user's typed in value.
450+
if (converted)
451+
{
452+
setter(value);
453+
}
407454
};
408455
return factory.Create<UIChangeEventArgs>(receiver, callback);
409456
}

src/Components/Components/test/EventCallbackFactoryBinderExtensionsTest.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components
1010
public class EventCallbackFactoryBinderExtensionsTest
1111
{
1212
[Fact]
13-
public async Task CreateBinder_ThrowsConversionException()
13+
public async Task CreateBinder_SwallowsConversionException()
1414
{
1515
// Arrange
1616
var value = 17;
@@ -20,12 +20,27 @@ public async Task CreateBinder_ThrowsConversionException()
2020
var binder = EventCallback.Factory.CreateBinder(component, setter, value);
2121

2222
// Act
23-
await Assert.ThrowsAsync<FormatException>(() =>
23+
await binder.InvokeAsync(new UIChangeEventArgs() { Value = "not-an-integer!", });
24+
25+
Assert.Equal(17, value); // Setter not called
26+
Assert.Equal(1, component.Count);
27+
}
28+
29+
[Fact]
30+
public async Task CreateBinder_ThrowsSetterException()
31+
{
32+
// Arrange
33+
var component = new EventCountingComponent();
34+
Action<int> setter = (_) => { throw new InvalidTimeZoneException(); };
35+
36+
var binder = EventCallback.Factory.CreateBinder(component, setter, 17);
37+
38+
// Act
39+
await Assert.ThrowsAsync<InvalidTimeZoneException>(() =>
2440
{
25-
return binder.InvokeAsync(new UIChangeEventArgs() { Value = "not-an-integer!", });
41+
return binder.InvokeAsync(new UIChangeEventArgs() { Value = "18", });
2642
});
2743

28-
Assert.Equal(17, value);
2944
Assert.Equal(1, component.Count);
3045
}
3146

src/Components/test/E2ETest/Tests/BindTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ public void CanBindTextboxDecimal()
397397
target.Clear();
398398
target.SendKeys("0.010\t");
399399
WaitAssert.Equal("0.010", () => boundValue.Text);
400-
Assert.Equal("0.010", mirrorValue.GetAttribute("value"));
400+
WaitAssert.Equal("0.010", () => mirrorValue.GetAttribute("value"));
401401
}
402402

403403
[Fact]

0 commit comments

Comments
 (0)