If you want to access LocalStorage within a DelegatingHandler (to get your access token by example), you will face this error :
« JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method »
The problem is DelegatingHandler are created in an other scope than the circuit scope (and also are cached), and you can’t reach thr circuit scope (which contains the correctly instanciated IJSRuntime).
The trick is to get the IServiceProvider from a scoped CircuitHandler, then we add it to the HttpContext Items (from IHttpContextAccessor, don’t forget to add builder.Services.AddHttpContextAccessor() in Startup)
public class CustomCircuitHandler : CircuitHandler
{
private readonly IServiceProvider _serviceProvider;
private readonly IHttpContextAccessor _contextAccessor;
public CustomCircuitHandler(IServiceProvider serviceProvider, IHttpContextAccessor contextAccessor)
{
_serviceProvider = serviceProvider;
_contextAccessor = contextAccessor;
}
public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
{
// Add the service provider in the Items of the HttpContext (SignalR circuit)
_contextAccessor.HttpContext.Items["CircuitServiceProvider"] = _serviceProvider;
return Task.CompletedTask;
}
}
in Program.cs, register it (Scoped is important here to get the right IServiceProvider, don’t register as Singleton)
// Register it as Scoped
builder.Services.AddScoped<CircuitHandler, CustomCircuitHandler>();
Then in your HttpClient DelegatingHandler:
public class CustomMessageHandler : DelegatingHandler
{
protected readonly IHttpContextAccessor _httpContextAccessor;
public CustomMessageHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var serviceProvider = _httpContextAccessor.HttpContext.Items["CircuitServiceProvider"] as IServiceProvider;
var protectedLocalStorage = serviceProvider.GetService<ProtectedLocalStorage>();
await protectedLocalStorage.SetAsync("hello", "hello local storage");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
Enjoy the access of all the javascript part in your DelegatingHandler