I am dealing with an issue regarding redirecting in server controller in hosted Blazor WebAssembly project.
As an example, I modified default WeatherForecastController to redirect one endpoint to another.
[HttpGet]
public IActionResult Get()
{
return Redirect("WeatherForecast/redirected");
}
[HttpGet("redirected")]
public IEnumerable<WeatherForecast> GetRedirected()
{
// default implementation returning some random WeatherForecasts
}
In the client, there are two implementations of service, which requests said endpoint. First one makes request using regular HttpClient, second with IFlurlClient.
class HttpWeatherForecastClient : IWeatherForecastClient
{
readonly HttpClient httpClient;
// constructor and stuff
public async Task<WeatherForecast[]> GetForecastsAsync()
{
return await httpClient.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast")
?? Array.Empty<WeatherForecast>();
}
}
class FlurlWeatherForecastClient : IWeatherForecastClient
{
readonly IFlurlClient flurlClient;
// constructor and stuff
public async Task<WeatherForecast[]> GetForecastsAsync()
{
var response = await flurlClient.Request("WeatherForecast").GetAsync();
Console.WriteLine($"{response.StatusCode}: {response.ResponseMessage}");
return await response.GetJsonAsync<WeatherForecast[]>()
?? Array.Empty<WeatherForecast>();
}
}
Implementation with HttpClient works fine. Implementation with IFlurClient keep returning response with ReasonPhrase opaqueredirect and StatusCode with value 0.
Is there way to configure IFlurClient to work with redirection?
I tried to implement custom IFlurlClientFactory to modify configuration of IFlurlClient. But I have no idea which option I need to change :(
public class AluPerBaseUrlFlurlClientFactory : PerBaseUrlFlurlClientFactory
{
protected override IFlurlClient Create(Url url)
{
return base
.Create(url)
.WithAutoRedirect(true)
;
}
}
If there is something relevant in documentation, I don't get it.
Example project: https://github.com/GodEmperorOfTime/FlurlWasmRedirect/
Edit - possible solution
Based on the answer provided by Todd Menier, I think a reasonable solution is to register IFlurlClient like this:
builder.Services.AddScoped(services => {
return new HttpClient() { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) };
});
builder.Services.AddScoped<IFlurlClient>(services => {
var httpClient = services.GetRequiredService<HttpClient>();
return new FlurlClient(httpClient);
});
The response you're getting is clearly originating from the client-side
fetch()operation that is ultimately handling the call:I believe at some point WASM is using a custom (and, sadly, internal) handler to somehow ensure that the
fetch()request uses"follow"instead of"manual"for that property.Fortunately there's a simpler option here than trying to reverse-engineer this to work the same way with Flurl: just allow WASM to provide the
HttpClient(as in your example that actually works), but within your service class, create aFlurlClientthat wraps it:Now you can use a
FlurlClientthat defers its work to the injectedHttpClient, which in turn defers its work to that handler we don't have direct access to. Although I've not tried this, my expectation is it should just work, and you shouldn't even have to care about those underlying details.