将回调值返回到启动异步方法的函数的最佳方法是什么?

时间:2013-09-26 07:40:56

标签: c# .net asynchronous callback event-handling

我是使用回调和异步函数的新手,所以我有点不确定最好的解决方法。

我创建了一个名为SendPhoto()的函数,由我的GUI调用。 SendPhoto()函数与我的GUI分开。

    public string SendPhoto(string filename)
    {
        byte[] response = PostFile(_url, filename);

        String responsestring = Encoding.ASCII.GetString(response);

        if (responsestring.StartsWith("ERROR:"))
            return responsestring;
        else if (responsestring.Contains("<valid>1</valid>"))
            return "OK";
        else
            return responsestring;
    }

我的PostFile()函数用于调用WebClient.UploadFile(),响应已返回SendPhoto(),效果很好。然后我决定要异步发送照片,因此在我的PostFile()函数中,我将调用从Uploadfile()更改为UploadFileAsync()

但是,我意识到UploadFileAsync()没有返回值,我必须使用UploadFileCompletedEventHandler来完成上传时的响应。所以,我在与SendPhoto()PostFile()相同的类中编写了一个回调函数来检索响应,在该函数上实例化一个UploadFileCompletedEventHandler,并将其传递给我的PostFile()函数。

问题在于我不确定如何将响应返回到SendPhoto()函数,以便它可以解释响应并将友好响应发送回GUI。之前,当一切都是同步时,响应刚刚传回堆栈,但现在,响应又回来了几层。

现在SendPhoto()无法再将回复函数发回给我,从回调函数回复到PostFile()的最佳方式是什么?我想过将事件处理程序回调移动到GUI并将UploadFileCompletedEventHandler传递给SendPhoto(),然后PostFile()将其发送到{{1}}。但我试图将“业务逻辑”(即解释响应)保留在GUI类之外。

1 个答案:

答案 0 :(得分:1)

好的,今天早上又做了一些工作,并通过使用“await”找到了一个非常优雅的解决方案(谢谢,Muctadir Dinar!)。我不得不改变对UploadFileTaskAsync()的调用,以便它支持“await”关键字,我不得不用“async”装饰我的所有方法并让它们返回任务,一直回到GUI的按钮点击事件处理程序,但当我完成后,它工作得很好!我相信这只适用于.NET framework 4.5。

    private async void UploadPhotoButton_Click(object sender, EventArgs e)
    {
        ...
        string theResult = await MyProvider.SendPhotoAsync(pathToFile, new UploadProgressChangedEventHandler(UploadProgressCallback));
        OutputBox.Text = theResult;
    }

    public async Task<string> SendPhotoAsync(string filename, UploadProgressChangedEventHandler changedHandler)
    {
        byte[] response = await PostFileAsync(_url, filename, changedHandler);

        String responsestring = Encoding.ASCII.GetString(response);

        if (responsestring.StartsWith("ERROR:"))
            return responsestring;
        else if (responsestring.Contains("<valid>1</valid>"))
            return "OK";
        else
            return responsestring;
    }

    async Task<byte[]> PostFileAsync(string uri, string filename, UploadProgressChangedEventHandler changedHandler)
    {
        byte[] response = null;
        using (WebClient client = new WebClient())
        {
            client.Headers = GetAuthenticationHeader();
            client.UploadProgressChanged += changedHandler;

            response = await client.UploadFileTaskAsync(new Uri(uri), filename);
        }

        return response;
    }