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

Blazor Server(.NET7)Message组件移除功能空引用异常排查

Blazor Server消息组件移除时的NullReferenceException问题解决

问题描述

基于.NET 7和Blazor Server构建消息查看器,将Message组件与消息列表封装为类库复用。所有功能正常,但点击Message组件的关闭按钮时,抛出System.NullReferenceException: Object reference not set to an instance of an object异常。

相关代码

Message组件Razor代码

@namespace TestApp.Components

@if(MessageText!=null){
    <div class="mt-3 @MessageClass">
        @MessageText
        <button class="btn-close" @onclick="CloseMessage">Close</button>
    </div>
}

Message组件后台代码

using Microsoft.AspNetCore.Components;

namespace TestApp.Components;
public partial class Message : ComponentBase
{
    public string MessageText {get;set;} = string.Empty;
    public string MessageClass {get;set;} = string.Empty;
    public Guid MessageId {get;set;} = new Guid();
    [Parameter] public Message Origin {set{
        MessageText=value.MessageText;
        MessageClass=value.MessageClass;
        MessageId=value.MessageId;
    }}
    public Message(){

    }
    public Message(string message){
        MessageText=message;
    }
    public event EventHandler CloseRequested=default!;

    private void CloseMessage()
    {
        CloseRequested(this,EventArgs.Empty);
    }
}

ApplicationState类代码

using TestApp.Components;

public class ApplicationState
{
    public List<Message> Messages {get;set;} = new();
    public event EventHandler OnMessagesChange = default!;

    public void AddMessage(string messageText)
    {
        var message = new Message(messageText);
        Messages.Add(message);
        EventHandler handler = OnMessagesChange;
        if(handler!=null)
            handler.Invoke(this,EventArgs.Empty);
        message.CloseRequested+=RemoveMessage;
    }

    private void RemoveMessage(object sender, EventArgs e)
    {
        var message = (Message?)sender;
        if(message!=null)
            Messages.Remove(message);
    }
}

问题根源

核心问题是Blazor渲染的Message组件实例与ApplicationState中持有的Message实例并非同一个对象:

  1. 调用AddMessage时,你创建了一个Message对象并订阅其CloseRequested事件,随后将该对象加入列表。
  2. 但在Blazor渲染组件时,通过[Parameter] public Message Origin赋值的过程中,Blazor会创建新的Message组件实例,而非直接使用你在ApplicationState中创建的那个对象。
  3. 新的组件实例的CloseRequested事件并未被订阅,触发时自然会抛出空引用异常。

解决方案

1. 分离数据模型与组件实例

创建独立的消息数据DTO类,用于存储消息内容,组件仅负责渲染和触发移除请求,不直接作为数据载体。

修改后的Message组件

@namespace TestApp.Components

@if(!string.IsNullOrEmpty(MessageText)){
    <div class="mt-3 @MessageClass">
        @MessageText
        <button class="btn-close" @onclick="CloseMessage">Close</button>
    </div>
}
using Microsoft.AspNetCore.Components;

namespace TestApp.Components;
public partial class Message : ComponentBase
{
    [Inject] private ApplicationState? AppState { get; set; }

    [Parameter] public string MessageText { get; set; } = string.Empty;
    [Parameter] public string MessageClass { get; set; } = string.Empty;
    [Parameter] public Guid MessageId { get; set; } = Guid.NewGuid();

    private void CloseMessage()
    {
        AppState?.RemoveMessageById(MessageId);
    }
}

修改后的ApplicationState与新增DTO类

using TestApp.Components;

public class ApplicationState
{
    public List<MessageData> Messages { get; set; } = new();
    public event EventHandler OnMessagesChange = default!;

    public void AddMessage(string messageText)
    {
        var message = new MessageData(messageText);
        Messages.Add(message);
        OnMessagesChange?.Invoke(this, EventArgs.Empty);
    }

    public void RemoveMessageById(Guid messageId)
    {
        var messageToRemove = Messages.FirstOrDefault(m => m.MessageId == messageId);
        if (messageToRemove != null)
        {
            Messages.Remove(messageToRemove);
            OnMessagesChange?.Invoke(this, EventArgs.Empty);
        }
    }
}

// 消息数据DTO类
public class MessageData
{
    public string MessageText { get; set; } = string.Empty;
    public string MessageClass { get; set; } = string.Empty;
    public Guid MessageId { get; set; } = Guid.NewGuid();

    public MessageData(string messageText)
    {
        MessageText = messageText;
    }
}

2. 页面渲染调整

在页面中遍历MessageData列表,为每个Message组件传递对应属性:

@foreach(var msg in AppState.Messages)
{
    <Message MessageText="@msg.MessageText" 
             MessageClass="@msg.MessageClass" 
             MessageId="@msg.MessageId" />
}

说明

这种修改方式彻底分离了数据模型与UI组件,避免了实例引用不一致的问题,同时通过唯一ID操作消息,逻辑更可靠,也符合Blazor组件的设计原则。

内容的提问来源于stack exchange,提问作者Z. Campbell

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:12:45