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

如果有人能说点什么,我将非常感激。我不是那种为了使用新技术而使用新技术的人。


但是我所做的是完全同步的

你可以使用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);
    }
}

至于为什么你应该在WebRequest上使用HttpClient,好吧,HttpClient是块上的新孩子,可以包含对旧客户端的改进。


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

您也不知道您的库将如何使用。也许用户将处理大量的请求,异步处理将帮助它更快更有效地执行。

如果您可以简单地做到这一点,那么当您可以为库的用户处理流时,尽量不要让他们承担试图使流异步化的负担。

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


我要重复唐尼·v和乔什的回答

“我不会使用异步版本的唯一原因是如果我在尝试 以支持尚未构建的。net旧版本 在异步支持中。”

(如果我有这样的名声,还会给我点赞。)

I can't remember the last time if ever, I was grateful of the fact HttpWebRequest threw exceptions for status codes >= 400. To get around these issues you need to catch the exceptions immediately, and map them to some non-exception response mechanisms in your code...boring, tedious and error prone in itself. Whether it be communicating with a database, or implementing a bespoke web proxy, its 'nearly' always desirable that the Http driver just tell your application code what was returned, and leave it up to you to decide how to behave.

因此HttpClient更可取。


在我的情况下,公认的答案不起作用。我从一个没有异步动作的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)));

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();
}

Then

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

如果你使用这个类来传递你的async方法作为参数,你可以以一种安全的方式从sync方法调用async方法。

解释如下: https://cpratt.co/async-tips-tricks/


对于现在遇到这个问题的人来说,. net 5.0已经向HttpClient添加了一个同步发送方法。https://github.com/dotnet/runtime/pull/34948

原因在这里有详细的讨论:https://github.com/dotnet/runtime/issues/32125

因此,您可以使用这个而不是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();
}

这段代码只是一个简化的示例,还不能用于生产。


在当今时代,对这个问题的最简短的回答是非常直接的:字面上说,除了HttpClient之外的所有先前的。net选项现在都已弃用/过时了。