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?

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");
    }
});

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"}}'

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

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.


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.