Maneira adequada de usar AJAX Post em jquery para passar o modelo da visão MVC3 fortemente tipada

100

Sou um programador web novato, então, por favor, me perdoe se meu "jargão" não estiver correto. Eu tenho um projeto usando ASP.NET usando a estrutura MVC3.

Estou trabalhando em uma visão de administrador em que o administrador modificará uma lista de equipamentos. Uma das funções é um botão "atualizar" que desejo usar jquery para editar dinamicamente a entrada na página da Web após enviar uma postagem para o controlador MVC.

Presumo que essa abordagem seja "segura" em uma única configuração de administrador em que haja uma preocupação mínima de a página da Web sair de sincronia com o banco de dados.

Eu criei uma visão fortemente tipada e esperava passar os dados do modelo para o controle MVC usando uma postagem AJAX.

No post a seguir, encontrei algo semelhante ao que estou procurando fazer: JQuery Ajax e ASP.NET MVC3 causando parâmetros nulos

Vou usar o exemplo de código da postagem acima.

Modelo:

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

Controlador:

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

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

script na visualização:

<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>

Eu não tive a chance de usar o acima ainda. Mas eu queria saber se este era o "melhor" método para passar os dados do modelo de volta para o controle MVC usando AJAX.

Devo me preocupar em expor as informações do modelo?

John stone
fonte

Respostas:

72

Você pode pular a declaração var e o stringify. Caso contrário, isso funcionará bem.

$.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
fonte
Obrigado por apontar o pequeno ajuste. Existe alguma preocupação em expor a estrutura do modelo do ponto de vista da segurança?
John Stone de
Nada flagrante se destaca como um problema de segurança para mim. Se você estiver realmente preocupado com isso, você sempre pode fazer um fichário de modelo personalizado no lado do mvc.
Craig M
8
Isso falhou para mim. Eu tive que usar JSON.stringify ({...}) para a chamada funcionar em MVC5.
Johncl
Percebi que preciso fazer o mesmo ao trabalhar com controladores de API. Esta resposta foi escrita 4 anos atrás, antes de existirem controladores de API.
Craig M
1
Deus caramba, eu tinha dataType em vez de contentType, esse sempre me pega !!
Phil
175

Encontrei 3 maneiras de implementar isso:

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

Açao:

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

JavaScript, você pode fazer isso de três maneiras:

1) String de consulta:

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

Os dados aqui são uma string.

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

2) Matriz de objetos:

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

Os dados aqui são uma matriz de pares de chave / valor:

=[{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'
});

Os dados aqui são uma string JSON serializada. Observe que o nome deve corresponder ao nome do parâmetro no servidor !!

='{"addressInfo":{"Address1":"blah","Address2":"blah","City":"blah","State":"blah", "ZipCode", "blah", "Country", "blah"}}'
Jazaret
fonte
1
Acabei de encontrar uma resposta excelente e completa que resolveu perguntas que eu ainda não sabia que tinha. +1, obrigado!
SeanKilleen
# 2 era o que eu procurava. Esta deve ser a resposta.
TheGeekZn
EDIT: tive que usar data: $('input, textarea, select').serialize(),para o meu funcionar.
TheGeekZn
Ei Jazaret !! como passar data para modelar com 3ª abordagem ??
Guruprasad Rao
1
Desculpe pela demora @GuruprasadRao Para passar uma data você pode fazer com que a data e hora sejam uma string no código javascript e o MVC irá traduzi-la para um objeto DateTime.
Jazaret,
12

É assim que funcionou para mim:

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

[HttpPost]
public ActionResult TV(MyModel id)
{
    return Json(new { success = true });
}
Sanchitos
fonte
8

o que você tem é bom - no entanto, para economizar um pouco de digitação, você pode simplesmente usar para seus dados

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

consulte http://www.ryancoughlin.com/2009/05/04/how-to-use-jquery-to-serialize-ajax-forms/ para obter detalhes, a sintaxe é bastante básica.

Adam Tuliper - MSFT
fonte
Para usar a função serializar, meu entendimento é que cada membro da classe precisa ser usado em um objeto de formulário. Se isso estiver correto, posso ser SOL.
John Stone de
1
ah ya .. se não você não pode usar serializar então. você sempre pode manipular o DOM e criar um formulário com esses elementos e serializá-lo - mas ... provavelmente seria mais limpo apenas ter os campos digitados manualmente.
Adam Tuliper - MSFT
@TahaRehmanSiddiqui serializar realmente funciona no IE, o que não funciona? Voce encontrou um erro?
Adam Tuliper - MSFT
todas as propriedades do meu modelo estão saindo nulas
Taha Rehman Siddiqui
@TahaRehmanSiddiqui o 'nome' dos campos do seu formulário correspondem aos nomes das propriedades do seu modelo?
MongooseNX
0

Se estiver usando MVC 5, leia esta solução!

Eu sei que a questão especificamente chamada para MVC 3, mas me deparei com esta página com MVC 5 e queria postar uma solução para qualquer outra pessoa na minha situação. Tentei as soluções acima, mas não funcionaram para mim, o filtro de ação nunca foi alcançado e não consegui descobrir o porquê. Estou usando a versão 5 em meu projeto e acabei com o seguinte filtro de ação:

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

- Anote o using System.Web.Mvce using System.Web.Mvc.Filters, não as httpbibliotecas (acho que é uma das coisas que mudou com MVC v5. -

Em seguida, basta aplicar o filtro [ValidateJSONAntiForgeryHeader]à sua ação (ou controlador) e ele deve ser chamado corretamente.

Na minha página de layout logo acima </body>eu tenho@AntiForgery.GetHtml();

Finalmente, em minha página do Razor, faço a chamada ajax da seguinte maneira:

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
fonte
1
Você está recuperando todos os valores do formulário manualmente? Porque não data: $("#the-form").serialize()?
Sinjai
1
@Sinjai Eu teria que olhar meu código novamente, mas acredito que estou fazendo algum outro processamento lá também. ".serialize ()" também funcionaria se você apenas precisar dos valores de entrada
blubberbo
Não se preocupe, eu estava apenas curioso.
Sinjai