はじめに
今回は.NET MAUIでASP.NETのSignalRというリアルタイム接続をサポートする機能を活用したチャットアプリを作っていきます。
ASP.NETのテンプレートからSignalRのサーバーアプリを作成する。
ASP.NETのMVCテンプレートからSignalR用のサーバーアプリを作ります。
使用するフレームワークは.NET6を選択します。(.NET7では私の環境だとエラーが出ました)
program.csには以下のようにSignalRをserviceに追加し、SignalRのハブを追加します。
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
//↓SignalRの追加
builder.Services.AddSignalR();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
//↓デバッグ(開発段階)ではこのメソッドを実行しない
app.UseHttpsRedirection();
}
//↓今回デバッグではHTTPS接続を使用しないため、↑へ移動した
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
//↓MapHuでChatHubを追加、()の中はエンドポイント
app.MapHub<ChatHub>("/chat");
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
次にMapHubで追加させるChatHubクラスを作成する。
using Microsoft.AspNetCore.SignalR;
namespace SignalRdemo
{
//Hubクラスを継承させる
public class ChatHub:Hub
{
//↓SendMessageメソッドの引数はユーザー名とメッセージの内容とする
public async void SendMessage(string user,string message)
{
//↓すべての接続されているクライアントに対して"ReceiveMessage"APIを通して送付する
await Clients.All.SendAsync("ReceiveMessage",user,message);
}
}
}
そしてサーバーアプリをローカルホストではなく、実行したPCのIPアドレスで実行させるためにPropetiesの中に入っているlaunchsetting.jsonを変更する
{
~
"profiles": {
"SignalRdemo": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
//↓localhostを0.0.0.0に変更すると立ち上げたときPCのIPでサーバーを構築できる
"applicationUrl": "https://0.0.0.0:7281;http://0.0.0.0:5103",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
~
}
}
.NET MAUI側でチャット機能の実装
次に.NET MAUI側でチャット機能を実装させる
MainPage.xamlではサンプルのScrollViewを削除し、以下のグリッドを追加する
<Grid RowDefinitions="Auto,7*,Auto,Auto"//←グリッドを4つに分割する。2番目の7*前の領域の7倍という意味
Margin="8">
<!--ユーザー名を記入するエントリー-->
<Entry x:Name="userEntry"
Placeholder="Your Name"/>
<!--チャットを表示する部分ー-->
<ScrollView Grid.Row="1">
<Label x:Name="lblChat"
FontSize="14"
HorizontalOptions="StartAndExpand"/>
</ScrollView>
<!--メッセージを入力するエントリー-->
<Entry x:Name="yourMessage"
Grid.Row="2"
Placeholder="Entry your message"/>
<!--送信ボタン-->
<Button x:Name="SendMessage"
Grid.Row="3"
Text="SendMessage"
HorizontalOptions="FillAndExpand"
Clicked="SendMessage_Clicked"/>
</Grid>
コードビハインドでチャット機能を実装させる
まず、SignalRを使用するため以下のパッケージをNuGetする
Microsoft.AspNetCore.SignalR.Client(←プログラムが.NET6なので.NET6で一番最新のものを追加した)
using Microsoft.AspNetCore.SignalR.Client;//←名前空間を記入
namespace SignalRdemoClient
{
public partial class MainPage : ContentPage
{
//↓SignalRのHubConnectionを読み込む
private readonly HubConnection hubConnection;
public MainPage()
{
InitializeComponent();
//↓自分のPCのIPアドレスとlaunchsetting.jsonで書かれていたhttp://のポート番号を書く
var baseUrl = "http://(自分のPCのIPアドレス(ex:123.45.67.89)):5103";
//SignalRと接続するための準備
hubConnection=new HubConnectionBuilder()
.WithUrl($"{baseUrl}/chat")//←先ほどのURLの後にエンドポイント("/chat")を追加する
.Build();
//↓受け取ったAPIからユーザー名とメッセージを反映する↓ChatHubで作成したAPIと一緒の名前
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
//受け取ったメッセージに改行文字を加えたものをどんどんラベルに追加していく
lblChat.Text += $"{user}:{message}{Environment.NewLine}";
});
Task.Run(() =>
{
//↓SignalRと接続している
Dispatcher.Dispatch(async () =>
{
await hubConnection.StartAsync();
});
});
}
private async void SendMessage_Clicked(object sender, EventArgs e)
{
//↓入力したエントリーの文字を配列にしてサーバー側のSendMessageメソッドに渡す。
await hubConnection.InvokeCoreAsync("SendMessage", args: new[]
{
userEntry.Text,
yourMessage.Text,
});
//↓メッセージを送付したら入力していたメッセージ欄の文字を削除する
yourMessage.Text= String.Empty;
}
}
}
各プラットフォームにはAPIと通信するための権限が必要となります。
Androidでは以下のようにAndroidManifest.xmlに追加します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"
android:usesCleartextTraffic="true">//←applicationにandroid:usesCleartextTrafficを追加してtrueとする
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
デバッグについて
このアプリは最初にサーバーが機能していないと使えないので、サーバーアプリの方から先に立ち上げる必要があります。
ソリューションエクスプローラーからサーバープロジェクトを右クリック、デバッグ→デバッグなしで開始とするとサーバーアプリが立ち上がります。
デバッグモードにならないため、いつも通り、.NET MAUIアプリをデバッグすることができます。
さいごに
この方法でPC内のWindowsアプリ同士でSignalR接続はできたのですが、ローカルAndroidで送信ボタンを押すと以下のようなエラーが出ました。
failed to connect to /{PC側のIPアドレス} (port 5103) from /{Android側のIPアドレス} (port 46710) after 86400000ms: isConnected failed: ETIMEDOUT (Connection timed out)
PC側のファイアーウォールで設定しないといけないかもしれません。
だれかわかる人いたらコメント欄で教えてください。