Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor 0.6.0 "wipes" Flurl-compatibility?

After updating Blazor from 0.5.1 (with working Flurl) to 0.6.0, calls via flurl throw an exception:

WASM: [Flurl.Http.FlurlHttpException] Call failed. Cannot invoke method 
because it was wiped. See stack trace for details.

The project creates a HttpClientFactory which gets Blazor's HttpClient for being used by Flurl:

Create FlurlClient with Blazor's HttpClient (http) using HttpClientFactoryForBlazor:

IFlurlClient c = new FlurlClient() { Settings = new Flurl.Http.Configuration.ClientFlurlHttpSettings { HttpClientFactory = new HttpClientFactoryForBlazor(http) }};

Use the FlurlClient (c) for example by via Flurl's extensionmethod "IFlurlRequest.WithClient(c);"

private class HttpClientFactoryForBlazor : Flurl.Http.Configuration.IHttpClientFactory
{
    private readonly HttpClient httpClient;

    public HttpClientFactoryForBlazor(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public virtual HttpClient CreateHttpClient(HttpMessageHandler handler)
    {
        return this.httpClient;
    }
}

So, it seems like this approach does no longer work.

Does anybody know how to make Flurl with Blazor 0.6.0 work?

Call-Stack is:

WASM: [Flurl.Http.FlurlHttpException] Call failed. Cannot invoke method because it was wiped. See stack trace for details. GET http://srv01.servicegrid.eu:4455/API/Status?forceLoadDbs=False blazor.webassembly.js:1:32098
WASM:   at Flurl.Http.FlurlRequest.HandleExceptionAsync (Flurl.Http.HttpCall call, System.Exception ex, System.Threading.CancellationToken token) <0x26945b8 + 0x001c2> in <c38761af4558433f81b1691eb86a1548>:0 blazor.webassembly.js:1:32098
WASM:   at Flurl.Http.FlurlRequest.SendAsync (System.Net.Http.HttpMethod verb, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken, System.Net.Http.HttpCompletionOption completionOption) <0x2665d30 + 0x005e6> in <c38761af4558433f81b1691eb86a1548>:0 blazor.webassembly.js:1:32098
WASM:   at Flurl.Http.FlurlRequest.SendAsync (System.Net.Http.HttpMethod verb, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken, System.Net.Http.HttpCompletionOption completionOption) <0x2665d30 + 0x0079a> in <c38761af4558433f81b1691eb86a1548>:0 blazor.webassembly.js:1:32098
WASM:   at Flurl.Http.HttpResponseMessageExtensions.ReceiveJson[T] (System.Threading.Tasks.Task`1[TResult] response) <0x26a2180 + 0x000d6> in <c38761af4558433f81b1691eb86a1548>:0 blazor.webassembly.js:1:32098
WASM:   at DotNetFabrik.FlurlExtensions.FlurlRequestExtensions.HandleWebApiExceptions[T] (System.Threading.Tasks.Task`1[TResult] task) <0x26a43f8 + 0x000e2> in <8c1e6df9d3f545cd831ff49915df2d85>:0 blazor.webassembly.js:1:32098
WASM:   at DotNetFabrik.FlurlExtensions.FlurlRequestExtensions.HandleWebApiExceptions[T] (System.Threading.Tasks.Task`1[TResult] task) <0x26a43f8 + 0x00264> in <8c1e6df9d3f545cd831ff49915df2d85>:0 blazor.webassembly.js:1:32098
WASM:   at BlazorCoreDMSTools.CommunicationService.CommunicationService.SetTokenAsync (System.String token, System.String database, System.String serverUri) <0x260dc60 + 0x00d9e> in <cb925648b50340888772566fbaeac465>:0 
like image 599
Sascha Avatar asked Sep 26 '18 16:09

Sascha


2 Answers

Just for some background, the Blazor team is in the process of significantly reducing the app's footprint, and resorting to some unusual measures to do so. In a nutshell, they've reduced it by about 20% by "wiping" HttpClientHandler.

wipe means "replace specified method bodies with a single throw instruction". Doing this (instead of actually removing the method entirely) means that the assembly retains a completely standard API surface, and if you try to use one of the wiped methods, you get an easy-to-understand exception stack trace that tells you which wiped method you're trying to call.

This is what you've bumped up against: Blazor is still aware of HttpClientHandler for compilation purposes, but will throw a runtime exception if you (or in this case a compatible library) try to use it.

But HttpClient must wrap some implementation of HttpMessageHandler Blazor has its own: BrowserHttpMessageHandler. And Flurl provides an easy way to swap this in via its HttpClientFactory. But you don't need to pass in an HttpClient instance or implement CreateHttpClient. Instead, inherit from DefaultHttpClientFactory and just override CreateMessageHandler:

private class HttpClientFactoryForBlazor : DefaultHttpClientFactory
{
    public override HttpMessageHandler CreateMessageHandler()
    {
        return new BrowserHttpMessageHandler();
    }
}

I'd also recommend registering this once globally on app startup, rather than every time you create a FlurlClient:

FlurlHttp.Configure(settings =>
{
    settings.HttpClientFactory = new HttpClientFactoryForBlazor();
});

It should also be noted that Blazor is still experimental and that BrowserHttpMessageHandler may be deprecated in a future release, so expect that this could be just a temporary work-around.

like image 54
Todd Menier Avatar answered Oct 08 '22 12:10

Todd Menier


Currently in my 3.0 preview 5, BrowserHttpMessageHandler is not there anymore. Here is my current fix by simply not using any HttpMessageHandler. As far as I am aware, no problem happens to me yet, but I am not sure in all use cases:

class BlazorHttpClientFactory : DefaultHttpClientFactory
{

    public override HttpClient CreateHttpClient(HttpMessageHandler handler)
    {
        return new HttpClient();
    }

    public override HttpMessageHandler CreateMessageHandler()
    {
        return null;
    }

}
like image 35
Luke Vo Avatar answered Oct 08 '22 12:10

Luke Vo