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

Errors and warnings using @functions block in Razor Pages

因为 @helper 指令在 ASP.NET Core Razor Pages 中不再受支持,我一直在使用 @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>
    }
}

这似乎有效,但出现错误:

Error MVC1006: The method contains a TagHelper and therefore must be async and return a Task. For instance, usage of ~/ typically results in a TagHelper and requires an async Task returning parent method.

所以我将此函数更改为 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): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
...\Razor\Pages\Tasks\Index.cshtml.g.cs(312,200,312,202): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

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

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

更新:

这是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() => {
        }
        );

至少有 4 个解决方法:

解决方案 1:Return Task 但不要 async:

您可以安全地忽略编译器说它必须是异步函数,因为编译器只关心函数 returns System.Threading.Tasks.Task。所以你可以 return 一个 System.Threading.Tasks.Task 而不使用 await 虽然这意味着你需要一个多余的 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>
    }
}

Microsoft has just confirmed 警告是错误。

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

async Task RenderName (string name)
{
    <a asp-action="TagHelperForcesAsync">dear @name</a>
}

二手

<p>Hello @{await RenderName("John");}</p>
@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>