ASP.NET MVC 3控制器中.Json方法序列化不考虑DataMember Name属性

4

在我的课程中,我学习了以下知识:

[DataMember(Name = "jsonMemberName", EmitDefaultValue = false, 
    IsRequired = false)]
public List<string> Member { get; set; }

通过将对象传递给控制器的Json(obj),返回System.Web.Mvc.JsonResult: 我得到了序列化后的json:{Member:...},但不是{jsonMemberName:...},因此它不会查看DataMember(Name =“jsonMemberName”)。
如果我使用System.Runtime.Serialization.Json中的序列化,则所有内容都按预期正常工作。
可能出了什么问题?

可能是ASP.NET MVC:使用JsonResult控制属性名称的序列化的重复问题。 - Jake Petroules
2个回答

12

您从控制器动作返回的 JsonResult 动作(使用 return Json(...))内部依赖于 JavaScriptSerializer 类。该类不考虑模型上的任何 DataMember 属性。

您可以编写自定义的 ActionResult,它使用 System.Runtime.Serialization.Json 命名空间中的序列化程序。

例如:

public class MyJsonResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        if (!string.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = this.ContentEncoding;
        }
        if (Data != null)
        {
            var serializer = new DataContractJsonSerializer(Data.GetType());
            serializer.WriteObject(response.OutputStream, Data);
        }
    }
}

然后在您的控制器操作中:

public ActionResult Foo()
{
    var model = ...
    return new MyJsonResult { Data = model };
}

那么有解决方案吗?不用重命名类中的成员,因为这样很丑陋。 - WHITECOLOR
@WHITECOLOR,当然,编写自定义的ActionResult - Darin Dimitrov
在MVC中,为一个变更请求或类似的事物进行投票会是一件不错的事情。如果默认的JSONResult使用DataContractJsonSerializer,会有什么缺点?会破坏什么吗? - Konstantin

2

System.Web.Mvc.JsonResult使用旧的JavaScriptSerializer类,该类不知道DataAnnotations程序集的任何信息。您需要改用DataContractJsonSerializer

如果需要,您可以使用以下内容替换JsonResult:

public class DataContractJsonResult : JsonResult
{
    public DataContractJsonResult(object data)
    {
        Data = data;
    }

    public DataContractJsonResult()
    {
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
            String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
        }

        HttpResponseBase response = context.HttpContext.Response;

        if (!string.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data != null)
        {
            var serializer = new DataContractJsonSerializer(Data.GetType());
            var ms = new MemoryStream();
            serializer.WriteObject(ms, Data);
            string json = Encoding.UTF8.GetString(ms.ToArray());
            response.Write(json);
        }
    }
}

我参考了ASP.NET MVC的源代码来创建这个。不确定是否需要以某种方式进行致谢。除此之外,我已经说够了。:))

您还可以将此添加到您的控制器继承的基类中:

protected JsonResult DataContractJson(object data)
{
    return new DataContractJsonResult(data);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接