From 0a8ab9025bf7ef74c75759f3a84d5bf7bb836065 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 11:08:19 -0700 Subject: [PATCH 1/6] Add workaround for current tooling We don't want to put this in one of the product assemblies because that would undo the API review xD --- .../test/testassets/BasicTestApp/BindMethods.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/Components/test/testassets/BasicTestApp/BindMethods.cs diff --git a/src/Components/test/testassets/BasicTestApp/BindMethods.cs b/src/Components/test/testassets/BasicTestApp/BindMethods.cs new file mode 100644 index 000000000000..78ec6cdd356a --- /dev/null +++ b/src/Components/test/testassets/BasicTestApp/BindMethods.cs @@ -0,0 +1,11 @@ +namespace Microsoft.AspNetCore.Components +{ + // This is a temporary workaround for the fact that public previews of VS look for + // this type. Without this the tooling won't understand bind or event handlers. + // + // This has already gotten better in 16.3 and we look for IComponent rather + // than specific implementation details. + public static class BindMethods + { + } +} From f9f21afc8204a8e8b5ec2c9d5987d0811ec89a16 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 11:14:38 -0700 Subject: [PATCH 2/6] Unskip weakly-typed component bind tests --- .../Blazor/Build/test/BindRazorIntegrationTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs b/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs index 3d7a9db6deb4..5c8eb3dca6c2 100644 --- a/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs +++ b/src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs @@ -55,7 +55,7 @@ public class MyComponent : ComponentBase frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(Action), 2)); } - [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")] + [Fact] public void Render_BindToComponent_SpecifiesValue_WithoutMatchingProperties() { // Arrange @@ -89,7 +89,7 @@ Task IComponent.SetParametersAsync(ParameterCollection parameters) frames, frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(EventCallback), 2)); + frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(EventCallback), 2)); } [Fact] @@ -129,7 +129,7 @@ public class MyComponent : ComponentBase frame => AssertFrame.Attribute(frame, "OnChanged", typeof(Action), 2)); } - [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")] + [Fact] public void Render_BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties() { // Arrange @@ -163,7 +163,7 @@ Task IComponent.SetParametersAsync(ParameterCollection parameters) frames, frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0), frame => AssertFrame.Attribute(frame, "Value", 42, 1), - frame => AssertFrame.Attribute(frame, "OnChanged", typeof(EventCallback), 2)); + frame => AssertFrame.Attribute(frame, "OnChanged", typeof(EventCallback), 2)); } [Fact] From a38f0405c4dc57aa5ac824c55243b180744d53b9 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 11:24:36 -0700 Subject: [PATCH 3/6] Add ability to specify culture and format This lets us specify the associations between the HTML5 field types and these settings. --- ...ft.AspNetCore.Components.netstandard2.0.cs | 12 ++++++---- .../Components/src/BindAttributes.cs | 8 +++---- .../src/BindInputElementAttribute.cs | 24 +++++++++++++++++-- 3 files changed, 33 insertions(+), 11 deletions(-) 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 d917970d516e..1221e96b0a74 100644 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs @@ -18,10 +18,10 @@ protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task - this is a fallback and will be ignored // when a specific type attribute is applied. - [BindInputElement(null, null, "value", "onchange")] + [BindInputElement(null, null, "value", "onchange", isInvariantCulture: false, format: null)] // Handles cases like - this is a fallback and will be ignored // when a specific type attribute is applied. - [BindInputElement(null, "value", "value", "onchange")] + [BindInputElement(null, "value", "value", "onchange", isInvariantCulture: false, format: null)] - [BindInputElement("checkbox", null, "checked", "onchange")] - [BindInputElement("text", null, "value", "onchange")] + [BindInputElement("checkbox", null, "checked", "onchange", isInvariantCulture: false, format: null)] + [BindInputElement("text", null, "value", "onchange", isInvariantCulture: false, format: null)] [BindElement("select", null, "value", "onchange")] [BindElement("textarea", null, "value", "onchange")] diff --git a/src/Components/Components/src/BindInputElementAttribute.cs b/src/Components/Components/src/BindInputElementAttribute.cs index fe618ca7bbc6..0cba1a8e84e7 100644 --- a/src/Components/Components/src/BindInputElementAttribute.cs +++ b/src/Components/Components/src/BindInputElementAttribute.cs @@ -1,7 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Globalization; namespace Microsoft.AspNetCore.Components { @@ -18,7 +19,13 @@ public sealed class BindInputElementAttribute : Attribute /// The suffix value. /// The name of the value attribute to be bound. /// The name of an attribute that will register an associated change event. - public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute) + /// + /// Determines whether binding will use or . + /// + /// + /// An optional format to use when converting values. + /// + public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute, bool isInvariantCulture, string format) { if (valueAttribute == null) { @@ -34,6 +41,8 @@ public BindInputElementAttribute(string type, string suffix, string valueAttribu Suffix = suffix; ValueAttribute = valueAttribute; ChangeAttribute = changeAttribute; + IsInvariantCulture = isInvariantCulture; + Format = format; } /// @@ -55,5 +64,16 @@ public BindInputElementAttribute(string type, string suffix, string valueAttribu /// Gets the name of an attribute that will register an associated change event. /// public string ChangeAttribute { get; } + + /// + /// Gets a value that determines whether binding will use or + /// . + /// + public bool IsInvariantCulture { get; } + + /// + /// Gets an optional format to use when converting values. + /// + public string Format { get; } } } From a3656a9f0f32e06107fc8165051c71a62e9b0eba Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 12:32:55 -0700 Subject: [PATCH 4/6] Add support for type="number" and type="date" --- .../ref/Microsoft.AspNetCore.Components.netstandard2.0.cs | 2 ++ src/Components/Components/src/BindAttributes.cs | 6 ++++++ .../testassets/BasicTestApp/GlobalizationBindCases.razor | 8 ++++---- 3 files changed, 12 insertions(+), 4 deletions(-) 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 1221e96b0a74..432c5563e111 100644 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs @@ -19,6 +19,8 @@ protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task

