Reputation: 2538
Is anyone able to capture for component use, a client IP address, in Blazor 9 hosted in Azure?
This question has been asked for several years, but for previous Blazor versions; IMHO, there isn't a satisfactory answer that applies to .NET 9 & Blazor. It can't be this difficult.
When running a Blazor interactive server app in Azure, with rendermode
of InteractiveServer
, it is very difficult to capture the client's IP address.
The first time OnInitialize
is hit, there is a valid HttpContext
. The second time (render), the HttpContext
is null. A HttpContext
value captured such as remoteipaddress
, even in a scoped service (which is really a singleton in interactive server mode), is gone. HttpContext
is missing. Scoped services are reinitialized.
I disabled prerendering, but then the only call to OnInitialized
, the HttpContext
is null. I get that HttpContext
is shady in interactive mode.
Things run stellar in localhost, but once deployed to Azure, the second OnInitialize
everything is reinitalized.
Upvotes: 0
Views: 182
Reputation: 21
I get the remote IP address like this. This works for me on Azure, however we're just on .NET8 for now. I can't see any reason this will not work in .NET9?
In App.razor, I get the IP address, and forward it to the "Routes.razor" component.
@{
string? remoteIpAddress = null;
// Get IP
httpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedFor);
if (forwardedFor.Count > 0)
{
remoteIpAddress = forwardedFor[0];
}
if (remoteIpAddress is null)
{
remoteIpAddress = httpContext.Connection.RemoteIpAddress?.ToString();
}
}
<Routes RemoteIpAddress="@remoteIpAddress" @rendermode="@(new InteractiveServerRenderMode(false))" />
And in Routes.razor, I store it in the authentication provider.
[Parameter] public string? RemoteIpAddress { get; set; }
protected override void OnInitialized()
{
try
{
var ip = System.Net.IPEndPoint.Parse(RemoteIpAddress ?? "").Address;
AuthProvider.IpAddress = ip;
}
catch (Exception)
{
// TODO log
}
}
Hope this helps and works for you!
Upvotes: 0
Reputation: 5703
1- In Blazor Server mode, in enabled prerendering HttpContext
will be unavailable during the initial lifecycle.
2- in Azure, since client IP is behind a load balancer or app gateway, X-Forwarded-For
header field is best way to get the actual client IP.
Here's a solution(not sure if it 100% work in all situations)
Create a middleware to capture the client IP address
public class ClientIpAddressMiddleware
{
private RequestDelegate _next;
public ClientIpAddressMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var _clientIp = context.Connection.RemoteIpAddress?.ToString();
if (context.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedFor))
{
_clientIp = forwardedFor.FirstOrDefault()?.Split(',')[0].Trim();
}
context.Items["ClientIp"] = _clientIp ;
await _next(context);
}
}
Then register the middleware before other middleware:
app.UseMiddleware<ClientIpMiddleware>();
More details: https://learn.microsoft.com/en-us/azure/application-gateway/how-application-gateway-works https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-7.0
Upvotes: 0