2016-01-27 20 views
5

Wykonuję połączenia HTTP za pomocą System.Net.Http.HttpClient. Wygląda na to, że wszystkie połączenia muszą być asynchroniczne.Unikaj zwracania typu Zadanie <Object> z funkcji asynchronicznej podczas korzystania z HttpClient

Powiedzmy mam strukturę projektu z następujących czynności: MVC Web App -> warstwy biznesowej -> Warstwa danych

w warstwie danych Robię HTTP wywołania API Web, aby powrócić danych i kończę przy użyciu funkcji takich jak to:

public async Task<IList<Product>> GetProducts() 
{ 
    HttpResponseMessage response = await client.GetAsync("api/products"); 
    string data = await response.Content.ReadAsStringAsync(); 
    IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data); 

    return products; 
} 

to następnie przechodzi do BusinessLayer:

public Task<IList<Product>> GetProducts(string name = null) 
{ 
    return _repository.GetProducts(name); 
} 

wreszcie w kontroler MVC:

public IActionResult Index() 
{ 
    Task<IList<Product>> ProductsTask = _manager.GetProducts(); 

    IList<Product> ProductsNonTask = products.Result.ToList(); 

    return View(); 
} 

Czy naprawdę muszę zrobić każda funkcja zwraca listę typu Task<IList<Product>> prowadzącej do mojego kontrolera MVC? Jak widać w kontrolerze MVC, muszę najpierw pobrać produkty z Zawijanym Zadaniem. Debugger wygląda trochę dziwnie, kiedy przejdę do przeglądania listy produktów za jego pośrednictwem. Więc jak widzisz, zamieniam je na regularną listę produktów.

Zastanawiam się, czy to jest właściwe, aby wszystkie funkcje zwracały typ Task<IList<Product>> do mojego kontrolera MVC lub jeśli istnieje obejście, aby moje funkcje mogły nadal zwracać standardową listę ale nadal używasz asynchronicznych możliwości urządzenia HttpClient?

UPDATE: Czy jest coś złego w następujący sposób:

public IList<Product> GetProducts() 
{ 
    Task<HttpResponseMessage> response = client.GetAsync("api/products"); 
    if (response.Result.IsSuccessStatusCode) 
    { 
      string data = response.Result.Content.ReadAsStringAsync().Result; 
      IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data); 

      retVal = products; 
    } 
} 
+0

'Czy jest coś złego w wykonywaniu następujących czynności:' Tak, kod nie jest kompilowany (z wielu różnych powodów). Mogłeś to wymyślić, po prostu próbując go skompilować. – Servy

+0

Przepraszam Przypadkowo zostawiłem oczekujące słowo kluczowe od momentu skopiowania, wklejenia i zmiany. Zostało to teraz naprawione. –

+0

Kod nadal nie będzie się kompilować, z wielu różnych powodów. – Servy

Odpowiedz

7

Jeśli chcesz operacja faktycznie być asynchroniczny musi być asynchroniczny aż do góry.

Moment zablokowania na Task z Wait lub nie jest już asynchroniczny.

Tak, nie. Albo użyj asynchronicznie do góry, albo nie używaj go w ogóle.

... Zastanawiam się, czy istnieje obejście tego problemu tak, że moje funkcje mogą jeszcze powrócić do standardowej listy produktów, ale nadal korzystać z możliwości async Spośród HttpClient?

Nie, tak naprawdę nie ma.

Powinieneś po prostu sprawić, by twój kod był asynchroniczny, ponieważ zapewnia wiele korzyści w zakresie skalowalności i wydajności. Ale jeśli jesteś przeciwko temu, możesz użyć WebClient, który ma synchroniczne operacje sieciowe.

+0

Jeśli tak jest, próbuję znaleźć sposób, aby nadal używać metody asynchronicznej HttpClient bez zwracania typu Zadanie dla mojej funkcji. Na przykład myślę, że mogę zrobić coś takiego: Zadanie response = client.GetAsync ("api/customers"); Wtedy moja funkcja nie musiałaby zwracać typu Task, ponieważ rezygnuję z oczekiwanego słowa kluczowego. –

+1

@BlakeRivell Nie. Albo użyj asynchronicznie do góry, albo po prostu go unikaj. Nie próbuj mieszać, ponieważ to tylko wpędza cię w kłopoty. – i3arnon

+0

@BlakeRivell więcej tutaj: http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx – i3arnon

1

Czy naprawdę muszę sprawić, aby każda funkcja zwróciła listę typu Zadanie> prowadzącą do mojego kontrolera MVC?

Tak, musisz i nawet nie złapałeś wszystkich miejsc, ponieważ samo Index musi być również asynchroniczne.

Async jest naprawdę zakaźny.Użyj, gdy to konieczne, a nie domyślnie.

+0

Czy muszę używać go w jego przypadku tylko dlatego, że używam HttpClient? –

+0

HttpClient wymusza asynchroniczne IO (niestety), ale możesz go zablokować, jeśli to ci wystarczy. To oszczędza ci "infekcji". Zobacz to, aby zdecydować: http://stackoverflow.com/a/25087273/122718 Dlaczego samouczek EF 6 używa asychronicznych wywołań? http://stackoverflow.com/a/12796711/122718 Czy powinniśmy domyślnie używać asynchronicznego wejścia/wyjścia? – usr

+0

Blokowanie zadań zwracanych przez HttpClient nigdy nie powoduje zakleszczeń, btw. Jest to bezpieczne, ponieważ HttpClient nie używa kontekstu synchronizacji, który może być zainstalowany. – usr