LoginSignup
3
0

More than 1 year has passed since last update.

BlazorServerでクライアントのIPアドレスを全ページで共有する

Posted at

クライアントのIPアドレスが必要になった

DBで保存しておきたいとか、ログに出しておきたいとか、それなりにありがちな要求にBlazorServerでどうすればいいのか調べてみた。

BlazorWASMであればさほど悩まなくて済むであろうクライアントのIPアドレス。

BlazorServerはその名の通りサーバーで動作している。
WASMと同じ方法(HttpContext.Connection.RemoteIpAddress)で取得して正しい値が得られるか気になったので先ずは検索。

最初にgithubのaspnetcoreにある以下のissueが目についた。

How to get the remote IP address of the end user in Blazor Server App running on IIS #31920
https://github.com/dotnet/aspnetcore/issues/31920

が、解決していない様子。
続いて、↓も見てみる

Get IP adress blazor server side #37728
https://github.com/dotnet/aspnetcore/issues/37728

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress; を、_Host.cshtmlで処理しておけばルートコンポーネントに渡せるとか書いてある。

そういえば#31920のコメントにあったサンプルにも_Host.cshtmlで似たようなことが書いてあった。

<component type="typeof(App)" param-InitialState="tokens" render-mode="ServerPrerendered" />

現時点で用意してある環境で試してみる

(サーバーを用意していないためほぼ意味がない)
Win11
IIS10
VS2022 .NET6

  • 適当な場所にクラス「UserInfo」を用意しておく。
UserInfo.cs
public class UserInfo
{
    public string UserAgent { get; set; }
    public string IPAddress { get; set; }
}
  • 一応XFFを考慮しつつ、UserInfoをDI
Program.cs
// 略
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
// 略
builder.Services.AddScoped<UserInfo>();
// 略
app.UseForwardedHeaders();
// 略
  • アプリのルートページでリクエスト元のIPアドレスを取得、ルートコンポーネントにパラメーターとして渡す。
_Host.cshtml
@using System.Net
@using Microsoft.AspNetCore.Authentication

@code {
    string ip = HttpContext.Connection?.RemoteIpAddress.ToString();

    // デバッグ実行してるとどうしても::1になる
    if (ip == "::1")
    {
        // TODO:AddressListは環境に依存してしまうので後で考える(ほとんどの環境で[2]なのではないだろうか・・・
        ip = Dns.GetHostEntry(Dns.GetHostName()).AddressList[3].ToString();
    }

    UserInfo _userInfo = new()
    {
        UserAgent = HttpContext.Request.Headers["User-Agent"],
        IPAddress = ip
    };
}

// param-InitialUserInfoの「InitialUserInfo」は後述のApp.razorでパラメーター定義
<component type="typeof(App)" param-InitialUserInfo="_userInfo" render-mode="ServerPrerendered" />
  • ルートコンポーネントにDIされたUserInfoのインスタンスに、ルートページから渡された値を戻すと、子コンポーネントでも同じ値が得られる
App.razor
@inject UserInfo UserInfo

@code {
    // ルートページから渡されるUserInfo
    [Parameter]
    public UserInfo InitialUserInfo { get; set; }

    protected override Task OnInitializedAsync()
    {
        // DIされたUserInfo
        UserInfo.IPAddress = InitialUserInfo.IPAddress;
        UserInfo.UserAgent = InitialUserInfo.UserAgent;

        return base.OnInitializedAsync();
    }
}
  • IPアドレスを使用したいコンポーネントでUserInfoをDIしてもらえるように記述するだけ
Index.razor
@inject UserInfo UserInfo
<p>@UserInfo.UserAgent</p>
<p>@UserInfo.IPAddress</p>

 
こんな感じで取れるはず
image.png

今後

サーバー立てて検証する予定

BlazorServerをUbuntuにデプロイすることも気になっている。

各Razorコンポーネントに @inject を書くことすら億劫なのでちゃんと共有できるように書き直す。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0