Api和控制台应用程序

时间:2015-11-12 17:43:55

标签: c# .net async-await task-parallel-library

如果我在.net web api

中运行此代码
public class ConfigurationApiClient : IConfigurationService
{
    private readonly HttpClient _client;

    public ConfigurationApiClient(IConfigurationManager configurationManager)
    {
        ;
        _client = new HttpClient();
        _client.BaseAddress = new Uri(configurationManager.GetAppSetting("ApiUrl"));
        _client.DefaultRequestHeaders.Accept.Clear();
        _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public Configuration GetConfiguration(int agentId)
    {
        return GetConfigurationAsync(agentId).Result;
    }

    private async Task<Configuration> GetConfigurationAsync(int agentId)
    {
        try
        {
            var response = await _client.GetAsync("resource").ConfigureAwait(false);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<Configuration>();
        }
        catch (HttpRequestException ex)
        {
            throw new Exception(string.Format("Exception when getting  configuration for agent: {0}", agentId), ex);
        }
    }

}

我依靠ConfigureAwait(false)使它成功,如果我删除它进入死锁。

但是,如果基于此example,我会在控制台应用程序中编写与之前相同的内容

class Program
{
    static void Main()
    {
        var product = RunAsync().Result;
    }

    static async Task<Product> RunAsync()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:8080/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


            // New code:
            HttpResponseMessage response = await client.GetAsync("api/resource");
            if (response.IsSuccessStatusCode)
            {
                return await response.Content.ReadAsAsync<Product>();
            }

            else
            {
                return null;
            }
        }
    }
}

即使我读到ConfigureAwait(false)我也不清楚为什么它在控制台中工作而不在api中。

1 个答案:

答案 0 :(得分:2)

除非SynchronizationContext.Current另有说明,否则使用等待捕获ConfigureAwait(false)。当await之后的代码恢复时,它会被发布到该上下文中。在UI应用程序中,这意味着在单个UI线程上运行。在asp.net应用程序(您的情况)中,它在原始请求的上下文中运行。

控制台应用程序没有任何SynchronizationContext开头,所以你不能开始死锁。

您可以通过查看SynchronizationContext.Current

中的内容来自行检查

但是,使用ConfigureAwait(false)只能用作最后一项措施。大多数情况下,您希望避免阻塞异步代码。