66using System ;
77using System . Diagnostics . CodeAnalysis ;
88using System . Text . Json ;
9+ using System . Text . Json . Serialization ;
10+ using System . Text . Json . Serialization . Metadata ;
11+ using Microsoft . AspNetCore . Components ;
912using Microsoft . AspNetCore . Components . RenderTree ;
10- using static Microsoft . AspNetCore . Internal . LinkerFlags ;
13+ using Microsoft . AspNetCore . Components . Web ;
14+
15+ [ assembly: JsonSerializable ( typeof ( WebEventDescriptor ) ) ]
16+ [ assembly: JsonSerializable ( typeof ( EventArgs ) ) ]
17+ [ assembly: JsonSerializable ( typeof ( ChangeEventArgs ) ) ]
18+ [ assembly: JsonSerializable ( typeof ( ClipboardEventArgs ) ) ]
19+ [ assembly: JsonSerializable ( typeof ( DragEventArgs ) ) ]
20+ [ assembly: JsonSerializable ( typeof ( ErrorEventArgs ) ) ]
21+ [ assembly: JsonSerializable ( typeof ( FocusEventArgs ) ) ]
22+ [ assembly: JsonSerializable ( typeof ( KeyboardEventArgs ) ) ]
23+ [ assembly: JsonSerializable ( typeof ( MouseEventArgs ) ) ]
24+ [ assembly: JsonSerializable ( typeof ( PointerEventArgs ) ) ]
25+ [ assembly: JsonSerializable ( typeof ( ProgressEventArgs ) ) ]
26+ [ assembly: JsonSerializable ( typeof ( TouchEventArgs ) ) ]
27+ [ assembly: JsonSerializable ( typeof ( WheelEventArgs ) ) ]
1128
1229namespace Microsoft . AspNetCore . Components . Web
1330{
1431 internal class WebEventData
1532 {
1633 // This class represents the second half of parsing incoming event data,
1734 // once the event ID (and possibly the type of the eventArgs) becomes known.
18- public static WebEventData Parse ( Renderer renderer , JsonSerializerOptions jsonSerializerOptions , string eventDescriptorJson , string eventArgsJson )
35+ public static WebEventData Parse (
36+ Renderer renderer ,
37+ IWebEventJsonSerializerContext jsonSerializerContext ,
38+ string eventDescriptorJson ,
39+ string eventArgsJson )
1940 {
2041 WebEventDescriptor eventDescriptor ;
2142 try
2243 {
23- eventDescriptor = Deserialize < WebEventDescriptor > ( eventDescriptorJson ) ;
44+ eventDescriptor = Deserialize ( eventDescriptorJson , jsonSerializerContext . WebEventDescriptor ) ;
2445 }
2546 catch ( Exception e )
2647 {
@@ -29,14 +50,18 @@ public static WebEventData Parse(Renderer renderer, JsonSerializerOptions jsonSe
2950
3051 return Parse (
3152 renderer ,
32- jsonSerializerOptions ,
53+ jsonSerializerContext ,
3354 eventDescriptor ,
3455 eventArgsJson ) ;
3556 }
3657
37- public static WebEventData Parse ( Renderer renderer , JsonSerializerOptions jsonSerializerOptions , WebEventDescriptor eventDescriptor , string eventArgsJson )
58+ public static WebEventData Parse (
59+ Renderer renderer ,
60+ IWebEventJsonSerializerContext jsonSerializerContext ,
61+ WebEventDescriptor eventDescriptor ,
62+ string eventArgsJson )
3863 {
39- var parsedEventArgs = ParseEventArgsJson ( renderer , jsonSerializerOptions , eventDescriptor . EventHandlerId , eventDescriptor . EventName , eventArgsJson ) ;
64+ var parsedEventArgs = ParseEventArgsJson ( renderer , jsonSerializerContext , eventDescriptor . EventHandlerId , eventDescriptor . EventName , eventArgsJson ) ;
4065 return new WebEventData (
4166 eventDescriptor . BrowserRendererId ,
4267 eventDescriptor . EventHandlerId ,
@@ -60,29 +85,35 @@ private WebEventData(int browserRendererId, ulong eventHandlerId, EventFieldInfo
6085
6186 public EventArgs EventArgs { get ; }
6287
63- private static EventArgs ParseEventArgsJson ( Renderer renderer , JsonSerializerOptions jsonSerializerOptions , ulong eventHandlerId , string eventName , string eventArgsJson )
88+ private static EventArgs ParseEventArgsJson (
89+ Renderer renderer ,
90+ IWebEventJsonSerializerContext jsonSerializerContext ,
91+ ulong eventHandlerId ,
92+ string eventName ,
93+ string eventArgsJson )
6494 {
6595 try
6696 {
67- if ( TryDeserializeStandardWebEventArgs ( eventName , eventArgsJson , out var eventArgs ) )
97+ if ( TryDeserializeStandardWebEventArgs ( eventName , eventArgsJson , jsonSerializerContext , out var eventArgs ) )
6898 {
6999 return eventArgs ;
70100 }
71101
72102 // For custom events, the args type is determined from the associated delegate
73103 var eventArgsType = renderer . GetEventArgsType ( eventHandlerId ) ;
74- return ( EventArgs ) JsonSerializer . Deserialize ( eventArgsJson , eventArgsType , jsonSerializerOptions ) ! ;
104+ return ( EventArgs ) JsonSerializer . Deserialize ( eventArgsJson , eventArgsType , jsonSerializerContext . Options ) ! ;
75105 }
76106 catch ( Exception e )
77107 {
78108 throw new InvalidOperationException ( $ "There was an error parsing the event arguments. EventId: '{ eventHandlerId } '.", e ) ;
79109 }
80110 }
81111
82- [ DynamicDependency ( JsonSerialized , typeof ( DataTransfer ) ) ]
83- [ DynamicDependency ( JsonSerialized , typeof ( DataTransferItem ) ) ]
84- [ DynamicDependency ( JsonSerialized , typeof ( TouchPoint ) ) ]
85- private static bool TryDeserializeStandardWebEventArgs ( string eventName , string eventArgsJson , [ NotNullWhen ( true ) ] out EventArgs ? eventArgs )
112+ private static bool TryDeserializeStandardWebEventArgs (
113+ string eventName ,
114+ string eventArgsJson ,
115+ IWebEventJsonSerializerContext jsonSerializerContext ,
116+ [ NotNullWhen ( true ) ] out EventArgs ? eventArgs )
86117 {
87118 // For back-compatibility, we recognize the built-in list of web event names and hard-code
88119 // 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
97128 case "change" :
98129 // Special case for ChangeEventArgs because its value type can be one of
99130 // several types, and System.Text.Json doesn't pick types dynamically
100- eventArgs = DeserializeChangeEventArgs ( eventArgsJson ) ;
131+ eventArgs = DeserializeChangeEventArgs ( eventArgsJson , jsonSerializerContext ) ;
101132 return true ;
102133
103134 case "copy" :
104135 case "cut" :
105136 case "paste" :
106- eventArgs = Deserialize < ClipboardEventArgs > ( eventArgsJson ) ;
137+ eventArgs = Deserialize < ClipboardEventArgs > ( eventArgsJson , jsonSerializerContext . ClipboardEventArgs ) ;
107138 return true ;
108139
109140 case "drag" :
@@ -113,20 +144,20 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
113144 case "dragover" :
114145 case "dragstart" :
115146 case "drop" :
116- eventArgs = Deserialize < DragEventArgs > ( eventArgsJson ) ;
147+ eventArgs = Deserialize < DragEventArgs > ( eventArgsJson , jsonSerializerContext . DragEventArgs ) ;
117148 return true ;
118149
119150 case "focus" :
120151 case "blur" :
121152 case "focusin" :
122153 case "focusout" :
123- eventArgs = Deserialize < FocusEventArgs > ( eventArgsJson ) ;
154+ eventArgs = Deserialize < FocusEventArgs > ( eventArgsJson , jsonSerializerContext . FocusEventArgs ) ;
124155 return true ;
125156
126157 case "keydown" :
127158 case "keyup" :
128159 case "keypress" :
129- eventArgs = Deserialize < KeyboardEventArgs > ( eventArgsJson ) ;
160+ eventArgs = Deserialize < KeyboardEventArgs > ( eventArgsJson , jsonSerializerContext . KeyboardEventArgs ) ;
130161 return true ;
131162
132163 case "contextmenu" :
@@ -137,11 +168,11 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
137168 case "mousedown" :
138169 case "mouseup" :
139170 case "dblclick" :
140- eventArgs = Deserialize < MouseEventArgs > ( eventArgsJson ) ;
171+ eventArgs = Deserialize < MouseEventArgs > ( eventArgsJson , jsonSerializerContext . MouseEventArgs ) ;
141172 return true ;
142173
143174 case "error" :
144- eventArgs = Deserialize < ErrorEventArgs > ( eventArgsJson ) ;
175+ eventArgs = Deserialize < ErrorEventArgs > ( eventArgsJson , jsonSerializerContext . ErrorEventArgs ) ;
145176 return true ;
146177
147178 case "loadstart" :
@@ -150,7 +181,7 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
150181 case "load" :
151182 case "loadend" :
152183 case "progress" :
153- eventArgs = Deserialize < ProgressEventArgs > ( eventArgsJson ) ;
184+ eventArgs = Deserialize < ProgressEventArgs > ( eventArgsJson , jsonSerializerContext . ProgressEventArgs ) ;
154185 return true ;
155186
156187 case "touchcancel" :
@@ -159,7 +190,7 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
159190 case "touchenter" :
160191 case "touchleave" :
161192 case "touchstart" :
162- eventArgs = Deserialize < TouchEventArgs > ( eventArgsJson ) ;
193+ eventArgs = Deserialize < TouchEventArgs > ( eventArgsJson , jsonSerializerContext . TouchEventArgs ) ;
163194 return true ;
164195
165196 case "gotpointercapture" :
@@ -172,16 +203,16 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
172203 case "pointerout" :
173204 case "pointerover" :
174205 case "pointerup" :
175- eventArgs = Deserialize < PointerEventArgs > ( eventArgsJson ) ;
206+ eventArgs = Deserialize < PointerEventArgs > ( eventArgsJson , jsonSerializerContext . PointerEventArgs ) ;
176207 return true ;
177208
178209 case "wheel" :
179210 case "mousewheel" :
180- eventArgs = Deserialize < WheelEventArgs > ( eventArgsJson ) ;
211+ eventArgs = Deserialize < WheelEventArgs > ( eventArgsJson , jsonSerializerContext . WheelEventArgs ) ;
181212 return true ;
182213
183214 case "toggle" :
184- eventArgs = Deserialize < EventArgs > ( eventArgsJson ) ;
215+ eventArgs = Deserialize < EventArgs > ( eventArgsJson , jsonSerializerContext . EventArgs ) ;
185216 return true ;
186217
187218 default :
@@ -219,13 +250,11 @@ private static bool TryDeserializeStandardWebEventArgs(string eventName, string
219250 return null ;
220251 }
221252
222- [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2026:RequiresUnreferencedCode" , Justification = "The correct members are preserved by DynamicDependencies." ) ]
223- // This should use JSON source generation
224- static T Deserialize < [ DynamicallyAccessedMembers ( JsonSerialized ) ] T > ( string json ) => JsonSerializer . Deserialize < T > ( json , JsonSerializerOptionsProvider . Options ) ! ;
253+ static T Deserialize < T > ( string json , JsonTypeInfo < T ? > jsonTypeInfo ) => JsonSerializer . Deserialize ( json , jsonTypeInfo ) ! ;
225254
226- private static ChangeEventArgs DeserializeChangeEventArgs ( string eventArgsJson )
255+ private static ChangeEventArgs DeserializeChangeEventArgs ( string eventArgsJson , IWebEventJsonSerializerContext jsonSerializerContext )
227256 {
228- var changeArgs = Deserialize < ChangeEventArgs > ( eventArgsJson ) ;
257+ var changeArgs = Deserialize ( eventArgsJson , jsonSerializerContext . ChangeEventArgs ) ;
229258 var jsonElement = ( JsonElement ) changeArgs . Value ! ;
230259 switch ( jsonElement . ValueKind )
231260 {
@@ -244,5 +273,28 @@ private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson)
244273 }
245274 return changeArgs ;
246275 }
276+
277+ #nullable disable
278+ // WebView has different nullability settings compared to Server and WebAssembly
279+ // which weirds out JSON's nullability for these types. Disable nullability for this contract
280+ // until we can update everything to haave uniform nullability.
281+ internal interface IWebEventJsonSerializerContext
282+ {
283+ JsonSerializerOptions Options { get ; }
284+
285+ JsonTypeInfo < ChangeEventArgs > ChangeEventArgs { get ; }
286+ JsonTypeInfo < WebEventDescriptor > WebEventDescriptor { get ; }
287+ JsonTypeInfo < ClipboardEventArgs > ClipboardEventArgs { get ; }
288+ JsonTypeInfo < DragEventArgs > DragEventArgs { get ; }
289+ JsonTypeInfo < FocusEventArgs > FocusEventArgs { get ; }
290+ JsonTypeInfo < KeyboardEventArgs > KeyboardEventArgs { get ; }
291+ JsonTypeInfo < MouseEventArgs > MouseEventArgs { get ; }
292+ JsonTypeInfo < ErrorEventArgs > ErrorEventArgs { get ; }
293+ JsonTypeInfo < ProgressEventArgs > ProgressEventArgs { get ; }
294+ JsonTypeInfo < TouchEventArgs > TouchEventArgs { get ; }
295+ JsonTypeInfo < PointerEventArgs > PointerEventArgs { get ; }
296+ JsonTypeInfo < WheelEventArgs > WheelEventArgs { get ; }
297+ JsonTypeInfo < EventArgs > EventArgs { get ; }
298+ }
247299 }
248300}
0 commit comments