diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
index e92c5c1f7d..961cc46bfc 100644
--- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
+++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs
@@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Components
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, float existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, string existingValue) { throw null; }
- public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, T existingValue) where T : System.Enum { throw null; }
+ public static Microsoft.AspNetCore.Components.EventCallback CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action setter, T existingValue) where T : struct, System.Enum { throw null; }
}
public static partial class EventCallbackFactoryUIEventArgsExtensions
{
diff --git a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs b/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
index d35eb287c1..ba0a23dd0a 100644
--- a/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
+++ b/src/Components/Components/src/EventCallbackFactoryBinderExtensions.cs
@@ -11,74 +11,263 @@ namespace Microsoft.AspNetCore.Components
///
public static class EventCallbackFactoryBinderExtensions
{
+ private delegate bool BindConverter(object obj, out T value);
+
// Perf: conversion delegates are written as static funcs so we can prevent
// allocations for these simple cases.
- private static Func
+
+ decimal (invalid-input):
+
+ @textboxDecimalInvalidValue
+
+
+
+ Nullable decimal (invalid-input):
+
+ @textboxNullableDecimalInvalidValue
+
+
Text Area
@@ -116,7 +128,7 @@
@if (includeFourthOption)
{
-
+
}
@selectValue
@@ -144,6 +156,8 @@
double? textboxNullableDoubleValue = null;
decimal textboxDecimalValue = 0.0000000000000000000000000001M;
decimal? textboxNullableDecimalValue = null;
+ decimal textboxDecimalInvalidValue = 0.0000000000000000000000000001M;
+ decimal? textboxNullableDecimalInvalidValue = null;
bool includeFourthOption = false;
enum SelectableValue { First, Second, Third, Fourth }
diff --git a/src/Mvc/test/Mvc.FunctionalTests/ComponentRenderingFunctionalTests.cs b/src/Mvc/test/Mvc.FunctionalTests/ComponentRenderingFunctionalTests.cs
index dbbdd61985..53f7f24221 100644
--- a/src/Mvc/test/Mvc.FunctionalTests/ComponentRenderingFunctionalTests.cs
+++ b/src/Mvc/test/Mvc.FunctionalTests/ComponentRenderingFunctionalTests.cs
@@ -1,12 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using AngleSharp.Parser.Html;
using BasicWebSite;
using BasicWebSite.Services;
+using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
@@ -17,18 +19,17 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public ComponentRenderingFunctionalTests(MvcTestFixture fixture)
{
Factory = fixture;
- Client = Client ?? CreateClient(fixture);
}
- public HttpClient Client { get; }
-
public MvcTestFixture Factory { get; }
[Fact]
public async Task Renders_BasicComponent()
{
// Arrange & Act
- var response = await Client.GetAsync("http://localhost/components");
+ var client = CreateClient(Factory);
+
+ var response = await client.GetAsync("http://localhost/components");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -41,9 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task Renders_BasicComponent_UsingRazorComponents_Prerrenderer()
{
// Arrange & Act
- var client = Factory
- .WithWebHostBuilder(builder => builder.ConfigureServices(services => services.AddRazorComponents()))
- .CreateClient();
+ var client = CreateClient(Factory, builder => builder.ConfigureServices(services => services.AddRazorComponents()));
var response = await client.GetAsync("http://localhost/components");
@@ -58,7 +57,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task Renders_RoutingComponent()
{
// Arrange & Act
- var response = await Client.GetAsync("http://localhost/components/routable");
+ var client = CreateClient(Factory, builder => builder.ConfigureServices(services => services.AddRazorComponents()));
+
+ var response = await client.GetAsync("http://localhost/components/routable");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -71,9 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task Renders_RoutingComponent_UsingRazorComponents_Prerrenderer()
{
// Arrange & Act
- var client = Factory
- .WithWebHostBuilder(builder => builder.ConfigureServices(services => services.AddRazorComponents()))
- .CreateClient();
+ var client = CreateClient(Factory, builder => builder.ConfigureServices(services => services.AddRazorComponents()));
var response = await client.GetAsync("http://localhost/components/routable");
@@ -84,6 +83,21 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
AssertComponent("\n Router component\nRouted successfully
\n", "Routing", content);
}
+ [Fact]
+ public async Task Renders_ThrowingComponent_UsingRazorComponents_Prerrenderer()
+ {
+ // Arrange & Act
+ var client = CreateClient(Factory, builder => builder.ConfigureServices(services => services.AddRazorComponents()));
+
+ var response = await client.GetAsync("http://localhost/components/throws");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
+ var content = await response.Content.ReadAsStringAsync();
+
+ Assert.Contains("InvalidTimeZoneException: test", content);
+ }
+
[Fact]
public async Task Renders_AsyncComponent()
{
@@ -138,8 +152,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
";
-
- var response = await Client.GetAsync("http://localhost/components");
+ var client = CreateClient(Factory);
+ var response = await client.GetAsync("http://localhost/components");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -164,12 +178,16 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
}
- private HttpClient CreateClient(MvcTestFixture fixture)
+ private HttpClient CreateClient(MvcTestFixture fixture, Action configure = null)
{
var loopHandler = new LoopHttpHandler();
var client = fixture
- .WithWebHostBuilder(builder => builder.ConfigureServices(ConfigureTestWeatherForecastService))
+ .WithWebHostBuilder(builder =>
+ {
+ configure?.Invoke(builder);
+ builder.ConfigureServices(ConfigureTestWeatherForecastService);
+ })
.CreateClient();
// We configure the inner handler with a handler to this TestServer instance so that calls to the
diff --git a/src/Mvc/test/WebSites/BasicWebSite/Controllers/RazorComponentsController.cs b/src/Mvc/test/WebSites/BasicWebSite/Controllers/RazorComponentsController.cs
index c499c5f345..28aab986a3 100644
--- a/src/Mvc/test/WebSites/BasicWebSite/Controllers/RazorComponentsController.cs
+++ b/src/Mvc/test/WebSites/BasicWebSite/Controllers/RazorComponentsController.cs
@@ -51,7 +51,7 @@ namespace BasicWebSite.Controllers
};
[HttpGet("/components")]
- [HttpGet("/components/routable")]
+ [HttpGet("/components/{component}")]
public IActionResult Index()
{
return View();
diff --git a/src/Mvc/test/WebSites/BasicWebSite/RazorComponents/Throws.razor b/src/Mvc/test/WebSites/BasicWebSite/RazorComponents/Throws.razor
new file mode 100644
index 0000000000..3291fba732
--- /dev/null
+++ b/src/Mvc/test/WebSites/BasicWebSite/RazorComponents/Throws.razor
@@ -0,0 +1,10 @@
+@page "/components/throws"
+
+@* This is expected to throw and result in a 500 *@
+@functions {
+ protected override async Task OnInitAsync()
+ {
+ await base.OnInitAsync();
+ throw new InvalidTimeZoneException("test");
+ }
+}
\ No newline at end of file