4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SignalR】ASP.NETでリアルタイムチャット機能を作る

Last updated at Posted at 2024-10-05

本記事のゴール

・リアルタイムで複数人がやり取りできるチャット機能を作る

image6.png

SignalRとは

通常のWebアプリケーションでは、画面表示時に一度だけサーバーからクライアントへ通信を行い情報を渡しています。しかし、リアルタイムチャットを実現しようとするとメッセージが来たという情報をサーバー側から通知する必要があります。
このサーバーとクライアントの間の通信を解決するライブラリが「SignalR」です。SignalRはMicrosoftが提供しているライブラリであり、サーバー及びブラウザの対応状況に応じて、WebSocketやロングポーリングなどを切り替えることでこれらを実現します。

WebSocket:ブラウザとサーバーとの間で常に双方向の通信を継続してやり取りを行う。
ロングポーリング:ブラウザがサーバーにリクエストを行い、サーバーは通信したい状況になるまでレスポンスを保留する。レスポンスが返ってくるとブラウザはすぐに次のリクエストを送信する。

SignalRを導入する

サーバー側

1.最新のバージョンでは既にSignalRが含まれているためインストールなどは必要ありません。
※「依存関係」→「フレームワーク」にMicrosoft.AspNetCore.SignalRなどが存在することが確認できます。

2.Program.csを以下のように書き換えてSignalRサーバーを構成するように設定します。

Program.cs
  var builder = WebApplication.CreateBuilder(args);

  // Add services to the container.
  builder.Services.AddControllersWithViews();
+ builder.Services.AddSignalR();

  var app = builder.Build();
  (下略)

クライアント側(JavaScript)

TypeScriptを採用する場合、以下公式ドキュメントを参照してください。
ただし、処理の仕組みが異なる訳ではないため本記事も参考になるかと思います。
https://learn.microsoft.com/ja-jp/aspnet/core/tutorials/signalr-typescript-webpack?view=aspnetcore-8.0&tabs=visual-studio

1.プロジェクトを右クリック→「追加」→「クライアント側のライブラリ」をクリックし、ライブラリ マネージャー (LibMan)を開きます。

image1.png

2.以下の通りに設定して「インストール」をクリックします。

  • プロバイダー:unpkg
  • ライブラリ:@microsoft/signalr@latest
  • 特定のファイルの選択をチェック
  • ファイル/dist/browserの中のsignalr.jssignalr.min.jsのみを選択
  • ターゲットロケーション:wwwroot/js/signalr/

image2.png

wwwroot配下にsignalr.jsが配置されていればOKです。

image3.png

リアルタイムチャット機能を実装する

ハブを作成・登録

サーバー側にハブ(クライアント側にリアルタイムデータを配信するクラス)を作成します。
アプリケーション直下にHubsフォルダを作成し、その中にSimpleChatHub.csを作成します。

Hubs/SimpleChatHub.cs
using Microsoft.AspNetCore.SignalR;

namespace Web.Hubs
{
    public class SimpleChatHub : Hub
    {
        // クライアント側からこのSendMessageを呼び出す
        public async Task SendMessage(string message)
        {
            // クライアント側に定義されているメソッドReceiveMessage宛に自分以外に通知する
            await Clients.Others.SendAsync("ReceiveMessage", message);
        }
    }
}

image4.png

Program.csに、作成したハブを登録します。

Program.cs
+ using Web.Hubs;

  var builder = WebApplication.CreateBuilder(args);
  (中略)
  app.MapControllerRoute(
      name: "default",
      pattern: "{controller=Home}/{action=Index}/{id?}");
+ app.MapHub<SimpleChatHub>("/SimpleChatHub");

  app.Run();

画面(View)を作成する

