-
-
Notifications
You must be signed in to change notification settings - Fork 385
feat(QueryPageOptions): SearchModel support serialize #7327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,11 +42,7 @@ public sealed class JsonFilterKeyValueActionConverter : JsonConverter<FilterKeyV | |
| action.FieldKey = reader.GetString(); | ||
| break; | ||
| case "fieldValueType": | ||
| var typeName = reader.GetString(); | ||
| if (!string.IsNullOrEmpty(typeName)) | ||
| { | ||
| fieldValueType = Type.GetType(typeName); | ||
| } | ||
| fieldValueType = TypeExtensions.GetSafeType(reader.GetString()); | ||
| break; | ||
| case "fieldValue": | ||
| if (fieldValueType != null) | ||
|
|
@@ -89,7 +85,7 @@ public override void Write(Utf8JsonWriter writer, FilterKeyValueAction value, Js | |
| writer.WriteStartObject(); | ||
| writer.WriteString("fieldKey", value.FieldKey); | ||
|
|
||
| writer.WriteString("fieldValueType", value.FieldValue?.GetType().FullName); | ||
| WriteFieldValueType(writer, value, options); | ||
|
|
||
| writer.WritePropertyName("fieldValue"); | ||
| writer.WriteRawValue(JsonSerializer.Serialize(value.FieldValue, options)); | ||
|
|
@@ -109,4 +105,13 @@ public override void Write(Utf8JsonWriter writer, FilterKeyValueAction value, Js | |
|
|
||
| writer.WriteEndObject(); | ||
| } | ||
|
|
||
| private static void WriteFieldValueType(Utf8JsonWriter writer, FilterKeyValueAction value, JsonSerializerOptions options) | ||
| { | ||
| if (value.FieldValue != null) | ||
| { | ||
| var type = value.FieldValue.GetType(); | ||
| writer.WriteString("fieldValueType", type.AssemblyQualifiedName); | ||
|
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -73,11 +73,7 @@ public sealed class JsonQueryPageOptionsConverter : JsonConverter<QueryPageOptio | |||||||||||||||||
| else if (propertyName == "searchModel") | ||||||||||||||||||
| { | ||||||||||||||||||
| reader.Read(); | ||||||||||||||||||
| var val = JsonSerializer.Deserialize<object>(ref reader, options); | ||||||||||||||||||
| if (val != null) | ||||||||||||||||||
| { | ||||||||||||||||||
| ret.SearchModel = val; | ||||||||||||||||||
| } | ||||||||||||||||||
| ReadSearchModel(ref reader, ret, options); | ||||||||||||||||||
| } | ||||||||||||||||||
| else if (propertyName == "pageIndex") | ||||||||||||||||||
| { | ||||||||||||||||||
|
|
@@ -229,8 +225,7 @@ public override void Write(Utf8JsonWriter writer, QueryPageOptions value, JsonSe | |||||||||||||||||
| } | ||||||||||||||||||
| if (value.SearchModel != null) | ||||||||||||||||||
| { | ||||||||||||||||||
| writer.WritePropertyName("searchModel"); | ||||||||||||||||||
| writer.WriteRawValue(JsonSerializer.Serialize(value.SearchModel, options)); | ||||||||||||||||||
| WriteSearchModel(writer, value.SearchModel, options); | ||||||||||||||||||
| } | ||||||||||||||||||
| if (value.PageIndex > 1) | ||||||||||||||||||
| { | ||||||||||||||||||
|
|
@@ -302,4 +297,52 @@ public override void Write(Utf8JsonWriter writer, QueryPageOptions value, JsonSe | |||||||||||||||||
| } | ||||||||||||||||||
| writer.WriteEndObject(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
||||||||||||||||||
| /// <summary> | |
| /// Serializes the specified search model object into a JSON structure with type information. | |
| /// </summary> | |
| /// <param name="writer">The <see cref="Utf8JsonWriter"/> to write the JSON to.</param> | |
| /// <param name="value">The search model object to serialize.</param> | |
| /// <param name="options">The serializer options to use when serializing the object.</param> |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using AssemblyQualifiedName for type serialization can potentially allow arbitrary type instantiation during deserialization if the JSON is received from untrusted sources. While the code uses GetSafeType with throwOnError: false, which prevents exceptions, it still allows any type that can be loaded to be instantiated. Consider implementing a whitelist of allowed types or adding validation to ensure only expected types can be deserialized through this mechanism.
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ReadSearchModel method lacks XML documentation comments. Consider adding a summary that describes the method's purpose and documents its parameters (reader, value, options) to maintain consistency with the public API documentation style in this codebase.
| /// <summary> | |
| /// Reads and deserializes the <c>searchModel</c> property from the JSON input and assigns it to the <see cref="QueryPageOptions.SearchModel"/> property of the specified <paramref name="value"/> instance. | |
| /// </summary> | |
| /// <param name="reader">The <see cref="Utf8JsonReader"/> to read from. Passed by reference.</param> | |
| /// <param name="value">The <see cref="QueryPageOptions"/> instance to assign the deserialized search model to.</param> | |
| /// <param name="options">The <see cref="JsonSerializerOptions"/> to use for deserialization.</param> |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The deserialization logic assumes the JSON properties "type" and "value" appear in a specific order, but JSON object property order is not guaranteed by the specification. If the "value" property appears before "type" in the JSON, the type variable will be null and deserialization will fall back to using JsonElement. Consider reading both properties first into local variables before attempting deserialization, or handle the case where properties might appear in any order.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||
| // Licensed to the .NET Foundation under one or more agreements. | ||||
| // Licensed to the .NET Foundation under one or more agreements. | ||||
| // The .NET Foundation licenses this file to you under the Apache 2.0 License | ||||
| // See the LICENSE file in the project root for more information. | ||||
| // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone | ||||
|
|
@@ -64,4 +64,20 @@ void EnsureNoAuthenticationSchemeSpecified() | |||
| public static string GetUniqueTypeName(this Type type) => type.IsCollectible | ||||
| ? $"{type.FullName}-{type.TypeHandle.Value}" | ||||
| : $"{type.FullName}"; | ||||
|
|
||||
|
|
||||
|
||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -182,7 +182,7 @@ public async Task Serialize_Ok() | |||||
| IsTriggerByPagination = true, | ||||||
| IsPage = true, | ||||||
| IsVirtualScroll = true, | ||||||
| SearchModel = new { Name = "Test1", Count = 2 } | ||||||
| SearchModel = new Foo { Name = "Test1", Count = 2 } | ||||||
| }; | ||||||
|
|
||||||
| model.Filters.Add(cut.Instance); | ||||||
|
|
@@ -196,6 +196,11 @@ public async Task Serialize_Ok() | |||||
| var expected = JsonSerializer.Deserialize<QueryPageOptions>(payload); | ||||||
| Assert.NotNull(expected); | ||||||
| Assert.Equal("SearchText", expected.SearchText); | ||||||
|
|
||||||
| var foo = expected.SearchModel as Foo; | ||||||
| Assert.NotNull(foo); | ||||||
| Assert.Equal("Test1", foo.Name); | ||||||
|
Comment on lines
+200
to
+202
|
||||||
|
|
||||||
| Assert.Equal("Name1", expected.SortName); | ||||||
| Assert.Equal(3, expected.StartIndex); | ||||||
| Assert.Equal(4, expected.PageIndex); | ||||||
|
|
@@ -216,6 +221,73 @@ public async Task Serialize_Ok() | |||||
| Assert.Equal(2, expected.AdvancedSortList.Count); | ||||||
| } | ||||||
|
|
||||||
| [Fact] | ||||||
| public void SearchModel_Serialize() | ||||||
| { | ||||||
| var model = new QueryPageOptions | ||||||
| { | ||||||
| SearchModel = new { Name = "Test1", Count = 2 } | ||||||
| }; | ||||||
| var payload = JsonSerializer.Serialize(model); | ||||||
| var expected = JsonSerializer.Deserialize<QueryPageOptions>(payload); | ||||||
|
|
||||||
| Assert.NotNull(expected); | ||||||
| Assert.NotNull(expected.SearchModel); | ||||||
| } | ||||||
|
|
||||||
| [Fact] | ||||||
| public void SearchModel_Serialize_TableSearchModel() | ||||||
| { | ||||||
| var model = new QueryPageOptions | ||||||
| { | ||||||
| SearchModel = new FooSearchModel { Name = "Test1" } | ||||||
| }; | ||||||
| var payload = JsonSerializer.Serialize(model); | ||||||
| var expected = JsonSerializer.Deserialize<QueryPageOptions>(payload); | ||||||
|
|
||||||
| Assert.NotNull(expected); | ||||||
| Assert.NotNull(expected.SearchModel); | ||||||
| Assert.Equal("FooSearchModel", expected.SearchModel.GetType().Name); | ||||||
| } | ||||||
|
|
||||||
| [Fact] | ||||||
| public void SearchModel_Serialize_NullType() | ||||||
|
||||||
| public void SearchModel_Serialize_NullType() | |
| public void SearchModel_Serialize_InvalidType() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The WriteFieldValueType method lacks XML documentation comments. Consider adding a summary that describes the method's purpose and documents its parameters (writer, value, options) to maintain consistency with the public API documentation style in this codebase.