开发者

Silverlight HttpWebRequest syncronous call

开发者 https://www.devze.com 2023-02-21 18:03 出处:网络
In my silverlight app I do a file upload. I break the file i开发者_高级运维nto chunks and then I upload each chunk. The problem is that I want to use the HttpWebRequest synchronously. My propblem is t

In my silverlight app I do a file upload. I break the file i开发者_高级运维nto chunks and then I upload each chunk. The problem is that I want to use the HttpWebRequest synchronously. My propblem is to ensure that all request are ok and to catch exceptions. Is that possible in Silverlight? I would like sopmething like:

while(chunk)
{
    try{
    HttpWebRequest req = ...
    req.BeginGetRequestStream(new AsyncCallback(WriteCallback), req);
    //add data into request stream
    req.BeginGetResponseStream(new AsyncCallback(ReadCallback), req);
    //parse the response
    chunk = new Chunk();
    }catch(Exception ex)
    {...}
}

Can you give me a hint how can I obtain this?

Thanks, Radu D


Silverlight does not support synchronous web requests. For this reason I wrote the Simple Asynchronous Operation Runner. One of the objectives is to be able to write code as if it were synchronous then modify it to work with the runner code.

First get the small chunk of code for the AsyncOperationService from part 1 and add it to your project (don't worry if you find the article a little heavy its not important to actually using it).

Using the code you already provided as "synchronous template" we can see we need a couple of AsyncOperation implementations for GetRequestStream and GetResponseStream so we'll write those an add them to the project as well:-

public static class WebRequestAsyncOps
{
    public static AsyncOperation GetRequestStreamOp(this WebRequest request, Action<Stream> returnResult)
    {
        return (completed) =>
        {
            request.BeginGetRequestStream((result) =>
            {
                try
                {
                    returnResult(request.EndGetRequestStream(result));
                    completed(null);
                }
                catch (Exception err)
                {
                    completed(err);
                }
            }, null);
        };
    }

    public static AsyncOperation GetResponseOp(this WebRequest request, Action<WebResponse> returnResult)
    {
        return (completed) =>
        {
            request.BeginGetResponse((result) =>
            {
                try
                {
                    returnResult(request.EndGetResponse(result));
                    completed(null);
                }
                catch (Exception err)
                {
                    completed(err);
                }
            }, null);
        };
    }
}

Now if you are chunking a file upload you'll probably want to report progress into the UI so I would suggest you have this AsyncOperation on hand as well (inject in to the existing AsyncOperationService class):-

    public static AsyncOperation SwitchToUIThread()
    {
        return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null)));
    }

Now we can creare an asynchronous version of your code:-

 IEnumerable<AsyncOperation> Chunker(Action<double> reportProgress)
 {
     double progress = 0.0;
     Chunk chunk = new Chunk();
     // Setup first chunk;
     while (chunk != null)
     {
          Stream outStream = null;
          HttpWebRequest req = ...

          yield return req.GetRequestStreamOp(s => outStream = s);

          // Do stuff to and then close outStream
          WebResponse response = null;

          yield return req.GetResponseOp(r => response = r);

          // Do stuff with response throw error is need be.
          // Increment progress value as necessary.

          yield return AsyncOperationService.SwitchToUIThread();

          reportProgress(progress);

          chunk = null;
          if (moreNeeded)
          {
             chunk = new Chunk();
             // Set up next chunk;
          }
      }
 }

Finally you just need to run it and handle any error:-

 Chunker.Run((err) =>
 {
     if (err == null)
     {
          // We're done
     }
     else
     {
          // Oops something bad happened.
     }

 });


It is absolutely not okay to block the main UI thread by executing a Synchronous function.

You can still upload your large file in chunks using an async mechanism. If you're using a WCF service check out this post. I have done the same thing using a Soap webservice running on JAXWS, so it has nothing to do with your backend of choice.

0

精彩评论

暂无评论...
验证码 换一张
取 消