我有一个从 .NET5 开始的 Blazor Web Assembly 项目。我正在使用 Blazorise,它对我来说效果很好。几周前,我升级到 .NET6,最初是在主项目中,发现我遇到了一个奇怪的错误。加载索引页面后不久,在服务器来回获取用户详细信息等之后。我收到了一个未处理的异常,其中包含一堆控制台消息,这些消息并没有真正指示(对我)错误在哪里......
我已经使用图像来浓缩信息。如果需要,我可以提供详细信息。我关注了一些链接,它们将我带入了 JS 领域。
这件事的奇怪之处在于:
a) 这直到我更新到 NET6 才发生 - 最初我认为可能是我更新错误,所以我使用 NET6 模板从头开始重建了应用程序。错误又回来了。
b)我花了几天时间使用消除过程来消除错误 - 详细信息如下:我有几个用于表单的组件:-an EditUserForm -an OrgansationForm -an AddressForm
它们都是组件并使用 Blazorise Modals。这是 EditUserForm:
@namespace blah.Client.Components.Forms
<Modal @ref="modalRef">
<ModalContent IsCentered="true">
<ModalHeader>
<ModalTitle>Editing @editUser.FullName</ModalTitle>
<CloseButton Clicked="@HideModal" />
</ModalHeader>
<ModalBody MaxHeight="50">
<div class="bg-light">
@if (editUser.IsComplete)
{
<p>Your Information is Complete - Make any changes and Press the 'Save' button.</p>
}
else
{
<p>Your Information is Incomplete - Please ensure you have completed at least your Name, Address, Mobile Number and Gender.</p>
}
</div>
<EditForm Model="@editUser" @onchange="() => Refresh()">
<DataAnnotationsValidator />
<Field>
<FieldLabel>Title</FieldLabel>
<TextEdit Placeholder="Enter Title..." @bind-Text="@editUser.Title" />
</Field>
<Field>
<FieldLabel>First Name</FieldLabel>
<TextEdit Placeholder="Enter First Name..." @bind-Text="@editUser.FirstName" />
</Field>
<Field>
<FieldLabel>Middle Name</FieldLabel>
<TextEdit Placeholder="Enter Middle Name..." @bind-Text="@editUser.MiddleName" />
</Field>
<Field>
<FieldLabel>Last Name</FieldLabel>
<TextEdit Placeholder="Enter Last Name..." @bind-Text="@editUser.FamilyName" />
</Field>
<Field>
<FieldLabel>Email</FieldLabel>
<TextEdit Placeholder="Enter Email..." @bind-Text="@editUser.Email" />
</Field>
<Field>
<FieldLabel>Phone No</FieldLabel>
<TextEdit Placeholder="Enter Phone No..." @bind-Text="@editUser.PhoneNumber" />
</Field>
<Field>
<FieldLabel>Date of Birth</FieldLabel>
<InputDate @bind-Value="@editUser.DoB" />
</Field>
<Field>
<FieldLabel>Gender</FieldLabel>
<Blazorise.Select TValue="AvailablePlayer.Shared.Enums.Gender" @bind-SelectedValue="@editUser.Gender">
@foreach (AvailablePlayer.Shared.Enums.Gender gendertype in Enum.GetValues(typeof(AvailablePlayer.Shared.Enums.Gender)))
{
var gtypetemp = gendertype;
<Blazorise.SelectItem Value="@gtypetemp">
@Enum.GetName(typeof(AvailablePlayer.Shared.Enums.Gender), gtypetemp).Replace('_', ' ');
</Blazorise.SelectItem>
}
</Blazorise.Select>
</Field>
<Field>
<FieldLabel>Address</FieldLabel>
<div>@getlongaddress()</div>
@if (editUser.Address != null && !editUser.Address.IsComplete)
{
<p>The Address is incomplete, please edit</p>
<Button Color="Color.Danger" Clicked="@EditAddress">Edit Address</Button>
}
else
{
<Button Color="Color.Secondary" Clicked="@EditAddress">Edit Address</Button>
}
</Field>
<Field>
<FieldLabel>Sign up as Player and Accept Player T's & C's</FieldLabel>
<InputCheckbox @bind-Value="Isplayer">Accept Player Terms <a href="Identity/Account/PlayerConditions.html">which you can see here</a></InputCheckbox>
</Field>
@if (Isplayer)
{
<Button Color="Color.Secondary" Clicked="@EditPlayer">Edit Player</Button>
}
<Field>
<FieldLabel>Sign up as a member of an organisation and Accept Member T's & C's</FieldLabel>
<InputCheckbox @bind-Value="Ismember">Accept Member Terms </InputCheckbox>
<a href="Identity/Account/PlayerConditions.html">which you can see here</a>
</Field>
@if (Ismember)
{
<Button Color="Color.Secondary" Clicked="@EditOrgMember">Edit Membership</Button>
}
</EditForm>
<AuthorizeView Roles="Administrator">
<Authorized Context="Auth">
<div class="bg-light">
<p>(Note: to remove Player Role also untick the 'Accept Player Terms' Box)</p>
@foreach (rolebool rolething in rolelist)
{
<div>
<Check TValue="bool" @bind-Checked="rolething.userisin">@rolething.role </Check>
</div>
}
</div>
</Authorized>
</AuthorizeView>
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="@HideModal">Close</Button>
<Button Color="Color.Primary" Clicked="@SaveAsync">Save Changes</Button>
</ModalFooter>
</ModalContent>
</Modal>
<CascadingValue Name="EditAddress" Value="@editUser.Address">
<AddressForm @ref="addressform" OnAddressSaved="AddressSaved"></AddressForm>
</CascadingValue>
<EditPlayerForm @ref="playereditform" OnPlayerSaved="Refresh" />
<OrganisationForm @ref="organisationForm" />
<Snackbar @ref="snackbar">
<SnackbarBody>
@StatusMessage
</SnackbarBody>
</Snackbar>
该代码位于一个单独的文件中,并且具有许多功能,因此为简洁起见,我只在这里展示基础知识:
namespace blah.Client.Components.Forms
{
public partial class EditUserForm : ComponentBase
{
[Inject] UserService UserService { get; set; }
...some stuff...
//private bool _ismember;
protected bool Ismember;
AddressForm addressform = new AddressForm();
EditPlayerForm playereditform = new EditPlayerForm();
OrganisationForm organisationForm = new OrganisationForm();
...some stuff...
protected void EditAddress()
{
addressform.ShowModal();
}
private void AddressSaved(AddressDTO address)
{
editUser.Address = address;
this.StateHasChanged(); // To reload the address.
}
public void Refresh()
{
this.StateHasChanged();
}
}
这是组织形式:
@namespace blah.Client.Components.Forms
<Modal @ref="modalRef">
<ModalContent IsCentered="true">
<ModalHeader>
<ModalTitle>Editing Organisation</ModalTitle>
<CloseButton Clicked="@HideModal" />
</ModalHeader>
<ModalBody MaxHeight="50">
<EditForm Model="@editOrganisation" @onchange="() => Refresh()">
<DataAnnotationsValidator />
<Field>
<FieldLabel>Organisation Name</FieldLabel>
<TextEdit Placeholder="blah..." @bind-Text="@editOrganisation.Name" />
</Field>
<Field>
<FieldLabel>Business Address</FieldLabel>
<div>@getlongaddress(editOrganisation.BusinessAddress)</div>
@if (editOrganisation.BusinessAddress != null && !editOrganisation.BusinessAddress.IsComplete)
{
<p>The Address is incomplete, please edit</p>
<Button Color="Color.Danger" Clicked="() => EditAddress(editOrganisation.BusinessAddress)">Edit Main Address</Button>
}
else
{
<Button Color="Color.Secondary" Clicked="() => EditAddress(editOrganisation.BusinessAddress)">Edit Main Address</Button>
}
</Field>
<Field>
<FieldLabel>Date Joined</FieldLabel>
<DateEdit @bind-Date="editOrganisation.DateJoined" />
</Field>
</EditForm>
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="@HideModal">Close</Button>
<Button Color="Color.Primary" Clicked="@SaveAsync">Save</Button>
</ModalFooter>
</ModalContent>
</Modal>
<AddressForm @ref="addressform" OnAddressSaved="AddressSaved"></AddressForm>
<Snackbar @ref="snackbar">
<SnackbarBody>
@StatusMessage
</SnackbarBody>
</Snackbar>
...以及 OrganisationForm 的代码(删除了一些功能)
namespace blah.Client.Components.Forms
{
public partial class OrganisationForm : ComponentBase
{
[Inject] ExecService ExecService { get; set; }
// reference to the modal component
protected Modal modalRef = new Modal();
AddressForm addressform = new AddressForm();
DatePicker<DateTime?> datepicker = new DatePicker<DateTime?>();
[Parameter]
public EventCallback<OrganisationDTO> OnOrganisationSaved { get; set; }
public OrganisationDTO editOrganisation { get; set; } = new OrganisationDTO();
private void AddressSaved(AddressDTO address)
{
editOrganisation.BusinessAddress = address;
this.StateHasChanged(); // To reload the address.
}
protected void EditAddress(AddressDTO addresstoedit)
{
addressform.editAddress = addresstoedit;
addressform.ShowModal();
}
protected async Task SaveAsync()
{
editOrganisation = await ExecService.AddUpdateOrganisationAsync(editOrganisation);
StatusMessage = editOrganisation.Status.Reason;
await snackbar.Show();
HideModal();
await OnOrganisationSaved.InvokeAsync(editOrganisation);
}
}
}
最后是 AddressForm:
@namespace blah.Client.Components.Forms
<Modal @ref="modalRef">
<ModalContent IsCentered="true">
<ModalHeader>
<ModalTitle>Editing Address</ModalTitle>
<CloseButton Clicked="@HideModal" />
</ModalHeader>
<ModalBody MaxHeight="50">
<div class="bg-light">
@if (editAddress.IsComplete)
{
<p>Your Address is Complete - Make any changes and Press the 'Save' button.</p>
}
else
{
<p>Your Address is Incomplete - Please ensure you have at least your Number, Street and PostCode.</p>
}
</div>
<EditForm Model="@editAddress" @onchange="() => checkaddress()">
<DataAnnotationsValidator />
<Field>
<FieldLabel>No. Name or Building</FieldLabel>
<TextEdit Placeholder="Enter House No, Name Building..." @bind-Text="@editAddress.Line1"/>
</Field>
<Field>
<FieldLabel>Street</FieldLabel>
<TextEdit Placeholder="Enter Street..." @bind-Text="@editAddress.Line2" />
</Field>
<Field>
<FieldLabel>Town/City</FieldLabel>
<TextEdit Placeholder="Enter Town/City..." @bind-Text="@editAddress.Line3" />
</Field>
<Field>
<FieldLabel>Region/State</FieldLabel>
<TextEdit Placeholder="Enter Region/State..." @bind-Text="@editAddress.Line4" />
</Field>
<Field>
<FieldLabel>Post Code</FieldLabel>
<TextEdit Placeholder="Enter Post Code..." @bind-Text="@editAddress.PostCode" />
</Field>
</EditForm>
</ModalBody>
<ModalFooter>
<Button Color="Color.Secondary" Clicked="@HideModal">Close</Button>
<Button Color="Color.Primary" Clicked="@SaveAsync">Save</Button>
</ModalFooter>
</ModalContent>
</Modal>
...和 AddressForm 代码:
namespace blah.Client.Components.Forms
{
public partial class AddressForm : ComponentBase
{
// reference to the modal component
protected Modal add_modal = new Modal();
[CascadingParameter(Name = "EditAddress")]
AddressDTO editAddress { get; set; } = new AddressDTO();
[Parameter]
public EventCallback<AddressDTO> OnAddressSaved { get; set; }
// Since this is going to be usually called from another form feed back the address
// by way of this event.
async Task SaveAsync()
{
await OnAddressSaved.InvokeAsync(editAddress);
await add_modal.Hide();
}
// Display functions
public void ShowModal()
{
add_modal.Show();
}
public void HideModal()
{
add_modal.Hide();
}
public void checkaddress()
{
this.StateHasChanged();
}
}
}
...我已经尝试了很多事情,但我一直回到我并不完全理解的错误消息,因为看起来 JS 互操作中的 null 正在发生一些事情,但我不清楚。
我可以通过将 AddressForm 简化为这样来解决问题:
@namespace blah.Client.Components.Forms
<h1>Address Form</h1>
<Modal @ref="add_modal">
<ModalContent IsCentered="true">
<h1>Address Form</h1>
</ModalContent>
</Modal>
大多数时候都会出错..然后它又回来了,尽管很难跟踪,因为 Chrome 调试器有时会缓存一些东西,我必须记住在缓存关闭的情况下刷新...如果我删除了 '@ref="模态定义中的 add_modal"' 它一直有效。
我知道这很奇怪,而且大多数时候错误中都有如何找到问题的线索。这似乎来来去去,感觉可能与时间有关。在所有渲染完成后,错误总是需要几秒钟才能出现,所以它就像 JS 类型的东西中的短暂超时或失败的承诺。
我已经尝试了很多东西,但是自从我升级到 NET6(以及其他组件)后,代码并没有真正改变。另一种可能性是,如果我可以添加一个异常处理程序并中断它或编写我自己的消息,但是,我不确定该放在哪里?
我正在寻找一些关于如何追踪这个问题的指示,因为我几乎无所适从。错误可能在消息中盯着我看,但我没有看到。
非常感谢布雷特