Angular2 HTTP Post ASP.NET MVC Web API

Как правильно создать POST веб-API из сложного объекта или нескольких параметров с помощью Angular2?

У меня есть сервисный компонент в Angular2, как показано ниже:

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

Целевая веб-api представлена ​​ниже:

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

Это не работает, потому что мне нужно преобразовать параметры веб-api в один объект класса POCO с атрибутами Email и Password и поместить атрибут [FromBody]: Signin([FromBody] Credential credential)

Без использования [FromURI] (запросы POST с строками запроса?), как я могу создавать POST из нескольких параметров или сложных объектов без преобразования этих параметров в один класс POCO?

Потому что, если у меня есть несколько POST-действий Web API с такими параметрами, как (string sensitiveInfo1, string name, int sensitiveInfo2) или (ClassifiedInfo info, string sensitiveInfo1, string sensitiveInfo2), мне нужно преобразовать их все в классы POCO и всегда использовать [FromBody]?

PS. Я использовал RestangularJS раньше, и он может размещать что-либо (mulitple примитивные объекты и сложные объекты) без моих действий веб-API с атрибутами [FromBody]. Будут собираться исследовать, как RestangularJS это делает.

Ответ 1

Без использования [FromURI] (запросы POST с строками запроса?), как я могу создавать POST из нескольких параметров или сложных объектов без преобразования этих параметров в один класс POCO?

Я знаю, что это не то, что вы хотите услышать, но из коробки это невозможно. Это не является ограничением кода браузера, делающего запрос. Это означает, что неважно, используете ли вы Angular, JQuery, прямой JavaScript или даже RestangularJS. Это ограничение (я использую это слово свободно, так как я уверен, что это по дизайну) веб-API (любая версия). Вот документация по этому проекту: привязка параметров в веб-интерфейсе ASP.NET от Майка Уосона.

Не больше одного параметра разрешено читать из тела сообщения. Так что это не сработает:

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

Итак, вопрос становится, каковы ваши варианты?

Создать модель

Это то, чего вы пытались избежать, но я перечислил его первым, потому что именно так должен был работать веб-API. Я еще не слышал убедительной причины не делать этого. Этот подход позволяет легко расширить вашу модель, не меняя подписи метода. Это также позволяет проверить модель на самой модели. Лично мне очень нравится этот подход.

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

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

Я не повторял ваш существующий код JavaScript, потому что то, что у вас есть, работает с указанным выше веб-кодом api

URL

Опять же, чего вы пытались избежать. Это делает возможным то, что вы хотите, с ограничением, которое вы должны передать этим параметрам, используя строку запроса в URL-адресе. 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);
}

Я не повторял ваш существующий код веб-API, потому что то, что у вас есть, работает с вышеуказанным веб-кодом JavaScript (по умолчанию считается, что FromUri полагается)

Пользовательское связующее устройство

См. Передача нескольких параметров POST методам управления веб-API Риком Стралом. Этот параметр позволяет создать настраиваемое связующее устройство, которое может делать то, что вы просите. Это целая куча дополнительного кода, хотя для ИМХО это не очень выгодно. Может быть, есть ситуации, когда это было бы полезно, хотя я действительно не могу думать ни о чем с моей головы.

Динамический

Наконец, вы также можете передать объект dynamic в качестве параметра вашего веб-API. Это по существу то же самое, что и получение JSON в виде строки и создание вашего кода контроллера, ответственного за десериализацию содержимого. Опять же, я считаю, что это сделает ваш код хуже в большинстве ситуаций, так как вам нужно выполнить выборочные проверки и проверки типов. Этот ответ был предложен ранее на SO Bes Ley. Опять же, может быть, есть ситуации, когда это было бы полезно, хотя я действительно не могу думать ни о чем с моей головы.

Ответ 2

Если вы вызываете почтовый метод Web API 2.2 из Angular 2 type script, не забудьте добавить следующий заголовок и объект параметра.

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

Ответ 3

Возможно, вам следует публиковать сообщения с параметрами:

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

и кодировать данные типа

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

Ответ 4

WebAPI не предоставляет это из коробки. Если вы попытаетесь получить представление о привязках веб-API, вы можете понять, почему.

Я думаю, эта статья может помочь.

Общие правила:

- простые, строко конвертируемые параметры (типы значений, строки, гиды, даты и т.д.) по умолчанию считываются из URI

- сложные типы по умолчанию считываются из тела

- коллекции простых параметров по умолчанию читаются также из тела

- вы не можете составить одну модель на основе ввода как URI, так и тела запроса, она должна быть одной или другой

Ответ 5

Я исправил проблему 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();

Ответ 6

WebApi сможет десериализовать ваш объект Credential, если объект JSON имеет одинаковые имена полей (я не уверен в случае, поэтому вы можете быть здесь). Кажется, что вы отсутствуете в заголовках почтового вызова в своем компоненте Angular2.

Вы можете проверить Content Type с помощью Chrome Debugger или Fiddler? Это должно быть application/json.

Ответ 7

Попробуйте это, передав объект сложного класса в один параметр данных.

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

вы можете получить его с помощью JObject в вашем контроллере API и десериализовать его как в соответствии с вашими классами.