[.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 blog, 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.




Une classe de paramètre simple peut être utilisée pour transmettre plusieurs paramètres dans un message:

public class AddCustomerArgs
{
    public string First { get; set; }
    public string Last { get; set; }
}

[HttpPost]
public IHttpActionResult AddCustomer(AddCustomerArgs args)
{
    //use args...
    return Ok();
}



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



À quoi ressemble votre routeTemplate pour ce cas?

Vous avez posté cette URL:

/offers/40D5E19D-0CD5-4FBD-92F8-43FDBB475333/prices/

Pour que cela fonctionne, je m'attendrais à un routage comme celui-ci dans votre WebApiConfig :

routeTemplate: {controller}/{offerId}/prices/

D'autres hypothèses sont les suivantes: - votre contrôleur s'appelle OffersController . - l'objet JSON que vous transmettez dans le corps de la requête est de type OfferPriceParameters (pas de type dérivé) - vous n'avez aucune autre méthode sur le contrôleur qui pourrait interférer avec celui-ci (si vous le faites, essayez de les commenter et de voir ce qui se produit)

Et comme Filip l'a mentionné, cela aiderait vos questions si vous commenciez à accepter des réponses comme «accepter un taux de 0%» pourrait faire croire aux gens qu'ils perdent leur temps




Nous avons passé l'objet Json par la méthode HttpPost et l'analysons dans un objet dynamique. ça fonctionne bien. ceci est un exemple de code:

ajaxPost:
...
Content-Type: application/json,
data: {"AppName":"SamplePrice",
       "AppInstanceID":"100",
       "ProcessGUID":"072af8c3-482a-4b1c‌​-890b-685ce2fcc75d",
       "UserID":"20",
       "UserName":"Jack",
       "NextActivityPerformers":{
           "39‌​c71004-d822-4c15-9ff2-94ca1068d745":[{
                 "UserID":10,
                 "UserName":"Smith"
           }]
       }}
...

webapi:

[HttpPost]
public string DoJson2(dynamic data)
{
   //whole:
   var c = JsonConvert.DeserializeObject<YourObjectTypeHere>(data.ToString()); 

   //or 
   var c1 = JsonConvert.DeserializeObject< ComplexObject1 >(data.c1.ToString());

   var c2 = JsonConvert.DeserializeObject< ComplexObject2 >(data.c2.ToString());

   string appName = data.AppName;
   int appInstanceID = data.AppInstanceID;
   string processGUID = data.ProcessGUID;
   int userID = data.UserID;
   string userName = data.UserName;
   var performer = JsonConvert.DeserializeObject< NextActivityPerformers >(data.NextActivityPerformers.ToString());

   ...
}

Le type d'objet complexe peut être un objet, un tableau et un dictionnaire.