Comment créer correctement une API Web POST d'objet complexe ou plusieurs paramètres en utilisant Angular2?
J'ai un composant de service dans Angular2, comme indiqué ci-dessous:
public signin(inputEmail: string, inputPassword: string): Observable<Response> {
return this.http.post('/api/account/signin', JSON.stringify({ Email: inputEmail, Password: inputPassword}), this.options);
}
L'API Web ciblée est visible ci-dessous:
[HttpPost]
[Route("signin")]
public async Task<IActionResult> Signin(string email, string password)
{
....
}
Cela ne fonctionne pas car je dois convertir les paramètres de l'API Web en une seule entité de classe POCO avec les propriétés Email et Password et mettre l'attribut [FromBody]: Signin([FromBody] Credential credential)
Sans utiliser [FromURI]
(requêtes POST avec des chaînes de requête?), Comment puis-je effectuer des POST de plusieurs paramètres ou objets complexes sans convertir ces paramètres en une seule classe POCO?
Parce que si j'ai plusieurs actions de l'API Web POST avec des paramètres tels que (string sensitiveInfo1, string name, int sensitiveInfo2)
ou (ClassifiedInfo info, string sensitiveInfo1, string sensitiveInfo2)
, dois-je toutes les convertir en classes POCO et toujours utiliser [FromBody]?
PS . J'utilisais RestangularJS
auparavant et il peut publier n'importe quoi (objets primitifs multiples et objets complexes) sans que mes actions de l'API Web aient les attributs [FromBody]
. Sera sur le point d’enquêter sur la façon dont RestangularJS le fait.
Sans utiliser [FromURI] (requêtes POST avec des chaînes de requête?), Comment puis-je effectuer des POST de plusieurs paramètres ou d'objets complexes sans convertir ces paramètres en une seule classe POCO?
Je sais que ce n'est pas ce que vous voulez entendre, mais ce n'est pas possible. Ce n'est pas une limitation du code du navigateur qui fait la demande. Cela signifie que peu importe que vous utilisiez Angular, JQuery, JavaScript ou encore RestangularJS. C’est une limitation (j’utilise ce mot vaguement car je suis sûr que c’est par nature] de l’API Web (n’importe quelle version). Voici la documentation sur cette conception: Liaison de paramètres dans l'API Web ASP.NET par Mike Wasson.
Au plus un paramètre est autorisé à lire dans le corps du message. Donc cela ne fonctionnera pas:
// Caution: Will not work! public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }
Alors la question devient, quelles sont vos options?
C’est ce que vous tentiez d’éviter, mais j’énumère cette liste en premier, car c’était comme cela que l’API Web devait se comporter. Je n'ai pas encore entendu de raison impérieuse de ne pas faire cela. Cette approche vous permet d'étendre facilement votre modèle sans avoir à changer la signature de la méthode. Cela permet également la validation du modèle sur le modèle lui-même. Personnellement j'aime beaucoup cette approche.
public class SignInModel{
public string Email {get;set;}
public string Password {get;set;}
}
[HttpPost]
[Route("signin")]
public async Task<IActionResult> Signin(SignInModel signInModel)
{
// ....
}
Je n'ai pas répété votre code JavaScript existant car ce que vous avez fonctionne tel quel avec le code de l'API Web ci-dessus
Encore une fois, ce que vous essayiez d'éviter. Cela rend ce que vous voulez possible avec la limitation que vous devez transmettre ces paramètres à l'aide de la chaîne de requête sur l'URL. Le JavaScript changerait, mais pas la signature que vous aviez sur la méthode de l'API Web.
public signin(inputEmail: string, inputPassword: string): Observable<Response> {
return this.http.post('/api/account/signin/?email=inputEmail&password=inputPassword', null, this.options);
}
Je n'ai pas répété votre code Web API existant car ce que vous avez fonctionne tel quel avec le code JavaScript Web ci-dessus (par défaut, FromUri est supposé, je crois)
Voir Passage de plusieurs paramètres POST à Web API Controller Methods par Rick Strahl. Cette option vous permet de créer un classeur de modèle personnalisé pouvant faire ce que vous demandez. C’est tout un tas de code supplémentaire, mais pour mon humble avis, il n’ya pas beaucoup d’avantages. Peut-être y a-t-il des situations où cela serait utile, même si je ne peux vraiment en penser à personne.
Enfin, vous pouvez également transmettre un objet dynamic
en tant que paramètre de votre API Web. Cela revient essentiellement à recevoir le JSON sous forme de chaîne et à rendre le code de votre contrôleur responsable de la désérialisation du contenu. Encore une fois, je pense que cela aggraverait votre code dans la plupart des situations, car vous devez implémenter une validation personnalisée et des contrôles de type. Cette réponse a été proposée précédemment sur SO par Bes Ley . Encore une fois, il y a peut-être des cas où cela serait utile, bien que je ne puisse vraiment en penser à personne.
Si vous appelez la méthode post Web API 2.2 à partir d'un script de type Angular 2, n'oubliez pas d'ajouter le contenu d'en-tête et l'objet de paramètre suivants.
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());
Peut-être devriez-vous poster avec des options:
{
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
}
et encoder des données comme
jQuery.param({user:'bla', password: 'bla'});
WebAPI ne fournit pas cela immédiatement. Si vous essayez de comprendre les liaisons API Web, vous pourrez peut-être comprendre pourquoi.
Je pense cet article pourrait aider.
Les règles génériques sont:
- les paramètres simples convertibles en chaînes (types de valeur, chaînes, Guids, DateTimes, etc.) sont lus par défaut à partir de l'URI
- les types complexes sont lus par défaut à partir du corps
- les collections de paramètres simples sont également lues à partir du corps
- vous ne pouvez pas composer un seul modèle en fonction des entrées de l'URI et du corps de la requête, il doit s'agir de l'un ou de l'autre
J'ai corrigé le problème de l'API Web ASP.NET MVC Angular2 HTTP Post
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();
Essayez ceci en passant un objet de classe complexe dans un seul paramètre de données.
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
vous pouvez le recevoir en utilisant un JObject dans votre contrôleur API et le désérialiser selon vos classes.
WebApi pourra désérialiser votre objet Credential à condition que l’objet JSON porte les mêmes noms de champ (je ne suis pas sûr de la casse, vous pouvez donc être ici). Vous semblez manquer les en-têtes de l'appel post dans votre composant Angular2.
Pouvez-vous vérifier le type de contenu en utilisant Chrome Debugger ou Fiddler? Ce devrait être application/json.