Make sure to visit Part 1. This is a continuation.

http://blogs.msdn.com/brunoterkaly/archive/2010/01/19/multicasting-messages-the-world-opens-up-spreading-the-message-part-1-of-10.aspx

Configuration Files (for MulticastClient and MulticastHost)

Learning the basics now for each side of the conversation is key. The configuration for Publisher and Subscriber is quite different in both code behind and in markup (xml) in the app.config file.

Lets explore each of the following:

  • App.config MulticastClient
  • Code-behind MulticastClient
  • App.config MulticastHost
  • Code-behind MulticastHost

Connection related code spread around for both (1) MulticastClient (2) MulticastHost

image

 

App.config MulticastClient

  • XML Chunk 1
    • This section defines the (1) contract (2) binding that client is using. The address part of the connection is added with code, where we construct the uri (see next code snippet (chunk 2) after this one).
    • This is how the client connects to the service bus. Code behind is present and is required for this to work.
  • XML Chunk 2
    • this code was injected by the Visual Studio 2010 tooling when we added a “web reference” to the National Weather Service.
    • It is used to connect to the National Weather Service. Note the PHP file we point to which returns our weather.
Code Snippet
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.   <configSections>
  4.     <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
  5.       <section name="MulticastClient.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  6.     </sectionGroup>
  7.   </configSections>
  8.   <system.serviceModel>
  9.     <bindings>
  10.       <netEventRelayBinding>
  11.         <binding name="default" />
  12.       </netEventRelayBinding>
  13.     </bindings>
  14.     <client>
  15.       <!--Contract must match in namespace. Be careful if you have a library-->
  16.       <!--XML Chunk 1-->
  17.       <endpoint name="RelayEndpoint"
  18.                 contract="DataContracts.IMulticastContract"
  19.                 binding="netEventRelayBinding"
  20.                 bindingConfiguration="default"
  21.                 address="http://AddressToBeReplacedInCode/" />
  22.     </client>
  23.   </system.serviceModel>
  24.   <!--XML Chunk 2-->
  25.   <applicationSettings>
  26.     <MulticastClient.Properties.Settings>
  27.       <setting name="MulticastClient_gov_weather_www_ndfdXML" serializeAs="String">
  28.         <value>http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php</value>
  29.       </setting>
  30.     </MulticastClient.Properties.Settings>
  31.   </applicationSettings>
  32. </configuration>

 

Code-behind MulticastClient.xaml.cs

Note the following:

  • Code chunk 1
    • Uses the issuer name and secret that you got when you signed up. You need to to go the Azure Web Portal for this.
  • Code chunk 2
    • Preparing our credentials so the client can be authorized to publish to the service bus end point.
    • Construct an address we can use to connect with. That’s what
      • This address points to the cloud.
    • Notice we have “MulticastServce” as part of the address. You can make up your own but make sure both client and host use the same endpoint.
  • Code chunk 3
    • Adds everything up and opens a connection
  • Code chunk 4 & 5
    • Display the connection icon
