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 RoutedEventArgs) Handles 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(Me, New PropertyChangedEventArgs(prop))
End Sub
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements 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>
-------------------------------------------------
<!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.
Any full source sample using SignalR and Winforms application for notify long running process?
ReplyDelete