Как не сериализовать свойство __type на объектах JSON

Каждый объект, который я возвращаю из WebMethod ScriptService в объект JSON с данными в свойстве с именем d . Ничего страшного. Но я не хочу, чтобы дополнительное свойство __type клиенту, поскольку я выполняю ручную обработку с помощью jQuery.

Является ли это возможным?

Ну, это было давно, как вы спросили. Я обнаружил, что если я сделаю конструктор по умолчанию моего classа, что мой веб-метод вернет что-либо, кроме публичного, он не будет сериализовать часть __type: ClassName.

Вы можете захотеть объявить свой protected internal ClassName(){} конструктор по умолчанию protected internal ClassName(){}

Решение Джона не работало для меня, поскольку тип, который я возвращаю, находится в отдельной DLL. Я имею полный контроль над этой DLL, но я не могу построить свой возвращаемый тип, если конструктор является внутренним.

Я задавался вопросом, может ли быть тип возврата, являющийся публичным типом в библиотеке, – я делал много Ajax и раньше не видел этого.

Быстрые тесты:

  • Временно переместил объявление типа возвращаемого значения в App_Code. Все еще получить __type .

  • То же самое и применил защищенный внутренний конструктор на JM. Это сработало (поэтому он получает голос).

Странно, я не получаю __type с общим типом возврата:

 [WebMethod] public static WebMethodReturn> GetAccountCredits() 

Однако решение для меня состояло в том, чтобы оставить мой тип возврата в DLL, но изменить тип возвращаемого объекта WebMethod на объект , т. Е.

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

вместо

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

Я пробовал некоторые из этих предложений с помощью службы .NET 4 WCF, и они, похоже, не работают – ответ JSON по-прежнему включает __type.

Самый простой способ, который я обнаружил, чтобы удалить подсказку типа, – это изменить поведение конечной точки с enableWebScript на webHttp.

     

По умолчанию действие enableWebScript требуется, если вы используете клиент ASP.NET AJAX, но если вы манипулируете JSON с помощью JavaScript или jQuery, то поведение webHttp, вероятно, является лучшим выбором.

Если вы используете ServiceStack.Text JSON Serializer, вам просто нужно:

 JsConfig.ExcludeTypeInfo = true; 

Эта функциональность была автоматически добавлена ​​обратно в v2.28 , но приведенный выше код сохраняет это из сериализации. Вы также можете изменить это поведение по Type с помощью:

 JsConfig.ExcludeTypeInfo = true; 

Передайте значение null для JavaScriptTypeResolver, и тип __ не будет сериализован

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

Я не уверен, что это хорошее решение, но если вы используете библиотеку Json.net , вы можете игнорировать некоторые свойства, добавив атрибут [JsonIgnore] .

Я думаю, что я сузил основную причину таинственного появления «__type»!

Вот пример, где вы можете воссоздать проблему.

 [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 и принимает class Cat как параметр …. __type будет добавлен в JSON, возвращенный из вызова другого метода: MyMethodB ().

Хотя они разные методы!

Моя теория такова:

  1. При написании таких веб-сервисов код Microsoft автоматически подключает поведение JSON для сериализации / десериализации, поскольку вы использовали правильные атрибуты, такие как [WebMethod] и [ScriptService].
  2. Когда этот автоматический магия кода Microsoft выполняется, он находит метод, который принимает class Cat в качестве параметра.
  3. Это цифры … о … хорошо …. хорошо, так как я буду получать объект Cat от JSON …. поэтому … если я когда-либо верну объект Cat как JSON из любого метода в текущем веб-сервисе class … Я дам ему свойство __type, поэтому его будет легко идентифицировать позже, когда десериализуем обратно на C #.
  4. Nyah-Хахаха …

Важно Take-Away Примечание

Вы можете избежать наличия свойства __type в вашем сгенерированном JSON, избегая при этом в рассматриваемом classе (Cat в моем случае) в качестве параметра для любого из ваших WebMethods в вашем веб-сервисе. Итак, в приведенном выше коде просто попробуйте изменить MyMethodA (), чтобы удалить параметр Cat. Это приводит к тому, что свойство __type не генерируется.

В дополнение к совету Джона Моррисона о внутреннем или защищенном внутреннем конструкторе в вашем classе DataContract, который отлично работает для веб-сервисов и большинства WCF, возможно, вам придется внести дополнительные изменения в ваш файл web.config. Вместо элемента используйте для своих конечных пользователей, например:

      

Немного поздно в stream, но здесь идет.

У нас была такая же проблема, когда свойство, добавляемое в строку json, было List . Мы сделали еще одно свойство, которое было массивом T, что-то вроде.

До.

 [DataMember] public List People { get; set; } 

После.

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

Хотя это не идеальное решение, он делает трюк.

Не используйте атрибут [Serializable].

Следующее должно просто сделать это

JavaScriptSerializer ser = новый JavaScriptSerializer (); string json = ser.Serialize (objectClass);

Это должно решить проблему.

В частном методе SerializeValue JavaScriptSerializer в System.WebExtensions.dll __type добавляется во внутренний словарь, если он может быть разрешен.

От рефлектора:

 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 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); } } 

