windows-phone-7

Want to return object after BeginGetRespone on MS window phone


I would like to return the object after the post HTTP Post or Get request. I could do on web application. Now I need to write this function the MS windows phone application. I read some article about performing an HTTP Get and Post Request, but I still cannot figure it out. I would like have a helper class to do the web request and return the object as same as I did on my web application. My windows application uses MVVM pattern. The web request will be called by viewmodel.How can I overload the BeginGetResponse to return object rather than IAsyncResult? Would someone give me the link or example to guide me. Thanks in advance.

There is my old code on web application

public static T GetData<T>(Uri relativeUri)
    {
        var request = CreateRequest(relativeUri);
        HttpWebResponse r;          

        try
        {
            r = (HttpWebResponse)request.GetResponse();                 
            return Deserializer<T>(r.GetResponseStream());
        }
        catch (WebException webex)
        {
            HttpWebResponse webResp = (HttpWebResponse)webex.Response;            
            setSessionError(webResp.GetResponseStream());

        }

        return Deserializer<T>(request.GetResponse().GetResponseStream());
    }


public static T Deserializer<T>(Stream s)
    {
        //Get results   
        var ser = new DataContractSerializer(typeof(T));
        var reader = XmlDictionaryReader.CreateTextReader(s,
            new System.Xml.XmlDictionaryReaderQuotas());
        ser = new DataContractSerializer(typeof(T));
        var deserializedItem = (T)ser.ReadObject(reader, true);
        reader.Close();
        return deserializedItem;
    }

I want to do something like that:

public static T GetData<T>(Uri relativeUri)
    {
        var request = CreateRequest(relativeUri);
        Stream ResponseStream;
       request.BeginGetResponse(ReadCallback, request, ResponseStream);
       return Deserializer<T>(ResponseStream);
 }

Solution

  • You can't do that without using IAsyncResults. You have two options, WebClient and HttpWebRequest...

    WebClient wc = new WebClient();
    wc.DownloadStringCompleted += delegate { //do something };
    wc.DownloadStringAsync(new Uri("http://website.com"));
    

    Or you can use HttpWebRequest which has more capabilities but is a little tougher to use.

    I suggest creating a helper class like you're doing, and adding event handlers to it. The event handlers will return your result. Here's a sample.

    public static event EventHandler CompletedDownload;
    
    public static void StartGetData()
    {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://website.com");
        req.Method = "GET"; //or POST
        req.ContentType = "application/x-www-form-urlencoded";
    
        req.BeginGetRequestStream(GetRequestStreamCompleted, req);
    }
    
    //You can send data through this method
    public static void GetRequestStreamCompleted(IAsyncResult result)
    {
        HttpWebRequest req = (HttpWebRequest)result.AsyncState;
        var stream = req.EndGetRequestStream(result);
    
        byte[] byteData = Encoding.UTF8.GetBytes("u=" + loginData.Username + "&p=" + loginData.Password);
    
        stream.Write(byteData, 0, byteData.Length);
        stream.Close();
    
        request.BeginGetResponse(GetResponseCompleted, request);
    }
    
    public static void GetResponseCompleted(IAsyncResult result)
    {
        HttpWebRequest request = (HttpWebRequest)result.AsyncState;
        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
    
        Stream stream = response.GetResponseStream();
    
        //Now trigger your CompletedDownload event, sending the deserialized data
        if (CompletedDownload != null)
            CompletedDownload(Deserializer(stream), new EventArgs());
    }
    

    Then in the code that's calling the download, subscribe to the CompletedDownload. In object sender, you'll have your deserialized data (you'll have to cast it). Then simply call StartGetData()!

    EDIT: Here's what you would call in your main data since you're not sure about that...

    public partial class MainPage : PhoneApplicationPage
    {
        ServiceHelper.CompletedDownload += new EventHandler(ServiceHelper_CompletedDownload);
    
        ServiceHelper.StartGetData();
    }
    
    void ServiceHelper_CompletedDownload(object sender, EventArgs e)
    {
        var q = sender as List<QueueItem>;
    
        //do the rest of your work here.
    
    
    
        //if you need to update something on the UI, you MUST call the dispatcher
        since this will be coming from a background thread... you would do this...
    
        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(delegate
        {
            textBoxTitle.Text = q;
            MessageBox.Show("Download finished!");
        });
    }
    

    Does that make sense? When your service helper finishes the download, it'll call the CompletedDownload event. The reason you can't simply do it in order and force the download to instantly return something is because that would freeze up your app until the download completes.

    In Windows 8 and WP8, you'll actually be able to use something called "await", which will let you do things in order without freezing it... but for WP7 you've gotta use these IAsyncResults and callback methods.

    By the way, with event handlers you have a number of ways of using them... here are two others:

    public partial class MainPage : PhoneApplicationPage
    {
        ServiceHelper.CompletedDownload += delegate
        {
            string answer = "I rock";
        };
    
        ServiceHelper.StartGetData();
    }
    

    Or also this other one. Both of these give you the advantage of having full access to the local variables you defined in your current method. This second one gives you the advantage of having access to object sender and EventArgs e from the event handler too.

    public partial class MainPage : PhoneApplicationPage
    {
        ServiceHelper.CompletedDownload += (sender, e) =>
        {
            string answer = "I rock";
        };
    
        ServiceHelper.StartGetData();
    }
    

    Enjoy!