SQL

【開発してみた】ASP.NET Core X SignalR でリアルタイムチャットを10分で開発してみた

「開発してみた」シリーズ第1弾です。

なんでも作ってみないと理解が深まらない、ということで、色々サクッと作っていきます。

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


目次[非表示]

  1. 1.SignalRとは
  2. 2.構築の下準備
  3. 3.コーディング
  4. 4.動かしてみる
  5. 5.おまけ


SignalRとは


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

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

そこで、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/


おまけ


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


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



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




ECXサイト編集部
ECXサイト編集部
トランスコスモスのECX本部が運営するサービスサイト「ECX」編集部です。コーディング、WEBデザイン、SEM、UI改善などの実務経験豊富なメンバーで執筆・運営・管理をしております。

Shopify(ショッピファイ)ストア構築・制作、
運用代行についてお問い合わせ

Shopifyアプリ解説・紹介記事

ShopifyのECサイト制作ならトランスコスモス

トランスコスモスは、Shopifyを使ったECサイト制作から、調査分析・戦略立案、WEB広告(SEM)、ECサイト制作、お客様サポート、受発注、フルフィルメントまで業務設計・運用代行いたします。

トランスコスモスのEC全領域を網羅するサービス


セミナー動画視聴


EC関連サービス

数字で見るトランスコスモスの強み

数字で見るトランスコスモスの強み
お気軽にお問い合わせください

Shopify(ショッピファイ)
ECストア構築・運用代行

実績豊富なトランスコスモスへぜひご相談ください
ECソリューションをお届けするサービスサイト

トランスコスモス株式会社
CX事業統括
ECX本部

〒150-0011
東京都渋谷区東1-2-20
渋谷ファーストタワー
050-1751-7700(代表)

経済産業省が定める「DX認定事業者」
トランスコスモスは経済産業省が定める「DX認定事業者」
トランスプラス
トランスコスモスの全社的な情報を発信するオウンドメディア
cotra
コンタクト/コールセンターに携わる方への情報サイト
法人向けメタバース情報メディア
「メタバース情報局 by transcosmos」
トランスコスモス株式会社
企業サイト(コーポレートHP)
Global Digital Transformation Partner.
お客様企業のデジタル・トランスフォーメーション・パートナー。
shopify構築・制作・運用