GrabDuck

SignalR in Web, WPF, Console and Windows Services App in VB

:


Update: I have updated this post to reflect the latest SignalR (1.0.1) release.  This is some testing I did with SignalR in VB for different kinds of .Net projects like Windows Service, console and WPF application.  This post has different sections and each section has its own .Net solution so you can run them individually.  All the sourcecode for this blog post is available on my github page.  There are two SignalR Owin Host applications, a Console application and a Windows Services Application written in Vb.NET and it will be consumed by various .NET client applications such as Console Application, Web Application using Javascript, WPF Application using VB.Net.

SignalR Owin Hosts

    Console Application

    Windows Services Application

SignalR Owin Clients

    Console Application

        Web Application

       WPF Application

So let’s get started by first creating our SignalR Owin Host Console Application. 

SignalR Server Console Application in VB

Create a console application in VB and Install following nuget packages using Package Manager Console to create SignalR Hub.

>Install-Package Microsoft.Aspnet. Owin.Hosting -pre

>Install-Package Microsoft.Aspnet. Owin.Host.HttpListener -pre

>Install-Package Microsoft.Aspnet.Signalr.Owin

Without further due here is the code to start the server and create a hub which will start sending messages to clients upon arrival.

---------------------------------------

Imports Microsoft.AspNet.SignalR

Imports Microsoft.AspNet.SignalR.Hubs

Imports Microsoft.Owin.Hosting

Imports Owin

Module  Module1

     Sub Main()

         Dim url  As  String =  "http://localhost:8080/"

         Using  WebApplication.Start( Of  Startup)(url)

             Console.ForegroundColor =  ConsoleColor.Green

             Console.WriteLine( "Server running on {0}", url)

             Console.WriteLine( "Press any key to start sending events to connected clients")

             Console.ReadLine()

             Dim context  As  IHubContext =  GlobalHost.ConnectionManager.GetHubContext( Of  MyHub)()

             For x  As  Integer = 0  To 100

                System.Threading. Thread.Sleep(3000)

                 Console.WriteLine( "Server Sending Value to Client X: " + x.ToString())

                context.Clients.All.addMessage(x.ToString())

             Next

             Console.ReadLine()

         End  Using

     End  Sub

     Public  Class  Startup

         Public  Sub Configuration( ByVal app  As  IAppBuilder)

             Dim config =  New  HubConfiguration  With {.EnableCrossDomain =  True}

            app.MapHubs(config)

         End  Sub

     End  Class

    < HubName( "myHub")> _

     Public  Class  MyHub

         Inherits  Hub

         Public  Sub Chatter(param  As  String)

             Console.WriteLine(param)

            Clients.All.addMessage(param)

         End  Sub

     End  Class

End  Module

-----------------------------------------------

 IHubContext will give you access to all the clients and then you can communicate to all the clients. When you run this application you will see the following screenshot.  Once you have your client code written then you can press any key and it will start sending values to connected clients. 

Now lets consume this Self Host in a Client Console Application

SignalR Client Console Application in VB.  

Create a Console Application in VB and install nuget package using Package Manager Console. 

>Install-Package Microsoft.Aspnet.Signalr.Client

Then paste the following code into your Module1.vb page.  And run the application assuming you have already started the host application.

--------------------------------------

Imports Microsoft.AspNet.SignalR.Client.Hubs

Imports Microsoft.AspNet.SignalR

Module  Module1

     Sub Main()

         Dim connection =  New  HubConnection( "http://localhost:8080")

         Dim myHub = connection.CreateHubProxy( "myHub")

        connection.Start().Wait()

         Console.ForegroundColor =  ConsoleColor.Yellow

        myHub.Invoke( Of  String)( "chatter""Hi!! Server") _

        .ContinueWith(

             Sub(task)

                 If task.IsFaulted  Then

                     Console.WriteLine( "Could not Invoke the server method Chatter: {0}", _

                                      task.Exception.GetBaseException())

                 Else

                     Console.WriteLine( "Success calling chatter method")

                 End  If

             End  Sub)

        myHub.On( Of  String)( "addMessage", _

             Sub(param)

                 Console.WriteLine( "Client receiving value from server: {0}", param.ToString())

             End  Sub)

         Console.ReadLine()

     End  Sub

End  Module

-----------------------------------

Now it is time to test our application.  Run our application side by side.  I have server or host running on the left hand side with green color text and client running on the right with yellow color text.

When the client application is started, it invokes the chatter method on the server. 

  

      myHub.Invoke( Of  String)( "chatter""Hi!! Server") _

        .ContinueWith(

             Sub(task)

                 If task.IsFaulted  Then

                     Console.WriteLine( "Could not Invoke the server method Chatter: {0}", _

                                      task.Exception.GetBaseException())

                 Else

                     Console.WriteLine( "Success calling chatter method")

                 End  If

             End  Sub)

You will see “Hi!! Server” value received by the server on the left.  That value is again round tripped to the client and you can see it displayed by the client on the right hand side. 

  myHub.On( Of  String)( "addMessage", _

             Sub(param)

                 Console.WriteLine( "Client receiving value from server: {0}", param.ToString())

             End  Sub)

Now click on the server console window and press any key.  It will start sending value to the client in real time.  We do this by first getting IHubContext object which knows about all the clients.

             Dim context  As  IHubContext =  GlobalHost.ConnectionManager.GetHubContext( Of  MyHub)()

             For x  As  Integer = 0  To 100

                System.Threading. Thread.Sleep(3000)

                 Console.WriteLine( "Server Sending Value to Client X: " + x.ToString())

                context.Clients.All.addMessage(x.ToString())

             Next

Now let’s create some more clients that will work with our SignalR Owin Host Console Application. 

SignalR Client WPF Application in VB 

Create a WPF Application in VB and install the following package using Package Manager Console.

>Install-Package Microsoft.AspNet.SignalR.Client.

XAML Side

When you create a WPF application by default MainWindow.xaml file is opened and there paste the following code.  There is a button which will invoke Chatter method on the server. 

< Window  x: Class="MainWindow"

     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

     xmlns: x="http://schemas.microsoft.com/winfx/2006/xaml"

     Title="MainWindow"  Height="350"  Width="525"  Loaded="MainWindow_Loaded" >

    < ScrollViewer>

        < StackPanel>

            < Button  x: Name="btnShowSignal"  Content="Invoke Chatter Method"   Click="btnShowSignal_Click"></ Button>

            < TextBlock  Name="txtblock_message"  Text="{ Binding  UpdateText}"></ TextBlock>

        </ StackPanel>

    </ ScrollViewer>

</ Window>

Codebehind side

On the codebehind side in the MainWindow.xaml.vb we will create a property named UpdateText which will be set everytime our client receives a new text.  In the XAML side, we bind our TextBlock to this UpdateText property so whenever this property is changed it will be shown in the UI.  For all this to happen we have to implement INotifyPropertyChanged Interface. 

--------------------------------------

Imports Microsoft.AspNet.SignalR.Client

Imports System.ComponentModel

Imports Microsoft.AspNet.SignalR.Client.Hubs

