Part 1: Getting SignalR running on Asp.Net MVC Core

Microsoft has a very powerful implementation of WebSockets available named SignalR. Personally, I like the fact it automatically scales down if needed to other communication solutions if WebSockets is not working (like long polling).

I used it in the past several times for dashboards but in my current project, I had a new challenge. We are using Asp.Net MVC Core. This is ‘the latest’ flavor of Asp.Net and our websites can now run on both Windows and Linux.

But Asp.Net MVC Core has broken with the past, which is a good thing but it also needs a different way to activate SignalR.

Microsoft has provided documentation but it was written towards the standard, non-MVC applications.

It took me a while to get SignalR running.

But first, let me introduce you to the steps to be taken to get SignalR running on Asp.Net MVC Core.

This is a series of blogs regarding using SignalR on Asp.Net MVC Core:

  1. Getting SignalR running on Asp.Net MVC Core
  2. Passing data from outside an Asp.Net MVC Core site to the browser using SignalR
  3. Adding Basic Authentication to Asp.Net Core the right way

Step 1: Select the right template in Visual Studio 2017

Open visual studio 2017 and start a new project, an ASP.NET Core application:

This opens a dialog. Next, select the Web Application (Model-View-Controller). I use neither Docker support nor Authentication:

Once the application is generated, compile it, select the right browser to run it in and run it. Select Chrome, that works for me:

Not handled in this blog but see that it’s possible to debug your javascript etc.:

Now your default template site is running in IISExpress, a lightweight web server on your machine:

Close the browser to go back to Visual Studio

Step 2: Add SignalR package

We need a ‘special’ NuGet package named “Microsoft.AspNetCore.SignalR”. You can add:

<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-alpha2-final" />

in the project file.

Or you can open the NuGet dialog (right click Dependencies in the app and select ‘Manage NuGet Packages’).

Do not forget to activate the selector ‘Include prerelease’ when you browse for “Microsoft.AspNetCore.SignalR”.

Note: At the time of writing this blog, the latest prerelease is ‘1.0.0-alpha2-final’.

Install the package and everything it is referencing (and that is a lot!).

Build the solution after adding all the packages to restore everything.

Step 3: Add the SignalR hub

All SignalR communication is done in a ‘hub’. Let’s add the default example hub.

Just create a new class named Chat in the main folder of your application.

Note the namespace, yours can differ if your application has another name:

</pre>
<pre>using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;

namespace SignalRApplication
{
    public class Chat : Hub
    {
        public Task Send(string message)
        {
            return Clients.All.InvokeAsync("Send", message);
        }
    }
}

Recompile (I just want you to be sure everything is still building).

Step 4: Activate SignalR and the Hub in the startup process of the application

Alter the Startup.cs in your application so it looks like this:

namespace Sample
{
  public class Startup
  {
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddSignalR();

      ... // original code
    }

    public void Configure(IApplicationBuilder app)
    {
      app.UseSignalR(routes =>
      {
        routes.MapHub<Chat>("chat");
      });

      ... // original code
    }
  }
}

Again, recompile.

Although the Chat hub is pretty worthless for now, we can already test if it’s available!

Run the app in the (Chrome) browser and alter the URL: append /chat:

You will get a simple answer saying a Connection ID is required. Nice, let’s do that!

Step 5: Add the SignalR javascript

We will access the Hub from javascript so we will need the library.

For that we have to execute somewhere on your laptop, on the Dos Prompt:

npm install @aspnet/signalr-client

Yes, this is the NodeJS Package manager! Be we are not interested in NodeJS, we are only interested in the packages/javascript which will be downloaded.

I recommend executing this command in the root of your application. File and folders will be created but your Application will ignore them…

Now browse to the relative path containing the SignalR js file and copy it to the js folder:

And do not forget to deploy the file during execution:

Step 6: Start building a web page with SignalR support

Go to the View named About.cshtml (in the Views\Home folder) and open it.

Af the bottom of the file, add this Scripts section:

@section Scripts {
  <script src="~/js/signalr-client-1.0.0-alpha2-final.js"></script>
}

We are referencing the file we just added.

Note: we make use of the Scripts section. This must be done in Asp.Net MVC!

This is a good moment to run the application again and open the About page. Nothing should happen (at least no exceptions).

Now add at the bottom of the About page, the following HTML:


<div class="container">
  <input type="text" id="txtMessage" />
  <input type="button" id="sendMessage" value="Send" onclick="sendMessage();" />

<div id="DisplayMessages"></div>

</div>

What we add are:

  1. an input text box to type a message
  2. a button to submit the message to the SignalR Hub
  3. a div which will contain the list of incoming messages

Alter the script section so it will look like this:

