在 ASP.NET MVC 中,在控制器的操作方法之前或之中反序列化 JSON
Posted
技术标签:
【中文标题】在 ASP.NET MVC 中,在控制器的操作方法之前或之中反序列化 JSON【英文标题】:In ASP.NET MVC, deserialize JSON prior to or in controller's action method 【发布时间】:2010-12-01 06:52:57 【问题描述】:我正在开发一个将 JSON 对象(使用 jQuery Post 方法)发布到服务器端的网站。
"ID" : 1,
"FullName" :
"FirstName" : "John",
"LastName" : "Smith"
同时,我在服务端为这个数据结构写了类。
public class User
public int ID get; set;
public Name FullName get; set;
public class Name
public string FirstName get; set;
public string LastName get; set;
当我在控制器类中使用以下代码运行网站时,FullName 属性不会被反序列化。我究竟做错了什么?
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Submit(User user)
// At this point, user.FullName is NULL.
return View();
【问题讨论】:
MVC 不支持开箱即用的 JSON 反序列化,但我们正在考虑为 v2.0 添加它。同时,您可以使用 javascriptSerializer 将请求正文转换为完全水合的 User 对象。 @Levi - 这应该是一个回答帖子;) 这很奇怪;不知何故,ID 属性被正确反序列化。如果我使用 JavaScriptSerializer,Submit() 的输入参数会是 Object 类型吗? 我只是使用 jQuery 表单库,它只是像普通表单一样发布它。如果你不能这样做,我会使用自定义模型绑定器。 【参考方案1】:我通过实施动作过滤器解决了我的问题;下面提供了代码示例。从研究中,我了解到还有另一种解决方案,即模型绑定器,如上述 takepara 所述。但我真的不知道这两种方法的利弊。
感谢 Steve Gentile 的 blog post 提供此解决方案。
public class JsonFilter : ActionFilterAttribute
public string Parameter get; set;
public Type JsonDataType get; set;
public override void OnActionExecuting(ActionExecutingContext filterContext)
if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
string inputContent;
using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
inputContent = sr.ReadToEnd();
var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
filterContext.ActionParameters[Parameter] = result;
[AcceptVerbs(HttpVerbs.Post)]
[JsonFilter(Parameter="user", JsonDataType=typeof(User))]
public ActionResult Submit(User user)
// user object is deserialized properly prior to execution of Submit() function
return View();
【讨论】:
awww snap,133t MVC 技能的weilin,你最好在星期一教我; ) 这个方法比自定义 ModelBinder 有一个显着的优势,你可以定义要反序列化的类型。使用自定义 ModelBinder,它是硬编码的,因此仅对一种类型有用。【参考方案2】:1.创建自定义模型绑定器
public class UserModelBinder : IModelBinder
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
User model;
if(controllerContext.RequestContext.HttpContext.Request.AcceptTypes.Contains("application/json"))
var serializer = new JavaScriptSerializer();
var form = controllerContext.RequestContext.HttpContext.Request.Form.ToString();
model = serializer.Deserialize<User>(HttpUtility.UrlDecode(form));
else
model = (User)ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
return model;
2.在application_start事件中添加模型绑定
ModelBinders.Binders[typeof(User)] = new UserModelBinder();
3.在查看客户端 JavaScript 代码中使用 jQuery $.get/$.post。
<% using(html.BeginForm("JsonData","Home",new,FormMethod.Post, newid="jsonform")) %>
<% = Html.TextArea("jsonarea","",new id="jsonarea") %><br />
<input type="button" id="getjson" value="Get Json" />
<input type="button" id="postjson" value="Post Json" />
<% %>
<script type="text/javascript">
$(function()
$('#getjson').click(function()
$.get($('#jsonform').attr('action'), function(data)
$('#jsonarea').val(data);
);
);
$('#postjson').click(function()
$.post($('#jsonform').attr('action'), $('#jsonarea').val(), function(data)
alert("posted!");
,"json");
);
);
</script>
【讨论】:
你的意思可能是“ContentType”而不是“AcceptTypes”【参考方案3】:你可以试试Json.NET。 documentation 还不错,应该可以do what you need。您还需要获取JsonNetResult,因为它返回一个可在 ASP.NET MVC 应用程序中使用的 ActionResult。它非常易于使用。
Json.NET 也适用于日期序列化。有关 can be found here 的更多信息。
希望这会有所帮助。
【讨论】:
【参考方案4】:试试这个;
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Submit(FormCollection collection)
User submittedUser = JsonConvert.DeserializeObject<User>(collection["user"]);
return View();
【讨论】:
【参考方案5】:经过一番研究,我发现 Takepara 的解决方案是用 Newtonsoft 的 Json.NET 替换默认 MVC JSON 反序列化器的最佳选择。它也可以推广到程序集中的所有类型,如下所示:
using Newtonsoft.Json;
namespace MySite.Web
public class MyModelBinder : IModelBinder
// make a new Json serializer
protected static JsonSerializer jsonSerializer = null;
static MyModelBinder()
JsonSerializerSettings settings = new JsonSerializerSettings();
// Set custom serialization settings.
settings.DateTimeZoneHandling= DateTimeZoneHandling.Utc;
jsonSerializer = JsonSerializer.Create(settings);
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
object model;
if (bindingContext.ModelType.Assembly == "MyDtoAssembly")
var s = controllerContext.RequestContext.HttpContext.Request.InputStream;
s.Seek(0, SeekOrigin.Begin);
using (var sw = new StreamReader(s))
model = jsonSerializer.Deserialize(sw, bindingContext.ModelType);
else
model = ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
return model;
那么,在Global.asax.cs
,Application_Start()
:
var asmDto = typeof(SomeDto).Assembly;
foreach (var t in asmDto.GetTypes())
ModelBinders.Binders[t] = new MyModelBinder();
【讨论】:
以上是关于在 ASP.NET MVC 中,在控制器的操作方法之前或之中反序列化 JSON的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ASP.NET MVC 中使用 jQuery ajax 方法将数据列表发送到控制器操作方法?
在 ASP.NET MVC 中,在控制器的操作方法之前或之中反序列化 JSON
使用 asp.net MVC 中的参数将 javascript 中的页面重新加载到特定控制器的操作方法
ASP.NET Core MVC 之控制器(Controller)