Właściwy sposób użycia AJAX Post w jquery do przekazania modelu z silnie wpisanego widoku MVC3

101

Jestem początkującym programistą internetowym, więc wybacz mi, jeśli któryś z moich „żargonów” nie jest poprawny. Mam projekt wykorzystujący ASP.NET przy użyciu frameworka MVC3.

Pracuję nad widokiem administratora, w którym administrator będzie modyfikował listę sprzętu. Jedną z funkcji jest przycisk "aktualizuj", którego chcę użyć jquery do dynamicznej edycji wpisu na stronie po wysłaniu posta do kontrolera MVC.

Przypuszczam, że to podejście jest „bezpieczne” w przypadku pojedynczego ustawienia administratora, w którym istnieje minimalna obawa, że ​​strona internetowa nie będzie zsynchronizowana z bazą danych.

Stworzyłem widok, który jest silnie wpisany i miałem nadzieję przekazać dane modelu do kontrolki MVC za pomocą posta AJAX.

W poniższym poście znalazłem coś, co jest podobne do tego, na co patrzę: JQuery Ajax i ASP.NET MVC3 powodujące parametry zerowe

Wykorzystam przykładowy kod z powyższego postu.

Model:

public class AddressInfo 
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Kontroler:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Check(AddressInfo addressInfo)
    {
        return Json(new { success = true });
    }
}

skrypt w widoku:

<script type="text/javascript">
var ai = {
    Address1: "423 Judy Road",
    Address2: "1001",
    City: "New York",
    State: "NY",
    ZipCode: "10301",
    Country: "USA"
};

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: JSON.stringify(ai),
    contentType: 'application/json; charset=utf-8',
    success: function (data.success) {
        alert(data);
    },
    error: function () {
        alert("error");
    }
});
</script>

Nie miałem jeszcze okazji skorzystać z powyższego. Ale zastanawiałem się, czy jest to „najlepsza” metoda przekazywania danych modelu z powrotem do kontrolki MVC przy użyciu AJAX?

Czy powinienem się martwić ujawnieniem informacji o modelu?

John Stone
źródło

Odpowiedzi:

72

Możesz pominąć deklarację var i stringify. W przeciwnym razie to zadziała dobrze.

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: {
        Address1: "423 Judy Road",
        Address2: "1001",
        City: "New York",
        State: "NY",
        ZipCode: "10301",
        Country: "USA"
    },
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
        alert(data.success);
    },
    error: function () {
        alert("error");
    }
});
Craig M.
źródło
Dziękuję za zwrócenie uwagi na drobną regulację. Czy istnieją obawy związane z ujawnieniem struktury modelu z punktu widzenia bezpieczeństwa?
John Stone
Nic nie rzuca się w oczy jako kwestia bezpieczeństwa. Jeśli jednak naprawdę się tym martwisz, zawsze możesz zrobić spoiwo modelu niestandardowego po stronie mvc.
Craig M
8
To mi się nie udało. Musiałem użyć JSON.stringify ({...}), aby wywołanie działało w MVC5.
Johncl
Zauważyłem, że muszę zrobić to samo podczas pracy z kontrolerami API. Ta odpowiedź została napisana 4 lata temu, zanim istniały kontrolery API.
Craig M
1
cholera, miałem dataType zamiast contentType, ten zawsze mnie dostaje !!
Phil
175

Znalazłem 3 sposoby na wdrożenie tego:

Klasa C #:

public class AddressInfo {
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Akcja:

[HttpPost]
public ActionResult Check(AddressInfo addressInfo)
{
    return Json(new { success = true });
}

JavaScript, możesz to zrobić na trzy sposoby:

1) Ciąg zapytania:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serialize(),
    type: 'POST',
});

Dane tutaj to ciąg.

"Address1=blah&Address2=blah&City=blah&State=blah&ZipCode=blah&Country=blah"

2) Tablica obiektów:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serializeArray(),
    type: 'POST',
});

Dane to tablica par klucz / wartość:

=[{name: 'Address1', value: 'blah'}, {name: 'Address2', value: 'blah'}, {name: 'City', value: 'blah'}, {name: 'State', value: 'blah'}, {name: 'ZipCode', value: 'blah'}, {name: 'Country', value: 'blah'}]

3) JSON:

$.ajax({
      url: '/en/Home/Check',
      data: JSON.stringify({ addressInfo:{//missing brackets
          Address1: $('#address1').val(),
          Address2: $('#address2').val(),
          City: $('#City').val(),
          State: $('#State').val(),
          ZipCode: $('#ZipCode').val()}}),
      type: 'POST',
      contentType: 'application/json; charset=utf-8'
});

Dane to serializowany ciąg JSON. Zauważ, że nazwa musi pasować do nazwy parametru na serwerze !!

