Thursday, March 31, 2011

Silverlight, HttpWebRequest, HTTP Stacks and the UI Thread

This one comes from a customer who thought that they were seeing an issue in using the browser HTTP stack in Silverlight to make lots of HTTP requests. The issue seemed to be that the stack was blocking the UI thread and causing the UI to stutter.

The suspicion was that the blocking was occurring while data was being read from the stream that is handed back to you when you’re reading an HTTP response.

I thought I’d see if I could reproduce this behaviour myself and so I set out to put something together that made quite a lot of use of the browser HTTP stack and quite a lot of HTTP requests.
By the way – if this talk of browser/client HTTP stacks in Silverlight doesn’t resonate then take a look at this video over here which runs through the basics of it.
I put together a quick UI;

 <Grid
    x:Name="LayoutRoot"
    Background="Black">
    <MediaElement
      Stretch="Fill"
      AutoPlay="True"
      MediaEnded="MediaElement_MediaEnded"
      Source="Wildlife.wmv" />
    <Viewbox>
      <StackPanel>
        <TextBlock
          Foreground="White"
          Text="{Binding MegabytesRead,StringFormat=MB Read \{0:F2\} }" />
        <TextBlock
          Foreground="White"
          Text="{Binding MegabytesPerSecond,StringFormat=MBps \{0:F2\} }" />
        <TextBlock
          Foreground="White"
          Text="{Binding OpenRequests,StringFormat=Requests \{0\} }" />
        <TextBlock
          Foreground="White"
          Text="{Binding TimerTick,StringFormat=Timer \{0\} }" />
      </StackPanel>
    </Viewbox>
  </Grid>

This is playing a video (wildlife.wmv which ships with Windows 7) which I have embedded into my XAP. It’s also attempting to display (via binding) 4 pieces of data;

Total megabytes downloaded over HTTP
Number of megabytes read in the last second
Number of open HTTP requests in flight
A “tick” text block which will simple turn True/False as a timer ticks
and I put some code together behind this;

 public partial class MainPage : UserControl, INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;
//#error This needs a Uri to a big file to download (mine is 1.5MB)
    static Uri videoFile = new Uri("http://localhost/wildlife.wmv", UriKind.Absolute);
    const int threadCount = 10;
    long bytesRead = 0;
    long requestsOpen = 0;    
    DateTime startTime;
    List<byte[]> bufferPool;
    public bool TimerTick
    {
      get
      {
        return (_TimerTick);
      }
      set
      {
        _TimerTick = value;
        RaisePropertyChanged("TimerTick");
      }
    }
    bool _TimerTick;
    public double MegabytesPerSecond
    {
      get
      {
        return (_MegabytesPerSecond);
      }
      set
      {
        _MegabytesPerSecond = value;
        RaisePropertyChanged("MegabytesPerSecond");
      }
    }
    double _MegabytesPerSecond;
    public double MegabytesRead
    {
      get
      {
        return (_Count);
      }

Read more: Mike Taulty's Blog