Code Snippet
  1.    private void button1_Click(object sender, RoutedEventArgs e)
  2.    {
  3.        // This is button1_Click for MulticastClient, MainWindow.xaml.cs
  4.        //------------------------------------------------------------
  5.        // Code chunk 1
  6.        //------------------------------------------------------------
  7.        this.Title = "About to try to connect...";
  8.        MyCredentials mycreds = new MyCredentials();
  9.        string session = "Bruno Practice Session";
  10.        string serviceNamespace = mycreds.ServiceNamespace;
  11.        string issuerName = mycreds.IssuerName;     // you need to do this part !
  12.        string issuerSecret = mycreds.IssuerSecret; // you got it from the web portal
  13.        string chatNickname = "The Bruno";
  14.        //------------------------------------------------------------
  15.        // Code chunk 2
  16.        //------------------------------------------------------------
  17.        TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior();
  18.        relayCredentials.CredentialType = TransportClientCredentialType.SharedSecret;
  19.        relayCredentials.Credentials.SharedSecret.IssuerName = issuerName;
  20.        relayCredentials.Credentials.SharedSecret.IssuerSecret = issuerSecret;
  21.        Uri serviceAddress = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace,
  22.               String.Format(CultureInfo.InvariantCulture, "{0}/MulticastService/", session));
  23.        //------------------------------------------------------------
  24.        // Code chunk 3
  25.        //------------------------------------------------------------
  26.        channelFactory = new ChannelFactory<IMulticastChannel>("RelayEndpoint", new EndpointAddress(serviceAddress));
  27.        channelFactory.Endpoint.Behaviors.Add(relayCredentials);
  28.        channel = channelFactory.CreateChannel();
  29.        channel.Open();
  30.        //------------------------------------------------------------
  31.        // // Code chunk 4
  32.        //------------------------------------------------------------
  33.        string personImage = "/images/connect.png";
  34.        Uri uri = new Uri(personImage, UriKind.RelativeOrAbsolute);
  35.        BitmapImage source = new BitmapImage(uri);
  36.        //------------------------------------------------------------
  37.        // // Code chunk 5
  38.        //------------------------------------------------------------
  39.        this.image1.Source = source;
  40.        this.Title = "It appears we are connected. Ready for next step...";
  41.    }

