【開発してみた】ASP.NET Core X SignalR でリアルタイムチャットを10分で開発してみた
「開発してみた」シリーズ第1弾です。
なんでも作ってみないと理解が深まらない、ということで、色々サクッと作っていきます。
それでは、ライブチャットを構築していきます。
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/
おまけ
せっかく作ったので、ライブ環境でも使えるようにリリースしてみましょう。プロジェクトを右クリックし、発行ボタンをクリックします。
新規作成を選択して、右下の発行をクリック。
新しいウェブアプリケーションサーバーを選択して作成をおえたら完了! こちらでライブ環境を利用できます。