By raberana


2016-03-29 15:23:42 8 Comments

How do you properly create a Web API POST of complex object or multiple parameters using Angular2?

I have a service component in Angular2 as seen below:

public signin(inputEmail: string, inputPassword: string): Observable<Response> {
    return this.http.post('/api/account/signin', JSON.stringify({ Email: inputEmail, Password: inputPassword}), this.options);
}

The targeted web api is seen below:

[HttpPost]
[Route("signin")]
public async Task<IActionResult> Signin(string email, string password)
{
       ....
}

This does not work because I need to convert the parameters of the web api into a single POCO class entity with Email and Password properties and put the [FromBody] attribute: Signin([FromBody] Credential credential)

Without using [FromURI] (POST requests with query strings?), how can I make POSTs of multiple parameters or complex objects without converting these parameters into a single POCO class?

Because what if I have numerous Web API POST actions with parameters like (string sensitiveInfo1, string name, int sensitiveInfo2) or (ClassifiedInfo info, string sensitiveInfo1, string sensitiveInfo2), do I need to convert them all to POCO classes and always use [FromBody]?

PS. I was using RestangularJS before and it can posts anything (mulitple primitive objects and complex objects) without my Web API actions having [FromBody] attributes. Will about to investigate how RestangularJS do it.

7 comments

@InderMoga 2016-12-26 10:53:27

I have fixed the issue of Angular2 HTTP Post ASP.NET MVC Web API

let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
let params: URLSearchParams = new URLSearchParams();
params.set('value', '2');

let options = new RequestOptions({
    headers: headers//,
    //search: params
});
let content = new URLSearchParams();
content.set('StudentName', 'Inderjit Singh';
content.set('Mobile', '+919041165398');            
content.set('Nationality', 'Indian');
content.set('AdmissionNo', '6');
content.set('SectionCode', '1');
content.set('Gender', 'Male');
content.set('RegNo', '18585');
content.set('ClassCode', '1');
this.http.post('YOUR_URL', content.toString(), { headers: headers }).map((res: Response) => { console.log("data is==>" + res.text()); }).subscribe();

@InderMoga 2016-12-26 10:55:09

I fixed the issue of Angular2 HTTP Post ASP.NET MVC Web API

@Ranuja Arumapperuma 2016-08-09 07:14:18

If you call Web API 2.2 post method from Angular 2 type script, dont forget to add following header content and parameter object.

let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }); 
 var params = new URLSearchParams();
        params.set('userid', '102');
        params.set('username', 'foo');

 return this._http.post('http://localhost:6579/api/PostUser', params.toString(), { headers: headers }).map(res => res.json());

@Guanxi 2016-04-04 19:48:46

WebAPI does not provide this out of the box. If you try to get understanding of web API bindings, you might be able to figure out why.

I think this article might help.

The generic rules are:

– simple, string-convertible parameters (value types, strings, Guids, DateTimes and so on) are by default read from URI

– complex types are by default read from the body

– collections of simple parameters are by default read from the body too

– you cannot compose a single model based on input from both URI and request body, it has to be one or the other

@kemsky 2016-04-03 23:31:32

Perhaps you should post with options:

{ 
   headers: new Headers({
   'Content-Type': 'application/x-www-form-urlencoded'
   })
}

and encode data like

jQuery.param({user:'bla', password: 'bla'});

@Igor 2016-04-01 12:15:07

Without using [FromURI] (POST requests with query strings?), how can I make POSTs of multiple parameters or complex objects without converting these parameters into a single POCO class?

I know its not what you want to hear but out of the box this is not possible. It is not a limitation of the browser code that is making the request. This means it does not matter if you are using Angular, JQuery, straight JavaScript, or even RestangularJS. This is a limitation (I use that word loosely as I am sure this is by design) of Web API (any version). Here is the documentation on this design: Parameter Binding in ASP.NET Web API by Mike Wasson.

At most one parameter is allowed to read from the message body. So this will not work:

// Caution: Will not work!
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

So the question becomes, what are your options?

Create a model

