如何不在JSON对象上序列化__type属性

我从ScriptServiceWebMethod返回的每个对象都被包装到一个JSON对象中,数据在一个名为d的属性中。 没关系。 但我不想额外的__type属性被提供给客户端,因为我用jQuery手动处理。

可能吗?

那么你问起来已经很久了。 我发现,如果我做我的类的默认构造函数,我的webmethod返回非public公开它不会序列化__type:ClassName部分。

你可能想声明你的默认构造函数protected internal ClassName(){}

约翰的解决scheme不适合我,因为我返回的types是在一个单独的DLL。 我完全控制该DLL,但如果构造函数是内部的(当然),我不能构造我的返回types。

我想知道,图书馆中的公共types是否可能是原因; 正如我所说,我已经做了很多的Ajax,并没有看到这个之前。

快速testing:

  • 暂时将返回types声明移到App_Code中。 仍然得到__type序列化。

  • 同上并应用每个JM的受保护的内部构造函数。 这工作(所以他得到了一票)。

奇怪的是,我不会得到带有generics返回types的__type:

 [WebMethod] public static WebMethodReturn<IEnumerable<FleetObserverLiteAddOns.VehicleAddOnAccountStatus>> GetAccountCredits() 

对我来说, 解决scheme是将我的返回types留在DLL中,但将WebMethod返回types更改为对象 ,即

 [WebMethod] public static object ApplyCredits(int addonid, int[] vehicleIds) 

代替

 [WebMethod] public static WebMethodReturn ApplyCredits(int addonid, int[] vehicleIds) 

我一直在尝试一些.NET 4 WCF服务的这些build议,他们似乎并没有工作 – JSON响应仍然包括__type。

我发现删除types提示最简单的方法是将terminal行为从enableWebScript更改为webHttp。

  <behavior name="MapData.MapDataServiceAspNetAjaxBehavior"> <webHttp /> </behavior> 

如果您使用的是ASP.NET AJAX客户端,则默认的启用Web脚本行为是必需的,但是如果您使用JavaScript或jQuery操作JSON,那么WebHttp行为可能是更好的select。

如果您使用ServiceStack.Text JSON序列化程序 ,则只需:

 JsConfig.ExcludeTypeInfo = true; 

这个function在v2.28中被自动添加,但是上面的代码保持了序列化的function。 您还可以通过Type来更改此行为:

 JsConfig<Type>.ExcludeTypeInfo = true; 

JavaScriptTypeResolver传入null,__type不会被序列化

 JavaScriptSerializer serializer = new JavaScriptSerializer(null); string json = serializer.Serialize(foo); 

我不确定这是一个好的解决scheme,但如果使用Json.net库,则可以通过添加[JsonIgnore]属性来忽略某些属性。

除了John Morrison对DataContract类中内部受保护的内部构造函数的build议之外,对Web服务和大多数WCF来说,这非常适用,您可能需要在web.config文件中进行额外的更改。 而不是<enableWebScript/>元素使用<webHttp/>作为您的endpointBehaviors,例如:

 <endpointBehaviors> <behavior name="MyServiceEndpoint"> <webHttp/> </behavior> </endpointBehaviors> 

有点迟到线程,但在这里。

当被添加到jsonstring的属性是List <T>时,我们遇到了同样的问题。 我们所做的是添加另一个属性是T的数组,类似的东西。

之前。

 [DataMember] public List<Person> People { get; set; } 

后。

 public List<Person> People { get; set; } [DataMember(Name = "People")] public Person[] Persons { get { return People.ToArray(); } private set { } } 

虽然不是一个理想的解决scheme,但它的确有用。

我想我已经缩小了神秘的出现“__type”的根本原因!

以下是可以重新创build问题的示例。

 [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class Test : System.Web.Services.WebService { public class Cat { public String HairType { get; set; } public int MeowVolume { get; set; } public String Name { get; set; } } [WebMethod] public String MyMethodA(Cat cat) { return "return value does not matter"; } [WebMethod] public Cat MyMethodB(String someParam) { return new Cat() { HairType = "Short", MeowVolume = 13, Name = "Felix the Cat" }; } } 

这是关键部分!

只是因为MyMethodA()存在于这个相同的.asmx文件中, 并且将类Cat作为参数…. __type将被添加到从调用另一个方法MyMethodB()返回的JSON中。

即使他们是不同的方法!

我的理论如下:

  1. 当编写这样的Web服务时,由于使用了正确的属性,比如[WebMethod]和[ScriptService],微软的代码会自动为你绑定JSON序列化/反序列化行为。
  2. 当这个自动魔法的Microsoft代码执行时,它会find一个将Cat类作为参数的方法。
  3. 它的数字…哦…确定….好,因为我将从JSON接收Cat对象….因此…如果我曾经从当前Web服务中的任何方法返回一个Cat对象作为JSON class …我会给它一个__type属性,以便在反序列化回C#时很容易识别。
  4. Nyah,哈哈哈哈…

重要带走注意

你可以避免让__type属性出现在生成的JSON中,避免把有问题的类(在我的情况下是Cat)作为Web服务中任何WebMethods的参数。 所以,在上面的代码中,只需修改MyMethodA()来删除Cat参数。 这会导致不会生成__type属性。

不要使用[Serializable]属性。

以下应该只是做到这一点

JavaScriptSerializer ser = new JavaScriptSerializer(); stringjson = ser.Serialize(objectClass);

这应该解决它。

在System.WebExtensions.dll中的JavaScriptSerializer的私有Seri​​alizeValue方法中,__type被添加到内部字典中,如果可以解决的话。

从reflection器:

 private void SerializeValue(object o, StringBuilder sb, int depth, Hashtable objectsInUse) { if (++depth > this._recursionLimit) { throw new ArgumentException(AtlasWeb.JSON_DepthLimitExceeded); } JavaScriptConverter converter = null; if ((o != null) && this.ConverterExistsForType(o.GetType(), out converter)) { IDictionary<string, object> dictionary = converter.Serialize(o, this); if (this.TypeResolver != null) { string str = this.TypeResolver.ResolveTypeId(o.GetType()); if (str != null) { dictionary["__type"] = str; } } sb.Append(this.Serialize(dictionary)); } else { this.SerializeValueInternal(o, sb, depth, objectsInUse); } } 

如果types不能确定,序列化将继续,但types将被忽略。 好消息是,由于匿名typesinheritancegetType(),并且返回的名称是由编译器dynamic生成的,所以TypeResolver对于ResolveTypeId返回null,并且“__type”属性随后被忽略。

我也采取了约翰·莫里森的build议与内部的构造函数,以防万一,虽然只是使用这种方法,我仍然得到__type属性在我的JSON响应。

 //Given the following class [XmlType("T")] public class Foo { internal Foo() { } [XmlAttribute("p")] public uint Bar { get; set; } } [WebService(Namespace = "http://me.com/10/8")] [System.ComponentModel.ToolboxItem(false)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class MyService : System.Web.Services.WebService { //Return Anonymous Type to omit the __type property from JSON serialization [WebMethod(EnableSession = true)] [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json, XmlSerializeString = false)] public object GetFoo(int pageId) { //Kludge, returning an anonymois type using link, prevents returning the _type attribute. List<Foo> foos = new List<Foo>(); rtnFoos.Add( new Foo(){ Bar=99 }}; var rtn = from g in foos.AsEnumerable() select g; return rtn; } } 

注意:我使用inheritance的JSONtypes转换器,它从序列化types读取XML序列化属性以进一步压缩JSON。 感谢CodeJournal 。 奇迹般有效。

我的2美分,但是在当天晚些时候:正如其他人所说,似乎有两种方法来防止“__type”属性:

a)保护无参数的构造函数

b)避免将类作为parameter passing给Web方法

如果你永远不需要传递类作为参数,那么你可以使构造函数“受保护的内部”。 如果你需要创build一个空对象,然后添加一个工厂方法或其他构造函数与一个虚拟参数。

但是,如果您需要将该类作为parameter passing给Web方法,则会发现如果无参数构造函数是受保护的(ajax调用失败,这可能是由于传入的json数据无法反序列化到您的类中)。

这是我的问题,所以我不得不使用(a)和(b)的组合:保护无参数的构造函数,并创build一个虚拟的派生类,专门用于Web方法的参数。 例如:

 public class MyClass { protected internal MyClass() { } public MyClass(Object someParameter) { } ... } // Use this class when we need to pass a JSON object into a web method public class MyClassForParams : MyClass { public MyClassForParams() : base() { } } 

任何需要在MyClass中的Web方法,然后使用MyClassForParams:

 [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] public MyClass DoSomething(MyClassForParams someObject) { // Do something with someObject ... // Maybe return a MyClass object ... } 

这是一个黑客,但这对我来说(使用C#):

 s = (JSON string with "__type":"clsname", attributes) string match = "\"__type\":\"([^\\\"]|\\.)*\","; RegEx regex = new Regex(match, RegexOptions.Singleline); string cleaned = regex.Replace(s, ""); 

适用于[DataContract][DataContract(Namespace="")]