You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:55:17