Comment publier un tableau d'objets complexes avec JSON, jQuery sur ASP.NET MVC Controller?

92

Mon code actuel ressemble à ce qui suit. Comment puis-je transmettre ma baie au contrôleur et quels types de paramètres mon action de contrôleur doit-elle accepter?

function getplaceholders() {
    var placeholders = $('.ui-sortable');
    var result = new Array();
    placeholders.each(function() {
        var ph = $(this).attr('id');
        var sections = $(this).find('.sort');
        var section;

        sections.each(function(i, item) {
            var sid = $(item).attr('id');

            result.push({ 'SectionId': sid, 'Placeholder': ph, 'Position': i });
        });
    });
    alert(result.toString());
    $.post(
        '/portal/Designer.mvc/SaveOrUpdate',
        result,
        function(data) {
            alert(data.Result);
        }, "json");
};

Ma méthode d'action de contrôleur ressemble à

public JsonResult SaveOrUpdate(IList<PageDesignWidget> widgets)
JSC
la source

Réponses:

84

J'ai trouvé une solution. J'utilise une solution de Steve Gentile, jQuery et ASP.NET MVC - envoi de JSON à une action - Revisité .

Mon code de vue ASP.NET MVC ressemble à ceci:

function getplaceholders() {
        var placeholders = $('.ui-sortable');
        var results = new Array();
        placeholders.each(function() {
            var ph = $(this).attr('id');
            var sections = $(this).find('.sort');
            var section;

            sections.each(function(i, item) {
                var sid = $(item).attr('id');
                var o = { 'SectionId': sid, 'Placeholder': ph, 'Position': i };
                results.push(o);
            });
        });
        var postData = { widgets: results };
        var widgets = results;
        $.ajax({
            url: '/portal/Designer.mvc/SaveOrUpdate',
            type: 'POST',
            dataType: 'json',
            data: $.toJSON(widgets),
            contentType: 'application/json; charset=utf-8',
            success: function(result) {
                alert(result.Result);
            }
        });
    };

et mon action de contrôleur est décorée avec un attribut personnalisé

[JsonFilter(Param = "widgets", JsonDataType = typeof(List<PageDesignWidget>))]
public JsonResult SaveOrUpdate(List<PageDesignWidget> widgets

Le code de l'attribut personnalisé peut être trouvé ici (le lien est maintenant rompu).

Parce que le lien est rompu, c'est le code pour le JsonFilterAttribute

public class JsonFilter : ActionFilterAttribute
{
    public string Param { get; set; }
    public Type JsonDataType { get; set; }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
        {
            string inputContent;
            using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
            {
                inputContent = sr.ReadToEnd();
            }
            var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
            filterContext.ActionParameters[Param] = result;
        }
    }
}

JsonConvert.DeserializeObject provient de Json.NET

Lien: sérialisation et désérialisation de JSON avec Json.NET

JSC
la source
Ça a l'air génial - Le billet de blog et les liens de code d'attribut personnalisé ne fonctionnent plus - pouvez-vous republier?
littlechris
4
Cette solution nécessite des modifications côté client et côté serveur. Je sais que vous en aviez besoin il y a longtemps, mais je peux également fournir un lien vers une approche différente, qui utilise un simple plugin jQuery qui permet de convertir n'importe quel objet Javascript en une forme que le classeur de modèle par défaut comprend et le modèle se lie aux paramètres. Aucun filtre nécessaire. erraticdev.blogspot.com/2010/12/… Je ne sais pas comment vous avez résolu les erreurs de validation mais j'ai aussi une solution pour cela: erraticdev.blogspot.com/2010/11/…
Robert Koritnik
3
Pouvez-vous donner la source / l'origine de JavaScriptConvert.DeserializeObject?
Matthieu
C'est la bibliothèque Newtonsoft Json - si vous ouvrez le gestionnaire de paquets nuget et effectuez une recherche sur Newtonsoft, il s'affichera pour vous (maintenant que nous sommes en 2016). C'est probablement maintenant évident, mais au cas où quelqu'un se demanderait.
Robb Sadler
22

Filtres d'action, jquery stringify, bleh ...

Peter, cette fonctionnalité est native de MVC. C'est l'une des choses qui rend MVC si génial.

$.post('SomeController/Batch', { 'ids': ['1', '2', '3']}, function (r) {
   ...
});

Et dans l'action,

[HttpPost]
public ActionResult Batch(string[] ids)
{
}

Fonctionne comme un charme:

entrez la description de l'image ici

Si vous utilisez jQuery 1.4+, vous voulez vous pencher sur la configuration du mode traditionnel:

jQuery.ajaxSettings.traditional = true;

Comme décrit ici: http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/02/24/jquery-1-4-breaks-asp-net-mvc-actions-with-array-parameters

Cela fonctionne même pour les objets complexes. Si vous êtes intéressé, vous devriez consulter la documentation MVC sur la liaison de modèle: http://msdn.microsoft.com/en-us/library/dd410405.aspx

