基于传入对象类型实现OData响应结果的泛型JSON反序列化
这个需求完全可以实现,两种常见实现方案如下:
方案1:泛型重构(推荐,类型安全性能高)
第一步:改造响应类为泛型
// 把原来的非泛型EntityListResponse改成泛型类,直接指定Records的元素类型 public class EntityListResponse<T> { [System.Text.Json.Serialization.JsonPropertyName("value")] public List<T> Records { get; set; } [System.Text.Json.Serialization.JsonPropertyName("@odata.count")] public int Total { get; set; } }
第二步:改造通用服务的GetAll方法为泛型
// 方法添加泛型参数,不需要再传object类型的entity public async Task<EntityListResponse<T>> GetAll<T>(DataSourceRequest request) { // 直接通过泛型参数拿类型名构造请求路径,避免实体ToString重写导致路径错误 var baseUrl = $"{typeof(T).Name}s?"; var requestUrl = $"{baseUrl}{request.ToODataString()}"; var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl); requestMessage.Headers.Add("Accept", "application/json"); var client = HttpClient.CreateClient("IndiciaStageApi"); var response = await client.SendAsync(requestMessage); if (response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(); var options = new JsonSerializerOptions(); options.Converters.Add(new JsonStringEnumConverter()); // 直接反序列化为对应泛型类型的响应,Records自动就是List<T>类型 var oDataResponse = JsonSerializer.Deserialize<EntityListResponse<T>>(body, options); return oDataResponse; } else { throw new HttpRequestException("Request failed. I need better error handling, e.g. returning empty data."); } }
第三步:Blazor组件侧调用
因为你的组件已经定义了TItem泛型参数,直接传入即可:
private async Task ReadEntity(GridReadEventArgs args) { var data = await _entityService.GetAll<TItem>(args.Request); // 此处data.Records自动就是List<TItem>类型,无需额外类型转换 }
方案2:反射动态构造类型(兼容原有非泛型方法签名)
如果你不想改动现有方法的入参定义,也可以通过反射动态生成反序列化目标类型实现需求:
public async Task<EntityListResponse> GetAll(DataSourceRequest request, object entity) { Type entityType = entity.GetType(); var baseUrl = $"{entityType.Name}s?"; var requestUrl = $"{baseUrl}{request.ToODataString()}"; var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl); requestMessage.Headers.Add("Accept", "application/json"); var client = HttpClient.CreateClient("IndiciaStageApi"); var response = await client.SendAsync(requestMessage); if (response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(); var options = new JsonSerializerOptions(); options.Converters.Add(new JsonStringEnumConverter()); // 动态构造对应实体类型的泛型响应类 Type genericResponseType = typeof(EntityListResponse<>).MakeGenericType(entityType); dynamic oDataResponse = JsonSerializer.Deserialize(body, genericResponseType, options); // 转换为原有非泛型响应类返回 return new EntityListResponse { Total = oDataResponse.Total, Records = oDataResponse.Records }; } else { throw new HttpRequestException("Request failed. I need better error handling, e.g. returning empty data."); } }
该方案返回的Records列表内部元素已经是对应实体类型,使用时通过Records.Cast<目标类型>()转换即可。
注意事项
- 原有代码中使用
$"{entity}s?"拼接请求路径存在风险,如果实体类重写了ToString方法会导致路径错误,统一使用typeof(T).Name或者entity.GetType().Name获取类型名更稳妥。 - 优先选择泛型方案,无需反射开销,类型安全,编译阶段就能排查类型不匹配问题。
内容的提问来源于stack exchange,提问作者Stefan Jaspers
相关产品推荐
相关产品推荐