Если тип не может быть определен, сериализация будет продолжаться, но тип будет проигнорирован. Хорошей новостью является то, что, поскольку анонимные типы наследуют getType (), а возвращаемые имена динамически генерируются компилятором, TypeResolver возвращает null для ResolveTypeId, а атрибут «__type» впоследствии игнорируется.

Я также принял совет Джона Моррисона с внутренним конструктором на всякий случай, хотя, используя только этот метод, я все еще получал свойства __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 foos = new List(); rtnFoos.Add( new Foo(){ Bar=99 }}; var rtn = from g in foos.AsEnumerable() select g; return rtn; } } 

Примечание. Я использую унаследованный конвертер типа JSON, который считывает атрибуты Serialization XML из сериализованных типов для дальнейшего сжатия JSON. С благодарностью CodeJournal . Работает как шарм.

Мои 2 цента, хотя и поздно в тот же день: как говорили другие, существует, по-видимому, два способа предотвратить свойство «__type»:

a) Защитите конструктор без параметров

b) Избегайте передачи classа в качестве параметра веб-методу

Если вам никогда не нужно передавать class в качестве параметра, вы можете сделать конструктор «защищенным внутренним». Если вам нужно создать пустой объект, добавьте фабричный метод или какой-нибудь другой конструктор с фиктивным параметром.

Однако, если вам нужно передать class в качестве параметра веб-методу, вы обнаружите, что это не будет работать, если конструктор без параметров будет защищен (вызов ajax не выполняется, предположительно, поскольку переданные в json данные не могут быть десериализованы в ваш class ).

Это была моя проблема, поэтому мне пришлось использовать комбинацию (a) и (b): защитить конструктор без параметров и создать производный class манекена, который будет использоваться исключительно для параметров для веб-методов. Например:

 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, вместо этого использует MyClassForParams:

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

Я решил объявить конструктор по умолчанию protected ClassName internal () {} См. Также ответ Джона Моррисона

Это немного взломать, но это сработало для меня (используя 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="")]

  • jackson не десериализует общий список, который он сериализовал
  • Есть ли версия $ getJSON, которая не использует обратный вызов?
  • Разбор JSON на Java без знания формата JSON
  • Как использовать пользовательские ключи с протоколом Swift 4 Decodable?
  • Итерация объекта Json с помощью ngFor
  • Как разбирать JSON без библиотеки JSON.NET?
  • POST на службу службы REST службы Джерси 415 Неподдерживаемый тип носителя
  • Ошибка Android JSon «Ожидается BEGIN_OBJECT, но BEGIN_ARRAY в строке 1 столбца 2»
  • Как использовать пользовательский Serializer с Jackson?
  • Почему Gson fromJson бросает исключение JsonSyntaxException: ожидается какой-то тип, но какой-то другой тип?
  • Могу ли я вернуть JSON из веб-службы .asmx, если ContentType не является JSON?
  • Давайте будем гением компьютера.