[.net] Paramètres multiples Put / Post WebAPI


Answers

WebAPI nativement ne prend pas en charge la liaison de plusieurs paramètres POST. Comme le souligne Colin, il y a un certain nombre de limitations qui sont décrites dans mon http://www.west-wind.com/weblog/posts/2012/May/08/Passing-multiple-POST-parameters-to-Web-API-Controller-Methods il référence des références.

Il existe une solution de contournement en créant un classeur de paramètres personnalisé. Le code pour le faire est moche et compliqué, mais j'ai posté du code avec une explication détaillée sur mon blog, prêt à être branché sur un projet ici:

Passage de plusieurs valeurs POST simples à l'API Web ASP.NET

Question

J'essaie d'afficher plusieurs paramètres sur un contrôleur WebAPI. Un paramètre provient de l'URL et l'autre du corps. Voici l'url: /offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

Voici mon code de contrôleur:

public HttpResponseMessage Put(Guid offerId, OfferPriceParameters offerPriceParameters)
{
    //What!?
    var ser = new DataContractJsonSerializer(typeof(OfferPriceParameters));
    HttpContext.Current.Request.InputStream.Position = 0;
    var what = ser.ReadObject(HttpContext.Current.Request.InputStream);

    return new HttpResponseMessage(HttpStatusCode.Created);
}

Le contenu du corps est en JSON:

{
    "Associations":
    {
        "list": [
        {
            "FromEntityId":"276774bb-9bd9-4bbd-a7e7-6ed3d69f196f",
            "ToEntityId":"ed0d2616-f707-446b-9e40-b77b94fb7d2b",
            "Types":
            {
                "list":[
                {
                    "BillingCommitment":5,
                    "BillingCycle":5,
                    "Prices":
                    {
                        "list":[
                        {
                            "CurrencyId":"274d24c9-7d0b-40ea-a936-e800d74ead53",
                            "RecurringFee":4,
                            "SetupFee":5
                        }]
                    }
                }]
            }
        }]
    }
}

Une idée de la raison pour laquelle la liaison par défaut n'est pas capable de se lier à l'argument offerPriceParameters de mon contrôleur? Il est toujours défini sur null. Mais je suis capable de récupérer les données du corps en utilisant le DataContractJsonSerializer .

J'essaie également d'utiliser l'attribut FromBody de l'argument mais cela ne fonctionne pas non plus.




Belle question et commentaires - appris beaucoup des réponses ici :)

Comme exemple supplémentaire, notez que vous pouvez également mélanger le corps et les routes, par exemple

[RoutePrefix("api/test")]
public class MyProtectedController 
{
    [Authorize]
    [Route("id/{id}")]
    public IEnumerable<object> Post(String id, [FromBody] JObject data)
    {
        /*
          id                                      = "123"
          data.GetValue("username").ToString()    = "user1"
          data.GetValue("password").ToString()    = "pass1"
         */
    }
}

Appelez comme ceci:

POST /api/test/id/123 HTTP/1.1
Host: localhost
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer x.y.z
Cache-Control: no-cache

username=user1&password=pass1


enter code here



Si vous ne voulez pas suivre la méthode ModelBinding, vous pouvez utiliser les DTO pour le faire pour vous. Par exemple, créez une action POST dans DataLayer qui accepte un type complexe et envoie des données à partir de BusinessLayer. Vous pouvez le faire en cas d'appel UI-> API.

Voici des exemples de DTO. Attribuez un enseignant à un étudiant et attribuez plusieurs articles / sujets à l'étudiant.

public class StudentCurriculumDTO
 {
     public StudentTeacherMapping StudentTeacherMapping { get; set; }
     public List<Paper> Paper { get; set; }
 }    
public class StudentTeacherMapping
 {
     public Guid StudentID { get; set; }
     public Guid TeacherId { get; set; }
 }

public class Paper
 {
     public Guid PaperID { get; set; }
     public string Status { get; set; }
 }

Ensuite, l'action dans DataLayer peut être créée comme suit:

[HttpPost]
[ActionName("MyActionName")]
public async Task<IHttpActionResult> InternalName(StudentCurriculumDTO studentData)
  {
     //Do whatever.... insert the data if nothing else!
  }

Pour l'appeler depuis BusinessLayer:

using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", dataof_StudentCurriculumDTO)
  {
     //Do whatever.... get response if nothing else!
  }

Maintenant, cela fonctionnera encore si je veux envoyer des données de plusieurs étudiants à la fois. Modifier le MyAction comme ci-dessous. Pas besoin d'écrire [FromBody], WebAPI2 prend le type complexe [FromBody] par défaut.

public async Task<IHttpActionResult> InternalName(List<StudentCurriculumDTO> studentData)

puis en l'appelant, passez une List<StudentCurriculumDTO> de données.

using (HttpResponseMessage response = await client.PostAsJsonAsync("myendpoint_MyActionName", List<dataof_StudentCurriculumDTO>)



Vous pouvez autoriser plusieurs paramètres POST en utilisant la classe MultiPostParameterBinding à partir de https://github.com/keith5000/MultiPostParameterBinding

Pour l'utiliser:

1) Téléchargez le code dans le dossier Source et ajoutez-le à votre projet API Web ou à tout autre projet de la solution.

2) Utilisez l'attribut [MultiPostParameters] sur les méthodes d'action qui doivent prendre en charge plusieurs paramètres POST.

[MultiPostParameters]
public string DoSomething(CustomType param1, CustomType param2, string param3) { ... }

3) Ajoutez cette ligne dans Global.asax.cs à la méthode Application_Start n'importe où avant l'appel à GlobalConfiguration.Configure (WebApiConfig.Register) :

GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, MultiPostParameterBinding.CreateBindingForMarkedParameters);

4) Demandez à vos clients de passer les paramètres en tant que propriétés d'un objet. Un exemple d'objet JSON pour la méthode DoSomething(param1, param2, param3) est:

{ param1:{ Text:"" }, param2:{ Text:"" }, param3:"" }

Exemple JQuery:

$.ajax({
    data: JSON.stringify({ param1:{ Text:"" }, param2:{ Text:"" }, param3:"" }),
    url: '/MyService/DoSomething',
    contentType: "application/json", method: "POST", processData: false
})
.success(function (result) { ... });

Visitez https://github.com/keith5000/MultiPostParameterBinding pour plus de détails.

Disclaimer: Je suis directement associé à la ressource liée.




Si le routage d'attribut est utilisé, vous pouvez utiliser les attributs [FromUri] et [FromBody].

Exemple:

[HttpPost()]
[Route("api/products/{id:int}")]
public HttpResponseMessage AddProduct([FromUri()] int id,  [FromBody()] Product product)
{
  // Add product
}



Links