为啥“InvokeAsync”在 Blazor 组件中显示为错误?

Posted

技术标签:

【中文标题】为啥“InvokeAsync”在 Blazor 组件中显示为错误?【英文标题】:Why does 'InvokeAsync' show as an error in a Blazor component?为什么“InvokeAsync”在 Blazor 组件中显示为错误? 【发布时间】:2021-10-16 07:35:33 【问题描述】:

我最近开始在我的 ASP.Net 核心 Web 应用程序中包含 Blazor 组件。我决定使用模式 [ComponentName].razor 和 [ComponentName].razor.cs 将我的组件拆分为多个文件,用于所有 C# 编码。

令人讨厌的是,我所有的状态更改通知调用都显示为错误。现在,当我构建和运行应用程序时,这些错误消失了,但它们仍然阻塞了我的错误列表窗口。如果我关闭然后打开 Visual Studio 2019,这些将消失,但它们会在几分钟后恢复。发生了什么?如何解决这些错误?

干杯!

InvokeAsync highlighted as an error

编辑:根据要求,这是一些代码。违规行位于 TransactionTableView.razor.cs 中。 'await InvokeAsync(StateHasChanged)' 显示为错误。

TransactionTableView.razor

<table class="table data-table" id="taskstable">
    <thead>
        <tr>
            @if (ShowSelect)
            
                <th>
                    <input type="checkbox" @bind="SelectAllTransactions" @bind:event="oninput" @onclick="() => CheckAllTransactions(!SelectAllTransactions)"/>
                    Select all
                </th>
            
            @if (ShowParent)
            
                <th>
                    Parent
                </th>
            
            <th>
                Task
            </th>
            <th>
                Status
            </th>
            <th>
                Due Date
            </th>
            <th>
                Completion Date
            </th>
            <th>
                Amount Due
            </th>
            <th>
                Amount Paid
            </th>
            <th>
                Comments
            </th>
        </tr>
    </thead>
    <tbody class="tasks-body">
        @if (Transactions != null)
        
            @foreach (var transaction in DisplayTransactions)
            
                <tr class="@transaction.AlertClassDisplay()">
                    @if (ShowSelect)
                    
                        <td>
                            <input @bind="transaction.Select" type="checkbox" @oninput="() => SelectSingleTask(transaction.TransactionId)"/>
                        </td>
                    
                    @if (ShowParent)
                    
                        <td>
                            @transaction.TenementKey
                        </td>
                    
                    <td>
                        @transaction.Description
                    </td>
                    <td class="task-status">
                        <a asp-action="Details" asp-controller="Alerts" method="get" asp-route-transactionId="@transaction.TransactionId">
                            @transaction.TransactionStatus
                        </a>

                    </td>
                    <td>
                        @transaction.DueDateDisplay()

                    </td>
                    <td>
                        @($"transaction.CompletionDate:dd MMM yyyy")
                    </td>
                    <td>
                        @transaction.AmountDue
                    </td>
                    <td>
                        @transaction.AmountPaid
                    </td>
                    <td>
                        @transaction.Comments
                    </td>
                </tr>
            
        
    </tbody>
</table>

TransactionTableView.razor.cs

