在jquery中使用AJAX Post的正确方法可以从强类型MVC3视图传递模型


100

我是Web程序员的新手,所以如果我的某些“行话”不正确,请原谅我。我有一个使用MVC3框架的ASP.NET项目。

我正在管理员视图上,管理员将在其中修改设备列表。功能之一是“更新”按钮,在将帖子发送到MVC控制器后,我想使用jquery动态编辑网页上的条目。

我认为这种方法在单个管理员设置中是“安全的”,在这种情况下,网页与数据库不同步的担忧最小。

我创建了一个强类型化的视图,希望使用AJAX发布将模型数据传递给MVC控件。

在下面的文章中,我发现了与我正在做的事情类似的事情: 导致空参数的JQuery Ajax和ASP.NET MVC3

我将使用以上文章中的代码示例。

模型:

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

控制器:

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

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

视图中的脚本:

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

我还没有机会使用以上内容。但是我想知道这是否是使用AJAX将模型数据传递回MVC控件的“最佳”方法?

我应该担心公开模型信息吗?

Answers:


72

您可以跳过var声明和stringify。否则,就可以了。

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

感谢您指出微调。从安全角度公开模型结构是否有问题?
约翰·斯通

对我而言,没有任何明显的问题成为安全问题。但是,如果您真的很担心,可以随时在mvc端制作自定义模型活页夹。
Craig M

8
这对我来说失败了。我必须使用JSON.stringify({...})进行调用才能在MVC5中工作。
Johncl

我注意到在使用API​​控制器时必须做同样的事情。这个答案是4年前写的,当时还没有API控制器。
Craig M

1
天哪,我有dataType而不是contentType,那总是让我得到!
菲尔(Phil)

175

我发现了三种实现方法:

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

行动:

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

您可以通过三种方式使用JavaScript

1)查询字串:

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

这里的数据是一个字符串。

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

2)对象数组:

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

这里的数据是键/值对的数组:

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

此处的数据是序列化的JSON字符串。请注意,该名称必须与服务器中的参数名称匹配!!

='{"addressInfo":{"Address1":"blah","Address2":"blah","City":"blah","State":"blah", "ZipCode", "blah", "Country", "blah"}}'

1
刚遇到一个很棒的,彻底的答案,解决了我不知道的问题。+1,谢谢!
SeanKilleen

#2是我一直在寻找的东西。这应该是答案。
TheGeekZn 2013年

编辑:不得不data: $('input, textarea, select').serialize(),用于我的工作。
TheGeekZn

嘿哈扎雷特!如何通过第三种方法将日期传递给模型?
Guruprasad Rao 2015年

1
抱歉@GuruprasadRao的延迟要传递日期,您可以将日期和时间设为javascript代码中的字符串,MVC会将其转换为DateTime对象。
Jazaret 2015年

12

这是它为我工作的方式:

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

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

8

您所拥有的都很好-但是,为了节省一些键入内容,您只需将其用于数据即可

数据:$('#formId')。serialize()

有关详细信息,请参见http://www.ryancoughlin.com/2009/05/04/how-to-use-jquery-to-serialize-ajax-forms/,该语法非常基本。


为了使用序列化功能,我的理解是该类的每个成员都需要在表单对象中使用。如果正确,那么我可能是SOL。
约翰·斯通

1
啊..如果不是,您就不能使用序列化。您仍然可以始终操纵DOM并使用这些元素创建一个表格并将其序列化-但...然后手动键入字段可能会更干净。
Adam Tuliper-MSFT 2011年

@TahaRehmanSiddiqui序列化确实在IE中有效,什么不起作用?你有错误吗?
Adam Tuliper-MSFT 2013年

我模型的每个属性都为空
Taha Rehman Siddiqui 2013年

@TahaRehmanSiddiqui表单字段的“名称”是否与模型属性的名称匹配?
MongooseNX

0

如果使用MVC 5,请阅读此解决方案!

我知道这个问题专门针对MVC 3,但是我偶然在MVC 5上浏览了此页面,并想针对我所遇到的其他情况发布解决方案。我尝试了上述解决方案,但它们对我不起作用,从未达到动作过滤器,而且我不知道为什么。我在项目中使用的是版本5,最后得到以下操作过滤器:

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

-请注意using System.Web.Mvcusing System.Web.Mvc.Filters,而不要注意http库(我认为这是MVC v5发生的变化之一。

然后只需将过滤器[ValidateJSONAntiForgeryHeader]应用于您的操作(或控制器),即可正确调用该过滤器。

在上方的布局页面中,</body>我有@AntiForgery.GetHtml();

最后,在我的Razor页面中,我进行如下的ajax调用:

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
您要手动检索所有表单值吗?为什么不data: $("#the-form").serialize()呢?
Sinjai

1
@Sinjai我将不得不再次查看我的代码,但我相信我也在其中进行其他处理。如果您只需要输入值,“。serialize()”也将起作用
blubberbo

不用担心,我只是好奇。
Sinjai
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.