Partial  Public  Class  MainWindow

     Inherits  Window

     Implements  INotifyPropertyChanged

     Public connection  As  HubConnection =  New  HubConnection( "http://localhost:8080")

     Public myHub  As  IHubProxy = connection.CreateHubProxy( "myHub")

     Private  Sub MainWindow_Loaded(sender  As  Object, e  As  RoutedEventArgsHandles  Me.Loaded

        DataContext =  Me

        connection =  New  HubConnection( "http://localhost:8080")

        myHub = connection.CreateHubProxy( "myHub")

        myHub.On( Of  String)( "addMessage"AddressOf addMessage)

     End  Sub

     Async  Sub btnShowSignal_Click(sender  As  Object, e  As  RoutedEventArgs)

         Await connection.Start()

         Await myHub.Invoke( "Chatter""Hello Server")

     End  Sub

     Private m_updatetext  As  String

     Public  Property UpdateText()  As  String

         Get

             Return m_updatetext

         End  Get

         Set( ByVal value  As  String)

            m_updatetext = value

            RaisePropertyChanged( "UpdateText")

         End  Set

     End  Property

     Private  Sub addMessage( ByVal sValue  As  String)

        UpdateText +=  Environment.NewLine

        UpdateText += sValue

     End  Sub

     Private  Sub RaisePropertyChanged(prop  As  String)

         RaiseEvent PropertyChanged( MeNew  PropertyChangedEventArgs(prop))

     End  Sub

     Public  Event PropertyChanged(sender  As  Object, e  As  PropertyChangedEventArgsImplements  INotifyPropertyChanged.PropertyChanged

End  Class

-----------------------------------------------

Let’s run both of our applications side by side. First Run the Host application and then run the WPF application and put them side by side.  In the screenshot below I have SignalR Owin Host Console Application on the left and WPF application on the right hand side.  Click on the button Invoke Chatter Method which will invoke the server’s Chatter method. 

 As soon as you click on the button it passes the value “Hello Server” to the server and server sends that value back to all the connected clients.  If you want to give it a try then fire up all the SignalR Client Console application too and press any key on the server console window.

After you press any key on the Host application it will send values to two clients as shown below.

And you might be tempted to ask me what about a web application which is the most used application by all of us right. 

SignalR Client Hub Web App consuming Owin Host

Let’s create an empty web application and install Nuget packages as shown below.

>Install-Package Jquery

>Install-Package Microsoft.AspNet.SignalR.JS

Create a simple html page, I have named it as SignalRClientNoProxy.html. You can run the application now to see the output.
-------------------------------------------------
<!DOCTYPE  html >

<html  xmlns ="http://www.w3.org/1999/xhtml">

<head >

     <title ></title >

     <script  src ="Scripts/jquery-2.0.0.min.js"></script >

     <script  src ="Scripts/jquery.signalR-1.0.1.min.js"></script >    

     <script  src ="/signalr/hubs"  type ="text/javascript"></script >

     <script  type ="text/javascript">

        $( function () {

             var connection = $.hubConnection( 'http://localhost:8080');

            connection.start();

             var myHub = connection.createHubProxy( "myHub");

            $( "#broadcast").click( function () {

                myHub.invoke( 'chatter', $( "#msg").val());

            });

            myHub.on( 'addMessage', function (message) {

                $( "#message").append( '<li>' + message +  '</li>');

            });

        });

     </script >

</head >

<body >

     <div >

         <input  id ="msg"  type ="text"/>

         <input  type ="button"  id ="broadcast"  value ="broadcast"  />

         <ul  id ="message">

         </ul >

     </div >

</body >

</html >

------------------------------------------

As a pre-requisite to running our client application on the right we run our server application on the left.

Type something in the textbox on the right window and post something to the server. 

Lets’ run all the applications so far and see how this works.  So one Host and three clients right.

Let now move on to some real world application like Windows Service Application running SignalR Owin Host sending messages to all clients.

SignalR Server Windows Services Application

Now porting this SignalR Owin Host code to window service is easy. Here is the code to do a simple service with signalR. You can check out the code to do a simple windows service from the All-In-One code framework from micrsoft.

------------------------------------------------------

Imports  System.Threading

Imports  Microsoft.AspNet.SignalR

Imports  Microsoft.AspNet.SignalR.Hubs

Imports  Microsoft.Owin.Hosting

Imports  Owin

Public  Class Service1

    Private stopping As Boolean

    Private stoppedEvent As ManualResetEvent

    'global variable context to update clients from everywhere in the service.

    Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of MyHub)()

    Dim url As String = "http://localhost:8080"

    Public Sub New()

        InitializeComponent()

        Me.stopping = False

        Me.stoppedEvent = New ManualResetEvent(False)

    End Sub

    Protected Overrides Sub OnStart(ByVal args() As String)

        ' Log a service start message to the Application log.

        Me.EventLog1.WriteEntry("Service is in OnStart.")

        Dim url As String = "http://localhost:8080/"

        Using WebApplication.Start(Of Startup)(url)

            

        End Using

        ' Queue the main service function for execution in a worker thread.

        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ServiceWorkerThread))

    End Sub

    ''' <summary>

    ''' The method performs the main function of the service. It runs on a 

    ''' thread pool worker thread.

    ''' </summary>

    ''' <param name="state"></param>

    Private Sub ServiceWorkerThread(ByVal state As Object)

        ' Periodically check if the service is stopping.

        Do While Not Me.stopping

            ' Perform main service function here...

            Dim context As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of MyHub)()

            For x As Integer = 0 To 100

                System.Threading.Thread.Sleep(3000)

                context.Clients.All.addMessage(x.ToString())

            Next

            Thread.Sleep(2000)  ' Simulate some lengthy operations.

        Loop

        ' Signal the stopped event.

        Me.stoppedEvent.Set()

    End Sub

    Protected Overrides Sub OnStop()

        ' Log a service stop message to the Application log.

        Me.EventLog1.WriteEntry("Service is in OnStop.")

        ' Indicate that the service is stopping and wait for the finish of 

        ' the main service function (ServiceWorkerThread).

        Me.stopping = True

        Me.stoppedEvent.WaitOne()

    End Sub

End  Class

Public  Class Startup

    Public Sub Configuration(ByVal app As IAppBuilder)

        Dim config = New HubConfiguration With {.EnableCrossDomain = True}

        app.MapHubs(config)

    End Sub

End  Class

<HubName("myHub")> _

Public  Class MyHub

    Inherits Hub

    Public Sub Chatter(param As String)

        Console.WriteLine(param)

        Clients.All.addMessage(param)

    End Sub

End  Class

----------------------------------------

You won’t be able to just hit F5 with a windows service, first you will have to install the windows service then you can run your WPF application and then you could see real time output from the windows service.  As I said before the entire source code for all these apps is on my GitHub page.