dotnet / razor

Compiler and tooling experience for Razor ASP.NET Core apps in Visual Studio, Visual Studio for Mac, and VS Code.
https://asp.net
MIT License
491 stars 190 forks source link

Async errors and warnings in Razor Pages @functions blocks #7049

Closed SoftCircuits closed 1 year ago

SoftCircuits commented 4 years ago

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.

mkArtakMSFT commented 4 years ago

Thanks for contacting us. @NTaylorMullen can you please look into this? Thanks!

NTaylorMullen commented 4 years ago

Ah nice report @SoftCircuits. I was able to reproduce this.

Reason that this is causing issues is because we treat the img tag in the above example as a TagHelper because it has a ~/ attribute however everything in the @functions block doesn't get treated the same as something in the body. For instance in the body of the Razor page we have these nice little pragma warning disable/restores:

        #pragma warning disable 1998
        public async override global::System.Threading.Tasks.Task ExecuteAsync()
        {
......
        }
        #pragma warning restore 1998

We need to add these to @code / @functions blocks.

SoftCircuits commented 4 years ago

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

MartinZikmund commented 4 years ago

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.

geoffappleford commented 4 years ago

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.

mkArtakMSFT commented 4 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

spaasis commented 3 years ago

I get the same error, but it persists even if I add the async/task definitions:

@functions{
    async Task RenderCompany(NotificationCompanyViewModel? vm) {
        <div>
            <dl>
                @if (vm != null) {
                   //snip
                    <dt><a href="~/Companies/CreateOrEdit/@vm.CompanyId">@vm.CompanyName</a></dt>
                }
            </dl>
        </div>
    }
}

Produces an error: 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.

PhilipF5 commented 3 years ago

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
}
spaasis commented 3 years ago

@PhilipF5 good find, seems to fix my case as well

jon49 commented 3 years ago

This is still broken in .NET 5

davidbuckleyni commented 3 years ago

This is still appears be to be an issue

//

pragma warning disable 1591

[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(Razor.Template), @"default", @"/Areas/PaymentPaypalExpress/Views/PaypalExpress/Index.cshtml")] namespace Razor {

line hidden

[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"21f81e1273ba63dee4e21fb39b04f70ebf4dc62b", @"/Areas/PaymentPaypalExpress/Views/PaypalExpress/Index.cshtml")]
public class Template
{
    #pragma warning disable 1998
    public async override global::System.Threading.Tasks.Task ExecuteAsync()
    {

nullable restore

line 1 "D:\GitMaster\WareHouseCrm\WarehouseCrm.Module.PaymentPaypalExpress\Areas\PaymentPaypalExpress\Views\PaypalExpress\Index.cshtml"

Layout = "_Layout";

line default

line hidden

nullable disable

        WriteLiteral("\n Test for a view");
    }
    #pragma warning restore 1998
}

}

pragma warning restore 1591

NTaylorMullen commented 3 years ago

@pranavkm this is still a compiler issue. The fix would be to add the following: dotnet/razor-tooling#7049

It's not ideal because it'd then suppress other diagnostics in the functions block; however, it might be a "better" solution.

SoftCircuits commented 3 years ago

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?

Neme12 commented 3 years ago

Does anybody even use this feature since it's so broken?

ryans610 commented 3 years ago

Does anybody even use this feature since it's so broken?

It can still be used, just disable nullable in the @functions block, like this:

@functions {
#nullable disable
    void Foo()
    {
        // do something with tag helper
    }
#nullable enable
}
pranavkm commented 3 years ago

Could I bother one of you to give us a minimal app that shows the problem with nullable enabled? The 6.0 templates have nullability on by default and if affects things out of the box, we would definitely want to prioritize it.

SoftCircuits commented 3 years ago

Could I bother one of you to give us a minimal app that shows the problem with nullable enabled? The 6.0 templates have nullability on by default and if affects things out of the box, we would definitely want to prioritize it.

You can see that someone from Microsoft was immediately able to reproduce the issue I originally reported. And I'm getting the same issue using the same thing with the latest release version of .NET. Are you saying now you need an entire app to repro?

Here's the current error:

Index.cshtml.g.cs(237,200,237,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.

It occurs any time I use ~/ in a link.

Neme12 commented 3 years ago

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

ryans610 commented 3 years ago

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

Yes, but it work for me. My guess is it has something to do with the Razor's pre-processing for the nullable part gone wrong, so when it generating the code about async/await it make some mistake.

SoftCircuits commented 3 years ago

Yes, but it work for me. My guess is it has something to do with the Razor's pre-processing for the nullable part gone wrong, so when it generating the code about async/await it make some mistake.

It doesn't work for me today. And I can't see how it's related to the original issue.

tibold commented 3 years ago

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

@{
    async Task RenderSomething()
    {
        <div>...</div>
    }
}
SoftCircuits commented 3 years ago

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!

ghost commented 2 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

NicolasDorier commented 2 years ago

This still isn't fixed

cabralRodrigo commented 2 years ago

Still waiting for this fix.

splitkb commented 2 years ago

Am still waiting for this fix as well.

jjonescz commented 1 year ago

The fix for this had to be reverted in https://github.com/dotnet/razor/pull/8719. Won't reopen as this is already tracked in https://github.com/dotnet/razor/issues/8344.