Views/Home/Index.html(一例)
@{
    ViewData["Title"] = "簡易チャット";
}
<style>
    .chat-container {
        max-width: 600px;
        margin: 0 auto;
        padding: 0;
        border: 1px solid #ccc;
        border-radius: 10px;
    }

    .chat-area {
        min-height: 150px;
        padding: 20px;
        border-top-left-radius: 10px;
        border-top-right-radius: 10px;
        background-color: #f8f9fa;
    }

    .chat-bubble {
        margin-bottom: 10px;
        width: 80%;
    }

    .chat-bubble.sent {
        text-align: right;
        margin-left: auto;
    }

    .chat-bubble.received {
        text-align: left;
        margin-right: auto;
    }

    .chat-bubble > span {
        display: inline-block;
        padding: 10px;
        border-radius: 10px;
    }

    .chat-bubble.sent > span {
        text-align: left;
        background-color: #dcf8c6;
    }

    .chat-bubble.received > span {
        background-color: #fff;
    }

    .form-area {
        border-top: 1px solid #ccc;
    }

    .form-area input {
        border: none;
        border-radius: 0;
        border-bottom-left-radius: 10px;
    }

    .form-area button {
        border-radius: 0;
        border-bottom-right-radius: 10px;
    }
</style>

<div class="container">
    <div class="chat-container">
        <div id="ChatArea" class="chat-area">
            <div class="chat-bubble received">
                <span>受信メッセージ1</span>
            </div>
            <div class="chat-bubble sent">
                <span>送信メッセージ1</span>
            </div>
            <div class="chat-bubble received">
                <span>受信メッセージ2</span>
            </div>
        </div>
        <div class="input-group form-area">
            <input id="MessageInput" type="text" class="form-control" placeholder="メッセージを入力" />
            <div class="input-group-append">
                <button id="SendButton" class="btn btn-primary">送信</button>
            </div>
        </div>
    </div>
</div>

image5.png

JavaScript処理を作成する

wwwroot/js/SimpleChat.js
// コネクション確立
//  - withUrl内はProgram.csで定義したパスを指定
var connection = new signalR.HubConnectionBuilder().withUrl("/SimpleChatHub").build();

// コネクション開始時処理
connection.start()
    .then(() => {
        // コネクション正常開始
        console.info("connection start");
    }).catch((err) => {
        // コネクションエラー
        return console.error(err.toString());
    });

// 通知を受けたときの処理 メソッド名: ReceiveMessage
connection.on("ReceiveMessage", (message) => {
    this.AddChatBubble(false, message);
});

// 送信ボタンクリック時処理
document.getElementById("SendButton").addEventListener("click", (event) => {
    var message = document.getElementById("MessageInput").value;
    if (message.trim() === "") return;
    // SimpleChatHubのSendMessageを呼び出す
    connection.invoke("SendMessage", message)
        .then(() => {
            // メッセージ送信成功
            this.AddChatBubble(true, message);
            document.getElementById("MessageInput").value = "";
        }).catch((err) => {
            // メッセージ送信エラー
            return console.error(err.toString());
        });
    event.preventDefault();
});

// メッセージをチャット画面に追加する
function AddChatBubble(isSent, message) {
    var bubble = document.createElement('div');
    bubble.classList.add("chat-bubble");
    bubble.classList.add(isSent ? "sent" : "received");
    var span = document.createElement("span");
    var text = document.createTextNode(message);

    span.appendChild(text);
    bubble.appendChild(span);
    document.getElementById("ChatArea").appendChild(bubble);
}

画面の仮メッセージを削除し、JavaScriptファイルを呼び出す。

Views/Home/Index.html
  (上略)
  <div class="container">
    <div class="chat-container">
        <div id="ChatArea" class="chat-area">
-           <div class="chat-bubble received">
-               <span>受信メッセージ1</span>
-           </div>
-           <div class="chat-bubble sent">
-               <span>送信メッセージ1</span>
-           </div>
-           <div class="chat-bubble received">
-               <span>受信メッセージ2</span>
-           </div>
        </div>
        <div class="input-group form-area">
        (中略)
        </div>
    </div>
</div>

+ <script src="~/js/signalr/dist/browser/signalr.js"></script>@* signalrライブラリ *@
+ <script src="~/js/SimpleChat.js"></script>@* 自作したjsファイル *@

動作確認

Aさんの表示

image6.png

Bさんの表示

image7.png

参考記事

ASP.NET Core SignalR の概要 - Microsoft Learn
https://learn.microsoft.com/ja-jp/aspnet/core/signalr/introduction?view=aspnetcore-8.0

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?