如何不在JSON对象上序列化__type属性
我从ScriptService
的WebMethod
返回的每个对象都被包装到一个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中。
即使他们是不同的方法!
我的理论如下:
- 当编写这样的Web服务时,由于使用了正确的属性,比如[WebMethod]和[ScriptService],微软的代码会自动为你绑定JSON序列化/反序列化行为。
- 当这个自动魔法的Microsoft代码执行时,它会find一个将Cat类作为参数的方法。
- 它的数字…哦…确定….好,因为我将从JSON接收Cat对象….因此…如果我曾经从当前Web服务中的任何方法返回一个Cat对象作为JSON class …我会给它一个__type属性,以便在反序列化回C#时很容易识别。
- Nyah,哈哈哈哈…
重要带走注意
你可以避免让__type属性出现在生成的JSON中,避免把有问题的类(在我的情况下是Cat)作为Web服务中任何WebMethods的参数。 所以,在上面的代码中,只需修改MyMethodA()来删除Cat参数。 这会导致不会生成__type属性。
不要使用[Serializable]属性。
以下应该只是做到这一点
JavaScriptSerializer ser = new JavaScriptSerializer(); stringjson = ser.Serialize(objectClass);
这应该解决它。
在System.WebExtensions.dll中的JavaScriptSerializer的私有SerializeValue方法中,__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="")]