2012-11-04 1 views
18

J'appelle un service externe à l'aide HttpClient à partir d'un projet Web APIs ASP.Net MVC 4 en cours d'exécution sur le Net Framework 4.5Appeler le service HTTP externe à l'aide HttpClient d'une API Web d'action

L'exemple de code est comme suit (ignorer les valeurs de retour comme cela est exemple de code pour tester appeler un service externe):

public class ValuesController : ApiController 
{ 
    static string _address = "http://api.worldbank.org/countries?format=json"; 
    private string result; 

    // GET api/values 
    public IEnumerable<string> Get() 
    { 
     GetResponse(); 
     return new string[] { result, "value2" }; 
    } 

    private async void GetResponse() 
    { 
     var client = new HttpClient(); 
     HttpResponseMessage response = await client.GetAsync(_address); 
     response.EnsureSuccessStatusCode(); 
     result = await response.Content.ReadAsStringAsync(); 
    } 
} 

Alors que le code dans la méthode privée ne fonctionne en effet le problème que j'ai est que le Get Controller() appelle la GetResponse() mais il n'attend pas le résultat mais exécute immédiatement le retour avec result = null.

J'ai aussi essayé d'utiliser un simple appel synchrone avec un WebClient comme suit:

// GET api/values 
    public IEnumerable<string> Get() 
    { 
     //GetResponse(); 

     var client = new WebClient(); 

     result = client.DownloadString(_address); 

     return new string[] { result, "value2" }; 
    } 

qui fonctionne très bien.

Qu'est-ce que je fais mal? Pourquoi Get() n'attend pas l'achèvement de la méthode privée dans l'exemple asynchrone?

+0

Sinon, cela n'attendra pas que cette méthode se termine ... et l'action de votre contrôleur finira directement par laisser le résultat être toujours nul. – jishi

+0

Oui mais je n'avais pas réalisé que je pourrais marquer le Get() comme async qui est requis pour utiliser await. – Redeemed1

Répondre

30

Aha, je devais faire ce qui suit (retourner une tâche plutôt que vide):

// GET api/values 
    public async Task<IEnumerable<string>> Get() 
    { 
     var result = await GetExternalResponse(); 

     return new string[] { result, "value2" }; 
    } 

    private async Task<string> GetExternalResponse() 
    { 
     var client = new HttpClient(); 
     HttpResponseMessage response = await client.GetAsync(_address); 
     response.EnsureSuccessStatusCode(); 
     var result = await response.Content.ReadAsStringAsync(); 
     return result; 
    } 

Je ne l'avais pas réalisé que je pouvais aussi marquer l'opération Get() comme async qui est ce qui m'a permis de attendre l'appel externe.

Merci à Stephen Cleary pour son article de blog Async and Await qui m'a orienté dans la bonne direction.

+0

Juste ce que je cherchais depuis 3 jours! Simple une fois que vous le savez :) La réponse la plus courte et la plus efficace. –

0

Avec le nom d'utilisateur et le mot de passe, appelez Httpclient. En cas d'authentification requise par l'API. Vous n'avez pas besoin d'appeler GetResponse() avec await aussi?

public async Task<ActionResult> Index() 
{ 

      const string uri = "https://testdoamin.zendesk.com/api/v2/users.json?role[]=agent"; 
      using (var client1 = new HttpClient()) 
      { 
       var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes("[email protected]:123456")));///username:password for auth 
       client1.DefaultRequestHeaders.Authorization = header; 
       var aa = JsonConvert.DeserializeObject<dynamic>(await client1.GetStringAsync(uri)); 

      } 
} 
+0

Karan, merci pour votre effort ici mais ce n'est pas lié à la question. Votre réponse concerne l'authentification, la question concerne les tâches asynchrones autour d'une API non authentifiée. – Redeemed1