='{"addressInfo":{"Address1":"blah","Address2":"blah","City":"blah","State":"blah", "ZipCode", "blah", "Country", "blah"}}'
Jazaret
źródło
1
Właśnie natknąłem się na tę wspaniałą, dokładną odpowiedź, która rozwiązała pytania, o których jeszcze nie wiedziałem. +1, dzięki!
SeanKilleen,
# 2 był tym, czego szukałem. To powinna być odpowiedź.
TheGeekZn
EDYCJA: musiałem użyć data: $('input, textarea, select').serialize(),do mojej pracy.
TheGeekZn
Hej Jazaret !! jak przejść na model z 3 podejściem?
Guruprasad Rao
1
Przepraszamy za opóźnienie @GuruprasadRao Aby przekazać datę, możesz ustawić datę i godzinę jako ciąg znaków w kodzie javascript, a MVC przetłumaczy je na obiekt DateTime.
Jazaret
12

Tak to zadziałało dla mnie:

$.post("/Controller/Action", $("#form").serialize(), function(json) {       
        // handle response
}, "json");

[HttpPost]
public ActionResult TV(MyModel id)
{
    return Json(new { success = true });
}
Sanchitos
źródło
8

to, co masz, jest w porządku - jednak aby zaoszczędzić trochę pisania, możesz po prostu użyć dla swoich danych

data: $ ('# formId'). serialize ()

zobacz http://www.ryancoughlin.com/2009/05/04/how-to-use-jquery-to-serialize-ajax-forms/, aby uzyskać szczegółowe informacje, składnia jest dość prosta.

Adam Tuliper - MSFT
źródło
Aby użyć funkcji serializacji, rozumiem, że każdy element członkowski klasy musi być używany w obiekcie formularza. Jeśli to prawda, mogę być SOL.
John Stone
1
ah ya .. jeśli nie, to nie możesz użyć serializacji. zawsze możesz jednak manipulować DOM i utworzyć formularz z tymi elementami i serializować go - ale ... byłoby prawdopodobnie czystsze, gdyby po prostu ręcznie wpisano pola.
Adam Tuliper - MSFT
@TahaRehmanSiddiqui serialize rzeczywiście działa w IE, co nie działa? Czy pojawia się błąd?
Adam Tuliper - MSFT
każda właściwość mojego modelu wychodzi null
Taha Rehman Siddiqui
@TahaRehmanSiddiqui czy „nazwa” pól formularza jest zgodna z nazwami właściwości modelu?
MongooseNX
0

Jeśli korzystasz z MVC 5, przeczytaj to rozwiązanie!

Znam pytanie dotyczące MVC 3, ale natknąłem się na tę stronę z MVC 5 i chciałem opublikować rozwiązanie dla każdego innego w mojej sytuacji. Wypróbowałem powyższe rozwiązania, ale u mnie nie zadziałały, nigdy nie dotarłem do Action Filter i nie mogłem zrozumieć dlaczego. Używam wersji 5 w moim projekcie i otrzymałem następujący filtr akcji:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;

namespace SydHeller.Filters
{
    public class ValidateJSONAntiForgeryHeader : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            string clientToken = filterContext.RequestContext.HttpContext.Request.Headers.Get(KEY_NAME);
            if (clientToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
            }

            string serverToken = filterContext.HttpContext.Request.Cookies.Get(KEY_NAME).Value;
            if (serverToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
            }

            System.Web.Helpers.AntiForgery.Validate(serverToken, clientToken);
        }

        private const string KEY_NAME = "__RequestVerificationToken";
    }
}

- Zanotuj using System.Web.Mvci using System.Web.Mvc.Filters, nie httpbiblioteki (myślę, że jest to jedna z rzeczy, które zmieniły się w MVC v5. -

Następnie po prostu nałóż filtr [ValidateJSONAntiForgeryHeader] do akcji (lub kontrolera) i powinna zostać poprawnie wywołana.

Na mojej stronie układu tuż powyżej </body>mam@AntiForgery.GetHtml();

Na koniec na mojej stronie Razor wykonuję wywołanie Ajax w następujący sposób:

var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();

$.ajax({
  type: "POST",
  url: serviceURL,
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  data: requestData,
  headers: {
     "__RequestVerificationToken": formForgeryToken
  },
     success: crimeDataSuccessFunc,
     error: crimeDataErrorFunc
});
blubberbo
źródło
1
Czy ręcznie pobierasz wszystkie wartości formularza? Dlaczego nie data: $("#the-form").serialize()?
Sinjai
1
@Sinjai Musiałbym ponownie spojrzeć na mój kod, ale wydaje mi się, że robię tam również inne przetwarzanie. „.serialize ()” również zadziała, jeśli potrzebujesz tylko wartości wejściowych
blubberbo,
Bez obaw, byłam po prostu ciekawa.
Sinjai