2

In another answer roughly the following code was used:

c.Events.OnRedirectToAccessDenied = async (context) => context.Response.StatusCode = 403;

The compiler warns on the arrow operator that the expression is not awaited in any form. Removing the async keyword confirms that OnRedirectToAccessDenied wants a function that returns a Task (Func<RedirectContext<CookieAuthenticationOptions>, Task>) and the following can't build:

c.Events.OnRedirectToAccessDenied = (context) => context.Response.StatusCode = 403;

The async keyword is only used to convert the expression to a task, it seems. I haven't seen async used this way before.

The following code will not give any compiler warnings, but it doesn't look as elegant.

c.Events.OnRedirectToAccessDenied = (context) => Task.Run(
                                                    () => context.Response.StatusCode = 403
                                                 );

Is the compiler warning unwarranted, and is it a good idea to use async in this manner?

2
  • 2
    Have you tried returning Task.CompletedTask instead of marking it as async? Marking something as async does more than make it return a Task, it also sets up a state machine, which is unnecessary if you're not doing an asynchronous call. Commented May 1, 2020 at 16:00
  • Just to elaborate on @mason 's answer: c.Events.OnRedirectToAccessDenied = (ctx) => {ctx.Response.StatusCode = 403; return Task.CompletedTask; } Commented May 1, 2020 at 16:04

2 Answers 2

6

If something needs a Task but you don't really have one, then you can return Task.CompletedTask to satisfy that requirement and to mark that handling is complete, while still keeping everything synchronous, and without the overhead of creating a state machine (which would be the result of using the async keyword):

c.Events.OnRedirectToAccessDenied = (context) =>
{
    context.Response.StatusCode = 403;
    return Task.CompletedTask;
}
Sign up to request clarification or add additional context in comments.

10 Comments

Yes I agree, but is the use of async in the example good or is it language abuse?
@CarlR I think the answer that Peter gave already explains why it's a bad idea.
@mason Reading your comment and Peters answer yes, but for another user just reading Peters answer it doesn't explain it completely. You know the Q n A style site this is. ;)
@CarlR No, it is not good use of async. async should be applied when you want to use await inside the routine. That is its only purpose, enabling the use of the keyword await inside. If you are using it for any other purpose, you are doing something wrong. Yes, async lambdas will return a Task, but non-async methods that return Tasks are just as awaitable as async methods that return Tasks. It's the task that is awaitable.
One important side note is that exception handling semantics are different without the async. So - while I agree that this is the correct solution for this scenario - this solution isn't broad enough to cover every "I need to return a Task but have nothing to await" problem.
|
0

You could also await something just to make the warning go away:

c.Events.OnRedirectToAccessDenied = async (context) =>
{
    context.Response.StatusCode = 403;
    await Task.CompletedTask; // Suppress the warning CS1998
};

The overhead of the state machine is negligible. So choose based on what you perceive as more natural and intuitive.

1 Comment

Without async await there is no warning. Peter's sample is complete.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.