如何使用 json 将复杂类型传递给 ASP.NET MVC 控制器

Posted

技术标签:

【中文标题】如何使用 json 将复杂类型传递给 ASP.NET MVC 控制器【英文标题】:How to pass complex type using json to ASP.NET MVC controller 【发布时间】:2010-09-21 00:41:54 【问题描述】:

我有一个视图,允许用户输入/编辑新窗口小部件的数据。我想将该数据形成一个 json 对象并通过 AJAX 将其发送到我的控制器,这样我就可以在服务器上进行验证而无需回发。

我已经完成了所有工作,只是我不知道如何传递数据,因此我的控制器方法可以接受复杂的 Widget 类型,而不是每个属性的单独参数。

所以,如果这是我的对象:

public class Widget

   public int Id  get; set; 
   public string Name  get; set; 
   public decimal Price  get; set; 

我希望我的控制器方法看起来像这样:

public JsonResult Save(Widget widget)

   ...

目前,我的 jQuery 看起来像这样:

var formData = $("#Form1").serializeArray();

$.post("/Widget/Save",
   formData,
   function(result), "json");

我的表单 (Form1) 为 Widget 上的每个属性(Id、Name、Price)都有一个输入字段。这很好用,但它最终将 Widget 的每个属性作为单独的参数传递给我的控制器方法。

有没有一种方法可以“拦截”数据,可能使用 ActionFilterAttribute,然后在调用控制器方法之前将其反序列化为 Widget 对象?

【问题讨论】:

【参考方案1】:

感谢 Jeff,这让我走上了正确的道路。 DefaultModelBinder 足够聪明,可以为我做所有的魔法……我的问题出在我的 Widget 类型上。匆忙中,我的类型被定义为:

public class Widget

   public int Id;
   public string Name;
   public decimal Price;

请注意,该类型具有公共字段而不是公共属性。一旦我将它们更改为属性,它就起作用了。下面是正确运行的最终源代码:

Widget.aspx:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Widget.aspx.cs" Inherits="MvcAjaxApp2.Views.Home.Widget" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <script src="../../Scripts/jquery-1.2.6.js" type="text/javascript"></script>   
    <script type="text/javascript"> 
    function SaveWidget()
    
        var formData = $("#Form1").serializeArray();

        $.post("/Home/SaveWidget",
        formData,
        function(data)
            alert(data.Result);
        , "json");
    
    </script>
    <form id="Form1">
        <input type="hidden" name="widget.Id" value="1" />
        <input type="text" name="widget.Name" value="my widget" />
        <input type="text" name="widget.Price" value="5.43" />
        <input type="button" value="Save" onclick="SaveWidget()" />
    </form>
</asp:Content>

HomeController.cs:

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

namespace MvcAjaxApp2.Controllers

    [HandleError]
    public class HomeController : Controller
    
        public ActionResult Index()
        
            ViewData["Title"] = "Home Page";
            ViewData["Message"] = "Welcome to ASP.NET MVC!";
            return View();
        

        public ActionResult About()
        
            ViewData["Title"] = "About Page";
            return View();
        

        public ActionResult Widget()
        
            ViewData["Title"] = "Widget";
            return View();
        

        public JsonResult SaveWidget(Widget widget)
        
            // Save the Widget
            return Json(new  Result = String.Format("Saved widget: '0' for $1", widget.Name, widget.Price) );
        
    
    public class Widget
    
        public int Id  get; set; 
        public string Name  get; set; 
        public decimal Price  get; set; 
    

【讨论】:

太棒了,很高兴你把它修好了。并感谢您发布您如何修复它,这将在未来对其他人有很大帮助! 公共字段是 .NET 中的恶魔。他们打破了一切。我告诉你的一切! @MrBoJangles - 字段的问题,解决方案是将它们更改为属性。 我在我的项目中使用了这种格式。它从来没有在$.post() 中运行回调函数,我只是在其中添加了一个通用的alert('Successful');,不知道为什么没有,但它确实发布了我的数据,我很高兴,所以+1。不知道为什么我的简单$('#Form1').submit() 不起作用,当我有method=postaction 中的控制器/更新时。 实际上,我发现如果我在回调结束时去掉, "json",警报就会起作用。仅供参考。【参考方案2】:

注意(在MrDustpan的解决方案中)MVC Action方法中的参数name widget必须与中使用的前缀匹配>name ASPX 文件中的属性。

如果不是这种情况,那么 Action 方法将始终接收 null 对象。

<input type="text" name="widget.Text" value="Hello" /> - OK
<input type="text" name="mywidget.Text" value="Hello" /> - FAILS

【讨论】:

优秀的一点,很容易被忽视。似乎也区分大小写。【参考方案3】:

Phil Haack 有 a good blog post 关于模型绑定可能会有所帮助。不是 100% 您在这里谈论的内容,但我认为这可能会让您对 DefaultModelBinder 有更好的整体了解。

【讨论】:

【参考方案4】:

您要做的是以与后端对象相同的方式构建 javascript 表单对象:

 Id : "id", Name : "name", Price : 1.0 

然后使用toJSON插件将其转换成上面的字符串。您将此字符串发送到后端并使用 JayRock 库之类的东西将其转换为新的 Widget 对象。

【讨论】:

以上是关于如何使用 json 将复杂类型传递给 ASP.NET MVC 控制器的主要内容,如果未能解决你的问题,请参考以下文章

Swift:如何将可编码类型作为函数输入传递给编码或解码 json

前端传递给后端复杂类型 webapi 等

Alamofire/Swiftyjson - 将 JSON 类型传递给 Objc 协议委托

如何将 JSON 传递给 REST API (IBKR)

如何不将英文字母传递给Json

无法将 JSON 数组传递给数组