0

Question
How to get an object from an asynchronous method?

Description
I am trying to do a similar project.
Link to the project - Link // github.com ;
  I try to repeat the method - GetPosts (int index, int pageSize, string tag = null).

public async Task<Page<Post>> GetPosts(int index, int pageSize, string tag = null)
    {
        var result = new Page<Post>() { CurrentPage = index, PageSize = pageSize };

        using (var context = ContextFactory.CreateDbContext(ConnectionString))
        {
            var query = context.Posts.AsQueryable();
            if (!string.IsNullOrWhiteSpace(tag))
            {
                query = query.Where(p => p.Tags.Any(t => t.TagName == tag));
            }

            result.TotalPages = await query.CountAsync();
            result.Records = await query.Include(p => p.Tags).Include(p => p.Comments).OrderByDescending(p => p.CreatedDate).Skip(index * pageSize).Take(pageSize).ToListAsync();
        }

        return result;
    }

I want to make a similar asynchronous method with an arbitrary request.
A query for example: query = query.Where (p => p.ContactName.Contains (" Maria "));.
    I try to make a simple method:

public Customer GetCustomers ()
{
    Customer result = new Customer ();
 
    using (var context = ContextFactory.CreateDbContext (ConnectionString))
    {
      var query = context.Customers.AsQueryable ();
      query = query.Where (p => p.ContactName.Contains ("Maria")); //
      result = query as Customer;
    }
    return result;
}

 
The result in the string query = query.Where (p => p.ContactName.Contains (" Maria ")); see picture.
 
Question.
How to make such a method asynchronous with the same or different request?

Attempt number - 1. Result - does not work.

public Task <Customer> GetCustomersTask ()
        {
            // Customer result = new Customer ();
 
            var result = new TaskCompletionSource <Customer> ();
 
            using (var context = ContextFactory.CreateDbContext (ConnectionString))
            {
                Task.Run (() =>
                {
                    var query = context.Customers.AsQueryable ();
                    query = query.Where (p => p.ContactName == "Maria");
 
                    result.SetResult (query as Customer);
                }
                );
            }
            return result.Task;
        }

Picture-1
enter image description here

Picture-2
enter image description here


Update 1. ##

According to the materials of the answer: Martin. link

I am using the method.

 public async Task <Customer> GetCustomerAsync ()
{
    Customer result = new Customer ();

    using (var context = ContextFactory.CreateDbContext (ConnectionString))
    {
      var query = context.Customers.AsQueryable ();
      query = query.Where (p => p.ContactName.Contains ("Maria")); //
      var results = await query.ToListAsync ();
      result = results.FirstOrDefault ();
    }
    return result;
}

I get an error:
"IQueryable " does not contain a definition of "ToListAsync", and could not find an available extension method "ToListAsync", host type "IQueryable " as the first argument (possibly using directive or assembly reference missing).

Picture-1
enter image description here


Update 2

Added by using Microsoft.EntityFrameworkCore;.
Now the class namespace has the form:
using DBRepository.Interfaces;
using Models;
using System;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.EntityFrameworkCore;

Error (see Update-1):
"IQueryable" does not contain a definition of "ToListAsync", and could not find an available extension method "ToListAsync", host type "IQueryable" as the first argument (possibly using directive or assembly reference missing). has disappeared.

Description.
I am running debugging.
I get into the string var results = await query.ToListAsync ();(of classICustomerRepositoryAnsw.GetCustomersTask1 ());
I press F11.
I get into the string string result =" "; (of the class TestAnsw method GetCustomersTask_Test() (this method calls ICustomerRepositoryAnsw.GetCustomersTask1()).
Result: debugging does not execute the string result = results.FirstOrDefault (); and return result;

Question.
1. Why are the lines result = results.FirstOrDefault (); and return result; not executed?

Picture-1 enter image description here

Picture-2 enter image description here

koverflow
  • 297
  • 1
  • 3
  • 10
  • Is there a reason why you are not simply use async/await pattern instead of the ```TaskCompletionSource```. There is a well written answer [here](https://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await) – Martin Mar 26 '20 at 13:10
  • @Martin **1.** `Is there a reason why you are not simply use async/await pattern instead of the TaskCompletionSource.` Is that a question? No. I'm just trying to figure out how to make a method that works asynchronously and returns the result I need. **2.** I am studying your link. – koverflow Mar 26 '20 at 13:15
  • Sorry I missed the question mark it was a question. I posted a possible answer. Maybe this will help you. – Martin Mar 26 '20 at 13:33
  • ```GetCustomersTask1``` needs to be awaited because its an async method. You can see this in "Raw View" that you only have the ```Task``` here. [See documentation of await](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await) – Martin Mar 28 '20 at 12:36

1 Answers1

1

There is good documentation on template the async/await - here(I already wrote in the comment above).
 As a summary, I can say:
 Task <T> or async NOT makes the method asynchronous.
Only the await keyword makes the method asynchronous.

So if you want your method to be run non-blocking you must use asynchronous API/Framework calls to the EntityFramework.

public Task<Customer> GetCustomerAsync ()
{
    Customer result = new Customer ();

    using (var context = ContextFactory.CreateDbContext (ConnectionString))
    {
      var query = context.Customers.AsQueryable ();
      query = query.Where(p => p.ContactName.Contains ("Maria")); //
      result = query.FirstOrDefault();
    }
    return Task.FromResult(result);
}

Looks asynchronous but is not.

But if you use the extensions method .ToListAsync()

public async Task<Customer> GetCustomerAsync ()
{
    Customer result = new Customer ();

    using (var context = ContextFactory.CreateDbContext (ConnectionString))
    {
      var query = context.Customers.AsQueryable ();
      query = query.Where (p => p.ContactName.Contains ("Maria")); //
      var results = await query.ToListAsync();
      result = results?.FirstOrDefault();
    }
    return result;
}

Now you can call this implementation via:

var customer = await YourClass.GetCustomerAsync();

Then it will run non-blocking async.

EntityFramework Core

koverflow
  • 297
  • 1
  • 3
  • 10
Martin
  • 3,096
  • 1
  • 26
  • 46
  • I do not understand your answer well. **1.** Do you mean that I need to use the `Framework` application? **2.** Have you noticed that I use `.net-core`,` entity-framework-core`? Or your solution for `.net-Framework` ? **3.** In the line `var results = await query.ToListAsync ()` I get an error: `"IQueryable " does not contain a definition of “ToListAsync”, and could not find an available extension method "ToListAsync", host type "IQueryable " as the first argument (possibly using using directive or assembly reference).` see `Update-1` – koverflow Mar 26 '20 at 14:14
  • 1. Use the ```[...]Async()``` Methods of EF or other SDKs. 2. yes, therefore I also updated my answer with a direct link to EF Core. 3. Maybe you have to add a ```using``` for this extension method – Martin Mar 26 '20 at 22:03
  • see `Update-2.` Added by `using Microsoft.EntityFrameworkCore;`. The error has disappeared. Result: debugging does not execute the string `result = results.FirstOrDefault ();` and `return result;` **Question.** ** 1. ** Why are the lines `result = results.FirstOrDefault ();` and `return result;` not executed? – koverflow Mar 28 '20 at 09:29
  • I updated your answer. I made corrections that I think will make your answer more understandable (sound better). I do not know English well, so I apologize if my interpretation of the answer seems incorrect to you. If you think your interpretation of the answer is better, then you should probably leave your answer option. – koverflow Mar 28 '20 at 17:56