web-dev-qa-db-fra.com

Passer plusieurs paramètres dans une API POST sans utiliser de classe DTO dans .Net Core MVC

J'ai une action sur mon projet web qui appelle une API

    [HttpPost]
    public async Task<IActionResult> ExpireSurvey(int id)
    {
        var token = await HttpContext.GetTokenAsync("access_token");

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

            var path = "/api/forms/ExpireSurvey";
            var url = Domain + path;
            var data = JsonConvert.SerializeObject(id);
            HttpContent httpContent = new StringContent(data, Encoding.UTF8, "application/json");
            var response = await client.PutAsync(url, httpContent);

            return Json(response);
        }
    }

Dans le projet API, cela est reçu comme suit:

[HttpPut]
    public IActionResult ExpireSurvey([FromBody] int surveyId)
    {
        _repository.ExpireSurvey(surveyId, expiryDate);
        return Ok();
    }

Cela fonctionne bien - cependant, disons que je veux passer un identifiant int et une variable DateTime, comment puis-je sérialiser et les passer tous les deux dans HttpContent? Je peux le faire avec un objet DTO, mais je ne veux pas configurer des objets DTO lorsqu'il n'y a que deux champs.

6
egmfrs

Vous pouvez utiliser des types anonymes comme celui-ci

var x = new { id = 2, date = DateTime.Now };
var data = JsonConvert.SerializeObject(x);

Lors de la réception des données, vous ne pouvez avoir qu'un seul paramètre [FromBody]. Cela ne fonctionne donc pas pour la réception de plusieurs paramètres (sauf si vous pouvez en mettre tous sauf un dans l'URL). Si vous ne voulez pas déclarer un DTO, vous pouvez utiliser un objet dynamique comme celui-ci:

[HttpPost]
public void Post([FromBody] dynamic data)
{
    Console.WriteLine(data.id);
    Console.WriteLine(data.date);
}

N'exagérez cependant pas en utilisant des types anonymes et des variables dynamiques. Ils sont très pratiques pour travailler avec JSON, mais vous perdez tout contrôle de type, ce qui rend C # vraiment agréable à travailler.

8
Hans Kilian

Je pense qu'il serait utile de reconnaître que ASP.NET Core est basé sur REST et REST traite fondamentalement du concept de ressources. Bien qu'il ne s'agisse pas d'une règle incassable, le l'idée générale est que vous devriez avoir ce que vous appelez des DTO ici. En d'autres termes, vous ne postez pas des bits de données distincts et sans rapport, mais un objet qui représente quelque chose.

Cela devient de plus en plus important si vous commencez à mélanger des choses comme Swagger pour générer de la documentation pour votre API. Les objets que vous créez font partie de cette documentation, donnant aux consommateurs de votre API un modèle à suivre dans le développement de leurs applications.

Long et court, je dirais embrasser le concept de ressources/objets/DTO/quoi que. Modèle les données avec lesquelles votre API fonctionne. Cela vous aidera à la fois en tant que développeur de l'API et en tant que consommateur de votre API.

5
Chris Pratt

Vous pouvez passer plusieurs paramètres en tant qu'URL comme dans l'exemple ci-dessous

Le nom du paramètre doit être le même (insensible à la casse). Si les noms ne correspondent pas, les valeurs des paramètres ne seront pas définies.

[HttpPost]
[Route("{surveyId}/{expiryDate}")]
public IActionResult Post(int surveyId, DateTime expiryDate)
{
    return Ok(new { surveyId, expiryDate });
}

URL d'appel

http://localhost:[port]/api/[controller]/1/3-29-2018
5
ElasticCode

vous pouvez le faire avec un dictionnaire

Dictionary<string, object> dict = new Dictionary<string, object>();
dict["id"] = 1
dict["date"] = DateTime.Now;

JsonConvert.SerializeObject(dict);
0
Steve

Sur la base des réponses ci-dessus, j'ai fait fonctionner le code suivant. J'espère que cela aide quelqu'un! (merci aux autres bien sûr de m'avoir mis sur la bonne voie)

/// <summary>
/// Post api/dostuff/{id}
[HttpPost]
[Route("dostuff/{id}")]
public async Task<IActionResult> DoStuff([FromBody]Model model, int id)
{
    // Both model and id are available for use!
}
0
Ross