ASP.NET Core X SignalR でリアルタイムチャットを10分で作ってみた

ASP.NET Core 2.1 x SignalR でライブチャットを10分で構築。ライブチャットの仕組みを、ここで解説しながら構築していきます。実際のコードは、Gitからダウロードして利用していただく事も可能です。

ASP.NET Core X SignalR でリアルタイムチャットを10分で作ってみた 's Header Image

07/18/2018

こんにちは、所長の下田です。「作ってみた」シリーズ第1弾です。
なんでも作ってみないと理解が深まらない、ということで、
色々サクッと作っていきます。

それでは、ライブチャットを構築していきます。

SingalRとは

簡単に言うと、ウェブサーバーとリアルタイムにやり取りするための仕組みをまとめたライブラリーです。

通常のウェブサーバーはリクエストに対して応える(レスポンス)という形式になっています。そのためクライアント側が常に能動的にサーバーに最新情報を問合せる必要があります。頻繁に更新されるデータであれば、いつもクライアントがサーバー側に最新状態のデータを取りに行く必要があり、サーバー側からしたら勘弁してくれよ・・という感じです。

そこで、SignalRではサーバー側からクライアント側に情報をプッシュすることによって無駄なリクエストを削減し、リアルタイムな体験を演出していきます。

下準備

まずはベースとなるプロジェクトを新しく作成します。ASP.NET Core Web アプリケーションを選択します。

次は、.NET Core x ASP.NET Core 2.1を選択し、Web アプリケーション(モデルビューコントローラー)を選択します。

次に、.NET Core x ASP.NET Core 2.1を選択して、WebApplicationSignalRDemo1を選択します。

コントローラー、モデル、ビューなどが自動生成されます。NuGetの中にコアのライブラリーであるMicrosoft.AspNetCore.Appがあることを確認します。

Microsoft.AspNetCore.Appの中にはすでに、Microsoft.AspNetCore.SignalRライブラリーが内包されていますので、とくにNuGetなどで個別にライブラリーを管理する必要はありません。

ただ、クライアント側で利用するJavascriptは必要になりますので、パッケージマネージャーコンソールから下記のコマンドを使って入手します。 npmは事前にインストールされている必要があります。(こちらよりインストール: https://nodejs.org/en/


npm init -y
npm install @aspnet/signalr

ダウンロードしたjsファイルは /wwwroot/lib/sinalr/signalr.js に格納します。

コーディング

さて、下準備が終わったところでコードを書いていきます。 まずはクライアント側とサーバー側のパイプとなるハブクラスを作ります。 プロジェクト傘下にHubsというフォルダーを作成し、その中にChatHub.csというクラスを作成します。


using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;

namespace WebApplicationSignalRDemo1.Hubs
{
    /// This is a hub class
    public class ChatHub : Hub
    {
        /// handle sending messages
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

次に、プロジェクトがSignalRを使うように設定をします。 Startup.ConfigureServices メソッドを編集です。ここにあるservices.AddSignalRでDIにて使えるようにします。


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WebApplicationSignalRDemo1.Hubs;

namespace WebApplicationSignalRDemo1
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            // Add SignalR
            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseCors("CorsPolicy");

            // Route to hub
            app.UseSignalR(routes =>
            {
                routes.MapHub("/chatHub");
            });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

あと少しで完成です。次はクライアント側のJavascript。wwwroot/js フォルダーの中に新たに chat.js を作成します。


"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

connection.on("ReceiveMessage", function (user, message) {
    var msg = message.replace(/&/g, "&").replace(//g, ">");
    var encodedMsg = user + " の発言: " + msg;
    var li = document.createElement("li");
    li.textContent = encodedMsg;
    document.getElementById("messagesList").appendChild(li);
});

connection.start().catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

最後にビューを作成します。 /Views/Home/Index.cshtml を作成します。


@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>リアルタイムチャット</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" integrity="sha384-Smlep5jCw/wG7hdkwQ/Z5nLIefveQRIY9nfy6xoR1uRYBtpZgI6339F5dgvm/e9B" crossorigin="anonymous">
</head>
<body>
    <div class="container py-5">
        <div class="row">
            <div class="col-sm-6 mb-3">
                <!--Input-->
                <div class="form-group">
                    <label for="messageInput">メッセージ</label>
                    <input type="text" id="messageInput" class="form-control" placeholder="メッセージをここに入力にしてください">
                </div>
                <div class="form-group">
                    <label for="userInput">名前</label>
                    <input type="text" class="form-control" id="userInput" placeholder="あなたのお名前を入力してください">
                </div>
                <button type="button" id="sendButton" class="btn btn-primary">送信</button>
            </div>
            <div class="col-sm-6 mb-3">
                <!--Output-->
                <ul id="messagesList"></ul>
            </div>
        </div>
    </div>
    <script src="~/lib/signalr/signalr.js"></script>
    <script src="~/js/site.js"></script>
    <script src="~/js/chat.js"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js" integrity="sha384-o+RDsa0aLu++PJvFqy8fFScvbHFLtbvScb8AjopnFD+iEQ7wo/CG0xlczd+2O/em" crossorigin="anonymous"></script>
</body>
</html>

動かしてみる

早速動かしてみます。EdgeとChrome2つのブラザーを開き、ローカル環境である https://localhost:44340/ と入力し、片方のブラザーでメッセージを入力してみます。左のブラウザーで送信ボタンを押したと同時に右のブラザーでも反映されました。

このライブラリーを使った応用技術はたくさんありますので、色々取組んでみてください。 今回作成したサンプルコードをこちらで公開しておきます。https://github.com/TRANSCOSMOSRND/SignalR-Demo1-ASP.NET-Core-2.1/

おまけ

せっかく作ったので、ライブ環境でも使えるようにリリースしてみましょう。プロジェクトを右クリックし、発行ボタンをクリックします。

新規作成を選択して、右下の発行をクリック。

新しいウェブアプリケーションサーバーを選択して作成をおえたら完了! こちらでライブ環境を利用できます。 

こちらのURLでライブをご利用ください。 http://webapplicationsignalrdemo120180718024018.azurewebsites.net/

トランスコスモス技術研究所では、各業種のデジタルトランスフォーメーションを推進するため、ウェブサービス開発エンジニアを随時募集しています。
C#を使って一緒に開発してみたいな!
という方はぜひご応募ください。
インターナショナルな仲間がお待ちしております。


作ってみた チャット SignaIR Core 2.1
シェア シェア
下田 昌平
株式会社トランスコスモス技術研究所、代表取締役兼最高技術責任者、トランスコスモス株式会社執行役員。アメリカ・日本・中国企業の経営を得て2017年にトランスコスモスに入社。米大学にて数学・統計学専攻から開発歴20年、C、C#、データ設計・管理を中心に多くの開発案件を完遂。

お問合せ