Async Best Practices for C# and Visual Basic

Sign in to queue

The Discussion

  • User profile image
    carlospined​ag

    Exception management for asynchronous tasks can be a little tricky.

    In the following example, I have implemented exception management. Suppose that server returns an error message using the header "Reason-Phrase"

    public byte[] getFile (String url,String fileName)
    {
      WebRequest request = WebRequest.Create(url);
      request.Method = "POST";
      request.ContentType = "application/x-www-form-urlencoded";
      using (Stream stream = request.GetRequestStream())
      {
        /* suppose that the name of requested file is sent in the
           body of POST. For REST services you can send
           parameters in the body of POST, "url-encoded"
           and separated by "&" */
        byte[] content = Encoding.UTF8.GetBytes("name=" + WebUtility.UrlEncode(fileName));
        stream.Write(content, 0, content.Length);
      }
      // the following call will not block
      Task<WebResponse> task = request.GetResponseAsync();
      // ...here you can do something while task complete...
      try
      {
        // waiting until task complete
        // note exception management for Wait()
        task.Wait();
      }
      catch (AggregateException e)
      {
        throw new Exception(((WebException)e.InnerException).Response.Headers["Reason-Phrase"]);
      }
      using (Stream stream = task.Result.GetResponseStream())
        using (MemoryStream m = new MemoryStream())
        {
          stream.CopyTo(m);
          return m.ToArray();
        }
      }
    }

  • User profile image
    BobTabor

    Fun session.  Thank you Mads!  You're one of my favorite speakers.

  • User profile image
    Ben Hayat

    Where is the video?
    Thanks!

  • User profile image
    sousathiago

    Where is the video?

  • User profile image
    carlospined​ag

    In order to improve User Experience in front-end Apps, is a good practice implement the callback pattern (methods which are invoked when asynchronous operations are completed). This pattern is also a little tricky.

    Here an example (suppose that server returns an error message using the header "Reason-Phrase");

    public void getFileAsync(String url,String fileName,Action<byte[]> callback)
    {
      WebRequest request = WebRequest.Create(url);
      request.Method = "POST";
      request.ContentType = "application/x-www-form-urlencoded";
      using (Stream stream = request.GetRequestStream())
      {
        /* suppose that the name of requested file is sent in the
           body of POST. For REST services you can send
           parameters in the body of POST, "url-encoded"
           and separated by "&" */
        byte[] content = Encoding.UTF8.GetBytes("name=" + WebUtility.UrlEncode(fileName));
        stream.Write(content, 0, content.Length);
      }
      // the following call will not block
      Task<WebResponse> task = request.GetResponseAsync();
      if (callback != null) task.ContinueWith((t, c) =>
      {
        try
        {
          using (Stream stream = t.Result.GetResponseStream())
          using (MemoryStream m = new MemoryStream())
          {
            stream.CopyTo(m);
            ((Action<byte[]>)c)(m.ToArray());
          }
        }
        catch (AggregateException e)
        {
          throw ((WebException)e.InnerException).Response != null ? 
            new Exception(((WebException)e.InnerException).Response.Headers["Reason-Phrase"]) :
            e.InnerException;
        }
      }, callback);
    }

    Finally, you only need invoke the following method (the callback function is inlined using a lambda expression):

    getFileAsync("my-url","file-name",(buffer) => {
        // buffer contains the received file
      });

    Note that method getFileAsync() not blocks. Also, note that AggregateException is used for exception management because the anonymous function inlined within ContinueWith() executes in a different context.

     

Add Your 2 Cents