9

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 
Sascha
  • 2,193
  • 3
  • 24
  • 38
  • Could you provide the call stack for the exception? I might need to see exactly where it threw in order to provide an effective fix/work-around. – Todd Menier Sep 26 '18 at 16:19
  • @ToddMenier Added the call stack. Hope, you find a solution - Blazor and Flurl are both great tools and did fine teamwork in the last months. – Sascha Sep 26 '18 at 20:14

2 Answers2

12

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.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 5
    Yikes. I'm not sure what the point is of maintaining an "API surface" that doesn't function. I would rather "target" and get get errors in the IDE rather than this. I really hope blazor succeeds but stuff like this is concerning. – Richard Collette Sep 27 '18 at 01:32
  • 3
    `BrowserHttpMessageHandler` "now" (https://github.com/aspnet/AspNetCore/commit/ceb1c8e562562b2655622b571d2a9ad083806ad5 ) is named `WebAssemblyHttpMessageHandler`. Still works with the code above when replaced. – springy76 May 20 '19 at 11:41
  • I have applied the above fix, it works on a mocky test, but when I try it on azure function with headers, it did not work. – Robin May 27 '19 at 04:07
1

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;
    }

}
Luke Vo
  • 17,859
  • 21
  • 105
  • 181