App.config MulticastHost

  • XML Chunk 1
    • This section defines the (1) contract (2) binding. The address is added with code, where we construct the uri (see next code snippet after this one).
    • This is how the host connects to the service bus to listen for message from MulticastClient. This is the subscriber. We can have more than one subscriber.
    Code Snippet
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <configuration>
    3.   <system.serviceModel>
    4.     <bindings>
    5.       <netEventRelayBinding>
    6.         <binding name="default" />
    7.       </netEventRelayBinding>
    8.     </bindings>
    9.     
    10.     <services>
    11.       <!--XML Chunk 1-->
    12.       <service name="MulticastHost.MulticastService">
    13.         <endpoint name="RelayEndpoint"
    14.                   contract="DataContracts.IMulticastContract"
    15.                   binding="netEventRelayBinding"
    16.                   bindingConfiguration="default"
    17.                   address="" />
    18.       </service>
    19.     </services>
    20.   </system.serviceModel>
    21. </configuration>

    Code-behind MulticastHost

    Note the following:

      • Code chunk 1
        • Uses the issuer name and secret that you got when you signed up. You need to to go the Azure Web Portal for this.
        • Preparing our credentials so the client can be authorized to publish to the service bus end point.
      • Code chunk 2
        • Construct an address we can use to connect with. That’s what
          • This address points to the cloud.
        • Notice we have “MulticastServce” as part of the address. You can make up your own but make sure both client and host use the same endpoint.
        • As a listener, we need to instantiate a ServiceHost() object, of type “MulticastService.”
      • Code chunk 3
        • Display an updated connection icon.
    Code Snippet
    1. private void button1_Click(object sender, RoutedEventArgs e)
    2.  {
    3.      // This is button1_Click for MulticastHost, MainWindow.xaml.cs
    4.      this.Title = "Prepping credentials...";
    5.      MyCredentials mycreds = new MyCredentials();
    6.      string session = "Bruno Practice Session";
    7.      string serviceNamespace = mycreds.ServiceNamespace;
    8.      string issuerName = mycreds.IssuerName;
    9.      string issuerSecret = mycreds.IssuerSecret;
    10.      //------------------------------------------------------------
    11.      // Code chunk 1
    12.      //------------------------------------------------------------
    13.      TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior();
    14.      relayCredentials.CredentialType = TransportClientCredentialType.SharedSecret;
    15.      relayCredentials.Credentials.SharedSecret.IssuerName = issuerName;
    16.      relayCredentials.Credentials.SharedSecret.IssuerSecret = issuerSecret;
    17.      //------------------------------------------------------------
    18.      // Code chunk 2
    19.      //------------------------------------------------------------
    20.      Uri serviceAddress = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace,
    21.             String.Format(CultureInfo.InvariantCulture, "{0}/MulticastService/", session));
    22.      ServiceHost host = new ServiceHost(typeof(MulticastService), serviceAddress);
    23.      host.Description.Endpoints[0].Behaviors.Add(relayCredentials);
    24.      this.Title = "About to connect....";
    25.      host.Open();
    26.      //------------------------------------------------------------
    27.      // Code chunk 3
    28.      //------------------------------------------------------------
    29.      string personImage = "/images/connect.png";
    30.      Uri uri = new Uri(personImage, UriKind.RelativeOrAbsolute);
    31.      BitmapImage source = new BitmapImage(uri);
    32.      this.image1.Source = source;
    33.      this.Title = "Connected !";
    34.  }

     

     

    image

    • Very simply put – the code below, creates the window above. The code below is very simple. IMulticastService implements IMulticastContract.ReportWeather(WeatherInfo weather_info).
    • We have 2 tables
      • Table 1 has 6 rows and 6 columns
      • Table 2 has 3 rows and 1 columns
    Code Snippet
    1. namespace MulticastHost
    2. {
    3.     using System;
    4.     using System.ServiceModel;
    5.     using DataContracts;
    6.     using System.Windows;
    7.     using System.Windows.Media;
    8.     using System.Xml;
    9.     using System.Windows.Media.Imaging;
    10.     using System.Drawing;
    11.     using System.Net;
    12.     using System.IO;
    13.     using System.Windows.Controls;
    14.     using System.Windows.Documents;
    15.     [ServiceBehavior(Name = "MulticastService", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
    16.     class MulticastService : IMulticastContract
    17.     {
    18.         FlowDocumentScrollViewer tf1 = null;
    19.         Table table1 = null, table2 = null;
    20.         void IMulticastContract.ReportWeather(WeatherInfo weather_info)
    21.         {
    22.             //--------------------------------------------------------------------------------------------
    23.             // Build a poup window
    24.             //--------------------------------------------------------------------------------------------
    25.             Window mainWindow = new System.Windows.Window();
    26.             mainWindow.MaxHeight = 900;
    27.             //--------------------------------------------------------------------------------------------
    28.             // Use a FlowDocumentScrollViewer(), which is a nice easy to use positioning of controls container
    29.             //--------------------------------------------------------------------------------------------
    30.             //// Create the parent viewer...
    31.             tf1 = new FlowDocumentScrollViewer();
    32.             tf1.Document = new FlowDocument();
    33.             //--------------------------------------------------------------------------------------------
    34.             // We'll populate a couple tables
    35.             //   ...and add it as a content element of the TextFlow.
    36.             //--------------------------------------------------------------------------------------------
    37.             table1 = new Table(); // for hi, low, and image array
    38.             table2 = new Table(); // for probability of precipitation
    39.             //--------------------------------------------------------------------------------------------
    40.             tf1.Document.Blocks.Add(table1);
    41.             tf1.Document.Blocks.Add(table2);
    42.             //--------------------------------------------------------------------------------------------
    43.             // Set some global formatting properties for the table.
    44.             //--------------------------------------------------------------------------------------------
    45.             table1.CellSpacing = 10;
    46.             table1.Background = System.Windows.Media.Brushes.White;
    47.             //--------------------------------------------------------------------------------------------
    48.             // Create 6 columns and add them to the table's Columns collection.
    49.             //--------------------------------------------------------------------------------------------
    50.             int numberOfColumns = 6;
    51.             for (int x = 0; x < numberOfColumns; x++)
    52.                 table1.Columns.Add(new TableColumn());
    53.             //--------------------------------------------------------------------------------------------
    54.             // Set alternating background colors for the middle colums.
    55.             //--------------------------------------------------------------------------------------------
    56.             table1.Columns[1].Background =
    57.                 table1.Columns[3].Background =
    58.                 System.Windows.Media.Brushes.LightSteelBlue;
    59.             table1.Columns[2].Background =
    60.                 table1.Columns[4].Background =
    61.                 System.Windows.Media.Brushes.Beige;
    62.             //--------------------------------------------------------------------------------------------
    63.             // Create and add an empty TableRowGroup to hold the table's Rows.
    64.             //--------------------------------------------------------------------------------------------
    65.             table1.RowGroups.Add(new TableRowGroup());
    66.             //--------------------------------------------------------------------------------------------
    67.             // Add the first (title) row.
    68.             //--------------------------------------------------------------------------------------------
    69.             table1.RowGroups[0].Rows.Add(new TableRow());
    70.             //--------------------------------------------------------------------------------------------
    71.             // Alias the current working row for easy reference.
    72.             //--------------------------------------------------------------------------------------------
    73.             TableRow currentRow = table1.RowGroups[0].Rows[0];
    74.             //--------------------------------------------------------------------------------------------
    75.             // Global formatting for the title row.
    76.             //--------------------------------------------------------------------------------------------
    77.             currentRow.Background = System.Windows.Media.Brushes.Silver;
    78.             currentRow.FontSize = 40;
    79.             currentRow.FontWeight = System.Windows.FontWeights.Bold;
    80.             //--------------------------------------------------------------------------------------------
    81.             // Add the header row with content. In this case, showing zip code.
    82.             //--------------------------------------------------------------------------------------------
    83.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Weather Report for " + weather_info.ZipCode))));
    84.             //--------------------------------------------------------------------------------------------
    85.             // and set the row to span all 6 columns. We need a column for each day of weather.
    86.             //--------------------------------------------------------------------------------------------
    87.             currentRow.Cells[0].ColumnSpan = 6;  // just like html, a typical column span
    88.             //--------------------------------------------------------------------------------------------
    89.             // Add the second (header) row.
    90.             //--------------------------------------------------------------------------------------------
    91.             table1.RowGroups[0].Rows.Add(new TableRow());
    92.             currentRow = table1.RowGroups[0].Rows[1];
    93.             //--------------------------------------------------------------------------------------------
    94.             // Global formatting for the header row. Big and bold.
    95.             //--------------------------------------------------------------------------------------------
    96.             currentRow.FontSize = 18;
    97.             currentRow.FontWeight = FontWeights.Bold;
    98.             //--------------------------------------------------------------------------------------------
    99.             // Add cells with content to the second row. Add (1) details (2) Today + next 5 or 6 days
    100.             //--------------------------------------------------------------------------------------------
    101.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Details"))));
    102.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Today"))));
    103.             System.DateTime today = System.DateTime.Now;
    104.             for (int i = 1; i < 5; i++)
    105.             {
    106.                 currentRow.Cells.Add(new TableCell(new Paragraph(new Run(string.Format("{0:dddd}", today.AddDays(i))))));
    107.             }
    108.             //--------------------------------------------------------------------------------------------
    109.             // Start a new row for high temperatures
    110.             //--------------------------------------------------------------------------------------------
    111.             table1.RowGroups[0].Rows.Add(new TableRow());
    112.             currentRow = table1.RowGroups[0].Rows[2];
    113.             //--------------------------------------------------------------------------------------------
    114.             // Global formatting for the row.
    115.             //--------------------------------------------------------------------------------------------
    116.             currentRow.FontSize = 12;
    117.             currentRow.FontWeight = FontWeights.Normal;
    118.             //--------------------------------------------------------------------------------------------
    119.             // SECTION: HIGH TEMPERATURE
    120.             // Add cells with content to the third row. Fill in the high temps.
    121.             //--------------------------------------------------------------------------------------------
    122.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Hi"))));
    123.             for (int i = 0; i < weather_info.weather_data.highTempF.Length; i++)
    124.             {
    125.                 currentRow.Cells.Add(new TableCell(new Paragraph(new Run(weather_info.weather_data.highTempF[i]))));
    126.             }
    127.             //--------------------------------------------------------------------------------------------
    128.             // Bold the first cell.
    129.             //--------------------------------------------------------------------------------------------
    130.             currentRow.Cells[0].FontWeight = FontWeights.Normal;
    131.             //--------------------------------------------------------------------------------------------
    132.             // Add the fourth row.
    133.             //--------------------------------------------------------------------------------------------
    134.             table1.RowGroups[0].Rows.Add(new TableRow());
    135.             currentRow = table1.RowGroups[0].Rows[3];
    136.             //--------------------------------------------------------------------------------------------
    137.             // Global formatting for the row. It will hold low temperatures.
    138.             //--------------------------------------------------------------------------------------------
    139.             currentRow.FontSize = 12;
    140.             currentRow.FontWeight = FontWeights.Normal;
    141.             //--------------------------------------------------------------------------------------------
    142.             // Fill in low temperatures
    143.             //--------------------------------------------------------------------------------------------
    144.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Low"))));
    145.             currentRow.FontWeight = FontWeights.Normal;
    146.             for (int i = 0; i < weather_info.weather_data.lowTempF.Length; i++)
    147.             {
    148.                 currentRow.Cells.Add(new TableCell(new Paragraph(new Run(weather_info.weather_data.lowTempF[i]))));
    149.             }
    150.             //--------------------------------------------------------------------------------------------
    151.             // Add the fifth row.
    152.             //--------------------------------------------------------------------------------------------
    153.             table1.RowGroups[0].Rows.Add(new TableRow());
    154.             currentRow = table1.RowGroups[0].Rows[4];
    155.             // Global formatting for the row.
    156.             currentRow.FontSize = 12;
    157.             currentRow.FontWeight = FontWeights.Normal;
    158.             //--------------------------------------------------------------------------------------------
    159.             // Store an image in the table cell. The image will depict the weather.
    160.             //--------------------------------------------------------------------------------------------
    161.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Image"))));
    162.             // Calulate height
    163.             System.Diagnostics.Debug.Assert(weather_info.weather_data.cloudIconURL.Length > 0);
    164.             Bitmap sample_bitmap = LoadPicture(weather_info.weather_data.cloudIconURL[0]);
    165.             //--------------------------------------------------------------------------------------------
    166.             // Loop through all the cloud icon urls
    167.             //--------------------------------------------------------------------------------------------
    168.             for (int i = 0; i < weather_info.weather_data.cloudIconURL.Length; i++)
    169.             {
    170.                 //--------------------------------------------------------------------------------------------
    171.                 // Create a BitmapImage object to become an ImageBrush to become a paragraph in a table cell
    172.                 //--------------------------------------------------------------------------------------------
    173.                 BitmapImage bmp0 = new BitmapImage();
    174.                 bmp0.BeginInit();
    175.                 bmp0.UriSource = new Uri(weather_info.weather_data.cloudIconURL[i]);
    176.                 bmp0.EndInit();
    177.                 Paragraph oParagraph0 = new Paragraph();
    178.                 //--------------------------------------------------------------------------------------------
    179.                 // Merge the BitmapImage into the ImageBrush object
    180.                 //--------------------------------------------------------------------------------------------
    181.                 ImageBrush ib = new ImageBrush(bmp0);
    182.                 ib.Stretch = Stretch.None;
    183.                 ib.AlignmentX = AlignmentX.Left;
    184.                 //--------------------------------------------------------------------------------------------
    185.                 // Put the ImageBrush in the paragraph which goes to the table cell
    186.                 //--------------------------------------------------------------------------------------------
    187.                 oParagraph0.Background = ib;
    188.                 //--------------------------------------------------------------------------------------------
    189.                 // The table cell gets added to the row. The current row will get a cell for
    190.                 // each day of the week
    191.                 //--------------------------------------------------------------------------------------------
    192.                 TableCell c = new TableCell(oParagraph0);
    193.                 c.LineHeight = ib.ImageSource.Height;
    194.                 c.LineHeight = sample_bitmap.PhysicalDimension.Height;
    195.                 currentRow.Cells.Add(c);
    196.             }
    197.             //--------------------------------------------------------------------------------------------
    198.             // Make a normal font row for "More to come..."  Give it a Light Gray background
    199.             //--------------------------------------------------------------------------------------------
    200.             currentRow.Cells[0].FontWeight = FontWeights.Normal;
    201.             table1.RowGroups[0].Rows.Add(new TableRow());
    202.             currentRow = table1.RowGroups[0].Rows[5];
    203.             //--------------------------------------------------------------------------------------------
    204.             // Light gray background
    205.             //--------------------------------------------------------------------------------------------
    206.             currentRow.Background = System.Windows.Media.Brushes.LightGray;
    207.             currentRow.FontSize = 18;
    208.             currentRow.FontWeight = System.Windows.FontWeights.Normal;
    209.             //--------------------------------------------------------------------------------------------
    210.             // Just say, "More to come..."
    211.             //--------------------------------------------------------------------------------------------
    212.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("More to come..."))));
    213.             //--------------------------------------------------------------------------------------------
    214.             // and set the row to span all 6 columns.
    215.             //--------------------------------------------------------------------------------------------
    216.             currentRow.Cells[0].ColumnSpan = 6;
    217.             //--------------------------------------------------------------------------------------------
    218.             // Get ready to put the satellite map of the weather.
    219.             // Add 1 column and make it blue, for the background
    220.             //--------------------------------------------------------------------------------------------
    221.             table2.CellSpacing = 10;
    222.             table2.Background = System.Windows.Media.Brushes.Aqua;
    223.             numberOfColumns = 1;
    224.             for (int x = 0; x < numberOfColumns; x++)
    225.                 table2.Columns.Add(new TableColumn());
    226.             table2.Columns[0].Background = System.Windows.Media.Brushes.LightSteelBlue;
    227.             //--------------------------------------------------------------------------------------------
    228.             // Create and add an empty TableRowGroup to hold the table's Rows.
    229.             //--------------------------------------------------------------------------------------------
    230.             table2.RowGroups.Add(new TableRowGroup());
    231.             //--------------------------------------------------------------------------------------------
    232.             // Add a new a new row to hold, "Hourly Precipitation Predictions"
    233.             //--------------------------------------------------------------------------------------------
    234.             table2.RowGroups[0].Rows.Add(new TableRow());
    235.             //--------------------------------------------------------------------------------------------
    236.             // Alias the current working row for easy reference.
    237.             //--------------------------------------------------------------------------------------------
    238.             currentRow = table2.RowGroups[0].Rows[0];
    239.             //--------------------------------------------------------------------------------------------
    240.             // Make a silver row (the column is light steel blue)
    241.             //--------------------------------------------------------------------------------------------
    242.             currentRow.Background = System.Windows.Media.Brushes.Silver;
    243.             currentRow.FontSize = 40;
    244.             currentRow.FontWeight = System.Windows.FontWeights.Bold;
    245.             //--------------------------------------------------------------------------------------------
    246.             // Write the text, "Hourly  Precipitation Predictions"
    247.             //--------------------------------------------------------------------------------------------
    248.             currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Hourly Precipitation Predictions"))));
    249.             //--------------------------------------------------------------------------------------------
    250.             // Write out hour probability of precipitation (ie, "10:00pm - 75%")
    251.             //--------------------------------------------------------------------------------------------
    252.             int count = weather_info.weather_data.prob_precip.Length;
    253.             for (int i = 0; i < count; i++)
    254.             {
    255.                 //--------------------------------------------------------------------------------------------
    256.                 // One of 8 rows, one for each hour
    257.                 //--------------------------------------------------------------------------------------------
    258.                 table2.RowGroups[0].Rows.Add(new TableRow());
    259.                 currentRow = table2.RowGroups[0].Rows[i + 1];
    260.                 currentRow.FontSize = 14;
    261.                 currentRow.FontWeight = FontWeights.Normal;
    262.                 string the_row = DateTime.Now.AddHours(i).ToShortTimeString() + " - " + weather_info.weather_data.prob_precip[i] + " %";
    263.                 //--------------------------------------------------------------------------------------------
    264.                 // Each cell is in a paragraph, making it effectivily like a new row
    265.                 //--------------------------------------------------------------------------------------------
    266.                 currentRow.Cells.Add(new TableCell(new Paragraph(new Run(the_row))));
    267.             }
    268.             //--------------------------------------------------------------------------------------------
    269.             // Make a row to hold the satellite image
    270.             //--------------------------------------------------------------------------------------------
    271.             table2.RowGroups[0].Rows.Add(new TableRow());
    272.             currentRow = table2.RowGroups[0].Rows[count + 1];
    273.             currentRow.FontSize = 14;
    274.             currentRow.FontWeight = FontWeights.Normal;
    275.             //--------------------------------------------------------------------------------------------
    276.             // This url holds the latest photo that we want to download
    277.             //--------------------------------------------------------------------------------------------
    278.             Bitmap bmpSat = LoadPicture(@"http://www.ssd.noaa.gov/goes/west/nepac/avn-l.jpg");
    279.             MemoryStream ms = new MemoryStream();
    280.             bmpSat.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
    281.             BitmapImage bImg = new BitmapImage();
    282.             bImg.BeginInit();
    283.             bImg.StreamSource = new MemoryStream(ms.ToArray());
    284.             bImg.EndInit();
    285.             //--------------------------------------------------------------------------------------------
    286.             // The paragraph will hold the satellite image.
    287.             //--------------------------------------------------------------------------------------------
    288.             Paragraph oParagraphSat = new Paragraph();
    289.             ImageBrush ibSat = new ImageBrush();
    290.             ibSat.ImageSource = bImg;
    291.             ibSat.Stretch = Stretch.None;
    292.             ibSat.AlignmentX = AlignmentX.Left;
    293.             oParagraphSat.Background = ibSat;
    294.             //--------------------------------------------------------------------------------------------
    295.             // Paragraph added to the table cell
    296.             //--------------------------------------------------------------------------------------------
    297.             TableCell mycell = new TableCell(oParagraphSat);
    298.             mycell.LineHeight = bmpSat.PhysicalDimension.Height;
    299.             currentRow.Cells.Add(mycell);
    300.             //--------------------------------------------------------------------------------------------
    301.             // Give the new will a title and show it
    302.             //--------------------------------------------------------------------------------------------
    303.             mainWindow.Title = "Weather Report";
    304.             mainWindow.Content = tf1;
    305.             mainWindow.Show();
    306.         }
    307.         //--------------------------------------------------------------------------------------------
    308.         // Method that returns a bitmap object from a url
    309.         //--------------------------------------------------------------------------------------------
    310.         private Bitmap LoadPicture(string url)
    311.         {
    312.             //--------------------------------------------------------------------------------------------
    313.             // Use the web request model and just stream the bytes into place
    314.             //--------------------------------------------------------------------------------------------
    315.             HttpWebRequest wreq;
    316.             HttpWebResponse wresp;
    317.             Stream mystream;
    318.             Bitmap bmp;
    319.             bmp = null;
    320.             mystream = null;
    321.             wresp = null;
    322.             //--------------------------------------------------------------------------------------------
    323.             // Stream the binary results of the url into our Bitmap object
    324.             //--------------------------------------------------------------------------------------------
    325.             try
    326.             {
    327.                 wreq = (HttpWebRequest)WebRequest.Create(url);
    328.                 wreq.AllowWriteStreamBuffering = true;
    329.                 wresp = (HttpWebResponse)wreq.GetResponse();
    330.                 if ((mystream = wresp.GetResponseStream()) != null)
    331.                     bmp = new Bitmap(mystream);
    332.             }
    333.             finally
    334.             {
    335.                 if (mystream != null)
    336.                     mystream.Close();
    337.                 if (wresp != null)
    338.                     wresp.Close();
    339.             }
    340.             return (bmp);
    341.         }
    342.     }
    343. }