razor: Async errors and warnings in Razor Pages @functions blocks

Because the @helper directive is no longer supported in ASP.NET Core Razor Pages, I’ve been using the @functions directive instead.

@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>
    }
}

However, this gives me an error:

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.

So I changed this function to be async, and I used the await keyword every place it is called.

@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>
    }
}

This actually works. But I get several warnings:

…\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 appears to be some sort of intermediary file. But I don’t know what the numbers are that follow it, and double clicking these warnings does not take me to the offending line.

At this point, I’m not sure what the problem is. I’ve Googled extensively but haven’t found a good example of this that shows what I’m supposed to be doing. Unless there is some special wave of the hands needed here, this appears to be a bug.

Note: I submitted a similar issue previously, but it was moved and closed and I didn’t get the notifications at the new location.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 10
  • Comments: 27 (7 by maintainers)

Most upvoted comments

This problem is affecting me too.

I can reproduce in a brand new Asp.net core app (eg File, New Aspnet Core in VS) and enabling nullable reference types. eg csproj looks like:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

Without enabling nullable, everything works as expected.

It also compiles fine (using dotnet build) when using sdk version 3.1.100 but fails in 3.1.200.

Visual Studio always compiles just fine but I don’t know if it’s using the sdk version specified in global.json.

This still isn’t fixed

This is still broken in .NET 5

In my case I can’t avoid this error:

@page "{code?}"
@using Microsoft.Net.Http.Headers
@model ErrorModel
@{
    ViewData["Title"] = LocalizedStrings.Error;
}

@{
    switch (Model.Code)
    {
        case 404:
            {
                await NotFoundHandlerAsync();
                break;
            }
        default:
            {
                await DefaultHandlerAsync();
                break;
            }
    }
}

@functions{
    async Task NotFoundHandlerAsync()
    {
        <section class="error-page text-center">
            <h1 class="display-4">@LocalizedStrings.Error404_Title</h1>
            <p>@LocalizedStrings.Error404_Description</p>

            @{
                await NextStepsAsync();
            }
        </section>
    }

    async Task DefaultHandlerAsync()
    {
        <section class="error-page text-center">
            <h1 class="display-4">@LocalizedStrings.Error500_Title</h1>
            <p>@LocalizedStrings.Error500_Description</p>

            @{
                await NextStepsAsync();
            }
        </section>
    }

    async Task NextStepsAsync()
    {
        <a onclick="window.history.back()" href="#" class="btn btn-lg btn-primary"><span class="icon-back"></span> Go back</a>
        <a asp-page="Contact" class="btn btn-lg btn-info"><span class="icon-contacts"></span> Contact me</a>
    }
}

I get a compile-time error that NextStepsAsync contains a TagHelper and must be async and return a Task - which is the case. The code compiled fine before updating to ASP.NET Core 3.1.

@ryans610 How is this related to nullable? The error is about async/await.

Am still waiting for this fix as well.

Still waiting for this fix.

Using the code blocks and declaring local functions instead of using the @functions {} seems to work fine.

Indeed it does! Wow, as the product matures, it’s getting harder and harder to know which of the different available constructs to use!

Much thanks!

Using the code blocks and declaring local functions instead of using the @functions {} seems to work fine.

@{
    async Task RenderSomething()
    {
        <div>...</div>
    }
}

And in July of 2021, this still appears to be an issue using the very latest versions of .NET and ASP.NET. How can a bug like this not be considered important?

This issue appears to still be present in 3.1.4. However, I was able to work around it fairly easily by adding #nullable disable and #nullable restore directives around my function definitions, like so:

@{
    #nullable disable
    async Task MyFunction()
    {
        // ...
    }
    #nullable restore
}

Thanks @NTaylorMullen . Glad to know it wasn’t just me.