简体   繁体   English

如何从asp.net中进行异步Web调用

[英]How to do asynchronous web calls from within asp.net

Lets say im within an ASP.NET application, WCF or web API, part of this applications job to is contact a 3rd party over the way. 可以说,在ASP.NET应用程序,WCF或Web API中,此应用程序工作的一部分是通过第三者联系。 Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. 我想异步地执行此操作,或者更希望非阻塞地执行此操作,以使线程池不会饿死。 However i dont want to change all my code in the service only the bit that makes the web call. 但是,我只想更改网络调用中的位,而不希望更改服务中的所有代码。

Here is some code i have written: 这是我写的一些代码:

    public string GetSomeData()
    {
        Task<string> stuff = CallApiAsync(); 

        return stuff.result; //does this block here?

    }

    private async Task<string> CallApiasync()
    {
        using (var httpClient = new HttpClient())
        {
            string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

            return response;
        }

    }

I thought the idea was as follows but please correct any misconceptions. 我认为这个主意如下,但请纠正任何误解。

The caller of CallApi can call the method and when it hits await there is a Task created which represents some work to be done asynchronously but that will take some time. CallApi的调用者可以调用该方法,当它等待时,将创建一个Task,该Task表示要异步完成的某些工作,但这将需要一些时间。 At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request. 此时,线程到达等待状态,返回线程池以执行其他操作,即处理其他请求。 Once the Task completes the await line wakes up and the code continues from there as if it was synchronous. 任务完成后,等待线将唤醒,代码从那里继续,就好像它是同步的一样。

If this is the case why do i need to return a Task from my apimethod. 如果是这种情况,为什么我需要从我的api方法返回一个任务。 The caller seems to have to call stuff.Result which implies that the task may not have finished and calling result could block ? 调用者似乎必须调用stuff.Result,这意味着任务可能尚未完成,并且调用结果可能会阻塞? Note i don't want to make the calling method async too as then the method that calls that would need to be async etc etc. 注意我也不想使调用方法异步,因为那样调用的方法就需要异步等等。

What is the order of event here in my code? 在我的代码中,事件的顺序是什么?

One other question is why did i need to set configureAwait to false? 另一个问题是为什么我需要将configureAwait设置为false? otherwise everything hangs. 否则,一切都会挂起。

Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. 我想异步地执行此操作,或者更希望非阻塞地执行此操作,以使线程池不会饿死。 However i dont want to change all my code in the service only the bit that makes the web call. 但是,我只想更改网络调用中的位,而不希望更改服务中的所有代码。

That's not possible. 那不可能 In order to be truly asynchronous, you must allow async to "grow" through the code as far as it needs to. 为了实现真正的异步, 必须允许async在代码中“增长”到需要的程度。 What you're trying to do is block on an asynchronous call, which won't give you any benefit (you're freeing up a thread by using async , but then you're turning around and consuming a thread by using Result ). 您试图做的是阻止异步调用,这不会给您带来任何好处(通过使用async释放线程,但随后通过使用Result转而使用线程)。

At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request. 此时,线程到达等待状态,返回线程池以执行其他操作,即处理其他请求。

Not quite. 不完全的。 When an async method hits an await , it returns an incomplete Task to its caller . async方法达到await ,它将未完成的Task返回给其调用方 If the caller, in turn, await s that task, then it returns an incomplete Task to its caller, etc. When the ASP.NET runtime receives an incomplete Task from your action/service method/whatever, then it releases the thread to the thread pool. 如果主叫方,反过来, await s表示任务,然后返回一个不完整的Task当ASP.NET运行时接收到一个不完整的,以它的调用者,等等Task从你的动作/服务法/不管, 那么它会释放线程的线程池。

So, you do have to go " async all the way" to see the real benefit of async . 因此,您必须“一路async ”才能看到async的真正好处。

I have an async intro on my blog if you want a more gentle introduction, as well as an MSDN article on async best practices (one of which is: async all the way). 如果您想要更温和的介绍,请在我的博客上找到一个async介绍 ,以及有关async最佳实践的MSDN文章(其中之一是:一直都是async的)。 I also have a blog post that describes the deadlock you were seeing . 我也有一篇博客文章,描述了您所看到僵局

The compiler handles a lot of the magic behind the async pattern for you, but syntactically, you have to tell it what you want it to do by providing a method prototype that says "ok, this is an asynchronous operation that can be awaited." 编译器为您处理了异步模式背后的许多魔术,但是在语法上,您必须通过提供一个方法原型来告诉它您想要做什么,该方法原型说“好吧,这是一个可以等待的异步操作”。

For this to happen, your method must return a Task or Task<T> . 为此,您的方法必须返回TaskTask<T> Any Task can be awaited. 任何任务都可以等待。

You should be VERY careful when using .Result and .Wait(), as they can block in some very unexpected circumstances, because the runtime may decide to execute your method synchronously. 使用.Result和.Wait()时应非常小心,因为它们在某些非常意外的情况下可能会阻塞,因为运行时可能决定同步执行您的方法。

You should say: await CallApiAsync(); 您应该说:等待CallApiAsync();

or, to actually take advantage of it: 或者,要真正利用它:

Task stuff = CallApiAsync();

//More code that can happen independetly of "stuff"

await stuff;

In order to do that, your GetSomeData() function must also be marked as async, but it doesn't have to, itself, return a Task. 为此,还必须将GetSomeData()函数标记为异步,但它本身不必返回Task。

Finished copy of a working async version of your code: 您的代码的异步版本的完成副本:

public async string GetSomeData() { Task stuff = CallApiAsync(); 公共异步字符串GetSomeData(){任务内容= CallApiAsync();

    return await stuff;

}

private async Task<string> CallApiasync()
{
    using (var httpClient = new HttpClient())
    {
        string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

        return response;
    }

}

Honestly, if that's all the CallApiAsync function is ever going to do, you may as well inline it, though. 老实说,如果这就是CallApiAsync函数要做的全部,那么您最好内联它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM