Adding a client-side method on the proxy and calling it from the server

In our journey through the recipes from Chapter 3, Using the JavaScript Hubs Client API and their adaptation to the .NET client Hubs library, we have just arrived at the point where we have to modify the recipe that has a similar name, in which we saw how we can define a client-side method to be called directly from inside a remote Hub. The server that we built there is already calling back its caller; therefore, in this recipe, we'll just need to connect to it, call the Say() method, and wait for the callback to happen.

Getting ready

The following code will connect to the EchoHub exposed in the Adding a client-side method on the proxy and calling it from the server recipe from Chapter 3, Using the JavaScript Hubs Client API, which we have to run before testing this Recipe.

How to do it…

Let's create a console application project as described in the introduction, and let's name it Recipe23. The source code of the Program class must be modified using the following steps:

  1. Let's write the skeleton of our client code as follows:
    using System;
    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR.Client;
    
    static void Main(string[] args)
    {
        Do().Wait();
    }
    static async Task Do()
    {
        const string url = "http://localhost:42171";
        var connection = new HubConnection(url);
    
        var echo = connection.CreateHubProxy("echo");
    
        ...
    }

    The port number we specify (42171) must match the port number used in the server project that we are connecting to. Please verify if that's the case. More details about this code can be found in the previous recipes in this chapter.

  2. On the proxy reference that we just retrieved, we can define any callback we might need. In this case, we proceed using the following code:
    echo.On("Greetings", message =>
        Console.WriteLine(message));

    The On() method allows us to define a callback method, giving it a name and defining its arguments and body, which in this case is an instance of an Action delegate receiving a string and printing it on the standard output window. It's like subscribing to an event, although the syntax is not the classic one for event handlers. When a server Hub pushes a method call on any of the available sets of connected clients (in the case of the server we are connecting to here, Clients.Caller), the request for that call is transferred onto the client and SignalR triggers the corresponding handler that we just registered over there using On(). The resolution, as usual, is performed at runtime.

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

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

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

  4. When the connection is ready, we can call the Say() method exposed by the remote Hub with the following code:
    await echo.Invoke<string>("Say", "hello!");

    The call will be executed asynchronously, and again we wait for its completion.

  5. We eventually make our code wait for the user to press Enter before exiting the application. The following code depicts this:
    Console.WriteLine("Press Enter to exit");
    Console.ReadLine();

    This code follows an awaited statement, therefore it will be executed only when the asynchronous call to Invoke() will be completed.

Launching the code, we will see how the hello! message pushed by the server towards the caller is eventually printed on the console.

How it works…

What happens when we execute this code? The Invoke() call will trigger the execution of the Say() method on the server-side Hub, which we know will call back the caller trying to invoke a client-side method called greetings(), if available. In our case, we have registered one with the On() method, which will just print the received message parameter on the console.

This sample is already showing how asynchronous code can easily become difficult to grasp. You might have noticed that in steps 3 and 4, we perform two subsequent asynchronous calls using await; this means that the first call will be awaited, and when completed, the second one will be triggered and again awaited before calling Console.ReadLine(). We can really appreciate the advantages of the async/await syntax here, because without it we would have two nested callbacks, and code would be harder to read and understand.

On the other hand, we could easily play with this code and observe subtly different behaviors. Pay attention to the sequence of messages on the screen. You will see that the hello! messages are always printed before the Press Enter to exit one. The .NET client is, in some way, making the remote asynchronous call run synchronously with respect to the client-side Invoke() call. It's as if the On() handler became part of the body of the Invoke() call.

Because of what we just said, if we now try to remove the await keyword in front of the Invoke() call and then launch the application again, everything would work as before, except that the two messages on the screen would appear in reverse order! Why? The On() handler is executed as it was part of the call that triggered it (the Invoke() call), but the Invoke() call is not awaited now. Hence, the asynchronous execution of the whole block consisting of the Invoke() and On() calls is completed after the Console.WriteLine() line, because writing a message on the console is for sure much faster than any operation involving network communication. We still have a chance to see the hello! message on screen because the ReadLine() call is making the process wait for interaction, and this gives time for the asynchronous invocation to be completed. However, the flow is totally different. If in this case, we remove the ReadLine() call, we will not see the hello! message printed at all.

Hopefully, this short digression around asynchronous code has been interesting; however, a good understanding of such concepts is important to write better SignalR code for sure, especially when using the .NET client library.

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

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