partial class TransactionTableView
    
        // Injected services
        [Inject]
        private ApplicationDbContext _context  get; set; 

        // Data
        public List<int> TenementIds  get; set; 
        public List<TransactionViewModel> Transactions  get; set; 
        public List<TransactionViewModel> DisplayTransactions  get; set; 
        public List<Filter> Filters  get; set;  = new List<Filter>();

        private bool ShowParent  get; set;  = true;
        private bool ShowSelect  get; set;  = true;
        private bool SelectAllTransactions  get; set;  = false;

        public async Task Refresh()
        
            var transactions = new List<Transaction>(_context.Transactions.Where(x => x.TenementId != null && TenementIds.Contains((int)x.TenementId)));

            transactions = transactions.OrderBy(x => x.DueDate).ToList();

            var models = new List<TransactionViewModel>();
            transactions.ForEach(x =>
            
                models.Add(x.GetViewModel(_context));
            );
            Transactions = models;
            await RefreshFilters();
        

        public async Task RefreshFilters()
        
            var holder = Transactions;

            if (Filters != null)
            
                foreach (var filter in Filters)
                
                    if(filter.FilteringProperty.PropertyType == typeof(string))
                    
                        holder = holder.Where(x => ((string)filter.FilteringProperty.GetValue(x)).ToLower().Contains(filter.Values.First().ToString().ToLower())).ToList();
                    

                    if(filter.FilteringProperty.PropertyType == typeof(DateTime) || filter.FilteringProperty.PropertyType == (typeof(DateTime?)))
                    
                        var dFilter = (DateFilter)filter;

                        if (dFilter.SelectedAfterDate)
                        
                            holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) > dFilter.TargetDate).ToList();
                        
                        else if (dFilter.SelectBeforeDate)
                        
                            holder = holder.Where(x => (DateTime)dFilter.FilteringProperty.GetValue(x) < dFilter.TargetDate).ToList();
                        
                        else if (dFilter.SelectBetweenDates)
                        
                            holder = holder.Where(x => 
                            
                                var targetDate = (DateTime)dFilter.FilteringProperty.GetValue(x);

                                return targetDate < dFilter.TargetDate && targetDate > (DateTime)dFilter.FirstTargetDate;
                            ).ToList();
                        
                    

                    if(filter.FilteringProperty.PropertyType == typeof(TransactionStatus))
                    
                        var targetStatuses = filter.Values.Select(x => (TransactionStatus)x);

                        holder = holder.Where(x => targetStatuses.Contains(x.TransactionStatus)).ToList();
                    
                
            

            DisplayTransactions = holder;
            await RefreshAllTaskSelector();
            await InvokeAsync(StateHasChanged);
        

        private async Task CheckAllTransactions(bool checkAll)
        
            foreach(var displayTask in DisplayTransactions)
            
                displayTask.Select = checkAll;
            

            await InvokeAsync(StateHasChanged);
        

        private async Task SelectSingleTask(int transactionId)
        
            var task = DisplayTransactions.SingleOrDefault(x => x.TransactionId == transactionId);
            task.Select = !task.Select;

            if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
            
                SelectAllTransactions = true;
            
            else
            
                SelectAllTransactions = false;
            

            await InvokeAsync(StateHasChanged);
        

        private async Task RefreshAllTaskSelector()
        
            if (DisplayTransactions.Any() && DisplayTransactions.Where(x => !x.Select).Count() == 0)
            
                SelectAllTransactions = true;
            
            else
            
                SelectAllTransactions = false;
            
        

        private async Task DeleteSelected()
        
            if (_context.ChangeTracker.HasChanges())
            
                throw new ApplicationException("DB already has changes");
            

            var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));

            foreach(var target in targets)
            
                Transactions.Remove(target);
                DisplayTransactions.Remove(target);
                var transaction = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
                _context.Transactions.Remove(transaction);
            

            await _context.SaveChangesAsync();
            await InvokeAsync(StateHasChanged);
        

        private async Task CompleteSelected()
        
            if (_context.ChangeTracker.HasChanges())
            
                throw new ApplicationException("DB already has changes");
            

            var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));

            foreach (var target in targets)
            
                var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
                dbTask.CompletionDate = DateTime.Now;
                dbTask.TransactionStatus = TransactionStatus.Completed;

                target.CompletionDate = dbTask.CompletionDate;
                target.TransactionStatus = dbTask.TransactionStatus;

                var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
                orig.CompletionDate = dbTask.CompletionDate;
                orig.TransactionStatus = dbTask.TransactionStatus;
            

            await _context.SaveChangesAsync();
            await RefreshFilters();
            await InvokeAsync(StateHasChanged);
        

        private async Task ArchiveSelected()
        
            if (_context.ChangeTracker.HasChanges())
            
                throw new ApplicationException("DB already has changes");
            

            var targets = new List<TransactionViewModel>(DisplayTransactions.Where(x => x.Select));

            foreach (var target in targets)
            
                var dbTask = _context.Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
                dbTask.CompletionDate = DateTime.Now;
                dbTask.TransactionStatus = TransactionStatus.Archived;

                target.CompletionDate = dbTask.CompletionDate;
                target.TransactionStatus = dbTask.TransactionStatus;

                var orig = Transactions.SingleOrDefault(x => x.TransactionId == target.TransactionId);
                orig.CompletionDate = dbTask.CompletionDate;
                orig.TransactionStatus = dbTask.TransactionStatus;
            

            await _context.SaveChangesAsync();
            await RefreshFilters();
            await InvokeAsync(StateHasChanged);
        
    

【问题讨论】:

能否分享您的代码? 你的应用是客户端(WASM)还是服务器端? 编译器好像找不到InvokeAsync方法,但是这个方法在ComponentBase类里面。您是否尝试将 : ComponentBase 添加到类定义中?像这样:public partial class TransactionTableView : ComponentBase 现在检查调试器在哪里找到 'InvokeAsync` 方法 嗨,克里斯,如果我的回复或 Henk 的回复满足您的需求,请在此处标记答案:***.com/help/someone-answers。 【参考方案1】:

我已经尝试了一个小测试项目,我可以确认您可能有 2 个问题:

您已在 TransactionTableView.razor(如 Henk 所说)之外的另一个文件夹中创建/移动文件 TransactionTableView.razor.cs 后面的代码,但未指定 @987654321 @路径 你还没有从ComponentBase派生你的类

如果您想分隔两个不同文件夹中的两个文件,您需要添加inherits,如下所示:

EmployeeData.razorPages 文件夹中

@page "/employee/Id"
@using TestMenu.Shared
@using TestMenu.Client.Services
@inherits TestMenu.Client.Pages.test.EmployeeData

<h3>Employee</h3>

Result data: <b>@employeeData</b>

EmployeeData.razor.csPages/test 文件夹中

using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using TestMenu.Client.Services;
using TestMenu.Shared;

namespace TestMenu.Client.Pages.test

    public partial class EmployeeData: ComponentBase
    
        [Inject] IEmployeeService EmployeeService  get; set; 

        [Parameter]
        public string Id  get; set; 

        protected Employee Employee = new();
        protected string employeeData;

        protected override async Task OnInitializedAsync()
        
            Employee = (await EmployeeService.GetEmployeeById(int.Parse(Id)));
            employeeData = Employee.Name;
            await InvokeAsync(StateHasChanged);
        
    

如果您从 EmployeeData.razor.cs 后面的代码中删除 : ComponentBase,您会收到与屏幕截图中类似的错误。

【讨论】:

就是这样!将 :ComponentBase 添加到我的 .razor.cs 类就可以了。谢谢! 现在使用继承与 2 个不同的类,而不是一个部分类。增加一点开销。

以上是关于为啥“InvokeAsync”在 Blazor 组件中显示为错误?的主要内容,如果未能解决你的问题,请参考以下文章

IJSRuntime 忽略服务器端 Blazor 项目中的自定义 json 序列化程序

为啥 Blazor 使用 post 而不是 WebSockets?

为啥 Blazor 生命周期方法会执行两次?

Blazor + Identity:为啥会出现错误?

为啥在全新安装后 Blazor Hot Reload 没有按预期工作?

Blazor 脚手架注册页面为啥 .cshtml 不是 .razor 文件?