Fix #954 - use weak typing for 'event handlers'
This change introduces a mechanism for bypassing type checking and then uses for the 'event handlers'. The event handler tag helpers have some ideosyncratic behaviors and rely on overloading at the render tree builder level.
This commit is contained in:
parent
97d044e479
commit
45544858a3
|
|
@ -1,4 +1,4 @@
|
|||
// 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;
|
||||
|
|
@ -422,7 +422,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
context.CodeWriter.Write(" = ");
|
||||
|
||||
// If we have a parameter type, then add a type check.
|
||||
if (node.BoundAttribute != null)
|
||||
if (node.BoundAttribute != null && !node.BoundAttribute.IsWeaklyTyped())
|
||||
{
|
||||
context.CodeWriter.Write(BlazorApi.RuntimeHelpers.TypeCheck);
|
||||
context.CodeWriter.Write("<");
|
||||
|
|
@ -436,7 +436,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
WriteCSharpToken(context, tokens[i]);
|
||||
}
|
||||
|
||||
if (node.BoundAttribute != null)
|
||||
if (node.BoundAttribute != null && !node.BoundAttribute.IsWeaklyTyped())
|
||||
{
|
||||
context.CodeWriter.Write(")");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.Razor
|
||||
|
|
@ -30,6 +30,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
public static readonly string DelegateSignatureKey = "Blazor.DelegateSignature";
|
||||
|
||||
public static readonly string WeaklyTypedKey = "Blazor.IsWeaklyTyped";
|
||||
|
||||
public static readonly string RuntimeName = "Blazor.IComponent";
|
||||
|
||||
public readonly static string TagHelperKind = "Blazor.Component";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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;
|
||||
|
|
@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
}
|
||||
else
|
||||
{
|
||||
if (node.BoundAttribute != null)
|
||||
if (node.BoundAttribute != null && !node.BoundAttribute.IsWeaklyTyped())
|
||||
{
|
||||
context.CodeWriter.Write(BlazorApi.RuntimeHelpers.TypeCheck);
|
||||
context.CodeWriter.Write("<");
|
||||
|
|
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
context.CodeWriter.Write(tokens[i].Content);
|
||||
}
|
||||
|
||||
if (node.BoundAttribute != null)
|
||||
if (node.BoundAttribute != null && !node.BoundAttribute.IsWeaklyTyped())
|
||||
{
|
||||
context.CodeWriter.Write(")");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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;
|
||||
|
|
@ -143,6 +143,10 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
// Use a string here so that we get HTML context by default.
|
||||
a.TypeName = typeof(string).FullName;
|
||||
|
||||
// But make this weakly typed (don't type check) - delegates have their own type-checking
|
||||
// logic that we don't want to interfere with.
|
||||
a.Metadata.Add(BlazorMetadata.Component.WeaklyTypedKey, bool.TrueString);
|
||||
|
||||
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
||||
// a C# property will crash trying to create the toolips.
|
||||
a.SetPropertyName(entry.Attribute);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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;
|
||||
|
|
@ -20,5 +20,18 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
attribute.Metadata.TryGetValue(key, out var value) &&
|
||||
string.Equals(value, bool.TrueString);
|
||||
}
|
||||
|
||||
public static bool IsWeaklyTyped(this BoundAttributeDescriptor attribute)
|
||||
{
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attribute));
|
||||
}
|
||||
|
||||
var key = BlazorMetadata.Component.WeaklyTypedKey;
|
||||
return
|
||||
attribute.Metadata.TryGetValue(key, out var value) &&
|
||||
string.Equals(value, bool.TrueString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,40 @@ namespace Test
|
|||
CompileToAssembly(generated);
|
||||
}
|
||||
|
||||
// Regression test for #954 - we need to allow arbitrary event handler
|
||||
// attributes with weak typing.
|
||||
[Fact]
|
||||
public void ChildComponent_WithWeaklyTypeEventHandler()
|
||||
{
|
||||
// Arrange
|
||||
AdditionalSyntaxTrees.Add(Parse(@"
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Blazor;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
public class DynamicElement : BlazorComponent
|
||||
{
|
||||
}
|
||||
}
|
||||
"));
|
||||
|
||||
// Act
|
||||
var generated = CompileToCSharp(@"
|
||||
@addTagHelper *, TestAssembly
|
||||
<DynamicElement onclick=""@OnClick"" />
|
||||
|
||||
@functions {
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
}");
|
||||
|
||||
// Assert
|
||||
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
|
||||
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
|
||||
CompileToAssembly(generated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChildComponent_WithExplicitEventHandler()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -166,6 +166,40 @@ namespace Test
|
|||
CompileToAssembly(generated);
|
||||
}
|
||||
|
||||
// Regression test for #954 - we need to allow arbitrary event handler
|
||||
// attributes with weak typing.
|
||||
[Fact]
|
||||
public void ChildComponent_WithWeaklyTypeEventHandler()
|
||||
{
|
||||
// Arrange
|
||||
AdditionalSyntaxTrees.Add(Parse(@"
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Blazor;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
public class DynamicElement : BlazorComponent
|
||||
{
|
||||
}
|
||||
}
|
||||
"));
|
||||
|
||||
// Act
|
||||
var generated = CompileToCSharp(@"
|
||||
@addTagHelper *, TestAssembly
|
||||
<DynamicElement onclick=""@OnClick"" />
|
||||
|
||||
@functions {
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
}");
|
||||
|
||||
// Assert
|
||||
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
|
||||
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
|
||||
CompileToAssembly(generated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChildComponent_WithExplicitEventHandler()
|
||||
{
|
||||
|
|
@ -759,8 +793,6 @@ Welcome to your new app.
|
|||
[Fact] // https://github.com/aspnet/Blazor/issues/773
|
||||
public void Regression_773()
|
||||
{
|
||||
GenerateBaselines = true;
|
||||
|
||||
// Arrange
|
||||
AdditionalSyntaxTrees.Add(Parse(@"
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
// <auto-generated/>
|
||||
#pragma warning disable 1591
|
||||
namespace Test
|
||||
{
|
||||
#line hidden
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Blazor;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
|
||||
{
|
||||
#pragma warning disable 219
|
||||
private void __RazorDirectiveTokenHelpers__() {
|
||||
((System.Action)(() => {
|
||||
global::System.Object __typeHelper = "*, TestAssembly";
|
||||
}
|
||||
))();
|
||||
}
|
||||
#pragma warning restore 219
|
||||
#pragma warning disable 0414
|
||||
private static System.Object __o = null;
|
||||
#pragma warning restore 0414
|
||||
#pragma warning disable 1998
|
||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
__o = Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
|
||||
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||
OnClick
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
);
|
||||
builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
|
||||
}
|
||||
));
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
#line 4 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
Document -
|
||||
NamespaceDeclaration - - Test
|
||||
UsingDirective - (3:1,1 [12] ) - System
|
||||
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
|
||||
UsingDirective - (53:3,1 [17] ) - System.Linq
|
||||
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
|
||||
UsingDirective - (104:5,1 [33] ) - Microsoft.AspNetCore.Blazor
|
||||
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
|
||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
|
||||
DesignTimeDirective -
|
||||
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
|
||||
DirectiveToken - (14:0,14 [9] ) - "*, Test"
|
||||
DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly
|
||||
CSharpCode -
|
||||
IntermediateToken - - CSharp - #pragma warning disable 0414
|
||||
CSharpCode -
|
||||
IntermediateToken - - CSharp - private static System.Object __o = null;
|
||||
CSharpCode -
|
||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||
CSharpCode -
|
||||
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
|
||||
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||
ComponentExtensionNode - (31:1,0 [37] x:\dir\subdir\Test\TestComponent.cshtml) - DynamicElement - Test.DynamicElement
|
||||
ComponentAttributeExtensionNode - (56:1,25 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick - onclick
|
||||
CSharpExpression -
|
||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
|
||||
IntermediateToken - (57:1,26 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
|
||||
IntermediateToken - - CSharp - )
|
||||
HtmlContent - (68:1,37 [4] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
IntermediateToken - (68:1,37 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
|
||||
CSharpCode - (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
IntermediateToken - (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private Action<UIMouseEventArgs> OnClick { get; set; }\n
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
|*, TestAssembly|
|
||||
Generated Location: (559:16,38 [15] )
|
||||
|*, TestAssembly|
|
||||
|
||||
Source Location: (57:1,26 [7] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
|OnClick|
|
||||
Generated Location: (1201:30,26 [7] )
|
||||
|OnClick|
|
||||
|
||||
Source Location: (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
|
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
|
||||
Generated Location: (1516:41,12 [62] )
|
||||
|
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// <auto-generated/>
|
||||
#pragma warning disable 1591
|
||||
namespace Test
|
||||
{
|
||||
#line hidden
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Blazor;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
|
||||
{
|
||||
#pragma warning disable 1998
|
||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
builder.OpenComponent<Test.DynamicElement>(0);
|
||||
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(OnClick));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
#line 4 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Document -
|
||||
NamespaceDeclaration - - Test
|
||||
UsingDirective - (3:1,1 [14] ) - System
|
||||
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
|
||||
UsingDirective - (53:3,1 [19] ) - System.Linq
|
||||
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
|
||||
UsingDirective - (104:5,1 [35] ) - Microsoft.AspNetCore.Blazor
|
||||
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
|
||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
|
||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||
CSharpCode -
|
||||
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
|
||||
ComponentExtensionNode - (31:1,0 [37] x:\dir\subdir\Test\TestComponent.cshtml) - DynamicElement - Test.DynamicElement
|
||||
ComponentAttributeExtensionNode - (56:1,25 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick - onclick
|
||||
CSharpExpression -
|
||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
|
||||
IntermediateToken - (57:1,26 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
|
||||
IntermediateToken - - CSharp - )
|
||||
CSharpCode - (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
IntermediateToken - (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private Action<UIMouseEventArgs> OnClick { get; set; }\n
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Source Location: (84:3,12 [62] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||
|
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
|
||||
Generated Location: (989:23,12 [62] )
|
||||
|
|
||||
private Action<UIMouseEventArgs> OnClick { get; set; }
|
||||
|
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
|
@ -97,6 +98,11 @@ namespace Test
|
|||
Assert.False(attribute.IsIndexerBooleanProperty);
|
||||
Assert.False(attribute.IsIndexerStringProperty);
|
||||
|
||||
Assert.Collection(
|
||||
attribute.Metadata.OrderBy(kvp => kvp.Key),
|
||||
kvp => Assert.Equal(kvp, new KeyValuePair<string, string>(BlazorMetadata.Component.WeaklyTypedKey, bool.TrueString)),
|
||||
kvp => Assert.Equal(kvp, new KeyValuePair<string, string>("Common.PropertyName", "onclick")));
|
||||
|
||||
Assert.Equal(
|
||||
"Sets the 'onclick' attribute to the provided string or delegate value. " +
|
||||
"A delegate value should be of type 'System.Action<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>'.",
|
||||
|
|
|
|||
Loading…
Reference in New Issue