223

我正在构建一个类库来与 API 交互。我需要调用 API 并处理 XML 响应。我可以看到使用HttpClient异步连接的好处,但我所做的是纯粹同步的,所以我看不到使用HttpWebRequest.

如果有人能阐明任何观点,我将不胜感激。我不是为了新技术而使用新技术的人。

4

6 回答 6

420

但我正在做的是纯粹同步的

您可以HttpClient很好地用于同步请求:

using (var client = new HttpClient())
{
    var response = client.GetAsync("http://google.com").Result;

    if (response.IsSuccessStatusCode)
    {
        var responseContent = response.Content; 

        // by calling .Result you are synchronously reading the result
        string responseString = responseContent.ReadAsStringAsync().Result;

        Console.WriteLine(responseString);
    }
}

至于为什么你应该使用HttpClientover WebRequest,嗯,HttpClient是新的孩子,可能包含对旧客户端的改进。

于 2013-01-21T09:20:38.897 回答
31

我会重申 Donny V. answer 和 Josh 的

“我不使用异步版本的唯一原因是,如果我试图支持尚未内置异步支持的旧版本 .NET。”

(如果我有声誉,请投票。)

我不记得上次是什么时候了,我很感激 HttpWebRequest 抛出状态码 >= 400 的异常。要解决这些问题,您需要立即捕获异常,并将它们映射到一些非异常响应机制在您的代码中......本身很无聊,乏味且容易出错。无论是与数据库通信,还是实现定制的 Web 代理,“几乎”总是希望 Http 驱动程序只告诉您的应用程序代码返回什么,并由您决定如何表现。

因此 HttpClient 更可取。

于 2014-05-21T10:41:11.800 回答
13

对于现在遇到此问题的任何人,.NET 5.0 已将同步Send方法添加到HttpClient. https://github.com/dotnet/runtime/pull/34948

优点以及为什么在这里详细讨论 - https://github.com/dotnet/runtime/issues/32125

因此,您可以使用 this 而不是SendAsync. 例如

public string GetValue()
{
    var client = new HttpClient();
            
    var webRequest = new HttpRequestMessage(HttpMethod.Post, "http://your-api.com")
    {
        Content = new StringContent("{ 'some': 'value' }", Encoding.UTF8, "application/json")
    };

    var response = client.Send(webRequest);

    using var reader = new StreamReader(response.Content.ReadAsStream());
            
    return reader.ReadToEnd();
}

这段代码只是一个简化的例子,它还没有准备好生产。

于 2021-03-16T13:18:57.687 回答
10
public static class AsyncHelper  
{
    private static readonly TaskFactory _taskFactory = new
        TaskFactory(CancellationToken.None,
                    TaskCreationOptions.None,
                    TaskContinuationOptions.None,
                    TaskScheduler.Default);

    public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();

    public static void RunSync(Func<Task> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();
}

然后

AsyncHelper.RunSync(() => DoAsyncStuff());

如果您使用该类将您的异步方法作为参数传递,您可以以安全的方式从同步方法中调用异步方法。

它在这里解释: https ://cpratt.co/async-tips-tricks/

于 2019-05-21T15:40:02.523 回答
8

如果您正在构建一个类库,那么您的库的用户可能希望异步使用您的库。我认为这是最大的原因。

你也不知道你的图书馆将如何被使用。也许用户会处理大量的请求,而异步执行将有助于它更快、更高效地执行。

如果您可以简单地做到这一点,请尽量不要将负担放在尝试使流程异步的库用户身上,因为您可以为他们处理它。

我不使用异步版本的唯一原因是,如果我试图支持尚未内置异步支持的旧版本 .NET。

于 2013-01-21T09:24:12.180 回答
6

就我而言,接受的答案不起作用。我从没有异步操作的 MVC 应用程序调用 API。

这就是我设法使它工作的方法:

private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static T RunSync<T>(Func<Task<T>> func)
    {           
        CultureInfo cultureUi = CultureInfo.CurrentUICulture;
        CultureInfo culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew<Task<T>>(delegate
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap<T>().GetAwaiter().GetResult();
    }

然后我这样称呼它:

Helper.RunSync(new Func<Task<ReturnTypeGoesHere>>(async () => await AsyncCallGoesHere(myparameter)));
于 2016-09-26T00:53:17.687 回答