Azure Service Bus – Eventing in the App Fabric – Project Weather Cloud – Creating the Weather Stations
This is an ongoing blog entry for Project Weather Cloud. At the end we’ll have a thoroughly documented and functional cloud application.
- https://blogs.msdn.com/brunoterkaly/archive/2010/01/01/azure-service-bus-intro-to-eventing-in-the-app-fabric-project-weather-cloud.aspx
- https://blogs.msdn.com/brunoterkaly/archive/2009/12/26/the-holy-grail-of-connecting-applications-net-services-bus-in-windows-azure.aspx
Weather Stations – Reporting the weather to listening endpoints
This next section is important. We are going to work on weather stations. After all, the weather stations are the source of the data that is floating around.
Weather Stations will need to manage security credentials. More specifically, we are using shared secret, as opposed to SAML Tokens or Simple Web Tokens. In code we’ll need to setup
RelayCredentials = new TransportClientEndpointBehavior();
RelayCredentials.CredentialType = TransportClientCredentialType.SharedSecret;
RelayCredentials.Credentials.SharedSecret.IssuerName = "onwer"
RelayCredentials.Credentials.SharedSecret.IssuerSecret = "the key I got from https://netservices.Azure.com";
Note that weather stations simply forward weather reports to WeatherCentral, which will then broadcast weather data to listening billboards.
Figure 2 : From previous blog entry showing Weather Stations, WeatherCentral, and Billboards (used to display weather at airports)
In order to get started, we need to go to a project on the .Net Services Portal at https://netservices.azure.com. After selecting “AppFabric” I chose “Add Service Namespace.”
Be careful here – if you already have a project (as I did), adding your second namespace is tricky. It seems like you add namespaces to whatever project you may have already created. So just click on your project (mine was “Basic Chat Application”).
The important thing is that you somehow find “Add Service Namespace.”
Figure 3 : Adding a namespace so we have something in the cloud to talk to
We will need to add two Service Namespaces:
- WeatherCentralService
- WeatherBillBoardService
Notice “Validate Name” will fail for you (because I have it!).
Figure 5 : Freshly minted namespaces
Note the Service Bus section below. This is the very important part of where the shared secret key can be found. Obviously, its blurred because you will have your own “Default Issuer Key” when you go to https://netservices.azure.com.
Figure 6 : Service Bus
In summary, here is what you need to write down:
- Registry URL
- Default Issuer Name
- Default Issuer Key
Weather Stations will acquire weather data and broadcast them through the Service Bus. Let’s talk briefly about the pieces.
Architecture we should understand before coding
- How weather stations report weather conditions
- How the AppFabric Service Bus listens to weather reports
- How the configuration settings work in a Weather Station Application
- How weather stations connect to the AppFabric Service Bus
- Weather Stations are simply WPF Clients
*Note* We will worry about the Weather Billboards (working at airport terminals) later.
How App.config Works
App.config plays a crucial role for the WPF Weather Station Application.
- It is used to specify client endpoints, so that you can connect to a WCF Service
- We are connecting to an “endpoint in the clouds”
- The endpoints in the cloud will get weather from Weather Stations and then Weather Central will pass this weather data to other listeners on that endpoint
- In the client section we specify the details of the binding of the WCF (Service Bus) that we are connecting to from the Weather Station WPF Client
- We also specify the “contract” and the “binding” (explained below)
- Notice that code below, “Channel.ReportWeather(now, …)” uses the settings in App.config
How Channel.ReportWeather works
- Weather Stations are client applications that connect to the AppFabric Service Bus endpoints
- Weather Stations connect to the Service Bus by using a combination of code and settings in configuration files.
Note that WeatherStations connect to sb: endpoints in the cloud and transmit weather data by using the “Channel” object to execute the “ReportWeather()” method. Parameters passed to the “ReportWeather()” method end up being parameters passed up to the cloud endpoint (sb://weathercentralservice.servicesbus.windows.net/WeatherCentral.
Figure 7 : How Weather Stations broadcast their weather for listeners
Our weather stations need to use the credentials (Issuer Name and Secret) that we got from https://netservices.azure.com. Notice we have a class called WeatherCentralConfig to specify needed connection information.
Figure 8 : A class dedicated to storing our secret credentials and service bus namespaces
Figure 9: Showing the main window code behind at a high level in Weather Station
- Notice we have objects to manage credentials and “channel” creation
- There is a ReportWeatherButton_Click() event so that when there is weather to report, we can type in the weather and click “Report Weather”
- Notice the controls in the XAML (2 textboxes, 2 labels, a button, etc)
Figure 10 : The user interface for the client to report the weather to the service bus
The code snippet below is our WPF application opening up a connection to the service bus for the purpose of reporting weather:
- Lines 5 to 8 are about incorporating security credentials
- Lines 10 to 14 are about preparing our endpoint for opening
- The endpoint needs a specially constructed “Uri()” object
- The endpoint relies on the contract named “IReportWeatherContract”
- The only method is ReportWeather()
- ReportWeather() will be called after the user hits the “Report Weather” button.
- Line 15 wraps things up by opening a connection
- The client can use the “Channel” object for further communications with the service bus endpoint in the cloud
Code Snippet
- public Window1()
- {
- InitializeComponent();
- RelayCredentials = new TransportClientEndpointBehavior();
- RelayCredentials.CredentialType = TransportClientCredentialType.SharedSecret;
- RelayCredentials.Credentials.SharedSecret.IssuerName = WeatherCentralConfig.WeatherCentralIssuerName;
- RelayCredentials.Credentials.SharedSecret.IssuerSecret = WeatherCentralConfig.WeatherCentralIssuerSecret;
- Uri serviceAddress = ServiceBusEnvironment.CreateServiceUri("sb", WeatherCentralConfig.WeatherCentralNS, WeatherCentralConfig.WeatherCentralServicePath);
- ChannelFactory = new ChannelFactory<IReportWeatherChannel>("ExternalWeatherEndpoint", new EndpointAddress(serviceAddress));
- ChannelFactory.Endpoint.Behaviors.Add(RelayCredentials);
- Channel = ChannelFactory.CreateChannel();
- Channel.Open();
- ConnectionConsole.Text = string.Format("Connected to {0}", serviceAddress);
- }
Figure 11 : The constructor for the main window for our WPF Weather Station Client. It opens a connection to the cloud endpoint.
Our Weather Station WPF Client application must implement the “ReportWeather()” method because it is part of the IReportWeatherContract interface at that endpoint.
Code Snippet
- [ServiceContract(Name = "IReportWeatherContract", Namespace = "https://brunoblogfiles.com/ServiceModel/Relay/")]
- public interface IReportWeatherContract
- {
- [OperationContract(IsOneWay = true)]
- void ReportWeather(DateTime dateReported,string weatherStationName, string weatherItem);
- }
Figure 12 : Our WPF Client (WeatherStation) will use “ReportWeather()”
- Service Bus Registry URL:
- Default Issuer Name:
- owner
- Default Issuer Key:
- 8YBdAXxxxxxxxxxxxxxxxxxxxxxxxxxxxPooNLcA=
A quick glance at the future user interface
This is what the WPF Client will look like when it is running. Right now “Report Weather” is not functional, because we haven’t implemented WeatherCentral (next blog entry).
Figure 13 : The User Interface waiting to report weather
Here is the URI that our Weather Station WPF Client will use to connect to the Service Bus. You are looking at the debugger at runtime. The Uri() rendered endpoint can be seen.
Figure 14 : The URI endpoint in the cloud seen from within the debugger
Final Steps
- Run the project
- Finish building this WPF Client
Running the project is just a right mouse click – Visual Studio 2008 Version
FIgure 15 : The project by itself in it’s simplest form (A WPF Project talking to an AppFabric Service Bus Endpoint
Final Steps
Right click on “References” and add the references you see above in blue.
- Note that “WeatherCentralContracts” is a project (you don’t need to “browse” to the dll)
Adding a Project
Lets add our first Weather Station in San Francisco. Remember, it is a WPF Application
Figure 16 : Adding a new WPF Client Application
We'll add similar WPF applications later for different cities.
Notes about Setting References
- Hopefully by now you've compiled WeatherCentralContracts
- It will take several right mouse clicks to get everything you need
- You will need to have already installed the .NET Services SDK (Nov 2009 CTP). You will use Microsoft.ServiceBus.dll
- The full path is C:\Program Files\Microsoft .NET Services SDK (Nov 2009 CTP)\Assemblies\MICROSOFT.SERVICEBUS.DLL
- The dll above is available once you install the SDK
- You will need to hit the “Browse” tab when setting references.
Specifically, there are 3 you have to add:- Microsoft.ServiceModel.dll (you’ll need to go to the “Browse” tab)
- System.ServiceModel.dll
- WeatherCentralContracts (you need to go to the “Project” tab)
Figure 17 : Adding References
Figure 18 : Our references are set
The final step is to code up the Weather Station WPF Client, where we need to:
- Code up the Main Window
- Add a user interface
- Some labels, text boxes, buttons
- Add code behind for the main window
- Add a user interface
- Add a connection to the Service Bus
- Use our settings from the portal
Add a user interface
Notice this a very basic window.
The code snippet below is the entire XAML declarative code for MainWindow.xaml.
You'll notice it is a basic grid with some labels, textboxes, and buttons. Later will spice it up with some cool stuff - like adding graphics of satellite images and such. But for now we'll keep it simple.
Remember, this thing will compile, but not run. We'll need to build WeatherCentral first, before WeatherStationSanFrancisco can run.
Code Snippet
- <Window x:Class="WeatherStationSanFrancisco.MainWindow"
- xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
- Title="Weather Station" Height="521" Width="571"
- WindowStartupLocation="CenterScreen" WindowState="Normal"
- WindowStyle="ThreeDBorderWindow" ResizeMode="NoResize" AllowsTransparency="False">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="433*" />
- <RowDefinition Height="0*" />
- <RowDefinition Height="50*" />
- </Grid.RowDefinitions>
- <TextBox Height="23" Margin="122,23,25,0" Name="weatherStationNameTextBox" VerticalAlignment="Top" />
- <Label Height="61" MaxWidth="100" HorizontalAlignment="Left" Margin="11,21,0,0" Name="label1" VerticalAlignment="Top" >
- <TextBlock Text="Weather Station Name:" TextWrapping="Wrap" HorizontalAlignment="Right"/>
- </Label>
- <Label Height="28" Margin="12,78,0,0" Name="label2" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120">Weather Item:</Label>
- <TextBox Margin="122,77,25,104" Name="weatherItemTextBox" TextWrapping="Wrap" />
- <Button Height="22" Margin="0,0,99,76" Name="ReportWeatherButton" VerticalAlignment="Bottom" Click="ReportWeatherButton_Click" HorizontalAlignment="Right" Width="110">Report Weather</Button>
- <Button Height="23" HorizontalAlignment="Right" Margin="0,0,25,75" Name="ExitButton" VerticalAlignment="Bottom" Width="68" Click="ExitButton_Click">Exit</Button>
- <TextBlock Height="28" Margin="122,0,25,29" Name="ErrorConsole" VerticalAlignment="Bottom" Text="" />
- <TextBlock Height="28" Margin="122,0,26,7" Name="ConnectionConsole" VerticalAlignment="Bottom" Text="" />
- <TextBlock Margin="122,0,26,28" Name="NewsReported" Text="" Height="28" Grid.RowSpan="3" VerticalAlignment="Bottom" />
- <Label Height="28" HorizontalAlignment="Left" Margin="11,0,0,34" Name="label3" VerticalAlignment="Bottom" Width="120">Errors:</Label>
- <Label Height="28" HorizontalAlignment="Left" Margin="11,0,0,12" Name="label4" VerticalAlignment="Bottom" Width="120">Connection Status:</Label>
- <Label HorizontalAlignment="Left" Margin="11,0,0,33" Name="label5" Width="120" Height="28" Grid.RowSpan="3" VerticalAlignment="Bottom">Last Reported Weather:</Label>
- </Grid>
- </Window>
Figure 19 : Code for MainWindow.xaml
The code here is in "design mode," which means that *we are not running* yet. I'm just showing you the XAML controls and the resulting window.
Figure 20: XAML and User Interface - MainWindow.xaml (Will be upgraded later)
You will need to add code to App.config, which is where the WCF plumbing will look when you create your channels later in the code behind.
Notice the client endpoints below. Those show you the name, contract, and binding.
We are connecting a non-WCF client to our WCF service. Therefore we need to get authorization to work by setting the proxy's credential state:
proxy.UseDefaultCredentials = true;
Code Snippet
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <client>
- <endpoint name="ExternalWeatherEndpoint"
- contract="WeatherCentralContracts.IReportWeatherContract"
- binding="netEventRelayBinding"/>
- </client>
- </system.serviceModel>
- <system.net>
- <defaultProxy
- useDefaultCredentials="true">
- <proxy autoDetect="True"/>
- </defaultProxy>
- </system.net>
- </configuration>
Figure 21: Code for App.config
Figure 22 : App.config must be right for any of this to work
Code Behind for MainWindow.xaml.cs
Here is the entire code behind. Obviously, the WeatherCentralIssuerSecret has been changed.
You can note the following:
- Line(s) 31 to 34 : Setup credentials
- Line(s) 36 to 47 : Opening a connection to the AppFabric Service Bus
- Line(s) 73 to 97 : Communicate across the open Service Bus connection
There is nobody listening yet on the other end so there is no point in running the application. You are dialing someone that has connected their phone.
But that is the next step. Stay tuned
Code Snippet
- using System;
- using System.ComponentModel;
- using System.Windows;
- using System.ServiceModel;
- using Microsoft.ServiceBus;
- using WeatherCentralContracts;
- namespace WeatherStationSanFrancisco
- {
- public static class WeatherCentralConfig
- {
- // You get this from the https://netservices.azure.com site
- public static string WeatherCentralNS = "WeatherCentralService";
- public static string WeatherCentralIssuerName = "owner";
- public static string WeatherCentralIssuerSecret = "8YBdAXoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXcA=";
- public static string WeatherCentralServicePath = "WeatherCentral";
- }
- // more code below ...owner
- public partial class MainWindow : Window
- {
- TransportClientEndpointBehavior RelayCredentials { get; set; }
- ChannelFactory<IReportWeatherChannel> ChannelFactory { get; set; }
- IReportWeatherChannel Channel { get; set; }
- public MainWindow()
- {
- InitializeComponent();
- RelayCredentials = new TransportClientEndpointBehavior();
- RelayCredentials.CredentialType = TransportClientCredentialType.SharedSecret;
- RelayCredentials.Credentials.SharedSecret.IssuerName = WeatherCentralConfig.WeatherCentralIssuerName;
- RelayCredentials.Credentials.SharedSecret.IssuerSecret = WeatherCentralConfig.WeatherCentralIssuerSecret;
- Uri serviceAddress = ServiceBusEnvironment.CreateServiceUri("sb",
- WeatherCentralConfig.WeatherCentralNS,
- WeatherCentralConfig.WeatherCentralServicePath);
- ChannelFactory = new ChannelFactory<IReportWeatherChannel>("ExternalWeatherEndpoint",
- new EndpointAddress(serviceAddress));
- ChannelFactory.Endpoint.Behaviors.Add(RelayCredentials);
- try
- {
- Channel = ChannelFactory.CreateChannel();
- Channel.Open();
- ConnectionConsole.Text = string.Format("Connected to {0}", serviceAddress);
- }
- catch (TimeoutException ex)
- {
- Console.WriteLine(ex.Message);
- }
- catch (System.ServiceModel.Security.SecurityNegotiationException ex)
- {
- Console.WriteLine(ex.Message);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- private void ExitButton_Click(object sender, RoutedEventArgs e)
- {
- Application.Current.Shutdown();
- }
- private void ReportWeatherButton_Click(object sender, RoutedEventArgs e)
- {
- // get weather station name and the weather
- NewsReported.Text = "Reporting weather....";
- if (ValidateInput())
- {
- DateTime now = DateTime.Now;
- try
- {
- Channel.ReportWeather(now, weatherStationNameTextBox.Text, weatherItemTextBox.Text);
- NewsReported.Text = string.Format("Last weather reported at:{0}", now);
- weatherItemTextBox.Text = "";
- weatherStationNameTextBox.Text = "";
- }
- catch (TimeoutException ex)
- {
- Console.WriteLine(ex.Message);
- }
- catch (System.ServiceModel.Security.SecurityNegotiationException ex)
- {
- Console.WriteLine(ex.Message);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- }
- private bool ValidateInput()
- {
- ErrorConsole.Text = "";
- bool valid = true;
- string errorMessage = "";
- if (string.IsNullOrEmpty(weatherStationNameTextBox.Text))
- {
- valid = false;
- errorMessage = errorMessage + "Please give a reporter name.";
- }
- if (string.IsNullOrEmpty(weatherItemTextBox.Text))
- {
- valid = false;
- errorMessage = errorMessage + "Please enter a weather item";
- }
- if (!valid)
- {
- ErrorConsole.Text = errorMessage;
- }
- return valid;
- }
- public void CloseChannel()
- {
- Channel.Close();
- ChannelFactory.Close();
- }
- protected override void OnClosing(CancelEventArgs e)
- {
- CloseChannel();
- base.OnClosing(e);
- }
- }
- }
Figure 23: Complete Code Behind for MainWindow.xaml.cs
Next Steps - Summary
At this point we have completed our first Weather Station. Later we’ll add additional weather stations to make Project Weather Cloud more interesting. The next step is to implement Weather Central.
Weather Central – The Next Project
Weather Central will listen for weather reports from weather stations. Stay Tuned.
Download Source
Click here to download.