Numbers using bind in number fields

- int: + int: @inputTypeNumberInt
- decimal: + decimal: @inputTypeNumberDecimal
@@ -43,12 +43,12 @@

Dates using bind in date fields

DateTime: - + @inputTypeDateDateTime
DateTimeOffset: - + @inputTypeDateDateTimeOffset
From da0edc8e4f565394781cc710e7add9ac62c02fbf Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 12:33:08 -0700 Subject: [PATCH 5/6] Attempt to fix bind tests for non-en-US While it's definitly intended for `@bind` to have culture-sensitive output for most cases, we want the tests to behave consistently for all developers. So this is an attempt to use a fixed culture for all of our testing. --- src/Components/test/testassets/BasicTestApp/Program.cs | 4 ++++ src/Components/test/testassets/TestServer/Startup.cs | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Components/test/testassets/BasicTestApp/Program.cs b/src/Components/test/testassets/BasicTestApp/Program.cs index 5e85aca979c2..cebb226e7c46 100644 --- a/src/Components/test/testassets/BasicTestApp/Program.cs +++ b/src/Components/test/testassets/BasicTestApp/Program.cs @@ -1,6 +1,7 @@ // 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.Globalization; using Microsoft.AspNetCore.Blazor.Hosting; namespace BasicTestApp @@ -9,6 +10,9 @@ public class Program { public static void Main(string[] args) { + // We want the culture to be en-US so that the tests for bind can work consistently. + CultureInfo.CurrentCulture = new CultureInfo("en-US"); + CreateHostBuilder(args).Build().Run(); } diff --git a/src/Components/test/testassets/TestServer/Startup.cs b/src/Components/test/testassets/TestServer/Startup.cs index c7024786d4e7..4aba67f9f98c 100644 --- a/src/Components/test/testassets/TestServer/Startup.cs +++ b/src/Components/test/testassets/TestServer/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -76,7 +77,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) options.AddSupportedCultures("en-US", "fr-FR"); options.AddSupportedUICultures("en-US", "fr-FR"); - // Cookie culture provider is included by default. + // Cookie culture provider is included by default, but we want it to be the only one. + options.RequestCultureProviders.Clear(); + options.RequestCultureProviders.Add(new CookieRequestCultureProvider()); + + // We want the default to be en-US so that the tests for bind can work consistently. + options.SetDefaultCulture("en-US"); }); app.UseRouting(); From 2b181c94b1545b4d0251b5f5e9b6481a0529670f Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 19 Jul 2019 12:51:54 -0700 Subject: [PATCH 6/6] Fix second part of #12286 We used to be inconsistent between what we'd do when formatting a value based on whether or not you specified a format. This change brings us back into consistency. For a `default` DateTime/DateTimeOffset we will just call ToString on it. For a `default` nullable of these types we will return the empty string. --- src/Components/test/E2ETest/Tests/BindTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Components/test/E2ETest/Tests/BindTest.cs b/src/Components/test/E2ETest/Tests/BindTest.cs index 1f0dd5c496d1..0ca35690bbee 100644 --- a/src/Components/test/E2ETest/Tests/BindTest.cs +++ b/src/Components/test/E2ETest/Tests/BindTest.cs @@ -759,7 +759,7 @@ public void CanBindTextboxNullableDateTimeOffset() // For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side // Blazor have different formatting behaviour by default. - [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")] + [Fact] public void CanBindTextboxDateTimeWithFormat() { var target = Browser.FindElement(By.Id("textbox-datetime-format")); @@ -770,11 +770,11 @@ public void CanBindTextboxDateTimeWithFormat() Assert.Equal(expected, DateTime.Parse(boundValue.Text)); Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value"))); - // Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format + // Clear textbox; value updates to the default target.Clear(); target.SendKeys("\t"); expected = default; - Browser.Equal(string.Empty, () => target.GetAttribute("value")); + Browser.Equal("01-01", () => target.GetAttribute("value")); Assert.Equal(expected, DateTime.Parse(boundValue.Text)); Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value"))); @@ -818,7 +818,7 @@ public void CanBindTextboxNullableDateTimeWithFormat() // For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side // Blazor have different formatting behaviour by default. - [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")] + [Fact] public void CanBindTextboxDateTimeOffsetWithFormat() { var target = Browser.FindElement(By.Id("textbox-datetimeoffset-format")); @@ -829,10 +829,10 @@ public void CanBindTextboxDateTimeOffsetWithFormat() Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text)); Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value"))); - // Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format + // Clear textbox; value updates to the default target.Clear(); expected = default; - Browser.Equal(string.Empty, () => target.GetAttribute("value")); + Browser.Equal("01-01", () => target.GetAttribute("value")); Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text)); Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));