在 Razor 页面中使用 @functions 块的错误和警告

Posted

技术标签:

【中文标题】在 Razor 页面中使用 @functions 块的错误和警告【英文标题】:Errors and warnings using @functions block in Razor Pages 【发布时间】:2020-07-02 16:12:52 【问题描述】:

由于 ASP.NET Core Razor 页面不再支持 @helper 指令,我一直在使用 @functions 指令。

@functions

    void RenderTask(Models.Task task)
    
        <tr>
            <td class="@Model.CssClass">
                <p class="compact">
                    <span class="font-weight-bold">@task.Title</span>
                    @if (!string.IsNullOrWhiteSpace(task.Description))
                    
                        <br />@task.Description
                    
                </p>
            </td>
            <td class="@Model.CssClass">
                <img src="~/images/Edit.png" class="edit-area button-img" data-id="@task.Id" title="Edit" />
                <img src="~/images/Delete.png" class="delete-area button-img" data-id="@task.Id" title="Delete" />
            </td>
        </tr>
    

这似乎可行,但出现错误:

错误 MVC1006:该方法包含一个 TagHelper,因此必须是异步的并返回一个任务。例如,使用 ~/ 通常会导致 TagHelper 并需要异步任务返回父方法。

所以我把这个函数改成了async,然后我在任何调用它的地方都使用了await关键字。

@functions

    async System.Threading.Tasks.Task RenderTask(Models.Task task)
    
        <tr>
            <td class="@Model.CssClass">
                <p class="compact">
                    <span class="font-weight-bold">@task.Title</span>
                    @if (!string.IsNullOrWhiteSpace(task.Description))
                    
                        <br />@task.Description
                    
                </p>
            </td>
            <td class="@Model.CssClass">
                <img src="~/images/Edit.png" class="edit-area button-img" data-id="@task.Id" title="Edit" />
                <img src="~/images/Delete.png" class="delete-area button-img" data-id="@task.Id" title="Delete" />
            </td>
        </tr>
    

这确实有效,但我收到警告:

...\Razor\Pages\Tasks\Index.cshtml.g.cs(286,200,286,202):警告 CS1998:此异步方法缺少“等待”运算符,将同步运行。考虑使用“await”运算符来等待非阻塞 API 调用,或“await Task.Run(...)”在后台线程上执行 CPU 密集型工作。 ...\Razor\Pages\Tasks\Index.cshtml.g.cs(312,200,312,202):警告 CS1998:此异步方法缺少“等待”运算符,将同步运行。考虑使用 'await' 运算符来等待非阻塞 API 调用,或使用 'await Task.Run(...)' 在后台线程上执行 CPU 密集型工作。

Index.cshtml.g.cs 似乎是某种中间文件。但我不知道它后面的数字是什么,双击这些警告不会把我带到违规行。

此时,我不确定问题出在哪里。我已经在 Google 上进行了广泛的搜索,但没有找到一个很好的例子来说明我应该做什么。任何建议表示赞赏。

更新:

这是Index.cshtml.g.cs的一部分:

#nullable restore
#line 86 "D:\Users\Jonathan\source\repos\Bamtok\Bamtok\Pages\Tasks\Index.cshtml"
                                                                          Write(task.Id);

#line default
#line hidden
#nullable disable
        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
        __tagHelperExecutionContext.AddHtmlAttribute("data-id", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
        __tagHelperExecutionContext.AddHtmlAttribute(__tagHelperAttribute_3);
        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); // *** ERROR HERE! ***
        if (!__tagHelperExecutionContext.Output.IsContentModified)
        
            await __tagHelperExecutionContext.SetOutputContentAsync();
        
        Write(__tagHelperExecutionContext.Output);
        __tagHelperExecutionContext = __tagHelperScopeManager.End();
        WriteLiteral("\r\n                ");
        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("img", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.SelfClosing, "5fc6845fce9caf31066e5edd3fc6a51f323364e715810", async() => 
        
        );

【问题讨论】:

【参考方案1】:

Microsoft has just confirmed 警告是一个错误。

【讨论】:

【参考方案2】:

至少有 4 种解决方法:

解决方案1:返回Task,但不要成为async

您可以放心地忽略编译器说它必须是异步函数,因为编译器所关心的只是函数返回System.Threading.Tasks.Task。因此,您可以在不使用 await 的情况下返回 System.Threading.Tasks.Task,但这意味着您需要在某处使用多余的 return Task.CompletedTask;

