Как не сериализовать свойство __type в объектах JSON - PullRequest
62 голосов
/ 09 марта 2009

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

Возможно ли это?

Ответы [ 15 ]

38 голосов
/ 22 апреля 2009

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

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

23 голосов
/ 01 октября 2010

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

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

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

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

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

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

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

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

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

вместо

[WebMethod]
public static WebMethodReturn ApplyCredits(int addonid, int[] vehicleIds)
16 голосов
/ 19 декабря 2010

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

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

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

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

11 голосов
/ 12 октября 2012

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

JsConfig.ExcludeTypeInfo = true;

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

JsConfig<Type>.ExcludeTypeInfo = true;
3 голосов
/ 18 октября 2012

Я думаю, что сузил причину таинственного появления "__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 и принимает класс Cat в качестве параметра .... __type будет добавлен в JSON, возвращаемый при вызове другого метода: MyMethodB ( ).

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

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

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

Важное примечание на вынос

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

3 голосов
/ 24 ноября 2011

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

JavaScriptSerializer serializer = new JavaScriptSerializer(null);
string json = serializer.Serialize(foo);
2 голосов
/ 03 октября 2012

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

<endpointBehaviors>
  <behavior name="MyServiceEndpoint">
    <webHttp/>
  </behavior>
</endpointBehaviors>
2 голосов
/ 03 марта 2010

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

1 голос
/ 05 ноября 2018

Вот способ обойти это

    [WebMethod]
    [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
    public void Status()
    {
        MyObject myObject = new MyObject(); // Your class here
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(myObject);

        HttpContext.Current.Response.Write(json);
    }
1 голос
/ 08 марта 2015

Мои 2 цента, однако в конце дня: как уже упоминали другие, кажется, есть два способа предотвратить свойство "__type":

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

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

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

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

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

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
    ...
}
...