Let's consider a simple blazor app (the standard template) in which i need to have some info about the user which is connected, like:
- SessionID
- IpAddress
- User Identity Name
Usually, I retrieve this informations from HttpContext. In particular, I follow this steps:
- adding in the startup
builder.Services.AddHttpContextAccessor();
- injecting the service in the blazor component
@inject IHttpContextAccessor hca
- printing info
<p> SessionID: @hca.HttpContext?.Connection?.Id </p>
<p> IP: @hca.HttpContext?.Connection?.RemoteIpAddress </p>
<p> User: @hca.HttpContext?.User?.Identity?.Name </p>
This approach still works, also in NET6+ (using NET8), but it's marked as wrong and not recommended in the official guide. (ref 1) (ref 2)
Limitation - NULL HttpContext if LongPolling transport mode
If the transport mode fallback from WebSockets to LongPolling, the HttpContext is null. You can easily test this, forcing LongPolling transport mode in the startup
app.MapBlazorHub(opt =>
{
opt.Transports =
//Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets |
Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
});
This is not new (ref 3).
Note that on some Blazor app I'm forced to use LongPolling since WebSocket are not supported before IIS8 - WinServer2012 and/or blocked by reverse proxy which can't be changed due to corps policy.
Another approach used by someone, also included in the official guide, is capturing the HttpContext "at the startup" and then cascading it.
The recommended approach for passing request state to the Blazor app is through root component parameters during the app's initial rendering
Example here. It seems that with this approach we can also cover the LongPolling case.
Limitation - single non-routable Blazor component instantiated from js
Now let's complicate the case a bit more. I have a NET8 non-blazor web app. I added a single non-routable blazor component instantiated from js
- declaring the component in the startup
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(options =>
{
options.DetailedErrors = true;
options.RootComponents.RegisterForJavaScript<SchedaWeb>(identifier: "scheda-web");
});
- initializing the component from javascript
Blazor.start()
.then(function () {
Blazor.rootComponents.add(_this.renderScheda[0], 'scheda-web', {
id: id,
})
});
In this situation I don't have any "root component": no App, no _Host. Can't apply the above solution. How should I retrieve the HttpContext using LongPolling?
Limitation - HttpContext not reliable
There are many other articles, also in SignalR thread (on which Blazor is based), that mention the non reliability of HttpContext (ref 4)
Based on the official documentation, we should
For scenarios where the HttpContext is required in interactive components, we recommend flowing the data via persistent component state from the server. For more information, see Server-side ASP.NET Core Blazor additional security scenarios.
Can someone explain what is the right way to reliably obtain HttpContext in all edge cases (with LongPolling transport mode, with Blazor integrated in a standard app, without having root App or _Host)?
This works to get the user visiting the page in a Service Side Rendered page. It's not the http request you get, but the user.
Then in the code you do
In a Server Static page, you can use