56 分 11 秒のセクションにあるビデオ「 ASP.NET SignalR を使用したリアルタイム Web のスケーリング」に触発されました。
SignalR を使用してサーバーと通信する Web ベースのチャット クライアントを想像してみてください。クライアントが接続すると、そのエンドポイント情報が Azure テーブルに格納されます。
チャット クライアントは、SignalR を介して別のチャット クライアントにメッセージを送信できます。SignalR は、目的の送信先クライアントのエンド ポイント (別のインスタンス上にある可能性があります) を検索し、Web API を使用して、SignalR を介して他のインスタンスにメッセージをクライアントに送信します。
サンプル アプリケーションを github にアップロードしました。
これはすべて、単一の Azure インスタンスがある場合に機能します。ただし、複数の azure インスタンスがある場合、サーバーからクライアントへの SignalR への最後の呼び出しはサイレントに失敗します。動的コードが存在しないか、「悪い」スレッドから外れているか、メッセージが何らかの形で間違ったインスタンスに送信されたか、または私が間違った間違いを犯したようです。
どんなアイデアでも大歓迎です。
Webページはこれで設定されています
<input type="radio" name='ClientId' value='A' style='width:30px'/>Chat client A</br>
<input type="radio" name='ClientId' value='B' style='width:30px'/>Chat client B</br>
<input type='button' id='register' value='Register' />
<input type='text' id='txtMessage' size='50' /><input type='button' id='send' value='Send' />
<div id='history'>
</div>
そしてJSは
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
chat.client.sendMessageToClient = function (message) {
$('#history').append("<br/>" + message);
};
// Start the connection.
$.connection.hub.start().done(function () {
$('#register').click(function () {
// Call the Send method on the hub.
chat.server.register($('input[name=ClientId]:checked', '#myForm').val());
});
$('#send').click(function () {
// Call the Send method on the hub.
chat.server.sendMessageToServer($('input[name=ClientId]:checked', '#myForm').val(), $('#txtMessage').val());
});
});
});
</script>
ハブは以下の通り。(エンドポイント情報を Azure テーブルに格納するための小さなストレージ クラスがあります)。静的メソッド SendMessageToClient に注意してください。これは最終的に失敗するものです。Web Api クラス (下記) から呼び出されます。
public class ChatHub : Hub
{
public void Register(string chatClientId)
{
Storage.RegisterChatEndPoint(chatClientId, this.Context.ConnectionId);
}
/// <summary>
/// Receives the message and sends it to the SignalR client.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="connectionId">The connection id.</param>
public static void SendMessageToClient(string message, string connectionId)
{
GlobalHost.ConnectionManager.GetHubContext<ChatHub>().Clients.Client(connectionId).SendMessageToClient(message);
Debug.WriteLine("Sending a message to the client on SignalR connection id: " + connectionId);
Debug.WriteLine("Via the Web Api end point: " + RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WebApi"].IPEndpoint.ToString());
}
/// <summary>
/// Sends the message to other instance.
/// </summary>
/// <param name="chatClientId">The chat client id.</param>
/// <param name="message">The message.</param>
public void SendMessageToServer(string chatClientId, string message)
{
// Get the chatClientId of the destination.
string otherChatClient = (chatClientId == "A" ? "B" : "A");
// Find out this other chatClientId's end point
ChatClientEntity chatClientEntity = Storage.GetChatClientEndpoint(otherChatClient);
if (chatClientEntity != null)
ChatWebApiController.SendMessage(chatClientEntity.WebRoleEndPoint, chatClientEntity.SignalRConnectionId, message);
}
}
最後に ChateWebApiController はこれです
public class ChatWebApiController : ApiController
{
[HttpGet]
public void SendMessage(string message, string connectionId)
{
//return message;
ChatHub.SendMessageToClient(message, connectionId);
}
/// <summary>
/// This calls the method above but on a different instance via Web API
/// </summary>
/// <param name="endPoint">The end point.</param>
/// <param name="connectionId">The connection id.</param>
/// <param name="message">The message.</param>
public static void SendMessage(string endPoint, string connectionId, string message)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://" + endPoint);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = "http://" + endPoint + "/api/ChatWebApi/SendMessage/?Message=" + HttpUtility.UrlEncode(message) + "&ConnectionId=" + connectionId;
client.GetAsync(url);
}
}