Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
signalr / SignalR Programming in Microsoft ASP.NET.pdf
Скачиваний:
65
Добавлен:
25.05.2015
Размер:
19.23 Mб
Скачать

// Private methods

private async Task<int> DoSum(int a, int b)

{

await Task.Delay(1000); return a + b;

}

Sending messages to clients

The same concept applied to sending messages from the client to the server is also employed in the opposite direction. Through its Clients property, the Hub class offers a wide variety of tools to determine the recipients of the message and “invoke their methods” in a simple way thanks to the flexibility provided by .NET dynamic types.

The following code shows an invocation of the showAlert() method in all the clients connected when one of them calls the Alert() method of the hub:

public class AlertService: Hub

{

public void Alert(string msg)

{

this.Clients.All.showAlert(msg);

}

}

Clients.All returns a reference to all connected clients in the form of a dynamic object that we can subsequently use to directly code the call to the method that we want to execute in all of them. Notice that the use of dynamic types is what makes the preceding code not fail in compilation despite the fact that there is no showAlert() method in the object on which we are making the call.

Internally, still at the server, all invocations to methods that are made on this dynamic object are captured and, following the command1 pattern, their specifications are entered into a data packet, which is what is really sent to the clients. When the information reaches the other end, the data will be interpreted to execute whatever logic has been implemented.

The structure sent from the server to the clients looks more or less like this:

{

"C": "d-B,2|F,2|G,3|H,0", "M": [

{

"H":"AlertService",

"M":"showAlert",

"A":["I felt a great disturbance in the force"]

}

]

}

1 Command pattern: http://en.wikipedia.org/wiki/Command_pattern

64 Chapter 5Hubs

www.it-ebooks.info

Although this data packet has a lot of control information, we can intuitively understand that when a client receives this information it will know that the message has been sent from the “AlertService” hub and that it must execute the “showAlert” local method, supplying it the text “I felt a great disturbance in the force” as an argument. Depending on the type of client (JavaScript, .NET, WP, and so on), it will be executed in one way or another. For example, with a JavaScript client, the packet will be translated into a call to the client.showAlert() method of the proxy created for the hub and its parameter will be supplied the specified text, as shown in Figure 5-3:

hubProxy.client.showAlert = function (msg) { alert(msg);

};

FIGURE 5-3  Alert shown after receiving the message from the server.

It is important to take into account that no checks are performed at the server on the name of the method or the coincidence of its signature, parameters, or types—there would be no way to do so, because they are physically separated. Therefore, the call specification will simply be “packaged”; if we make any mistake, no error will be generated: the packet will be sent to the recipients, but they will not know how to interpret it, and thus the effects will not be as expected.

If we go back to the server side, we find that besides Clients.All, we can use various constructions to select the recipients of the calls. All of them are used in the same way, because they return a dynamic object on which we must make the invocations of the functions on the client side. The delivery tools offered by SignalR hubs are as follows:

■■Clients.All  Allows us to “invoke” a method in all the clients connected to the hub, with no exceptions.

public class ChatHub: Hub

{

public Task Broadcast(string text)

{

// Invokes the function "Message" in all connected clients return Clients.All.Message(text);

}

}

■■Clients.AllExcept(connections)  Indicates that the call must be sent to all the clients, except those whose connectionIds are passed as an argument in the form of an array or strings, or simply separated by commas, because the parameter received by this method is a params string[]:

Clients.AllExcept(darkSideUser1, darkSideUser2)

.Message("May the force be with you");

HubsChapter 5

65

www.it-ebooks.info

// Or

string[] darkSidePeople = _getDarkSidePeople(); Clients.AllExcept(darkSidePeople)

.Message("May the force be with you");

■■Clients.Caller  Identifies that the recipient of the invocation is the client that has made the call to the hub method currently being executed.

public Task Broadcast(string message)

{

Task broadcast = Clients.All.Message("Broadcast: " + message); Task notification = Clients.Caller.Message(

">> Your message was sent!"); return broadcast.ContinueWith(_ => notification);

}

■■Clients.Client(connectionId)  Sends the invocation of the method to the client with the specified connection identifier only.

Clients.Client(lukeConnectionId).Message("Use the force");

■■Clients.Clients(connectionIds)  Sends the invocation of the method to the clients whose connection identifier is specified in the form of an IList<string>:

var jedis = _rebelServices.GetJedisConnectionIds(); Clients.Clients(jedis).Message("Use the force");

■■Clients.Others  Represents all the clients connected except the one who has invoked the method being executed. It is equivalent to using AllExcept() and supplying it the identifier of the current connection.

public Task Broadcast(string message)

{

return Clients.Others.Message("Broadcast: " + message);

}

■■Clients.Group(groupName, excludeConnectionIds)  Allows invoking functions only in clients belonging to the group specified as an argument. Although we will go into deeper details later in this chapter in the section “Managing groups,” it should be remarked here that hubs, like persistent connections, allow creating arbitrary groups and linking clients to them.

public Task MessageToGroup(string group, string text)

{

return Clients.Group(group).Message(text);

}

The second parameter is useful to enter the identifiers of the clients that, despite belonging to the specified group, must not receive the message.

66 Chapter 5Hubs

www.it-ebooks.info

■■Clients.Groups(groupNames, excludeConnectionIds)  Similar to the preceding method, sends the invocation of the method to the clients belonging to the groups specified in the form of string lists.

public Task MessageToAdmins(string text)

{

var groups = new[] { "admins", "superadmins", "ninjas" }; return Clients.Groups(groups).Message(text);

}

■■Clients.OthersInGroup(groupName)  Allows us to select all the clients belonging to a group, except the one making the current call to the hub.

public Task BroadcastToGroup(string group, string text)

{

return Clients.OthersInGroup(group).Message(text);

}

■■Clients.OthersInGroups(groupNames)  Allows us to specify all the clients belonging to the groups entered as recipients of the message, except the client making the current call to the hub.

public Task BroadcastToGroups(IList<string> groups, string text)

{

return Clients.OthersInGroups(groups).Message(text);

}

■■Clients.User(userName)  Enables us to state the specific user on which the method will be invoked but, in contrast to Clients.Client(), in this case we will use their name as the search criterion. In the next section, “Sending messages to specific users,” we will come back to this, but for now it will suffice to know that this name will initially be the name of the user authenticated in the system:

public Task ObiWanMessage()

{

return Clients.User("luke").Message("Use the force");

}

An important detail to keep in mind, which we have anticipated in some of the previous examples, is that the invocation of any method from the client side on a selection of recipients returns a Task type object, which allows employing it as a return of asynchronous methods or using the capabilities offered by this type to coordinate processes executed in parallel, as well as easy use of the async­ /­await­ constructs of the language:

public async Task Alert(string msg)

{

await Clients.All.showAlert(msg);

await Clients.Caller.showAlert("Your alert has been sent");

}

HubsChapter 5

67

www.it-ebooks.info

Соседние файлы в папке signalr