WebPushをBlazor WASMに送ろう
WebPushを送る案件に出会いました。WebPushに関しJavascriptでの文献は色々ありますが、Blazor + .NETでの実装は見かけることがありませんでしたので、JavascriptをBlazorに変換してみました。
環境
.NET8
Blazor WASM
ソース
上記のコードに後述するPublicKey、PrivateKeyを設定することで試すことが出来ます。
PublicKey、PrivateKeyの作成
web-pushコマンドがインストールされていない場合はPowerShellなどでインストールします
npm install web-push -g
PublicKey、PrivateKeyを生成
web-push generate-vapid-keys
生成されたPublicKey(PublicKey),PrivateKey(PrivateKey)を大切に保管してください(GithubなどにもPushしないでください)
=======================================
Public Key:
BCrj9mDVHUW7Lw5e1v4OnusRY6A4Z02pwl5nfTex0YjH--o9pUsYHqlAewyWzSysFkq0-EIXDZLs42diK10sKOM
Private Key:
JMHs03rsWmF-adpMCz1ocGOQ5YanmdsiyekkQFI9aAc
=======================================
組み込み
Server
WebAPIを作成しWebPush.Serverを参照設定
Program.csに
builder.Services.AddWebPush(config =>
{
config.PublicKey = "{{PublicKey}}";
config.PrivateKey = "{{PrivateKey}}";
});
本来は環境変数から取得してください
新たにControllerを追加(WebPushController.cs)
using BlazorWebPush.Shared;
using Microsoft.AspNetCore.Mvc;
using PushService.Server;
namespace BlazorTest.Server.Controllers;
[Route("api/[controller]")]
[ApiController]
public class WebPushController : ControllerBase
{
private ILogger<WebPushController> _logger { get; init; }
private static List<Subscription> _subscriptions { get; } = new();
private IPushNotification _pushNotification { get; init; }
public WebPushController(ILogger<WebPushController> logger, IPushNotification pushNotification)
{
_logger = logger;
_pushNotification = pushNotification;
}
/// <summary>
/// 購読追加
/// </summary>
/// <param name="subscription"></param>
/// <returns></returns>
[HttpPost("Subscribe")]
public IActionResult Subscribe([FromBody] Subscription subscription)
{
try
{
_logger.LogInformation("Subscribe: {0}", subscription);
_subscriptions.Add(subscription);
}
catch (Exception ex)
{
_logger.LogError(ex, "Subscribe: {0}", subscription);
return BadRequest();
}
return Ok();
}
/// <summary>
/// WebPush通知送信
/// </summary>
/// <returns></returns>
[HttpPost("Send")]
public async Task<IActionResult> SendAsync()
{
try
{
_logger.LogInformation("SendAsync");
foreach (var token in _subscriptions)
{
_logger.LogInformation("SendAsync: {0}", token);
await _pushNotification.PushAsync(token.EndPoint, token.P256dh, token.Auth, "Hello, World!!!!");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "SendAsync");
return BadRequest();
}
return Ok();
}
}
- SubscribeはClientで購読した情報を登録
- Sendは購読一覧にメッセージを送信
Client
WebPush.Clientを参照設定します。
購読管理を行うページに
<WebPushControl @ref="webPushControl" WebPushPublicKey="@webPushPublicKey"></WebPushControl>
{{PublicKey}}は置き換えてください
@code{
private string webPushPublicKey = "{{PublicKey}}";
}
購読処理(サンプルではhome.razorにInitボタンで行っています)
<button @onclick="RequestNotificationSubscriptionAsync">Init</button>
public required WebPushControl webPushControl;
async Task RequestNotificationSubscriptionAsync()
{
var subscription = await webPushControl.RequestNotificationSubscriptionAsync();
// subscriptionがnullじゃない場合Consoleに出力
if (subscription != null)
{
Console.WriteLine(subscription.Url);
Console.WriteLine(subscription.P256dh);
Console.WriteLine(subscription.Auth);
await _webPushUsecase.SubscribeAsync(subscription.Url!, subscription.P256dh!, subscription.Auth!);
}
}
WebPushControlは機能的にはほぼ何もしておらず、WebPushJsInteropを呼んでいます。
WebPushJsInteropはJavascriptのロードやServiceWorker登録を行っています。
public class WebPushJsInterop : IAsyncDisposable
{
private readonly Lazy<Task<IJSObjectReference>> moduleTask;
public WebPushJsInterop(IJSRuntime jsRuntime)
{
moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>(
"import", "./_content/WebPush.Client/web-push.js").AsTask());
}
public async ValueTask ServiceWorkRegister()
{
var module = await moduleTask.Value;
await module.InvokeVoidAsync("serviceWorkRegister", null);
}
public async ValueTask<NotificationSubscription> RequestSubscription(string publicKey)
{
var module = await moduleTask.Value;
return await module.InvokeAsync< NotificationSubscription>("requestSubscription", publicKey);
}
public async ValueTask DisposeAsync()
{
if (moduleTask.IsValueCreated)
{
var module = await moduleTask.Value;
await module.DisposeAsync();
}
}
}
動作確認
上記を組み込み、ClientのInitボタンを押すと
swaggerを開きSendを実行します。
購読を解除する場合は
Edge:設定→Cookieとサイトのアクセス許可→通知を選択し削除してください。
Chrome:設定→プライバシーとセキュリティ→サイトの設定→通知
Edgeの場合ダイアログではなく
アドレスバーにベルマークが出る場合があります。
その場合、ベルマークを押すと許可することが出来ます。
WebPushの内容
WebPushはWebPush.Clientプロジェクトにあるservice-worker.js
self.addEventListener('push', event => {
const payload = event.data.json();
event.waitUntil(
self.registration.showNotification('BLAZOR', {
body: payload.message,
icon: 'icon-192.png',
vibrate: [100, 50, 100],
data: { url: payload.url }
})
);
});
でおこなっていますので、ここをカスタマイズしてください。
参考ページ