@section Scripts {
  <script src="~/js/signalr-client-1.0.0-alpha2-final.js"></script>

  <script>
    let connection = new signalR.HubConnection("/chat", { transport: signalR.TransportType.LongPolling });

    connection.on('send', data => {
      var DisplayMessagesDiv = document.getElementById("DisplayMessages");
      DisplayMessagesDiv.innerHTML += "
" + data;
    });

    connection.start().then(() => connection.invoke('send', 'Hello'));

    function sendMessage() {
      var msg = document.getElementById("txtMessage").value;
      connection.invoke('send', msg);
    }
  </script>
}

What do we see?

  1. We create HubConnection to the Chat Hub
  2. We use LongPolling??? Yes, remember, you are using IIS Express. This lightweight web server does not understand SignalR. So for now, we force our communication towards long polling
  3. We start listening to incoming messages from the Hub. If messages arrive, we add them to the list at the bottom of the page
  4. When out local HubConnection is connected to the Chat Hub, we send a message saying “Hello”
  5. We provide a message for the submit button. The messages written by the user is sent to the Chat hub

We are now ready to send and receive SignalR messages!

Step 7: Testing the communication

Run the application en go to the About page:

This is a magic moment, at the bottom of the page, ‘Hello’ is written. This means the roundtrip is done. The Javascript in the About page is now a client towards the Chat Hub. When connected for the first time, that ‘Hello’ is sent to the server and the server bounces it back to ALL clients, including our own page.

Send a message by typing in some text and push the Send button:

I have submitted four separate messages (the first three are just single words, this is not a failure :-))

Now try to submit message while opening the same page in multiple brands of browsers:

This is working fine! All three browsers (Chrome, Firefox and Edge) are communicating together.

Note: Edge has only one ‘Hello’ message. It was the last browser to be opened so it missed the message from Firefox (the one opened before Edge).

Step 8: Preparing deployment to the cloud

Our ultimate goal is to deploy our website to the cloud. This means we have to fix that LongPolling thingy. But we still want to test our Signal locally. So let’s make an adjustment. Our Javascript code will switch between Debug and Release.

First, we add a Viewbag property in the About action in the HomeController:

public IActionResult About()
{
#if DEBUG
  ViewBag.RunState = "Debug";
#else
  ViewBag.RunState = "Release";
#endif

  ViewData["Message"] = "Your application description page.";

  return View();
}

This is a simple way to react to Debug or Release in the script section.

So alter the script section too:


...
<script>
    let connection;

    if (@ViewBag.RunState = 'Debug') {
        connection = new signalR.HubConnection("/chat", { transport: signalR.TransportType.LongPolling }); //debug
    }
    else {
        connection = new signalR.HubConnection("/chat"); //release
    }

    connection.on('send', data => {
    ...
    connection.start().then(() => connection.invoke('send', '@ViewBag.RunState'));
    ...
 

In the javascript, based on the ViewBag property, we decide which kind of communication we want to use.

Run the application for the last time in the browser. Just to see if we have broken something.

Step 9: Deploy to Azure

Deployment to Azure means a few things:

  • you need access to your Azure subscription from within Visual Studio
  • We will deploy into a new WebApp, running in a new Web Application Plan (with a standard format server)
  • The deployment will succeed and we should see the application is deployed in release mode

But first, Let us deploy the application (from the project, right-click the root folder and select Publish):

We deploy to a new App service!

Next, we fill in the administration for a new WebApp:

And at last, we create the WebApp.

We can see the progress of publishing in the Output window:

Publish Succeeded.
Web App was published successfully http://signalrapplication.azurewebsites.net/
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========

And if we go to the About page in the browser, we will see that we can use SignalR:

Nice work!

But is it communicated using WebSockets? I’m not sure. But I know there are some settings we have to check!

Step 10: Checking Application Settings

First, we have to actually activate WebSockets on the server in the AppSettings:

Next, we have to give our clients access to our website using the CORS (Cross-Origin Resource Sharing) setting. Here I give access to the whole world! In production, I rather should limit that a bit:

Are we now finally communicating WebSockets?

I’m still not sure.

We are using SignalR and we have set the two settings I know of which are important for SignalR.

But I have not found a way to check it for sure.

I have tried to force the usage of WebSockets with:

if (@ViewBag.RunState = 'Debug') {
    connection = new signalR.HubConnection("/chat", { transport: signalR.TransportType.LongPolling }); //debug
}
else {
    connection = new signalR.HubConnection("/chat", { transport: signalR.TransportType.WebSockets }); //release
}

But still, in the Chrome console, I have seen:

So I am not 100% sure how to force WebSockets…

I dug a bit deeper and found this thread. I’m not sure but it seems .Net Core does not support WebSockets yet?

Conclusion

So, with a little bit of work, we managed to get SignalR running on Asp.Net MVC Core. This is great!

Ok, this is an alpha2 release so we have to way a little bit longer until WebSockets are supported. But overall, the implementation is quite stable and we can work with it.

I will show how to send a message outside the WebApp, using Azure Functions, on the next blog.

Advertenties

Een reactie op “Part 1: Getting SignalR running on Asp.Net MVC Core

Reacties zijn gesloten.