0

I've make some codes implementing some web API. This API method returns last record of Foo Table.

public class FooController : ApiController
{
    private FooContext db = new FooContext();

    // GET: api/Foo
    [ResponseType(typeof(Foo))]
    public async Task<IHttpActionResult> GetLastFoo()
    {
        Foo foo = await db.Foo.Last();
        if (foo == null)
        {
            return NotFound();
        }
        return Ok(foo);
    }
}

I want make this API asynchronous, but there is no LastAsync() method. Why and how can I solve it? Thanks in advance.

3 Answers3

5

You should not use Task.Run in ASP.NET:

Async and await on ASP.NET are all about I/O. They really excel at reading and writing files, database records, and REST APIs. However, they’re not good for CPU-bound tasks. You can kick off some background work by awaiting Task.Run, but there’s no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics. If you have CPU-bound work to do on ASP.NET, your best bet is to just execute it directly on the request thread. As a general rule, don’t queue work to the thread pool on ASP.NET.

From Async Programming : Introduction to Async/Await on ASP.NET

Still it does not mean you can't use async and await in ASP.NET for I/O (and that's what you want) just use real async methods and not a fake async wrappers over synchronous methods (that will just push the work into other ThreadPool thread and you will not gain any performance benfit from it).

Since you don't have LastAsync method in EF I suggest you to use OrderBy to order your collection as you want and to use FirstAsync method (or FirstAsync overload that supports lambda predicate) instead of using Last method, FirstAsync is a true async I/O method that is supported in EF.

More info about when it's appropriate to use Task.Run can be found in Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation article in Stephen Cleary's blog.

Your question why there is no LastAsync method in the first place should be directed to the team at Microsoft that desiged EF api, but my guess is that they didn't bother implementing it since it is so easy to achieve the same functionally with FirstAsync method as I suggested.

YuvShap
  • 3,825
  • 2
  • 10
  • 24
0

A working version of that code would look like this:

    public class FooController : ApiController
{
    private FooContext db = new FooContext();

    // GET: api/Foo
    [ResponseType(typeof(Foo))]
    public async Task<IHttpActionResult> GetLastFoo()
    {
        Foo foo = await db.Foo.OrderByDesc(x=> x.Timestamp).FirstOrDefaultAsync(); 
        if (foo == null)
        {
            return NotFound();
        }
        return Ok(foo);
    }
}

Last etc don't work against an EF IQueryable because SQL doesn't have an equivalent command

Tom Clelford
  • 691
  • 6
  • 8
-5

about how to solve it

you can use

 await Task.Run(()=>db.Foo.Last());