Je travaille sur un nouveau projet en utilisant un serveur backend WebAPI et j'ai du mal à publier sur le contrôleur à partir d'un site Web réel, bien que Postman n'ait aucun problème à publier sur le contrôleur. J'obtiens une erreur 415, la journalisation de la console du navigateur:
HTTP415: UNSUPPORTED MEDIA TYPE - The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.
(XHR)OPTIONS - http://localhost:5000/api/Users
Alors que le journal de Kestrel est
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 OPTIONS http://localhost:5000/api/Users 0
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 OPTIONS http://localhost:5000/api/Users 0
info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]
Executing HttpStatusCodeResult, setting HTTP status code 415
Microsoft.AspNetCore.Mvc.StatusCodeResult:Information: Executing HttpStatusCodeResult, setting HTTP status code 415
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action SchoolsChat.Controllers.UserContoller.Post (SchoolsChat) in 2.5323ms
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action SchoolsChat.Controllers.UserContoller.Post (SchoolsChat) in 2.5323ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 6.6615ms 415
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 6.6615ms 415
J'essaie de publier le JSON suivant:
{
UserDOB: "2016-12-18",
UserFirstName: "asdf",
UserLastName: "asasdf",
UserName: "asdf",
UserSecret: "asdf"
}
en utilisant cette classe TypeScript
/**
* JsonPost
*/
class JsonPost {
private _response: number;
public get Reponse(): number {
return this._response;
}
constructor(link: string, data: Object) {
let request = new XMLHttpRequest();
request.withCredentials = true;
request.open("POST", APIUri + link, true);
request.setRequestHeader("content-type", "application/json");
request.setRequestHeader("cache-control", "no-cache");
request.onreadystatechange = () => this._response = request.status;
console.log(request);
request.send(JSON.stringify(data));
}
}
Le modèle de l'utilisateur est
public class User
{
[KeyAttribute]
public int UserId { get; set; }
[RequiredAttribute]
public int SchoolId { get; set; }
[RequiredAttribute]
public string UserName { get; set; }
[RequiredAttribute]
[DataTypeAttribute(DataType.Password)]
public string UserSecret { get; set; } // Unnecessary due to school linking?
[RequiredAttribute]
public virtual School UserSchool { get; set; }
}
Alors que le contrôleur de publication est simple, il suffit de sortir le prénom
[HttpPost]
public IActionResult Post([FromBody]User user)
{
Console.WriteLine(user.UserName);
return StatusCode(200);
}
Edit Bien que la réponse de nemec ait été utile pour résoudre le problème, j'ai trouvé que pour WebAPI, la meilleure résolution était de configurer uniquement les cors en utilisant app.UseCors en tant que services.AddCors dans de nombreux cas, n'a pas réellement inclure les en-têtes nécessaires dans la réponse.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
}
Comme Evan l'a mentionné dans son commentaire, votre POST
se transforme en OPTIONS
lorsque vous effectuez une demande ajax d'origine croisée. En raison des politiques de sécurité multi-origine des navigateurs, votre API Web doit indiquer au navigateur/js que votre site Web est autorisé à effectuer des requêtes ajax contre lui.
https://docs.Microsoft.com/en-us/aspnet/core/security/cors
Pour configurer CORS pour votre application, ajoutez le
Microsoft.AspNetCore.Cors
package à votre projet.Ajoutez les services CORS dans Startup.cs:
public void ConfigureServices(IServiceCollection services) { services.AddCors(); }
Si vous suivez les instructions liées, vous pouvez même utiliser IApplicationBuilder.UseCors
pour personnaliser davantage les sites autorisés.
Par exemple:
app.UseCors(builder =>
builder.WithOrigins("http://example.com")
.AllowAnyHeader()
);
Postman est une application et a donc la possibilité de s'exempter des règles d'origine croisée.
Dans mon cas, le problème était que je mettais un attribut FromBody
avant mon paramètre d'action.
De:
[HttpPost("Contact")]
public async Task<IActionResult> NewContact([FromBody]Contact contact)
À:
[HttpPost("Contact")]
public async Task<IActionResult> NewContact(Contact contact)
Nous avons mis à niveau vers .NET core 3.0, ce qui était nécessaire pour utiliser [FromQuery] lorsque vous créez un objet à partir de paramètres de requête, par exemple avec une demande GET.
Exemple:
[HttpGet("Hierarchy")]
public virtual async Task<IActionResult> GetHierarchy([FromServices] IDeviceHierarchyService service, [FromQuery] HierarchyStructureRequest structureLoad)
Je ne sais pas encore pourquoi, je suis encore assez nouveau pour les API Web .Net Core. J'ai supprimé l'attribut de contrôleur [ApiController] et tout s'est mis en place.
Dans ma situation, j'ai une interface MVC & WebApi sur le même projet. J'espère que cela aide quelqu'un.