0

It can do a GET OK, but it just can't do a POST. I have tried all manner of Header combinations. Its to the localhost.

Here is my Reactjs App call

export function saveStaff(data) {
       return fetch(baseUrl, {
    mode: "no-cors",
    method: "POST", 
    headers: {
      Host: "localhost:44370",
      Allow: "GET, POST",
      Accept: "application/json, text/plain",
      "Content-Type": "application/json"
    },
    body: { Name: "tuesday", Department: "tuesday", visitorcount: 0 } // data // JSON.stringify(data)
  })
    .then(handleResponse)
    .catch(handleError);
}

Here are the headers from Postman this works!

POST /api/StaffNamesAPI HTTP/1.1
Host: localhost:44370
Allow: GET, POST
Content-Type: application/json
Accept: application/json, text/plain
User-Agent: PostmanRuntime/7.16.3
Cache-Control: no-cache
Postman-Token: a5b282c7-24e7-46a6-ba22-4f74a31fa9bd,2232ec6c-b3e9-4e29-88e3-abf63675486c
Host: localhost:44370
Accept-Encoding: gzip, deflate
Content-Length: 122
Connection: keep-alive
cache-control: no-cache

 {"Name": "Wednesday TestWithPostman",
    "Department": "Groan",
    "visitorcount": 0 }

Here is the API Controller

    [HttpPost]
    [Consumes("application/json")] //https://github.com/aspnet/AspNetCore/issues/4396
    public async Task<ActionResult<StaffNames>> PostStaffNames(StaffNames staffNames)
    {
        _context.StaffNames.Add(staffNames);
        await _context.SaveChangesAsync();

        return CreatedAtAction("GetStaffNames", new { id = staffNames.Id }, staffNames);
    }

My class is simple at this stage

public class StaffNames
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public int VisitorCount { get; set; }

}

And in my startup.cs I have the CORS set up

  //https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2#ecors
        services.AddCors(options =>
        {
            options.AddPolicy(MyAllowSpecificOrigins,
                builder =>
                {
                    builder.WithOrigins("http://localhost:3000/",
                        "http://www.contoso.com")
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                });
        });

Here is my useCors

 app.UseCors(MyAllowSpecificOrigins);
        //https://stackoverflow.com/questions/52896068/reactasp-net-core-no-access-control-allow-origin-header-is-present-on-the-r
        app.UseCors(builder => builder
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());

Thanks for your help, I have been pondering this for hours!

netchicken
  • 355
  • 2
  • 7
  • 20
  • Hi David, without quotes I get an error Line 40: Parsing error: Unexpected token, expected "," – netchicken Sep 10 '19 at 21:53
  • I guess the cause is a problem with deserializing of posted JSON to `StaffNames` data type. It would be nice to see `StaffNames` class definition to be more certain... – Oleksandr Tyshchenko Sep 10 '19 at 22:27
  • @netchicken I am glad that you have resolved the problem with the solution which I have suggested in my answer.Did you see that?Could you accept the answer if you have no problems? – Ryan Sep 12 '19 at 07:04

2 Answers2

1

If you have two projects, you need to set your mode as cors.And I met the same problem of CORS.Finally, I overcome it by removing the / in your original url like

services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
            builder =>
            {
                //Do not use `http://localhost:3000/`
                builder.WithOrigins("http://localhost:3000",
                    "http://www.contoso.com")
                    .AllowAnyHeader()
                    .AllowAnyMethod();
            });
    });

Configure method:
app.UseCors(MyAllowSpecificOrigins);

React:

return fetch(baseUrl, {
        mode: "cors",
        method: "POST",
        headers: {
            Host: "localhost:44370",
            Allow: "GET, POST",
            Accept: "application/json, text/plain",
            "Content-Type": "application/json"
        },
        body: JSON.stringify({ Name: "tuesday", Department: "tuesday", visitorcount: 0 })
    })
Ryan
  • 19,118
  • 10
  • 37
  • 53
0

For some reason using no-cors mode prevents setting Content-Type header value to application/json and it's set to test/plain by default which causes the issue. After some research I've found out that mode cors works fine for your case, so first of all consider learning more about all those modes and choose most suitable one for you.

And, secondly, you need to add [FromBody] attribute you action parameter in order to allow model binder parse json body on server side. On client side you need to serialize object to json before sending it since fetch doesn't do this for you. The minimal working code looks like this

Controller

[HttpPost]
[Consumes("application/json")]
public IActionResult PostStaffNames([FromBody]StaffNames staffNames)

React

export function saveStaff(data) {
    return fetch(baseUrl, {
        mode: "cors",
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
    })
    .then(handleResponse)
    .catch(handleError);
}
Alexander
  • 9,104
  • 1
  • 17
  • 41
  • Hi Alexander, thanks for your ideas, cors, just give me the error Access to fetch at 'https://localhost:44370/api/StaffNamesAPI' from origin 'http://localhost:3000' has been blocked by CORS policy: I included my class, and my Cors setup in the Startup.cs file in my question as well. – netchicken Sep 11 '19 at 00:08
  • @netchicken You are probably missing `UseCors` call in `Startup.Configure` method – Alexander Sep 11 '19 at 11:10
  • Hi Alexander, I am using it :-) I have added to my original post with code from the startup.cs. I can call a GET from my website OK, its just the POST that doesn't work. – netchicken Sep 11 '19 at 21:24
  • 1
    @netchicken Remove the trailing slash. It should be `http://localhost:3000` instead of `http://localhost:3000/` – Alexander Sep 11 '19 at 22:07
  • Gaaarrr!!!! I hate training slashes :-) Thanks so much for saving me from such an annoying error :-) – netchicken Sep 12 '19 at 02:32
  • @netchicken No problem:) Please, consider accepting the answer if it was helpful – Alexander Sep 12 '19 at 11:12