From fe57c67d0ffac7b84178b07cd9fb312f6ea6aecb Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 9 Apr 2018 15:45:29 -0700 Subject: [PATCH] Remove old workaround @onclick and @bind This change removes support for the old syntax used for event handlers and two-way binding. See the relevant issues for details on the new features and improvements: bind https://github.com/aspnet/Blazor/issues/409 event handlers https://github.com/aspnet/Blazor/issues/503 Along with this change we've removed a few additional things Blazor could do that aren't part of Razor's usual syntax. ---- The features that was used to make something like: ``` + @functions { int currentCount = 0; - void IncrementCount() + void IncrementCount(UIMouseEventArgs e) { currentCount++; } diff --git a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorDiagnosticFactory.cs b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorDiagnosticFactory.cs index b00be8179..c99f32c66 100644 --- a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorDiagnosticFactory.cs +++ b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorDiagnosticFactory.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using AngleSharp; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -13,6 +12,43 @@ namespace Microsoft.AspNetCore.Blazor.Razor { internal static class BlazorDiagnosticFactory { + public static readonly RazorDiagnosticDescriptor CodeBlockInAttribute = + new RazorDiagnosticDescriptor( + "BL9979", + () => + "Code blocks delimited by '@{...}' like '@{{ {0} }}' for attributes are no longer supported " + + "These features have been changed to use attribute syntax. " + + "Use 'attr=\"@(x => {... }\"'.", + RazorDiagnosticSeverity.Error); + + public static RazorDiagnostic Create_CodeBlockInAttribute(SourceSpan? source, string expression) + { + var diagnostic = RazorDiagnostic.Create( + CodeBlockInAttribute, + source ?? SourceSpan.Undefined, + expression); + return diagnostic; + } + + public static readonly RazorDiagnosticDescriptor ExpressionInAttributeList = + new RazorDiagnosticDescriptor( + "BL9980", + () => + "Expressions like '{0}' inside of a tag must be part of an attribute. " + + "Previous releases of Blazor supported constructs like '@onclick(...)' or '@bind(...)'." + + "These features have been changed to use attribute syntax. " + + "Use 'onclick=\"@...\"' or 'bind=\"...\" respectively.", + RazorDiagnosticSeverity.Error); + + public static RazorDiagnostic Create_ExpressionInAttributeList(SourceSpan? source, string expression) + { + var diagnostic = RazorDiagnostic.Create( + ExpressionInAttributeList, + source ?? SourceSpan.Undefined, + expression); + return diagnostic; + } + public static readonly RazorDiagnosticDescriptor UnexpectedClosingTag = new RazorDiagnosticDescriptor( "BL9981", () => "Unexpected closing tag '{0}' with no matching start tag.", diff --git a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs index 0b281e4ae..b59d7e212 100644 --- a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs +++ b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs @@ -5,14 +5,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using AngleSharp; using AngleSharp.Html; using AngleSharp.Parser.Html; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; -using Microsoft.CodeAnalysis.CSharp; namespace Microsoft.AspNetCore.Blazor.Razor { @@ -27,15 +25,11 @@ private readonly static HashSet htmlVoidElementsLookup = new HashSet( new[] { "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr" }, StringComparer.OrdinalIgnoreCase); - private readonly static Regex bindExpressionRegex = new Regex(@"^bind\((.+)\)$"); - private readonly static CSharpParseOptions bindArgsParseOptions - = CSharpParseOptions.Default.WithKind(CodeAnalysis.SourceCodeKind.Script); private readonly ScopeStack _scopeStack = new ScopeStack(); private string _unconsumedHtml; private List _currentAttributeValues; private IDictionary _currentElementAttributes = new Dictionary(); - private IList _currentElementAttributeTokens = new List(); private int _sourceSequence = 0; private struct PendingAttribute @@ -43,11 +37,6 @@ private struct PendingAttribute public List Values { get; set; } } - private struct PendingAttributeToken - { - public IntermediateToken AttributeValue; - } - public override void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node) { if (context == null) @@ -118,27 +107,26 @@ public override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, throw new InvalidOperationException($"Invoked {nameof(WriteCSharpCodeAttributeValue)} while {nameof(_currentAttributeValues)} was null."); } - // For attributes like "onsomeevent=@{ /* some C# code */ }", we treat it as if you - // wrote "onsomeevent=@(_ => { /* some C# code */ })" because then it works as an - // event handler and is a reasonable syntax for that. - var innerCSharp = (IntermediateToken)node.Children.Single(); - innerCSharp.Content = $"_ => {{ {innerCSharp.Content} }}"; - _currentAttributeValues.Add(innerCSharp); + // We used to support syntaxes like but this is no longer the + // case. + // + // We provide an error for this case just to be friendly. + var content = string.Join("", node.Children.OfType().Select(t => t.Content)); + context.Diagnostics.Add(BlazorDiagnosticFactory.Create_CodeBlockInAttribute(node.Source, content)); + return; } public override void WriteCSharpExpression(CodeRenderingContext context, CSharpExpressionIntermediateNode node) { - // To support syntax like (which in turn supports syntax - // like ), check whether we are currently in the middle of - // writing an element. If so, treat this C# expression as something that should evaluate - // as a RenderTreeFrame of type Attribute. + // We used to support syntaxes like but this is no longer the case. + // The APIs that a user would need to do this correctly aren't accessible outside of Blazor's core + // anyway. + // + // We provide an error for this case just to be friendly. if (_unconsumedHtml != null) { - var token = (IntermediateToken)node.Children.Single(); - _currentElementAttributeTokens.Add(new PendingAttributeToken - { - AttributeValue = token - }); + var content = string.Join("", node.Children.OfType().Select(t => t.Content)); + context.Diagnostics.Add(BlazorDiagnosticFactory.Create_ExpressionInAttributeList(node.Source, content)); return; } @@ -279,15 +267,6 @@ public override void WriteHtmlContent(CodeRenderingContext context, HtmlContentI _currentElementAttributes.Clear(); } - if (_currentElementAttributeTokens.Count > 0) - { - foreach (var token in _currentElementAttributeTokens) - { - WriteElementAttributeToken(context, nextTag, token); - } - _currentElementAttributeTokens.Clear(); - } - _scopeStack.OpenScope( tagName: nextTag.Data, isComponent: false); } @@ -325,56 +304,6 @@ public override void WriteHtmlContent(CodeRenderingContext context, HtmlContentI } } - private void WriteElementAttributeToken(CodeRenderingContext context, HtmlTagToken tag, PendingAttributeToken token) - { - var bindMatch = bindExpressionRegex.Match(token.AttributeValue.Content); - if (bindMatch.Success) - { - // TODO: Consider alternatives to the @bind syntax. The following is very strange. - - // The @bind(X, Y, Z, ...) syntax is special. We convert it to a pair of attributes: - // [1] value=@BindMethods.GetValue(X, Y, Z, ...) - var valueParams = bindMatch.Groups[1].Value; - WriteAttribute(context.CodeWriter, "value", new[] - { - new IntermediateToken - { - Kind = TokenKind.CSharp, - Content = $"{BlazorApi.BindMethods.GetValue}({valueParams})" - } - }); - - // [2] @onchange(BindSetValue(parsed => { X = parsed; }, X, Y, Z, ...)) - var parsedArgs = CSharpSyntaxTree.ParseText(valueParams, bindArgsParseOptions); - var parsedArgsSplit = parsedArgs.GetRoot().ChildNodes().Select(x => x.ToString()).ToList(); - if (parsedArgsSplit.Count > 0) - { - parsedArgsSplit.Insert(0, $"_parsedValue_ => {{ {parsedArgsSplit[0]} = _parsedValue_; }}"); - } - var parsedArgsJoined = string.Join(", ", parsedArgsSplit); - var onChangeAttributeToken = new PendingAttributeToken - { - AttributeValue = new IntermediateToken - { - Kind = TokenKind.CSharp, - Content = $"onchange({BlazorApi.BindMethods.SetValue}({parsedArgsJoined}))" - } - }; - WriteElementAttributeToken(context, tag, onChangeAttributeToken); - } - else - { - // For any other attribute token (e.g., @onclick(...)), treat it as an expression - // that will evaluate as an attribute frame - context.CodeWriter - .WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.AddAttribute)}") - .Write((_sourceSequence++).ToString()) - .WriteParameterSeparator() - .Write(token.AttributeValue.Content) - .WriteEndMethodInvocation(); - } - } - public override void WriteUsingDirective(CodeRenderingContext context, UsingDirectiveIntermediateNode node) { context.CodeWriter.WriteUsing(node.Content, endLine: true); diff --git a/src/Microsoft.AspNetCore.Blazor/Components/BindAttributes.cs b/src/Microsoft.AspNetCore.Blazor/Components/BindAttributes.cs index 4c44cd18c..976025640 100644 --- a/src/Microsoft.AspNetCore.Blazor/Components/BindAttributes.cs +++ b/src/Microsoft.AspNetCore.Blazor/Components/BindAttributes.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Blazor.Components [BindInputElement("text", null, "value", "onchange")] [BindElement("select", null, "value", "onchange")] + [BindElement("textarea", null, "value", "onchange")] public static class BindAttributes { } diff --git a/src/Microsoft.AspNetCore.Blazor/Components/BlazorComponent.cs b/src/Microsoft.AspNetCore.Blazor/Components/BlazorComponent.cs index 1f5ee20fe..b25ba06bb 100644 --- a/src/Microsoft.AspNetCore.Blazor/Components/BlazorComponent.cs +++ b/src/Microsoft.AspNetCore.Blazor/Components/BlazorComponent.cs @@ -178,50 +178,5 @@ void IHandleEvent.HandleEvent(UIEventHandler handler, UIEventArgs args) // at the end of every event callback. StateHasChanged(); } - - // At present, if you have a .cshtml file in a project with , - // Visual Studio will run design-time builds for it, codegenning a class that attempts to override - // this method. Therefore the virtual method must be defined, even though it won't be used at runtime, - // because otherwise VS will display a design-time error in its 'Error List' pane. - // TODO: Track down what triggers the design-time build for .cshtml files and how to stop it, then - // this method can be removed. - /// - /// Not used. Do not invoke this method. - /// - /// Always throws an exception. - public virtual Task ExecuteAsync() - => throw new NotImplementedException($"Blazor components do not implement {nameof(ExecuteAsync)}."); - - /// - /// Applies two-way data binding between the element and the property. - /// - /// The model property to be bound to the element. - protected RenderTreeFrame bind(object value) - => throw new NotImplementedException($"{nameof(bind)} is a compile-time symbol only and should not be invoked."); - - /// - /// Applies two-way data binding between the element and the property. - /// - /// The model property to be bound to the element. - protected RenderTreeFrame bind(DateTime value, string format) - => throw new NotImplementedException($"{nameof(bind)} is a compile-time symbol only and should not be invoked."); - - /// - /// Handles click events by invoking . - /// - /// The handler to be invoked when the event occurs. - /// A that represents the event handler. - protected RenderTreeFrame onclick(Action handler) - // Note that the 'sequence' value is updated later when inserted into the tree - => RenderTreeFrame.Attribute(0, "onclick", handler != null ? (_ => handler()) : (UIEventHandler)null); - - /// - /// Handles change events by invoking . - /// - /// The handler to be invoked when the event occurs. The handler will receive the new value as a parameter. - /// A that represents the event handler. - protected RenderTreeFrame onchange(Action handler) - // Note that the 'sequence' value is updated later when inserted into the tree - => RenderTreeFrame.Attribute(0, "onchange", args => handler(((UIChangeEventArgs)args).Value)); } } diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/DiagnosticRazorIntegrationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/DiagnosticRazorIntegrationTest.cs index e5391c39a..972a6a56c 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/DiagnosticRazorIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/DiagnosticRazorIntegrationTest.cs @@ -47,5 +47,45 @@ public void RejectsEndTagWithDifferentNameToStartTag() Assert.Equal(20, item.Span.CharacterIndex); }); } + + // This is the old syntax used by @bind and @onclick, it's explicitly unsupported + // and has its own diagnostic. + [Fact] + public void OldEventHandlerSyntax_ReportsError() + { + // Arrange/Act + var generated = CompileToCSharp(@" + +@functions { + void MyHandler() + { + } + + string foo(Action action) + { + return action.ToString(); + } +}"); + + // Assert + var diagnostic = Assert.Single(generated.Diagnostics); + Assert.Equal("BL9980", diagnostic.Id); + } + + // This used to be a sugar syntax for lambdas, but we don't support that anymore + [Fact] + public void OldCodeBlockAttributeSyntax_ReportsError() + { + // Arrange/Act + var generated = CompileToCSharp(@" + +@functions { + public bool DidInvokeCode { get; set; } = false; +}"); + + // Assert + var diagnostic = Assert.Single(generated.Diagnostics); + Assert.Equal("BL9979", diagnostic.Id); + } } } diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs index ebf50539e..94c8375d9 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs @@ -315,34 +315,6 @@ void MyHandleEvent(Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) frame => AssertFrame.Whitespace(frame, 2)); } - [Fact] - public void SupportsAttributesWithCSharpCodeBlockValues() - { - // Arrange/Act - var component = CompileToComponent( - @" - @functions { - public bool DidInvokeCode { get; set; } = false; - }"); - var didInvokeCodeProperty = component.GetType().GetProperty("DidInvokeCode"); - var frames = GetRenderTree(component); - - // Assert - Assert.False((bool)didInvokeCodeProperty.GetValue(component)); - Assert.Collection(frames, - frame => AssertFrame.Element(frame, "elem", 2, 0), - frame => - { - Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType); - Assert.NotNull(frame.AttributeValue); - Assert.Equal(1, frame.Sequence); - - ((UIEventHandler)frame.AttributeValue)(null); - Assert.True((bool)didInvokeCodeProperty.GetValue(component)); - }, - frame => AssertFrame.Whitespace(frame, 2)); - } - [Fact] public void SupportsUsingStatements() { @@ -359,42 +331,41 @@ public void SupportsUsingStatements() } [Fact] - public void SupportsAttributeFramesEvaluatedInline() + public void SupportsTwoWayBindingForTextboxes() { // Arrange/Act var component = CompileToComponent( - @" + @" @functions { - public bool DidInvokeCode { get; set; } = false; - void MyHandler() - { - DidInvokeCode = true; - } + public string MyValue { get; set; } = ""Initial value""; }"); - var didInvokeCodeProperty = component.GetType().GetProperty("DidInvokeCode"); + var myValueProperty = component.GetType().GetProperty("MyValue"); // Assert - Assert.False((bool)didInvokeCodeProperty.GetValue(component)); - Assert.Collection(GetRenderTree(component), - frame => AssertFrame.Element(frame, "elem", 2, 0), + var frames = GetRenderTree(component); + Assert.Collection(frames, + frame => AssertFrame.Element(frame, "input", 3, 0), + frame => AssertFrame.Attribute(frame, "value", "Initial value", 1), frame => { - Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType); - Assert.NotNull(frame.AttributeValue); - Assert.Equal(1, frame.Sequence); + AssertFrame.Attribute(frame, "onchange", 2); - ((UIEventHandler)frame.AttributeValue)(null); - Assert.True((bool)didInvokeCodeProperty.GetValue(component)); + // Trigger the change event to show it updates the property + ((UIEventHandler)frame.AttributeValue)(new UIChangeEventArgs + { + Value = "Modified value" + }); + Assert.Equal("Modified value", myValueProperty.GetValue(component)); }, - frame => AssertFrame.Whitespace(frame, 2)); + frame => AssertFrame.Text(frame, "\n", 3)); } [Fact] - public void SupportsTwoWayBindingForTextboxes() + public void SupportsTwoWayBindingForTextareas() { // Arrange/Act var component = CompileToComponent( - @" + @" @functions { public string MyValue { get; set; } = ""Initial value""; }"); @@ -403,7 +374,7 @@ public void SupportsTwoWayBindingForTextboxes() // Assert var frames = GetRenderTree(component); Assert.Collection(frames, - frame => AssertFrame.Element(frame, "input", 3, 0), + frame => AssertFrame.Element(frame, "textarea", 3, 0), frame => AssertFrame.Attribute(frame, "value", "Initial value", 1), frame => { @@ -534,7 +505,7 @@ public void SupportsEventHandlerWithMethodGroup() // Arrange var component = CompileToComponent(@" @using Microsoft.AspNetCore.Blazor - - + + @foreach (var message in currentChildrenMessages) { @@ -12,13 +13,13 @@ Child components follow. int numAdded = 0; List currentChildrenMessages = new List(); - void AddChild() + void AddChild(UIMouseEventArgs e) { numAdded++; currentChildrenMessages.Add($"Child {numAdded}"); } - void RemoveChild() + void RemoveChild(UIMouseEventArgs e) { if (currentChildrenMessages.Count > 0) { diff --git a/test/testapps/BasicTestApp/BindCasesComponent.cshtml b/test/testapps/BasicTestApp/BindCasesComponent.cshtml index 86a418ae4..b0b1d5058 100644 --- a/test/testapps/BasicTestApp/BindCasesComponent.cshtml +++ b/test/testapps/BasicTestApp/BindCasesComponent.cshtml @@ -1,4 +1,5 @@ -

Textbox

+@using Microsoft.AspNetCore.Blazor +

Textbox

Initially blank: @@ -13,12 +14,12 @@

Text Area

Initially blank: - + @textAreaIntiallyBlankValue

Initially populated: - + @textAreaIntiallyPopulatedValue

@@ -46,7 +47,7 @@ } @selectValue - +

@functions { @@ -63,7 +64,7 @@ enum SelectableValue { First, Second, Third, Fourth } SelectableValue selectValue = SelectableValue.Second; - void AddAndSelectNewSelectOption() + void AddAndSelectNewSelectOption(UIMouseEventArgs e) { includeFourthOption = true; selectValue = SelectableValue.Fourth; diff --git a/test/testapps/BasicTestApp/CounterComponent.cshtml b/test/testapps/BasicTestApp/CounterComponent.cshtml index d54b508aa..6edcd7621 100644 --- a/test/testapps/BasicTestApp/CounterComponent.cshtml +++ b/test/testapps/BasicTestApp/CounterComponent.cshtml @@ -1,9 +1,10 @@ -

Counter

+@using Microsoft.AspNetCore.Blazor +

Counter

Current count: @currentCount

-

+

@@ -11,7 +12,7 @@ int currentCount = 0; bool handleClicks = true; - void IncrementCount() + void IncrementCount(UIMouseEventArgs e) { currentCount++; } diff --git a/test/testapps/BasicTestApp/CounterComponentUsingChild.cshtml b/test/testapps/BasicTestApp/CounterComponentUsingChild.cshtml index 2b59f4f18..1f654d054 100644 --- a/test/testapps/BasicTestApp/CounterComponentUsingChild.cshtml +++ b/test/testapps/BasicTestApp/CounterComponentUsingChild.cshtml @@ -1,14 +1,15 @@ -

Counter

+@using Microsoft.AspNetCore.Blazor +

Counter

Current count:

- + @functions { int currentCount = 0; - void IncrementCount() + void IncrementCount(UIMouseEventArgs e) { currentCount++; } diff --git a/test/testapps/BasicTestApp/ExternalContentPackage.cshtml b/test/testapps/BasicTestApp/ExternalContentPackage.cshtml index 49f86823a..864010358 100644 --- a/test/testapps/BasicTestApp/ExternalContentPackage.cshtml +++ b/test/testapps/BasicTestApp/ExternalContentPackage.cshtml @@ -1,4 +1,5 @@ @addTagHelper *, TestContentPackage +@using Microsoft.AspNetCore.Blazor @using TestContentPackage

Functionality and content from an external package

@@ -11,7 +12,7 @@

Click the following button to invoke a JavaScript function.

- + @if (!string.IsNullOrEmpty(result)) { @@ -31,7 +32,7 @@ { string result; - void ShowJavaScriptPrompt() + void ShowJavaScriptPrompt(UIMouseEventArgs e) { result = MyPrompt.Show("Hello!"); } diff --git a/test/testapps/BasicTestApp/HttpClientTest/CookieCounterComponent.cshtml b/test/testapps/BasicTestApp/HttpClientTest/CookieCounterComponent.cshtml index 9efde52e6..c8bd65a12 100644 --- a/test/testapps/BasicTestApp/HttpClientTest/CookieCounterComponent.cshtml +++ b/test/testapps/BasicTestApp/HttpClientTest/CookieCounterComponent.cshtml @@ -1,10 +1,11 @@ -@inject System.Net.Http.HttpClient Http +@using Microsoft.AspNetCore.Blazor +@inject System.Net.Http.HttpClient Http

Cookie counter

The server increments the count by one on each request.

-

TestServer base URL:

- - +

TestServer base URL:

+ + @if (!requestInProgress) { @@ -17,13 +18,13 @@ string testServerBaseUrl; string responseText; - async void DeleteCookie() + async void DeleteCookie(UIMouseEventArgs e) { await DoRequest("api/cookie/reset"); StateHasChanged(); } - async void GetAndIncrementCounter() + async void GetAndIncrementCounter(UIMouseEventArgs e) { await DoRequest("api/cookie/increment"); StateHasChanged(); diff --git a/test/testapps/BasicTestApp/HttpClientTest/HttpRequestsComponent.cshtml b/test/testapps/BasicTestApp/HttpClientTest/HttpRequestsComponent.cshtml index 5f9fd817b..06f21f59f 100644 --- a/test/testapps/BasicTestApp/HttpClientTest/HttpRequestsComponent.cshtml +++ b/test/testapps/BasicTestApp/HttpClientTest/HttpRequestsComponent.cshtml @@ -1,5 +1,6 @@ @using System.Net @using System.Net.Http +@using Microsoft.AspNetCore.Blazor @using Microsoft.AspNetCore.Blazor.Browser.Http @inject HttpClient Http @@ -7,12 +8,12 @@

URI:
- { uri = (string)value; }) size="60"/> +

Method:
- @@ -22,7 +23,7 @@

Request body:
- +

@@ -30,20 +31,20 @@ @foreach (var header in requestHeaders) {

- Name: { header.Name = (string)value; }) /> - Value: { header.Value = (string)value; }) /> - [ RemoveHeader(header))>remove] + Name: + Value: + [remove]
} - +

Request referrer:
- { requestReferrer = (string)value; }) /> +

- + @if (responseStatusCode.HasValue) { @@ -71,7 +72,7 @@ string responseBody; string responseHeaders; - async void DoRequest() + async void DoRequest(UIMouseEventArgs e) { responseStatusCode = null; @@ -124,7 +125,7 @@ StateHasChanged(); } - void AddHeader() + void AddHeader(UIMouseEventArgs e) => requestHeaders.Add(new RequestHeader()); void RemoveHeader(RequestHeader header) diff --git a/test/testapps/TestContentPackage/ComponentFromPackage.cshtml b/test/testapps/TestContentPackage/ComponentFromPackage.cshtml index a621fcf29..59b85f87c 100644 --- a/test/testapps/TestContentPackage/ComponentFromPackage.cshtml +++ b/test/testapps/TestContentPackage/ComponentFromPackage.cshtml @@ -1,14 +1,14 @@ -
+@using Microsoft.AspNetCore.Blazor +
This component, including the CSS and image required to produce its elegant styling, is in an external NuGet package. - +
-@functions -{ +@functions { string buttonLabel = "Click me"; - void ChangeLabel() + void ChangeLabel(UIMouseEventArgs e) { buttonLabel = "It works"; }