From 3a6588fe91102ed3f5fa8ae9d7139e81bc2db17f Mon Sep 17 00:00:00 2001
From: Pranav K
Date: Mon, 3 May 2021 18:24:34 -0700
Subject: [PATCH 1/6] Use System.Text.Json's source generated code to
deserialize WebEvents
Also address missing "type" property on TouchEvent
Fixes https://github.com/dotnet/aspnetcore/issues/32357
---
.../Server/src/Circuits/CircuitHost.cs | 8 +-
src/Components/Server/src/JsonContext.cs | 12 ++
...rosoft.AspNetCore.Components.Server.csproj | 5 +-
src/Components/Shared/src/WebEventData.cs | 112 +++++++++++++-----
.../Web.JS/src/Rendering/Events/EventTypes.ts | 2 +
.../src/Infrastructure/JSInteropMethods.cs | 10 +-
.../src/Infrastructure/JsonContext.cs | 12 ++
...onents.WebAssembly.WarningSuppressions.xml | 4 +-
...t.AspNetCore.Components.WebAssembly.csproj | 2 +
.../WebView/WebView/src/IpcReceiver.cs | 8 +-
.../WebView/WebView/src/JsonContext.cs | 10 ++
.../test/E2ETest/Tests/EventTest.cs | 16 +++
.../BasicTestApp/TouchEventComponent.razor | 3 +-
13 files changed, 166 insertions(+), 38 deletions(-)
create mode 100644 src/Components/Server/src/JsonContext.cs
create mode 100644 src/Components/WebAssembly/WebAssembly/src/Infrastructure/JsonContext.cs
create mode 100644 src/Components/WebView/WebView/src/JsonContext.cs
diff --git a/src/Components/Server/src/Circuits/CircuitHost.cs b/src/Components/Server/src/Circuits/CircuitHost.cs
index d604959c0f57..3b353fa363c4 100644
--- a/src/Components/Server/src/Circuits/CircuitHost.cs
+++ b/src/Components/Server/src/Circuits/CircuitHost.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Security.Claims;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
@@ -24,6 +25,7 @@ internal class CircuitHost : IAsyncDisposable
private readonly ILogger _logger;
private bool _initialized;
private bool _disposed;
+ private JsonSourceGeneration.JsonContext _jsonContext;
// This event is fired when there's an unrecoverable exception coming from the circuit, and
// it need so be torn down. The registry listens to this even so that the circuit can
@@ -398,8 +400,10 @@ public async Task DispatchEvent(string eventDescriptorJson, string eventArgsJson
WebEventData webEventData;
try
{
- var jsonSerializerOptions = JSRuntime.ReadJsonSerializerOptions();
- webEventData = WebEventData.Parse(Renderer, jsonSerializerOptions, eventDescriptorJson, eventArgsJson);
+ // JsonSerializerOptions are tightly bound to the JsonContext. Cache it on first use using a copy
+ // of the serializer settings.
+ _jsonContext ??= new(new JsonSerializerOptions(JSRuntime.ReadJsonSerializerOptions()));
+ webEventData = WebEventData.Parse(Renderer, _jsonContext, eventDescriptorJson, eventArgsJson);
}
catch (Exception ex)
{
diff --git a/src/Components/Server/src/JsonContext.cs b/src/Components/Server/src/JsonContext.cs
new file mode 100644
index 000000000000..00689c6de7c8
--- /dev/null
+++ b/src/Components/Server/src/JsonContext.cs
@@ -0,0 +1,12 @@
+// 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.Text.Json.Serialization;
+using Microsoft.AspNetCore.Components.Web;
+
+namespace Microsoft.AspNetCore.Components.Server.JsonSourceGeneration
+{
+ internal partial class JsonContext : JsonSerializerContext, WebEventData.IWebEventJsonSerializerContext
+ {
+ }
+}
diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
index 6eca5b05b72c..26a25b971996 100644
--- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
+++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
@@ -1,4 +1,4 @@
-
+
$(DefaultNetCoreTargetFramework)
Runtime server features for ASP.NET Core Components.
@@ -24,6 +24,9 @@
+
+
+
diff --git a/src/Components/Shared/src/WebEventData.cs b/src/Components/Shared/src/WebEventData.cs
index 3443530d2d3f..0caaa811ae3a 100644
--- a/src/Components/Shared/src/WebEventData.cs
+++ b/src/Components/Shared/src/WebEventData.cs
@@ -6,8 +6,25 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Text.Json.Serialization.Metadata;
+using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.RenderTree;
-using static Microsoft.AspNetCore.Internal.LinkerFlags;
+using Microsoft.AspNetCore.Components.Web;
+
+[assembly: JsonSerializable(typeof(WebEventDescriptor))]
+[assembly: JsonSerializable(typeof(EventArgs))]
+[assembly: JsonSerializable(typeof(ChangeEventArgs))]
+[assembly: JsonSerializable(typeof(ClipboardEventArgs))]
+[assembly: JsonSerializable(typeof(DragEventArgs))]
+[assembly: JsonSerializable(typeof(ErrorEventArgs))]
+[assembly: JsonSerializable(typeof(FocusEventArgs))]
+[assembly: JsonSerializable(typeof(KeyboardEventArgs))]
+[assembly: JsonSerializable(typeof(MouseEventArgs))]
+[assembly: JsonSerializable(typeof(PointerEventArgs))]
+[assembly: JsonSerializable(typeof(ProgressEventArgs))]
+[assembly: JsonSerializable(typeof(TouchEventArgs))]
+[assembly: JsonSerializable(typeof(WheelEventArgs))]
namespace Microsoft.AspNetCore.Components.Web
{
@@ -15,12 +32,16 @@ internal class WebEventData
{
// This class represents the second half of parsing incoming event data,
// once the event ID (and possibly the type of the eventArgs) becomes known.
- public static WebEventData Parse(Renderer renderer, JsonSerializerOptions jsonSerializerOptions, string eventDescriptorJson, string eventArgsJson)
+ public static WebEventData Parse(
+ Renderer renderer,
+ IWebEventJsonSerializerContext jsonSerializerContext,
+ string eventDescriptorJson,
+ string eventArgsJson)
{
WebEventDescriptor eventDescriptor;
try
{
- eventDescriptor = Deserialize(eventDescriptorJson);
+ eventDescriptor = Deserialize(eventDescriptorJson, jsonSerializerContext.WebEventDescriptor);
}
catch (Exception e)
{
@@ -29,14 +50,18 @@ public static WebEventData Parse(Renderer renderer, JsonSerializerOptions jsonSe
return Parse(
renderer,
- jsonSerializerOptions,
+ jsonSerializerContext,
eventDescriptor,
eventArgsJson);
}
- public static WebEventData Parse(Renderer renderer, JsonSerializerOptions jsonSerializerOptions, WebEventDescriptor eventDescriptor, string eventArgsJson)
+ public static WebEventData Parse(
+ Renderer renderer,
+ IWebEventJsonSerializerContext jsonSerializerContext,
+ WebEventDescriptor eventDescriptor,
+ string eventArgsJson)
{
- var parsedEventArgs = ParseEventArgsJson(renderer, jsonSerializerOptions, eventDescriptor.EventHandlerId, eventDescriptor.EventName, eventArgsJson);
+ var parsedEventArgs = ParseEventArgsJson(renderer, jsonSerializerContext, eventDescriptor.EventHandlerId, eventDescriptor.EventName, eventArgsJson);
return new WebEventData(
eventDescriptor.BrowserRendererId,
eventDescriptor.EventHandlerId,
@@ -60,18 +85,23 @@ private WebEventData(int browserRendererId, ulong eventHandlerId, EventFieldInfo
public EventArgs EventArgs { get; }
- private static EventArgs ParseEventArgsJson(Renderer renderer, JsonSerializerOptions jsonSerializerOptions, ulong eventHandlerId, string eventName, string eventArgsJson)
+ private static EventArgs ParseEventArgsJson(
+ Renderer renderer,
+ IWebEventJsonSerializerContext jsonSerializerContext,
+ ulong eventHandlerId,
+ string eventName,
+ string eventArgsJson)
{
try
{
- if (TryDeserializeStandardWebEventArgs(eventName, eventArgsJson, out var eventArgs))
+ if (TryDeserializeStandardWebEventArgs(eventName, eventArgsJson, jsonSerializerContext, out var eventArgs))
{
return eventArgs;
}
// For custom events, the args type is determined from the associated delegate
var eventArgsType = renderer.GetEventArgsType(eventHandlerId);
- return (EventArgs)JsonSerializer.Deserialize(eventArgsJson, eventArgsType, jsonSerializerOptions)!;
+ return (EventArgs)JsonSerializer.Deserialize(eventArgsJson, eventArgsType, jsonSerializerContext.Options)!;
}
catch (Exception e)
{
@@ -79,10 +109,11 @@ private static EventArgs ParseEventArgsJson(Renderer renderer, JsonSerializerOpt
}
}
- [DynamicDependency(JsonSerialized, typeof(DataTransfer))]
- [DynamicDependency(JsonSerialized, typeof(DataTransferItem))]
- [DynamicDependency(JsonSerialized, typeof(TouchPoint))]
- private static bool TryDeserializeStandardWebEventArgs(string eventName, string eventArgsJson, [NotNullWhen(true)] out EventArgs? eventArgs)
+ private static bool TryDeserializeStandardWebEventArgs(
+ string eventName,
+ string eventArgsJson,
+ IWebEventJsonSerializerContext jsonSerializerContext,
+ [NotNullWhen(true)] out EventArgs? eventArgs)
{
// For back-compatibility, we recognize the built-in list of web event names and hard-code
// rules about the deserialization type for their eventargs. This makes it possible to declare
@@ -97,13 +128,13 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "change":
// Special case for ChangeEventArgs because its value type can be one of
// several types, and System.Text.Json doesn't pick types dynamically
- eventArgs = DeserializeChangeEventArgs(eventArgsJson);
+ eventArgs = DeserializeChangeEventArgs(eventArgsJson, jsonSerializerContext);
return true;
case "copy":
case "cut":
case "paste":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.ClipboardEventArgs);
return true;
case "drag":
@@ -113,20 +144,20 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "dragover":
case "dragstart":
case "drop":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.DragEventArgs);
return true;
case "focus":
case "blur":
case "focusin":
case "focusout":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.FocusEventArgs);
return true;
case "keydown":
case "keyup":
case "keypress":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.KeyboardEventArgs);
return true;
case "contextmenu":
@@ -137,11 +168,11 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "mousedown":
case "mouseup":
case "dblclick":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.MouseEventArgs);
return true;
case "error":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.ErrorEventArgs);
return true;
case "loadstart":
@@ -150,7 +181,7 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "load":
case "loadend":
case "progress":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.ProgressEventArgs);
return true;
case "touchcancel":
@@ -159,7 +190,7 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "touchenter":
case "touchleave":
case "touchstart":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.TouchEventArgs);
return true;
case "gotpointercapture":
@@ -172,16 +203,16 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
case "pointerout":
case "pointerover":
case "pointerup":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.PointerEventArgs);
return true;
case "wheel":
case "mousewheel":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.WheelEventArgs);
return true;
case "toggle":
- eventArgs = Deserialize(eventArgsJson);
+ eventArgs = Deserialize(eventArgsJson, jsonSerializerContext.EventArgs);
return true;
default:
@@ -219,13 +250,11 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
return null;
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The correct members are preserved by DynamicDependencies.")]
- // This should use JSON source generation
- static T Deserialize<[DynamicallyAccessedMembers(JsonSerialized)] T>(string json) => JsonSerializer.Deserialize(json, JsonSerializerOptionsProvider.Options)!;
+ static T Deserialize(string json, JsonTypeInfo jsonTypeInfo) => JsonSerializer.Deserialize(json, jsonTypeInfo)!;
- private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson)
+ private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson, IWebEventJsonSerializerContext jsonSerializerContext)
{
- var changeArgs = Deserialize(eventArgsJson);
+ var changeArgs = Deserialize(eventArgsJson, jsonSerializerContext.ChangeEventArgs);
var jsonElement = (JsonElement)changeArgs.Value!;
switch (jsonElement.ValueKind)
{
@@ -244,5 +273,28 @@ private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson)
}
return changeArgs;
}
+
+#nullable disable
+ // WebView has different nullability settings compared to Server and WebAssembly
+ // which weirds out JSON's nullability for these types. Disable nullability for this contract
+ // until we can update everything to haave uniform nullability.
+ internal interface IWebEventJsonSerializerContext
+ {
+ JsonSerializerOptions Options { get; }
+
+ JsonTypeInfo ChangeEventArgs { get; }
+ JsonTypeInfo WebEventDescriptor { get; }
+ JsonTypeInfo ClipboardEventArgs { get; }
+ JsonTypeInfo DragEventArgs { get; }
+ JsonTypeInfo FocusEventArgs { get; }
+ JsonTypeInfo KeyboardEventArgs { get; }
+ JsonTypeInfo MouseEventArgs { get; }
+ JsonTypeInfo ErrorEventArgs { get; }
+ JsonTypeInfo ProgressEventArgs { get; }
+ JsonTypeInfo TouchEventArgs { get; }
+ JsonTypeInfo PointerEventArgs { get; }
+ JsonTypeInfo WheelEventArgs { get; }
+ JsonTypeInfo EventArgs { get; }
+ }
}
}
diff --git a/src/Components/Web.JS/src/Rendering/Events/EventTypes.ts b/src/Components/Web.JS/src/Rendering/Events/EventTypes.ts
index 06ddcf32de4d..2f1eb9e195c3 100644
--- a/src/Components/Web.JS/src/Rendering/Events/EventTypes.ts
+++ b/src/Components/Web.JS/src/Rendering/Events/EventTypes.ts
@@ -144,6 +144,7 @@ function parseTouchEvent(event: TouchEvent): TouchEventArgs {
shiftKey: event.shiftKey,
altKey: event.altKey,
metaKey: event.metaKey,
+ type: event.type
};
}
@@ -357,6 +358,7 @@ interface TouchEventArgs {
shiftKey: boolean;
altKey: boolean;
metaKey: boolean;
+ type: string;
}
interface TouchPoint {
diff --git a/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JSInteropMethods.cs b/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JSInteropMethods.cs
index c0d46530c195..45dcb3f0414c 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JSInteropMethods.cs
+++ b/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JSInteropMethods.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel;
+using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.Web;
@@ -18,6 +19,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Infrastructure
[EditorBrowsable(EditorBrowsableState.Never)]
public static class JSInteropMethods
{
+ private static JsonSourceGeneration.JsonContext? _jsonContext;
+
///
/// For framework use only.
///
@@ -35,7 +38,12 @@ public static Task DispatchEvent(WebEventDescriptor eventDescriptor, string even
{
var renderer = RendererRegistry.Find(eventDescriptor.BrowserRendererId);
var jsonSerializerOptions = DefaultWebAssemblyJSRuntime.Instance.ReadJsonSerializerOptions();
- var webEvent = WebEventData.Parse(renderer, jsonSerializerOptions, eventDescriptor, eventArgsJson);
+
+ // JsonSerializerOptions are tightly bound to the JsonContext. Cache it on first use using a copy
+ // of the serializer settings.
+ _jsonContext ??= new(new JsonSerializerOptions(jsonSerializerOptions));
+
+ var webEvent = WebEventData.Parse(renderer, _jsonContext, eventDescriptor, eventArgsJson);
return renderer.DispatchEventAsync(
webEvent.EventHandlerId,
webEvent.EventFieldInfo,
diff --git a/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JsonContext.cs b/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JsonContext.cs
new file mode 100644
index 000000000000..5313094440fc
--- /dev/null
+++ b/src/Components/WebAssembly/WebAssembly/src/Infrastructure/JsonContext.cs
@@ -0,0 +1,12 @@
+// 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.Text.Json.Serialization;
+using Microsoft.AspNetCore.Components.Web;
+
+namespace Microsoft.AspNetCore.Components.WebAssembly.JsonSourceGeneration
+{
+ internal partial class JsonContext : JsonSerializerContext, WebEventData.IWebEventJsonSerializerContext
+ {
+ }
+}
diff --git a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.WarningSuppressions.xml b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.WarningSuppressions.xml
index 87284ed7ea4d..43fc9984ff21 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.WarningSuppressions.xml
+++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.WarningSuppressions.xml
@@ -17,7 +17,7 @@
ILLink
IL2026
member
- M:Microsoft.AspNetCore.Components.Web.WebEventData.ParseEventArgsJson(Microsoft.AspNetCore.Components.RenderTree.Renderer,System.Text.Json.JsonSerializerOptions,System.UInt64,System.String,System.String)
+ M:Microsoft.AspNetCore.Components.Web.WebEventData.ParseEventArgsJson(Microsoft.AspNetCore.Components.RenderTree.Renderer,Microsoft.AspNetCore.Components.Web.WebEventData.IWebEventJsonSerializerContext,System.UInt64,System.String,System.String)
ILLink
@@ -53,7 +53,7 @@
ILLink
IL2072
member
- M:Microsoft.AspNetCore.Components.Web.WebEventData.ParseEventArgsJson(Microsoft.AspNetCore.Components.RenderTree.Renderer,System.Text.Json.JsonSerializerOptions,System.UInt64,System.String,System.String)
+ M:Microsoft.AspNetCore.Components.Web.WebEventData.ParseEventArgsJson(Microsoft.AspNetCore.Components.RenderTree.Renderer,Microsoft.AspNetCore.Components.Web.WebEventData.IWebEventJsonSerializerContext,System.UInt64,System.String,System.String)
ILLink
diff --git a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
index 86a4dce4ae66..dceb2cd529c6 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
+++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
@@ -4,6 +4,8 @@
$(DefaultNetCoreTargetFramework)
Build client-side single-page applications (SPAs) with Blazor running under WebAssembly.
$(NoWarn);BL0006
+
+ $(NoWarn);CS8603
true
enable
true
diff --git a/src/Components/WebView/WebView/src/IpcReceiver.cs b/src/Components/WebView/WebView/src/IpcReceiver.cs
index 107ced59dbd1..c406d46eb8ea 100644
--- a/src/Components/WebView/WebView/src/IpcReceiver.cs
+++ b/src/Components/WebView/WebView/src/IpcReceiver.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop.Infrastructure;
@@ -26,6 +27,7 @@ namespace Microsoft.AspNetCore.Components.WebView
internal class IpcReceiver
{
private readonly Func _onAttachMessage;
+ private JsonSourceGeneration.JsonContext _jsonContext;
public IpcReceiver(Func onAttachMessage)
{
@@ -89,7 +91,10 @@ private Task DispatchBrowserEventAsync(PageContext pageContext, string eventDesc
{
var renderer = pageContext.Renderer;
var jsonSerializerOptions = pageContext.JSRuntime.ReadJsonSerializerOptions();
- var webEventData = WebEventData.Parse(renderer, jsonSerializerOptions, eventDescriptor, eventArgs);
+ // JsonSerializerOptions are tightly bound to the JsonContext. Cache it on first use using a copy
+ // of the serializer settings.
+ _jsonContext ??= new(new JsonSerializerOptions(jsonSerializerOptions));
+ var webEventData = WebEventData.Parse(renderer, _jsonContext, eventDescriptor, eventArgs);
return renderer.DispatchEventAsync(
webEventData.EventHandlerId,
webEventData.EventFieldInfo,
@@ -112,3 +117,4 @@ private void OnLocationChanged(PageContext pageContext, string uri, bool interce
}
}
}
+
diff --git a/src/Components/WebView/WebView/src/JsonContext.cs b/src/Components/WebView/WebView/src/JsonContext.cs
new file mode 100644
index 000000000000..063f272d5d42
--- /dev/null
+++ b/src/Components/WebView/WebView/src/JsonContext.cs
@@ -0,0 +1,10 @@
+// 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.Text.Json.Serialization;
+using Microsoft.AspNetCore.Components.Web;
+
+namespace Microsoft.AspNetCore.Components.WebView.JsonSourceGeneration
+{
+ internal partial class JsonContext : JsonSerializerContext, WebEventData.IWebEventJsonSerializerContext { }
+}
diff --git a/src/Components/test/E2ETest/Tests/EventTest.cs b/src/Components/test/E2ETest/Tests/EventTest.cs
index 9b2e68aeb3c3..15f0593e8b81 100644
--- a/src/Components/test/E2ETest/Tests/EventTest.cs
+++ b/src/Components/test/E2ETest/Tests/EventTest.cs
@@ -177,6 +177,22 @@ public void DragDrop_CanTrigger()
Browser.Equal("ondragstart,", () => output.Text);
}
+ [Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/32373")]
+ public void TouchEvent_CanTrigger()
+ {
+ Browser.MountTestComponent();
+
+ var input = Browser.Exists(By.Id("touch_input"));
+
+ var output = Browser.Exists(By.Id("output"));
+ Assert.Equal(string.Empty, output.Text);
+
+ var actions = new TouchActions(Browser).SingleTap(input);
+
+ actions.Perform();
+ Browser.Equal("touchstarttouchend,", () => output.Text);
+ }
+
[Fact]
public void PreventDefault_AppliesToFormOnSubmitHandlers()
{
diff --git a/src/Components/test/testassets/BasicTestApp/TouchEventComponent.razor b/src/Components/test/testassets/BasicTestApp/TouchEventComponent.razor
index 492d42565a79..1d3489203c7d 100644
--- a/src/Components/test/testassets/BasicTestApp/TouchEventComponent.razor
+++ b/src/Components/test/testassets/BasicTestApp/TouchEventComponent.razor
@@ -7,7 +7,8 @@
Output: @message
-
@if (serializedValue != null)
@@ -17,6 +18,7 @@
Deserialize (small)
Deserialize (large)
+Deserialize (large with sourcegen)
@if (numPeopleDeserialized > 0)
{
@@ -26,6 +28,7 @@
@code {
Person smallOrgChart = Person.GenerateOrgChart(1, 4);
Person largeOrgChart = Person.GenerateOrgChart(5, 4);
+ PersonJsonContext personJsonContext = new(new(JsonSerializerDefaults.Web));
string smallOrgChartJson;
string largeOrgChartJson;
int numPeopleDeserialized;
@@ -55,12 +58,18 @@
void SerializeLarge()
=> serializedValue = JsonSerializer.Serialize(largeOrgChart);
+ void SerializeLargeSourceGen()
+ => serializedValue = JsonSerializer.Serialize(largeOrgChart, personJsonContext.Person);
+
void DeserializeSmall()
=> numPeopleDeserialized = Deserialize(smallOrgChartJson);
void DeserializeLarge()
=> numPeopleDeserialized = Deserialize(largeOrgChartJson);
+ void DeserializeLargeSourceGen()
+ => numPeopleDeserialized = CountPeople(JsonSerializer.Deserialize(largeOrgChartJson, personJsonContext.Person));
+
static int Deserialize(string json)
{
var ceo = JsonSerializer.Deserialize(json);
diff --git a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Person.cs b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Person.cs
index ecaa7d23ecda..53b028c14dda 100644
--- a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Person.cs
+++ b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Person.cs
@@ -15,7 +15,7 @@ public class Person
public int Salary { get; set; }
public bool IsAdmin { get; set; }
public List Subordinates { get; set; }
- public Dictionary SecurityClearances { get; set; }
+ public Dictionary SecurityClearances { get; set; }
public static Person GenerateOrgChart(int totalDepth, int numDescendantsPerNode, int thisDepth = 0, string namePrefix = null, int siblingIndex = 0)
{
@@ -28,7 +28,7 @@ public static Person GenerateOrgChart(int totalDepth, int numDescendantsPerNode,
IsAdmin = siblingIndex % 2 == 0,
Salary = 10000000 / (thisDepth + 1),
SecurityClearances = Clearances
- .ToDictionary(c => c, _ => (object)(rng.Next(0, 2) == 0)),
+ .ToDictionary(c => c, _ => rng.Next(0, 2) == 0),
Subordinates = Enumerable.Range(0, thisDepth < totalDepth ? numDescendantsPerNode : 0)
.Select(index => GenerateOrgChart(totalDepth, numDescendantsPerNode, thisDepth + 1, name, index))
.ToList()
diff --git a/src/Components/benchmarkapps/Wasm.Performance/TestApp/PersonJsonContext.cs b/src/Components/benchmarkapps/Wasm.Performance/TestApp/PersonJsonContext.cs
new file mode 100644
index 000000000000..708274644348
--- /dev/null
+++ b/src/Components/benchmarkapps/Wasm.Performance/TestApp/PersonJsonContext.cs
@@ -0,0 +1,12 @@
+// 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.Text.Json.Serialization;
+
+namespace Wasm.Performance.TestApp
+{
+ [JsonSerializable(typeof(Person), GenerationMode = JsonSourceGenerationMode.MetadataAndSerialization)]
+ internal partial class PersonJsonContext : JsonSerializerContext
+ {
+ }
+}
diff --git a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
index 76237492831d..c037307cd628 100644
--- a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
+++ b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
@@ -13,5 +13,6 @@
+
diff --git a/src/Components/benchmarkapps/Wasm.Performance/TestApp/wwwroot/benchmarks/jsonHandling.js b/src/Components/benchmarkapps/Wasm.Performance/TestApp/wwwroot/benchmarks/jsonHandling.js
index 05c8e421c09d..b00916bd7871 100644
--- a/src/Components/benchmarkapps/Wasm.Performance/TestApp/wwwroot/benchmarks/jsonHandling.js
+++ b/src/Components/benchmarkapps/Wasm.Performance/TestApp/wwwroot/benchmarks/jsonHandling.js
@@ -31,6 +31,14 @@ group('JSON handling', () => {
}
});
+ benchmark('Serialize 340kb (Source Generated)', () =>
+ benchmarkJson(app, '#serialize-large-sourcegen', '#serialized-length', 339803), {
+ descriptor: {
+ name: 'blazorwasm/jsonserialize-sourcegen-340kb',
+ description: 'Serialize JSON (SourceGen) 340kb - Time in ms'
+ }
+ });
+
benchmark('Deserialize 1kb', () =>
benchmarkJson(app, '#deserialize-small', '#deserialized-count', 5), {
descriptor: {
@@ -47,6 +55,14 @@ group('JSON handling', () => {
}
});
+ benchmark('Deserialize 340kb (Source Generated)', () =>
+ benchmarkJson(app, '#deserialize-large-sourcegen', '#deserialized-count', 1365), {
+ descriptor: {
+ name: 'blazorwasm/jsondeserialize-sourcegen-340kb',
+ description: 'Deserialize JSON (SourceGen) 340kb - Time in ms'
+ }
+ });
+
benchmark('Serialize 340kb (JavaScript)', () => {
const json = JSON.stringify(largeObjectToSerialize);
if (json.length !== 339803) {
From 90e5ef539b2991fa77b6e88ef109a80f1f4144d6 Mon Sep 17 00:00:00 2001
From: Pranav K
Date: Fri, 11 Jun 2021 09:41:21 -0700
Subject: [PATCH 6/6] Update src/Components/WebView/WebView/src/IpcReceiver.cs
Co-authored-by: Tanay Parikh
---
src/Components/WebView/WebView/src/IpcReceiver.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Components/WebView/WebView/src/IpcReceiver.cs b/src/Components/WebView/WebView/src/IpcReceiver.cs
index 3cb809eb9736..11e75e9892ec 100644
--- a/src/Components/WebView/WebView/src/IpcReceiver.cs
+++ b/src/Components/WebView/WebView/src/IpcReceiver.cs
@@ -121,4 +121,3 @@ private void OnLocationChanged(PageContext pageContext, string uri, bool interce
}
}
}
-