Levitikon
la source
1
vous avez peut-être raison, mais le classeur de modèles JSON est nouveau dans MVC3 et la question a été posée en 2008 alors que cela n'était pas pris en charge. Cela mériterait d'être mentionné dans votre réponse.
Piotr Owsiak
3
En quoi est-ce un exemple de passage d'un tableau d' objets complexes ?
DuckMaestro
Ce n'est pas le cas, mais l'exemple s'applique toujours (MVC 3+). Tant que vos noms de paramètres correspondent au modèle que vous attendez, vous n'aurez aucun problème.
J. Mitchell
La clé ici est de créer un objet JSON avec le nom du paramètre de méthode ("ids"), puis d'y placer le tableau d'objets complexes. De plus, définissez le troisième paramètre sur "vrai" et vous vous occuperez du mode traditionnel.
redwards510
11

In .NET4.5, MVC 5pas besoin de widgets.

Javascript:

objet dans JS: entrez la description de l'image ici

mécanisme qui ne poste.

    $('.button-green-large').click(function() {
        $.ajax({
            url: 'Quote',
            type: "POST",
            dataType: "json",
            data: JSON.stringify(document.selectedProduct),
            contentType: 'application/json; charset=utf-8',
        });
    });

C #

Objets:

public class WillsQuoteViewModel
{
    public string Product { get; set; }

    public List<ClaimedFee> ClaimedFees { get; set; }
}

public partial class ClaimedFee //Generated by EF6
{
    public long Id { get; set; }
    public long JourneyId { get; set; }
    public string Title { get; set; }
    public decimal Net { get; set; }
    public decimal Vat { get; set; }
    public string Type { get; set; }

    public virtual Journey Journey { get; set; }
}

Manette:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Quote(WillsQuoteViewModel data)
{
....
}

Objet reçu:

entrez la description de l'image ici

J'espère que cela vous fera gagner du temps.

Matas Vaitkevicius
la source
8

Vers la seconde moitié de Create REST API utilisant ASP.NET MVC qui parle à la fois JSON et XML brut , pour citer:

Nous devons maintenant accepter les données utiles JSON et XML, fournies via HTTP POST. Parfois, votre client peut souhaiter télécharger une collection d'objets en une seule fois pour le traitement par lots. Ainsi, ils peuvent télécharger des objets au format JSON ou XML. Il n'y a pas de prise en charge native dans ASP.NET MVC pour analyser automatiquement le JSON ou le XML publié et mapper automatiquement aux paramètres d'action. Alors, j'ai écrit un filtre qui le fait. "

Il implémente ensuite un filtre d'action qui mappe les objets JSON aux objets C # avec le code affiché.

anonyme
la source
J'écrivais juste ma réponse. Mais je le posterai quand même ;-)
JSC
7

Téléchargez d'abord ce code JavaScript, JSON2.js , qui nous aidera à sérialiser l'objet en une chaîne.

Dans mon exemple, je poste les lignes d'un jqGrid via Ajax:

    var commissions = new Array();
    // Do several row data and do some push. In this example is just one push.
    var rowData = $(GRID_AGENTS).getRowData(ids[i]);
    commissions.push(rowData);
    $.ajax({
        type: "POST",
        traditional: true,
        url: '<%= Url.Content("~/") %>' + AREA + CONTROLLER + 'SubmitCommissions',
        async: true,
        data: JSON.stringify(commissions),
        dataType: "json",
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            if (data.Result) {
                jQuery(GRID_AGENTS).trigger('reloadGrid');
            }
            else {
                jAlert("A problem ocurred during updating", "Commissions Report");
            }
        }
    });

Maintenant sur le contrôleur:

    [HttpPost]
    [JsonFilter(Param = "commissions", JsonDataType = typeof(List<CommissionsJs>))]
    public ActionResult SubmitCommissions(List<CommissionsJs> commissions)
    {
        var result = dosomething(commissions);
        var jsonData = new
        {
            Result = true,
            Message = "Success"
        };
        if (result < 1)
        {
            jsonData = new
            {
                Result = false,
                Message = "Problem"
            };
        }
        return Json(jsonData);
    }

Créez une classe JsonFilter (grâce à la référence JSC).

    public class JsonFilter : ActionFilterAttribute
    {
        public string Param { get; set; }
        public Type JsonDataType { get; set; }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
            {
                string inputContent;
                using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
                {
                    inputContent = sr.ReadToEnd();
                }
                var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
                filterContext.ActionParameters[Param] = result;
            }
        }
    }

Créez une autre classe afin que le filtre puisse analyser la chaîne JSON en objet manipulable réel: Cette classe comissionsJS sont toutes les lignes de mon jqGrid.

    public class CommissionsJs
    {
        public string Amount { get; set; }

        public string CheckNumber { get; set; }

        public string Contract { get; set; }
        public string DatePayed { get; set; }
        public string DealerName { get; set; }
        public string ID { get; set; }
        public string IdAgentPayment { get; set; }
        public string Notes { get; set; }
        public string PaymentMethodName { get; set; }
        public string RowNumber { get; set; }
        public string AgentId { get; set; }
    }

J'espère que cet exemple vous aidera à illustrer comment publier un objet complexe.

Sanchitos
la source
0

Oh mon Dieu. pas besoin de faire quelque chose de spécial. uniquement dans votre section de publication, procédez comme suit:

    $.post(yourURL,{ '': results})(function(e){ ...}

Dans le serveur, utilisez ceci:

   public ActionResult MethodName(List<yourViewModel> model){...}

ce lien vous aide à faire ...

mahdi moghimi
la source
-1
    [HttpPost]
    public bool parseAllDocs([FromBody] IList<docObject> data)
    {
        // do stuff

    }
JsonW
la source