使用Async CTP在单个函数中异步HTTP提交数据

3
我试图使用Async CTP构建一个能异步运行并返回一个值的函数。
以下是我的示例代码,但我不知道为什么它不能填充“resp”变量并返回该值。
public async Task<string> sendRequest(string url, string postdata)
{
    WebClient client = new WebClient();
    byte[] data = Encoding.UTF8.GetBytes(postdata);
    Uri uri = new Uri(url);
    client.UploadDataAsync(uri,"POST", data);
    string resp = "";
    await TaskEx.Run(()=>
    client.UploadDataCompleted += (e, s) =>
    {
        resp = System.Text.Encoding.UTF8.GetString(s.Result);
    });
    return resp;
}

我也尝试了这个,但程序卡住了(不再做任何事情,不仅仅是暂停一会儿)。也许有所更正可以帮助解决问题。

public async Task<string> sendRequest(string url, string postdata)
{
    string resp = "";
    WebClient client = new WebClient();
    byte[] data = Encoding.UTF8.GetBytes(postdata);
    Uri uri = new Uri(url);
    data = await TaskEx.Run(()=>client.UploadData(uri,"POST", data));

    return System.Text.Encoding.UTF8.GetString(data);
}

在开始上传之后,您正在订阅事件。这意味着您可能会遇到竞态条件。 - CodesInChaos
1
实际上有两种情况 - @CodeInChaos提到的一种,然后你最后的await是等待你订阅事件 - 但不能保证事件是否已经发生。 - Damien_The_Unbeliever
2个回答

7
你可以使用UploadDataTaskAsync扩展方法(CTP的一部分)来代替自己编写管道代码:
public async Task<string> sendRequest(string url, string postdata)
{
    WebClient client = new WebClient();
    byte[] data = Encoding.UTF8.GetBytes(postdata);
    Uri uri = new Uri(url);
    resp = System.Text.Encoding.UTF8.GetString(await client.UploadDataTaskAsync(uri,"POST", data));
    return resp;
}

该扩展方法的实现正确处理事件订阅,并确保当事件实际触发时任务得以完成。

你和我同时完成了这个任务。我提到过,程序会在“await”处冻结。 - ShirazITCo
@ShirazITCo - 如果你POST数据的URL没有响应,那么这与异步代码无关(但这表明原始错误是第二个被识别的错误-你的原始方法在UploadDataCompleted方法触发之前返回了-它实际上从未触发)。 - Damien_The_Unbeliever
@ShirazITCo:你是否在某个地方进行了阻塞的“等待”或“结果”操作?如果将“await client.UploadDataTaskAsync(..)”更改为“await client.UploadDataTaskAsync(..)。ConfigureAwait(false)”,它是否能正常工作? - Stephen Cleary

0

在开始上传之前,您应该订阅UploadDataCompleted。不确定这是否是导致您问题的原因,但这是一个错误,可能会导致resp未被设置。


@ShirazITCo 即使它不是您目前问题的原因,它仍然是一个错误。 - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接