Exchanging messages between a server and a .NET client

SignalR's natural environment is the Web, that's why we tend to prefer the JavaScript client for our examples that illustrate its features. Nevertheless, the .NET client is as important and relevant as the JavaScript one, and it definitely deserves to be analyzed too. This last recipe of the chapter will be a translation of what we did in the previous recipe, but here the JavaScript client code will be replaced by C# code hosted in a console application. The server-side portion of this example will be the same as the one we wrote in the previous recipe, hence we'll avoid repeating the same code here and we'll be connecting to that application instead, using the same approach we had been applying throughout Chapter 4, Using the .NET Hubs Client API.

Getting ready

As already mentioned, we'll be connecting to the server we wrote in the previous recipe, so make sure you have that code ready and running before proceeding. Let's then create a console application project, naming it Recipe29, and then let's add to it the Microsoft ASP.NET SignalR .NET Client package from NuGet, as already explained in Chapter 4, Using the .NET Hubs Client API.

How to do it…

The Program class source code must be modified in the following manner:

  1. We first add the necessary using directives as follows:
    using System;
    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR.Client;
  2. We then apply the strategy we already described in Chapter 4, Using the .NET Hubs Client API, in order to be able to use the async/await syntax for our asynchronous calls as follows:
    static void Main(string[] args)
    {
        Do().Wait();
    }
    static async Task Do()
    {
        ...
    }
  3. Let's start writing the actual implementation of the Do() method by preparing the connection as follows:
        const string url = "http://localhost:14622/echo";
        var connection = new Connection(url);

    The SignalR client library exposes a Connection type, which is the equivalent of the $.connection object we used with the JavaScript client. This type plays the same role as the HubConnection type we saw in Chapter 4, Using the .NET Hubs Client API, but it works on the lower-level Persistent Connection API. It has to be configured with an endpoint to target, represented by the URL we are passing as its only argument. The port number we specify (14622) must match the port number used to expose EchoConnection in the previous recipe. Please verify and fix it if it does not.

  4. We can now attach event handlers on the Received event member exposed by connection. In our case, we define just one handler in order to send to the standard output the message we will receive in response to our outgoing call:
         connection.Received += message =>
             Console.WriteLine("Received: {0}", message);

    Received differs from the equivalent On() method from HubConnection because in this case we deal with a classic .NET event handler, while On() has the goal of registering a callback function to be called by name directly from the server. The more general-purpose approach of the Persistent Connection API fits nicely with the idiom exposed by a plain old .NET event handler.

    As for the JavaScript client, the declaration of these event handlers must be done before connecting to the server.

  5. Now we are ready to connect to our Hub using the following code:
        await connection.Start();

    This code is asynchronously initiating the connection and, as we already saw in the earlier recipes, we are waiting for its completion thanks to the await keyword.

  6. When the connection is ready, we can call the Send() method exposed by the Connection type and supply our payload to it as follows:
        connection.Send(new { body = "Hello" });

    The Send() method is very straightforward, and it's basically the same as the one we saw when discussing the JavaScript client. The supplied payload is an instance of an anonymous type, whose shape must match the one we are expecting to receive on the server side of the previous recipe, and you can easily verify that it does. In this way, we'll ensure that the server will be able to correctly understand what we are sending to it.

  7. We eventually make our code wait for the user to press Enter before exiting the application as follows:
    Console.WriteLine("Sending...");
    Console.ReadLine();

There is something worth noting about the Received member: it does not conform to the traditional signature of an event handler. Usually, two arguments are expected as follows:

  • The sender of the event
  • A type derived from EventArgs that passes any context information

In the case of Received, the sender is not provided, and the context is in the form of a simple string containing the received payload. Should the server send a complex object, the Received event would be supplied with its JSON representation.

We are ready to test our code by launching the project from Visual Studio and observing the output displayed on the console window.

How it works…

What goes on behind the scenes is no different from what we have been describing earlier in this chapter, but there is something interesting to highlight about the way we called Send(). In fact, even if it's an asynchronous method and could therefore be awaited, in our code we are not waiting for its completion as we have normally been doing earlier in the book. Because of that, the final effect is something like what's shown in the following screenshot:

How it works…

You can see that the Sending… message is printed out before the received payload, and that's because we did not wait for Send() to complete. We can modify our call on the Send() method to be like the following code:

await connection.Send(new { body = "Hello" });

In this case, the output will change, reflecting the fact that we used await to wait for the call to complete, and the two messages would be swapped.

It's also worth noting that the server payload is received as a string, whose content represents the JSON serialization of the object prepared on the server side. This illustrates the fact that, even if the type used to exchange messages is a simple string, a complex object is able to go through anyway, and it can be received and then properly deserialized if enough knowledge about its shape is available to the client.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset