Asp.net mvc 如何将某些公共属性从序列化为JsonResult中排除?

Asp.net mvc 如何将某些公共属性从序列化为JsonResult中排除?,asp.net-mvc,json,serialization,Asp.net Mvc,Json,Serialization,我有一个自定义viewmodel,它使用JsonResult进行序列化。ViewModel有一些属性必须是公共的,但同时这些属性在生成的Json输出中不应可见 我已经尝试使用[NonSerialized]属性,但似乎没有任何效果 有什么简单的方法可以做到这一点吗?或者我必须为自己的结果类型编写代码(在这种情况下,我可能不会麻烦)?这不是您想要的答案,但您可以使用以下代码和匿名类来欺骗Json(): MyModel model = ...; return Json(new MyModel {mod

我有一个自定义viewmodel,它使用JsonResult进行序列化。ViewModel有一些属性必须是公共的,但同时这些属性在生成的Json输出中不应可见

我已经尝试使用[NonSerialized]属性,但似乎没有任何效果


有什么简单的方法可以做到这一点吗?或者我必须为自己的结果类型编写代码(在这种情况下,我可能不会麻烦)?

这不是您想要的答案,但您可以使用以下代码和匿名类来欺骗
Json()

MyModel model = ...;
return Json(new MyModel {model.Prop1, model.Prop2});

您可以创建一个包装器类,该类只公开您想要在JsonResult中显示的那些属性。在下面的示例中,Cow有两个属性——“Leg”和“Moo”。假设您只想将“Leg”作为属性公开。然后

尺寸cw为整流罩=新整流罩(c)

将返回一个仅公开“Leg”的包装器类。如果您只想显示某些属性子集,这对于DataGridView之类的东西也很有用

公营母牛

作为字符串的公共只读属性Leg()

   get

      return "leg"

   end get
   get

      return "moo"

   end get
   get

      return m_cow.Leg()

   end get
端属性

作为字符串的公共只读属性Moo()

   get

      return "leg"

   end get
   get

      return "moo"

   end get
   get

      return m_cow.Leg()

   end get
端属性

末级

公共类牛仔装

Private m_cow as Cow = Nothing

Public Sub New(ByVal cow as Cow)

   m_cow = cow

end Sub


    m_cow = cow
作为字符串的公共只读属性Leg()

   get

      return "leg"

   end get
   get

      return "moo"

   end get
   get

      return m_cow.Leg()

   end get
端属性

结束类

扩展该类,使其不包括具有
非序列化数据属性的属性
。然后,您可以创建一个自定义的
ActionResult
,它使用
JavaScriptConverter
来序列化对象


这将创建一个可靠且可测试的类,而无需(重新)生成包装器类或使用匿名对象。

看看James Newton King。它将满足您的需要。

您可以在不应序列化的成员上添加
[ScriptIgnore]
属性。请参阅以获取示例。

只需创建一个要返回的接口,而不是类

public interface IMyViewModel {
   string MyPublicProperty { get; set; }
}
然后创建一个继承接口的类

public class MyViewModel : IMyViewModel {
   public string MyPublicProperty { get; set; }
   public string MyNotSoPublicProperty { get; set; }
}
并在控制器操作中返回接口,而不是类

public JsonResult MyJson(){
    IMyViewModel model = new MyViewModel();
    return Json(model);
}
生成的JSON将是

{
    'MyPublicProperty': ''
}
客户端脚本编写的挑战之一是,如果要更改类,则不知道是否要破坏客户端实现。如果您在JSON中使用接口类型,您就会明白,如果您更改接口,您正在做的事情可能会扼杀客户端实现。而且,如果您正在更改某些不在接口中的内容(因此未被序列化),它还可以避免徒劳地重复检查客户端

而且,很多时候,ViewModels中可能包含大型集合或复杂类型,您不一定要将其输出到客户端。序列化或公开不属于客户机代码的信息可能需要很长时间。使用接口将使了解输出中的内容更加透明


此外,在属性上使用[ScriptIgnore]等属性仅适用于特定场景(JavaScript序列化),例如,如果以后要序列化为XML,则会面临完全相同的问题。这将不必要地为ViewModel添加大量属性。你到底想要多少?使用intefaces适用于任何地方,并且viewmodel不需要添加额外的属性。

我知道我可以使用匿名类型。但这使得单元测试结果更加困难。这意味着我要么必须解析序列化结果,要么使用反射。单元测试JsonResults很难开始。你以前是怎么做的?看起来您无法检索驱动JsonResult的底层模型,这一点都没有问题。Data属性包含要序列化的对象。因为我使用的是自定义viewmodel而不是匿名对象类型,所以我可以简单地获取该对象并测试其属性。虽然很痛苦,但您可以创建新版本的类,并简单地复制所需的属性。我用这种方法编辑了我的文章。@Adrian:谢谢,我不知道数据引用了序列化对象。这是可行的,但代价是必须复制很多属性,所以这不是我真正想要的。代价是什么?编程?在类文件作为输入的情况下,编写一个简单的实用程序来构造这些类,或者编写一个可以使用内省动态构造属性的类应该很简单。运行时间?额外引用的代价是可以忽略的。我不知道你的意思是通过反射在运行时构造这样的类型。这当然涵盖了我的所有自定义viewmodel类型,而无需任何额外的编码。这是一种有效的方法,但与使用现成工具(即Json.Net)相比太复杂了。太棒了!(有现成的工具)。我应该写“它应该是可能的”而不是“它应该是简单的”。。因为我自己对内省知之甚少。在用LINQ to SQL类填充DataGridView时,我使用了包装类(硬编码,不使用内省)。通常我不想显示表中的所有字段,所以包装器会处理这个问题。这也是我想到的方法。这当然是可行的,但因为这只是为了节省每个Json请求的几个字节,所以我希望有更简单的方法。很好的方法,但与我的案例相比,工作太多了。太完美了!事实证明,James还编写了一个匹配的JsonResult类型:对于其他类型,该属性的完整名称空间是[System.Web.Script.Serialization.ScriptIgnore],在使用常规MVC
return Json()时,它看起来像
ScriptIgnore
---然后
JsonIgnore
如果使用
Json.NET
大多数答案都是使用Attribute或wrapper。我只想简单地排除s