简体   繁体   中英

What to use if i want to return the result of a webclient

take the following code:

    public async Task<string> AuthenticatedGetData(string url, string token)
    {
        WebClient client = new WebClient();
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WebClient_DownloadStringCompleted);
        client.DownloadStringAsync(new Uri(url + "?oauth_token=" + token));
    }

    private void WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        string response = e.Result;    
    }

WebClient_DownloadStringCompleted gets called... and response = the response I want... Great. perfect...

Now consider how i'm calling this AuthenticatedGetData method:

It is being called from a kind of repository... The repository wants a string so that it can serialize and do stuff with the resulting object...

So everything is running async fromt he repository... The call gets made to the authenticatedgetdata, it then makes a request... but because the downloadstringasync does not have a .Result() method and because downloadstringcompleted requires a void method to call... I cannot return the result string to the calling repository.

Any ideas on what I must do to get client.DownloadStringAsync to return the response string on completion?

Is it that I just simply have to tightly couple my data access operations to this specific app.. It seems so un..re-usable :( I really want to keep my whole authentication stuff totally separate from what's going to happen. and I do not want to keep repeating the above code for each repository, because it's going to be the same for each anyway!

Edit:://

I've created an abstract method in my class that deals with the above requests... and then I extend this class with my repository and implement the abstract method. sound good?

Edit:// Calling code as requested:

public class OrganisationRepository
{
    PostRequest postRequest;

    public OrganisationRepository()
    {
        this.postRequest = new PostRequest();
    }
    public IEnumerable<Organisation> GetAll()
    {
        string requestUrl = BlaBla.APIURL + "/org/";
        string response = postRequest.AuthenticatedGetData(requestUrl, BlaBla.Contract.AccessToken).Result;
    }
}

public class PostRequest
{

    public Task<string> AuthenticatedGetData(string url, string token)
    {

        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();

        WebClient client = new WebClient();
        client.DownloadStringCompleted += (sender, e) =>
        {
            if (e.Error != null)
            {
                tcs.TrySetException(e.Error);
            }
            else if (e.Cancelled)
            {
                tcs.TrySetCanceled();
            }
            else
            {
                tcs.TrySetResult(e.Result);
            }
        };
        client.DownloadStringAsync(new Uri(url + "?oauth_token=" + token));
        return tcs.Task;
    }
}

I'm not sure what the windows-phone-8 limitations are with regards to this. But I think this should work.

public Task<string> AuthenticatedGetData(string url, string token)
    {
        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();

        WebClient client = new WebClient();
        client.DownloadStringCompleted += (sender, e) =>
        {
            if (e.Error != null)
            {
                tcs.TrySetException(e.Error);
            }
            else if (e.Cancelled)
            {
                tcs.TrySetCanceled();
            }
            else
            {
                tcs.TrySetResult(e.Result);
            }            
        };
        client.DownloadStringAsync(new Uri(url + "?oauth_token=" + token));
        return tcs.Task;
    }

You might also be able to get away with this (not sure if it works on windows phone 8)

public Task<string> AuthenticatedGetData(string url, string token)
    {
        WebClient client = new WebClient();
        return client.DownloadStringTaskAsync(new Uri(url + "?oauth_token=" + token));

    }

A solution is to not use the WebClient library at all. Here's the issue: you are awaiting your async AuthenticatedGetData Task, but it does nothing because the Task has no await calls in it meaning it will finish instantly. Calling the .result on the task will always be null because you can never return a value in that method. The WebClient relies on calling a function call after the DownloadCompleted event is fired. However, there is no way for anyone to know exactly when this happens, unless they also subscribe to that DownloadCompleted event handler, which is silly. I recommend making a true async web request service using HttpWebRequest http://blogs.msdn.com/b/andy_wigley/archive/2013/02/07/async-and-await-for-http-networking-on-windows-phone.aspx good luck.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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