9
votes

I'm getting a 'TypeError: Failed to fetch' error when trying to call my AspNetCore Restful API from Blazor Wasm. I can call it from Postman, and it works fine.

My Environment: Microsoft Visual Studio Community 2019 Preview Version 16.6.0 Preview 3.0

Client: Blazor Wasm Service (dotnetstandard 2.1)

  • AspNet.WebApi.Client 5.2.7
  • AspNetCore..WebAssembly 3.2 preview 4.2
  • System.Net.Http.Json 3.2 preview 5.2

Important Usings:

using Microsoft.AspNetCore.JsonPatch;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;

Parent namespace and class omitted _httpClient is injected into parent class

public async Task<MyDto> UpdatePartialAsync(Guid primaryId, ObjectForUpdateDto objectForUpdateDto)
{

    MyDto dtoFromApi = null;

    var patchDoc = new JsonPatchDocument<ObjectForUpdateDto>()
        .Replace(o => o.Name, objectForUpdateDto.Name)
        .Replace(o => o.Description, objectForUpdateDto.Description)

    var uri = $"MyUri/myResources/{primaryId}";

    try
    {
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var serializedPatchDoc = JsonConvert.SerializeObject(patchDoc);
        var json = new StringContent(serializedPatchDoc, Encoding.UTF8, "application/json-patch+json");

        var response = await _httpClient.PatchAsync(uri, json);
        return await response.Content.ReadAsAsync<MyDto>();
    }
    catch (Exception)
    {   
        throw; //throws 'TypeError: Failed to fetch'
    }

    return dtoFromApi;
}

My API (.Net 5.0, also tried .Net Core 3.1):

[HttpPatch]
[Route("{primaryId}")]
public ActionResult UpsertPartial([FromRoute]Guid primaryId, [FromBody] JsonPatchDocument<ObjectForUpdateDto> objectForUpdateDto)
{
    //client call never makes it here
    return NoContent();
}
3

3 Answers

5
votes

What a misleading error message. It was a CORS issue.

The fix was adding "PATCH" to my CORS policy in my API's startup.cs ConfigureServices method (which previously was "GET, DELETE, PUT, POST, OPTIONS").

services.AddCors(options =>
{
    options.AddPolicy(CorsAllowAll,
    builder =>
    {
            builder.WithOrigins(Constants.ApiClientCors).AllowAnyHeader().WithMethods("GET, PATCH, DELETE, PUT, POST, OPTIONS");
    });  
});
2
votes

@inliner49er, I wish that I could add a comment to clarify what you responded, since your answer is correct, but I don't have enough reputation points. Therefore, I'll post my tweaks to your answer as a separate answer.

You nailed it, the CORS issue fixed my program also. The only part of your code that didn't make sense was the reference that you have to a class called Constants. I am in the process of trying to complete the PluralSight tutorial, and because I'm working entirely internally, I can safely replace your code with the following:

services.AddCors(options =>
{
    options.AddPolicy("PolicyName", builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
});

I am super new to all of this, literally hours into the process of learning about it, so there is a buttload that I don't understand. I just thought I'd post this to help anyone who might have similar questions to what I had.

2
votes

You can also try adding these lines directly to the Configure method of the Startup class:

//ENABLE CORS
app.UseCors(x => x
   .AllowAnyMethod()
   .AllowAnyHeader()
   .SetIsOriginAllowed(origin => true) // allow any origin  
   .AllowCredentials());               // allow credentials