Blazor Web应用JSON反序列化失败:无法转为Applier类型
Blazor Web应用编辑/查看求职者页面反序列化错误排查
我正在使用Visual Studio开发Blazor Web应用,目前可通过索引页创建和删除求职者(Applier)实体数据,但进入编辑或查看页面时触发以下错误:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The JSON value could not be converted to BandA.Shared.Domain.Applier. Path: $ | LineNumber: 0 | BytePositionInLine: 1. System.Text.Json.JsonException: The JSON value could not be converted to BandA.Shared.Domain.Applier. Path: $ | LineNumber: 0 | BytePositionInLine: 1. at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Applier& value) at System.Text.Json.Serialization.JsonConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Applier& value) at System.Text.Json.Serialization.JsonConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore[Applier](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore[Applier](JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& state, JsonConverter converterBase) at System.Text.Json.JsonSerializer.<ReadAsync>d__20`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() at System.Net.Http.Json.HttpContentJsonExtensions.<ReadFromJsonAsyncCore>d__3`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__9`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() at BandA.Client.Pages.Applier.Edit.OnParametersSetAsync() in C:\Users\boris\source\repos\BandA\BandA\Client\Pages\Applier\Edit.razor:line 15 at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync() at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
经排查,该错误是应用尝试将HTTP GET请求的JSON响应反序列化为BandA.Shared.Domain.Applier类型时触发。虽然通过Postman测试GET接口可正常返回数据,但调整领域类、检查端点后问题仍未解决,且Visual Studio无编译错误,请求协助排查问题。
相关代码
Applier/Index.razor
@page "/appliers/" @inject HttpClient _client @inject IJSRuntime js @attribute [Authorize] <h3 class="card-title"> 求职者列表 </h3> <br /> <a href="/appliers/create" class="btn btn-secondary"> <span class="oi oi-plus"></span> 创建新求职者 </a> <br /> <br /> @if (Appliers == null) { <div class="alert alert-info">加载求职者数据...</div> } else { <table class="table table-responsive"> <thead> <tr> <th>姓名</th> <th>身份证号(NRIC)</th> <th>出生日期</th> <th>性别</th> <th>联系电话</th> <th>邮箱</th> <th>地址</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var applier in Appliers) { <tr> <td>@applier.FirstName @applier.LastName</td> <td>@applier.NRIC</td> <td>@applier.DateOfBirth</td> <td>@applier.Gender</td> <td>@applier.ContactNumber</td> <td>@applier.EmailAddress</td> <td>@applier.Address</td> <td> <a href="/appliers/view/@applier.Id" class="btn btn-primary"> <span class="oi oi-book"></span> </a> <a href="/appliers/edit/@applier.Id" class="btn btn-warning"> <span class="oi oi-pencil"></span> </a> <button class="btn btn-danger" @onclick="@(()=>Delete(applier.Id))"> <span class="oi oi-delete"></span> </button> </td> </tr> } </tbody> </table> } @code { private List<Applier> Appliers; protected async override Task OnInitializedAsync() { Appliers = await _client.GetFromJsonAsync<List<Applier>>($"{Endpoints.AppliersEndpoint}"); } async Task Delete(int applierId) { var applier = Appliers.First(q => q.Id == applierId); var confirm = await js.InvokeAsync<bool>("confirm", $"确定要删除 {applier.NRIC} 吗?"); if (confirm) { await _client.DeleteAsync($"{Endpoints.AppliersEndpoint}/{applierId}"); await OnInitializedAsync(); } } }
Applier/View.razor
@page "/appliers/view/{id:int}" @inject HttpClient _client @inject NavigationManager _navManager <h3>查看求职者信息</h3> <FormComponent applier="applier" Disabled="true" /> @code { [Parameter] public int id { get; set; } Applier applier = new Applier(); protected async override Task OnParametersSetAsync() { applier = await _client.GetFromJsonAsync<Applier>($"{Endpoints.AppliersEndpoint}/{id}"); } }
Applier/Edit.razor
@page "/appliers/edit/{id:int}" @inject HttpClient _client @inject NavigationManager _navManager <h3>编辑求职者信息</h3> <FormComponent ButtonText="更新" OnValidSubmit="EditApplier" applier="applier" /> @code { [Parameter] public int id { get; set; } Applier applier = new Applier(); protected async override Task OnParametersSetAsync() { applier = await _client.GetFromJsonAsync<Applier>($"{Endpoints.AppliersEndpoint}/{id}"); } async Task EditApplier() { await _client.PutAsJsonAsync($"{Endpoints.AppliersEndpoint}/{id}", applier); _navManager.NavigateTo("/appliers/"); } }
Applier/FormComponents.razor
<EditForm Model="@applier" OnValidSubmit="@OnValidSubmit"> <DataAnnotationsValidator /> <ValidationSummary /> <fieldset disabled="@Disabled"> <div class="form-group"> <label>名字: </label> <div> <InputText @bind-Value="@applier.FirstName" class="form-control" /> <ValidationMessage For="@(() => applier.FirstName)" /> </div> </div> <div class="form-group"> <label>姓氏: </label> <div> <InputText @bind-Value="@applier.LastName" class="form-control" /> <ValidationMessage For="@(() => applier.LastName)" /> </div> </div> <div class="form-group"> <label>身份证号(NRIC): </label> <div> <InputText @bind-Value="@applier.NRIC" class="form-control" /> <ValidationMessage For="@(() => applier.NRIC)" /> </div> </div> <div class="form-group"> <label>出生日期: </label> <div> <InputDate @bind-Value="@applier.DateOfBirth" class="form-control" /> <ValidationMessage For="@(() => applier.DateOfBirth)" /> </div> </div> <div class="form-group"> <label>性别: </label> <div> <InputText @bind-Value="@applier.Gender" class="form-control" /> <ValidationMessage For="@(() => applier.Gender)" /> </div> </div> <div class="form-group"> <label>联系电话: </label> <div> <InputText @bind-Value="@applier.ContactNumber" class="form-control" /> <ValidationMessage For="@(() => applier.ContactNumber)" /> </div> </div> <div class="form-group"> <label>邮箱: </label> <div> <InputText @bind-Value="@applier.EmailAddress" class="form-control" /> <ValidationMessage For="@(() => applier.EmailAddress)" /> </div> </div> <div class="form-group"> <label>地址: </label> <div> <InputText @bind-Value="@applier.Address" class="form-control" /> <ValidationMessage For="@(() => applier.Address)" /> </div> </div> </fieldset> @if (!Disabled) { <button type="submit" class="btn btn-success btn-block"> @ButtonText </button> } <BackToList Target="appliers" /> </EditForm> @code { [Parameter] public Applier applier { get; set; } [Parameter] public string ButtonText { get; set; } = "保存"; [Parameter] public EventCallback OnValidSubmit { get; set; } [Parameter] public bool Disabled { get; set; } = false; }
Client/Shared/Domain/Applier.cs
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BandA.Shared.Domain { public class Applier : BaseDomainModel { [Required] [StringLength(100, MinimumLength = 2, ErrorMessage = "名字长度不符合要求,需在2-100字符之间")] public string FirstName { get; set; } [Required] [StringLength(100, MinimumLength = 2, ErrorMessage = "姓氏长度不符合要求,需在2-100字符之间")] public string LastName { get; set; } [Required] [RegularExpression(@"^[STFGstfg]\d{7}[A-Za-z]", ErrorMessage = "身份证号(NRIC)格式不符合要求")] // NRIC正则规则:[STFGstfg] - 大小写的S、T、F或G开头 \d{7} - 中间7位数字 [A-Za-z] - 最后一位为字母 public string NRIC { get; set; } [Required] public DateTime? DateOfBirth { get; set; } // 地址为非必填项,未添加数据验证注解 public string Gender { get; set; } [Required] [DataType(DataType.PhoneNumber)] [RegularExpression(@"(6|8|9)\d{7}", ErrorMessage = "联系电话格式无效,需以6、8或9开头,共8位数字")] // 手机号正则规则:(6|8|9) - 以6、8或9开头 \d{7} - 后续7位为数字 public string ContactNumber { get; set; } [Required] [DataType(DataType.EmailAddress, ErrorMessage = "邮箱格式无效")] [EmailAddress] public string EmailAddress { get; set; } // 地址为非必填项,未添加数据验证注解 public string Address { get; set; } public virtual List<Resume> Resumes { get; set; } public virtual List<Application> Applications { get; set; } } }
Client/Endpoint.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace BandA.Client.Static { public static class Endpoints { private static readonly string Prefix = "api"; public static readonly string AppliersEndpoint = $"{Prefix}/appliers"; public static readonly string ResumesEndpoint = $"{Prefix}/resumes"; public static readonly string ApplicationsEndpoint = $"{Prefix}/applications"; } }
内容的提问来源于stack exchange,提问作者BorisLimTP
相关产品推荐
相关产品推荐

