aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Blazor server DelegatingHandler for http client causing JavaScript error with prerendering disabled

Open McVanS opened this issue 3 years ago • 8 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

Converting an application to Blazor server, I was going to use HttpFactory. Initial code worked as expected. While refactoring the Http client was changed and setup to use a DelegatingHandler with the aim of retrieving token information from protected local storage and adding the authentication header to the client instead of manually adding the header per http client session. A javascript error occurs with in the DelegatingHandler when the protected local storage function is executed despite prerendering being disabled and the action being triggered by a button click which is outside the rendering cycle.

Expected Behavior

With server prerendering disabled there should not be no difference between accessing protected local storage directly or using a DelegatingHandler and then accessing protected local storage when needed. Raising a prerendering error when prerendering is disabled is a little confusing.

Steps To Reproduce

https://github.com/McVanS/DelegatingHandler-problem-project

Exceptions (if any)

[2022-02-21T13:00:45.690Z] Error: System.InvalidOperationException: 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. at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId) at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args) at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args) at Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage.ProtectedBrowserStorage.GetAsync[TValue](String purpose, String key) at DelegatingHandlerProblem.AuthenticationHeaderHandler.GetTokenAsync() in C:\Temp\DelegatingHandler problem project\DelegatingHandlerProblem\AuthenticationHeaderHandler.cs:line 39 at DelegatingHandlerProblem.AuthenticationHeaderHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in C:\Temp\DelegatingHandler problem project\DelegatingHandlerProblem\AuthenticationHeaderHandler.cs:line 15 at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at DelegatingHandlerProblem.Pages.Index.ErrorHttpClient() in C:\Temp\DelegatingHandler problem project\DelegatingHandlerProblem\Pages\Index.razor:line 90 at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

.NET Version

6.0.102

Anything else?

I have seen this issue in the MAUI Blazor section. I have been researching for a few days now with no definitive answer to this problem. If the capability is there to setup a http client like this but Blazor Server for some reason can not utilize such settings surly the documentation would point that out.

Thank you for reading up to here. Your effort is appreciated.

McVanS avatar Feb 21 '22 13:02 McVanS

Thanks for contacting us, @McVanS.

The underlying issue here is the same as https://github.com/dotnet/aspnetcore/issues/25758, which we're planning to come up with a design for in .NET 7.

SteveSandersonMS avatar Feb 21 '22 17:02 SteveSandersonMS

I'll put this on backlog, but it will be linked to https://github.com/dotnet/aspnetcore/issues/25758 and should be resolved at the same time.

SteveSandersonMS avatar Feb 21 '22 17:02 SteveSandersonMS

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Feb 21 '22 17:02 ghost

@SteveSandersonMS should this have been closed?

SimonCropp avatar Mar 22 '22 01:03 SimonCropp

@SimonCropp, no - reopening. Thanks for pointing this out!

SteveSandersonMS avatar Mar 23 '22 11:03 SteveSandersonMS

@SteveSandersonMS thanks

SimonCropp avatar Mar 27 '22 07:03 SimonCropp

Is there a known work around for this available? I am running into this scenario as well when attempting to add a user token in a delegating handler

mreyeros avatar Sep 20 '22 16:09 mreyeros

I was actually able to get around this in my case by moving the code to append the headers into a service class that utilized the HttpClient implementation that called my api. Once the code was moved, I was able to successfully attach the headers to the api requests that I needed to make.

mreyeros avatar Sep 21 '22 16:09 mreyeros

Closing this out since the feature described by https://github.com/dotnet/aspnetcore/issues/30287 should have implemented everything necessary to support this scenario.

MackinnonBuck avatar Dec 05 '23 00:12 MackinnonBuck

Should this be closed? I'm still getting the issue described by the OP in Blazor .Net 8.

A delegating handler that tries to access protected storage, either from a button click or OnAfterRenderAsync, from a page with @rendermode InteractiveServer, gives InvalidOperationException: 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 error message actually contradicts the scenario, insofar as it is performed during the OnAfterRenderAsync.

Should a DelegatingHandler not be used for that scenario? Can you give advice on what should be used instead?

Thanks for your efforts

Alan-Steadman avatar Dec 29 '23 22:12 Alan-Steadman