@functions

    System.Threading.Tasks.Task RenderTask( Models.Task task )
    
        <tr>
            <td class="@Model.CssClass">
                <p class="compact">
                    <span class="font-weight-bold">@task.Title</span>
                    @if (!string.IsNullOrWhiteSpace(task.Description))
                    
                        <br />@task.Description
                    
                </p>
            </td>
            <td class="@Model.CssClass">
                <img src="~/images/Edit.png" class="edit-area button-img" data-id="@task.Id" title="Edit" />
                <img src="~/images/Delete.png" class="delete-area button-img" data-id="@task.Id" title="Delete" />
            </td>
        </tr>

        return Task.CompletedTask;
    

解决方案 2:或者,使用包装器:

@functions

    System.Threading.Tasks.Task ShutUpRazor<T>( Action<T> renderFunc, T arg )
    
        renderFunc( arg );
        return Task.CompletedTask;
    

    void RenderTask( Models.Task task )
    
        <tr>
            <td class="@Model.CssClass">
                <p class="compact">
                    <span class="font-weight-bold">@task.Title</span>
                    @if (!string.IsNullOrWhiteSpace(task.Description))
                    
                        <br />@task.Description
                    
                </p>
            </td>
            <td class="@Model.CssClass">
                <img src="~/images/Edit.png" class="edit-area button-img" data-id="@task.Id" title="Edit" />
                <img src="~/images/Delete.png" class="delete-area button-img" data-id="@task.Id" title="Delete" />
            </td>
        </tr>
    

用法:

<section>
    @( this.ShutUpRazor( this.RenderTask, this.Model.MyTask ); )
</section>

解决方案 3:抑制警告:

@ #pragma warning disable 1998 
@functions

    void RenderTask( etc )
    
        etc
    

@ #pragma warning enable 1998 

解决方案 4:使用 async 函数和 awaitYield

@functions

    async System.Threading.Tasks.Task RenderTask( Models.Task task )
    
        await Task.Yield();

        <tr>
            <td class="@Model.CssClass">
                <p class="compact">
                    <span class="font-weight-bold">@task.Title</span>
                    @if (!string.IsNullOrWhiteSpace(task.Description))
                    
                        <br />@task.Description
                    
                </p>
            </td>
            <td class="@Model.CssClass">
                <img src="~/images/Edit.png" class="edit-area button-img" data-id="@task.Id" title="Edit" />
                <img src="~/images/Delete.png" class="delete-area button-img" data-id="@task.Id" title="Delete" />
            </td>
        </tr>
    

【讨论】:

解决方案 1 给了我几个警告和错误。 : 错误 CS4032: 'await' 运算符只能在异步方法中使用。考虑使用“async”修饰符标记此方法并将其返回类型更改为“Task”。. 另外,如果我在没有await 的情况下调用它,我会收到警告警告 CS4014:由于未等待此调用,因此在调用完成之前继续执行当前方法。考虑将“等待”运算符应用于调用结果。. @JonathanWood 这个错误很有趣——你能找到 Razor 编译器生成的 *.cs 文件(通常在你的 PC 的“Temporary ASP.NET Files”文件夹或项目的“Obj”文件夹中)并添加它到你的问题帖子 - 我想看看。 文件很大,但我在问题中添加了几行。 (评论指出错误的位置。) @JonathanWood 啊,我现在看到了问题所在。我忘记了 Razor 现在添加的所有 不必要的 async/await 东西(我希望他们在下一个版本中修复它)。不幸的是,像您一样必须使用async Task&lt;&gt; - 但您可以安全地添加#pragma warning disable... 以禁止在不使用await 的情况下使用async 的警告(因为Razor 正在添加await它将您的代码编译到...g.cs 文件中)。【参考方案3】:
@functions 

    public async Task RenderItem(string date,string time,string id)
    
        <td>@date</td>
        <td>@time</td>
        <td>
            <form method="post" class="form-inline" asp-page-handler="view" asp-route-id="@id">
                <button type="submit" class="btn btn-link">@id</button>
            </form>
        </td>
    


Usage

 <tr>@await RenderItem(@date.ToShortDateString(), time, id);</tr>

【讨论】:

一般建议:通常最好在问题中添加错误和/或警告。【参考方案4】:

当前 Razor 错误最适合我的解决方法是创建函数 async 并在 razor 代码范围内使用 await 调用它。示例:

async Task RenderName (string name)

    <a asp-action="TagHelperForcesAsync">dear @name</a>

二手

<p>Hello @await RenderName("John");</p>

【讨论】:

以上是关于在 Razor 页面中使用 @functions 块的错误和警告的主要内容,如果未能解决你的问题,请参考以下文章

链接到 Razor 页面的 JQuery 数据表行

c#/Razor:如何从 .cshtml 页面引用用户定义的函数?

如何使用Razor语法重定向到Jquery中的另一个页面

如何在 Razor 页面中使用 MVC 部分视图和布局

什么时候在 Razor 页面中使用 OnPut 或 OnDelete?

在 Razor 页面中使用 OnPost 页面处理程序处理 AJAX 请求