This is the thing you were trying to avoid but I list it first because this is how Web API was intended to behave. I have not yet heard a compelling reason not to do this. This approach allows you to extend your model easily without having to change the method signature. It also allows for model validation on the model itself. Personally I really like this approach.

public class SignInModel{
    public string Email {get;set;}
    public string Password {get;set;}
}

[HttpPost]
[Route("signin")]
public async Task<IActionResult> Signin(SignInModel signInModel)
{
       // ....
}

I did not repeat your existing JavaScript code because what you have works as is with the above web api code

URL

Again, what you were trying to avoid. This does make what you want possible with the limitation that you have to pass these parameters using the Query string on the URL. The JavaScript would change but the signature you had on the Web API method would not.

public signin(inputEmail: string, inputPassword: string): Observable<Response> {
    return this.http.post('/api/account/signin/?email=inputEmail&password=inputPassword', null, this.options);
}

I did not repeat your existing Web API code because what you have works as is with the above web JavaScript code (by default FromUri is assumed I believe)

Custom Model Binder

See Passing multiple POST parameters to Web API Controller Methods by Rick Strahl. This option allows you to create a custom model binder that could do what you are asking. It is a whole bunch of extra code though for, IMHO, not much benefit. Maybe there are situations where it would be useful although I really cannot think of any off the top of my head.

Dynamic

Finally you could also pass in a dynamic object as the parameter of your Web API. This is essentially the same as receiving the JSON as a string and making your Controller code responsible for the deserialization of content. Again, I believe that this would make your code worse in most situations as you have to implement custom validation and type checks. This answer was proposed previously on SO by Bes Ley. Again, maybe there are situations where it would be useful although I really cannot think of any off the top of my head.

@Marcus Höglund 2016-04-07 07:28:27

This is on spot. Regardless of which javascript framework your using they all uses the same protocol (http) which has its rules and limitations.

@Vivek Singh 2016-04-01 11:06:31

Try this, passing a complex class object into a single data parameter.

var SearchQuery = function () {
    this.Alphabet = null;
    this.Search = false;
    this.Keyword = null;
    this.RegionList = null;
};
var para = new SearchQuery();
{ data: JSON.stringify(para) } - Post Data

you can receive it using a JObject in your API controller and deserialize it as according to your classes.

@KnowHoper 2016-03-30 00:50:16

WebApi will be able to deserialize your Credential object provided the JSON object has the same field names (I am not sure about case so you may be right here). You seem to be missing the headers from the post call in your Angular2 component.

Can you check the Content-Type using Chrome Debugger or Fiddler? It should be application/json.

@raberana 2016-03-30 00:51:54

i added the header on the options parameter. my problem is if your post parameters are only three strings, should you still convert them into a single object always?

@KnowHoper 2016-03-30 01:06:59

Query strings on posts are usually there to designate how the posted Body should be dealt with. If you are persisting anything on the server, or mutating anything, use the body and a poco. I would use multiple lightweight pocos, this is considered good design. ServiceStack for instance actually maps routes to Pocos. github.com/ServiceStack/ServiceStack/wiki/Routing Does that help?

@raberana 2016-03-30 01:17:36

kinda. but i have seen some other 3rd party js framework that can post to web apis that have multiple complex parameters without using [FromBody] (eg restangular)

Related Questions

Sponsored Content

11 Answered Questions

25 Answered Questions

[SOLVED] ASP.NET Web Site or ASP.NET Web Application?

29 Answered Questions

[SOLVED] How do I get ASP.NET Web API to return JSON instead of XML using Chrome?

8 Answered Questions

[SOLVED] Compile Views in ASP.NET MVC

2 Answered Questions

[SOLVED] ASP.NET Web API - how to pass unknown number of form-encoded POST values

  • 2018-01-12 06:30:59
  • user1451111
  • 65 View
  • 1 Score
  • 2 Answer
  • Tags:   asp.net-web-api

4 Answered Questions

1 Answered Questions

1 Answered Questions

[SOLVED] Simple post to Web Api

Sponsored Content