2

I'm trying to do a basic HTTP Post to an ASP.NET Core back end.

Angular:

var parms = {
    userRoles: ['User', 'Worker'],
    email: '[email protected]'
};

this.http.post('/UserRole/SaveUserRoles', parms)
    .subscribe(result => { });

Controller:

[HttpPost]
public async Task<IActionResult> SaveUserRoles([FromBody]string[] userRoles, string email)
{
    return Ok();
}

My parameters are showing null. I can get this working by creating a complex object C# side, but that's not what I want to do. I don't need an object just for 2 parameters.

What's missing here?

10
  • 1
    I don't need an object just for 2 parameters is a pretty poor reason for not creating a class. For me at least, it's much more readable than using FromBody Commented Jan 8, 2019 at 11:58
  • 1
    AFAIK you can't do what you're trying to do. It would be [FromBody] parms and that object would have the userRoles and email properties. Commented Jan 8, 2019 at 12:00
  • [FromBody] isn't selective - you can't bind to a specific JSON property from the input object like you're trying to do here. [FromBody] will just attempt to bind the input against the type being decorated, which fails in your case as there's no match between an object (the input) and an array (the C# type). Commented Jan 8, 2019 at 12:16
  • 1
    Worrying about class files "cluttering your project" is a very peculiar thing to say IMO. And using classes to wrap API input seems like an eminently sensible thing to do also. But hey ho, each to their own! Commented Jan 8, 2019 at 12:21
  • 2
    The benefit for a class in this case is simply that it works and is how the [FromBody] attribute is designed to be used. Commented Jan 8, 2019 at 13:20

2 Answers 2

8

You have to set proper header for your request like,

var postData = {
        userRoles: ['User', 'Worker'],
        email: '[email protected]'
    };

const headers: HttpHeaders = new  HttpHeaders();
headers.set('Content-Type', 'application/x-www-form-urlencoded');

this.http.post('/UserRole/SaveUserRoles', postData, { headers: headers })
    .subscribe(result => {
});

And for your controller side,

I don't need an object just for 2 parameters.

But this is a good practice to catch all your posted data in the model or c# object.

So here I create a sample class.

class PostData
{
    public string[] userRoles { get; set; }
    public string email { get; set; }
}

[HttpPost]
public async Task<IActionResult> SaveUserRoles([FromBody]PostData postData)
{
    return Ok();
}
Sign up to request clarification or add additional context in comments.

Comments

0

You basically want to consider your POST data as individual parameters. You can send them as "params" which will translate into querystring parameters.

params is a property on the second argument for get and third argument for post on the HttpClient.

var body = null;

var parms = {
    userRoles: ['User', 'Worker'],
    email: '[email protected]'
};

this.http.post('/UserRole/SaveUserRoles', body, {params: parms})
    .subscribe(result => {
    });

You'd want to update your API controller to use the [FromQuery] attribute on the arguments that you want to bind.

[HttpPost]
public async Task<IActionResult> SaveUserRoles([FromQuery]string email, [FromQuery]string[] userRoles)
{
    return Ok();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.