简体   繁体   English

Angular2 HTTP Post ASP.NET MVC Web API

[英]Angular2 HTTP Post ASP.NET MVC Web API

How do you properly create a Web API POST of complex object or multiple parameters using Angular2? 如何使用Angular2正确创建复杂对象或多个参数的Web API POST?

I have a service component in Angular2 as seen below: 我在Angular2中有一个服务组件,如下所示:

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: 目标Web API如下所示:

[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) 这不起作用,因为我需要将Web api的参数转换为具有Email和Password属性的单个POCO类实体,并放置[FromBody]属性: 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? 不使用[FromURI] (带有查询字符串的POST请求?),如何在不将这些参数转换为单个POCO类的情况下进行多个参数或复杂对象的POST?

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]? 因为如果我有许多带有参数的Web API POST操作,这些操作的参数为(string sensitiveInfo1, string name, int sensitiveInfo2)(ClassifiedInfo info, string sensitiveInfo1, string sensitiveInfo2) ,我需要将它们全部转换为POCO类并始终使用[FromBody ]?

PS. 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. 我以前使用过RestangularJS ,它可以发布任何内容(多个基本对象和复杂对象),而我的Web API操作没有[FromBody]属性。 Will about to investigate how RestangularJS do it. 将要研究RestangularJS如何做到这一点。

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? 不使用[FromURI](带有查询字符串的POST请求?),如何在不将这些参数转换为单个POCO类的情况下进行多个参数或复杂对象的POST?

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. 这意味着无论您使用的是Angular,JQuery,纯JavaScript还是RestangularJS。 This is a limitation ( I use that word loosely as I am sure this is by design ) of Web API (any version). 这是Web API(任何版本)的局限性( 我确信这是设计使然,所以我会宽松地使用该词 )。 Here is the documentation on this design: Parameter Binding in ASP.NET Web API by Mike Wasson. 这是有关此设计的文档:Mike Wasson 在ASP.NET Web API中进行参数绑定

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. 这是您想要避免的事情,但我首先列出了它,因为这是Web API的预期行为。 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 我没有重复您现有的JavaScript代码,因为您使用的代码与上述网络api代码相同

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. 这确实使您可以实现所需的限制,因为您必须使用URL上的查询字符串来传递这些参数。 The JavaScript would change but the signature you had on the Web API method would not. JavaScript会更改,但您在Web API方法上拥有的签名不会更改。

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) 我没有重复您现有的Web API代码,因为您使用的内容与上述Web JavaScript代码一样(默认情况下,我认为FromUri是假定的)

Custom Model Binder 定制模型活页夹

See Passing multiple POST parameters to Web API Controller Methods by Rick Strahl. 请参阅Rick Strahl的将多个POST参数传递给Web API控制器方法 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. 最后,您还可以传入dynamic对象作为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. 这本质上与以字符串形式接收JSON并使控制器代码负责反序列化内容相同。 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 . 此答案先前由Bes Ley在SO上提出。 Again, maybe there are situations where it would be useful although I really cannot think of any off the top of my head. 再说一次,也许在某些情况下它会很有用,尽管我真的想不起任何事情。

If you call Web API 2.2 post method from Angular 2 type script, dont forget to add following header content and parameter object. 如果您从Angular 2类型脚本调用Web API 2.2 post方法,请不要忘记添加以下标头内容和参数对象。

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());

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'});

WebAPI does not provide this out of the box. WebAPI不提供此功能。 If you try to get understanding of web API bindings, you might be able to figure out why. 如果您尝试了解Web API绑定,则可以找出原因。

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 –默认情况下,简单的,可字符串转换的参数(值类型,字符串,Guid,DateTimes等)是从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 –您不能基于URI和请求正文的输入来组合一个模型,它必须是一个模型或另一个模型

I have fixed the issue of Angular2 HTTP Post ASP.NET MVC Web API 我已经解决了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();

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). 如果JSON对象具有相同的字段名,WebApi将能够反序列化您的Credential对象(我不确定大小写,因此您可能就在这里)。 You seem to be missing the headers from the post call in your Angular2 component. 您似乎在Angular2组件的post调用中缺少标题。

Can you check the Content-Type using Chrome Debugger or Fiddler? 您可以使用Chrome调试器或Fiddler检查Content-Type吗? It should be application/json. 它应该是application / json。

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. 您可以在API控制器中使用JObject接收它,并根据您的类对其进行反序列化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM