web-dev-qa-db-fra.com

Renvoyer JsonResult à partir d'une API Web sans ses propriétés

J'ai un contrôleur API Web et à partir de là, je retourne un objet en tant que JSON à partir d'une action.

Je fais ça comme ça:

public ActionResult GetAllNotificationSettings()
{
    var result = new List<ListItems>();
    // Filling the list with data here...

    // Then I return the list
    return new JsonResult { Data = result };
}

Mais de cette manière, l'objet JsonResult, y compris son attribut Data, est sérialisé en tant que JSON. Donc, mon JSON final renvoyé par l'action ressemble à ceci:

{
    "ContentEncoding": null,
    "ContentType": null,
    "Data": {
        "ListItems": [
            {
                "ListId": 2,
                "Name": "John Doe"
            },
            {
                "ListId": 3,
                "Name": "Jane Doe"
            },
        ]
    },
    "JsonRequestBehavior": 1,
    "MaxJsonLength": null,
    "RecursionLimit": null
}

Je ne peux pas sérialiser cette chaîne JSON car l'objet JsonResult lui a ajouté toutes sortes d'autres propriétés. Je ne m'intéresse qu'à ListItems, rien d'autre. Mais cela ajoutait automatiquement des choses comme: ContentType, MaxJsonLength etc ...

Maintenant, cela ne fonctionnera pas pour moi à cause de toutes les autres propriétés de la chaîne JSON ...

var myList = JsonConvert.DeserializeObject<List<ListItems>>(jsonString);

Existe-t-il un moyen d’envoyer un objet JSON à partir de l’action pour qu’il n’ajoute pas toutes les propriétés dont je n’ai pas besoin?

19
Vivendi

En tant que personne ayant travaillé avec l’API ASP.NET pendant environ 3 ans, je vous recommanderais plutôt de renvoyer un HttpResponseMessage. N'utilisez pas ActionResult ou IEnumerable!

ActionResult est mauvais parce que, comme vous l'avez découvert.

Return IEnumerable <> est incorrect car vous souhaiterez peut-être l'étendre ultérieurement et ajouter des en-têtes, etc.

L'utilisation de JsonResult est une mauvaise solution car vous devez autoriser l'extension de votre service et prendre en charge d'autres formats de réponse, le cas échéant. si vous voulez sérieusement le limiter, vous pouvez le faire en utilisant les attributs d'action, pas dans le corps de l'action.

public HttpResponseMessage GetAllNotificationSettings()
{
    var result = new List<ListItems>();
    // Filling the list with data here...

    // Then I return the list
    return Request.CreateResponse(HttpStatusCode.OK, result);
}

Dans mes tests, j'utilise généralement la méthode d'assistance ci-dessous pour extraire mes objets de HttpResponseMessage:

 public class ResponseResultExtractor
    {
        public T Extract<T>(HttpResponseMessage response)
        {
            return response.Content.ReadAsAsync<T>().Result;
        }
    }

var actual = ResponseResultExtractor.Extract<List<ListItems>>(response);

De cette façon, vous avez réalisé ce qui suit:

  • Votre action peut également renvoyer des messages d'erreur et des codes d'état tels que 404 non trouvés, vous permettant ainsi de la gérer facilement.
  • Votre action n'est pas limitée à JSON mais prend en charge JSON en fonction des préférences de demande du client et des paramètres du formateur.

Regardez ceci: http://www.asp.net/web-api/overview/formats-and-model-binding/content-negotiation

46
Dynamic

Lorsque vous utilisez WebAPI, vous devez simplement renvoyer l'objet plutôt que de renvoyer spécifiquement Json, car l'API renvoie JSON ou XML en fonction de la demande.

Je ne sais pas pourquoi votre WebAPI renvoie un ActionResult, mais je changerais le code en quelque chose comme:

public IEnumerable<ListItems> GetAllNotificationSettings()
{
    var result = new List<ListItems>();
    // Filling the list with data here...

    // Then I return the list
    return result;
}

Cela se traduira par JSON si vous l'appelez depuis un code AJAX.

P.S WebAPI est supposé être RESTful. Votre contrôleur doit donc s'appeler ListItemController et votre méthode simplement s'appeler Get. Mais c'est pour un autre jour.

12
Tim B James

J'ai eu un problème similaire (les différences étant que je voulais retourner un objet déjà converti en chaîne json et que mon contrôleur reçoive retourne un IHttpActionResult)

Voici comment je l'ai résolu. D'abord j'ai déclaré une classe utilitaire

public class RawJsonActionResult : IHttpActionResult
{
    private readonly string _jsonString;

    public RawJsonActionResult(string jsonString)
    {
        _jsonString = jsonString;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var content = new StringContent(_jsonString);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = content };
        return Task.FromResult(response);
    }
}

Cette classe peut ensuite être utilisée dans votre contrôleur. Voici un exemple simple

public IHttpActionResult Get()
{
    var jsonString = "{\"id\":1,\"name\":\"a small object\" }";
    return new RawJsonActionResult(jsonString);
}
9
Joe King