C# 如何不序列化 JSON 对象上的 __type 属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/627356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:52:18  来源:igfitidea点击:

How to not serialize the __type property on JSON objects

c#asp.netjsonasmxjavascriptserializer

提问by

Every object I return from a WebMethodof a ScriptServiceis wrapped into a JSON object with the data in a property named d. That's ok. But I don't want the additional __typeproperty to be served to the client, since I do manual processing with jQuery.

我从 aWebMethod的 a返回的每个对象都ScriptService被包装到一个 JSON 对象中,数据位于名为 的属性中d。没关系。但我不希望将附加__type属性提供给客户端,因为我使用 jQuery 进行手动处理。

Is it possible?

是否可以?

回答by

I found that if I make the default constructor of my class that my webmethod returns anything other than public it will not serialize the __type:ClassNameportion.

我发现,如果我使我的类的默认构造函数使我的 webmethod 返回除 public 之外的任何内容,则它不会序列化该__type:ClassName部分。

You may want to declare your default constructor protected internal ClassName() { }

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

回答by sean

Do not use the [Serializable] attribute.

不要使用 [Serializable] 属性。

The following should just do it

以下应该只是这样做

JavaScriptSerializer ser = new JavaScriptSerializer(); string json = ser.Serialize(objectClass);

JavaScriptSerializer ser = new JavaScriptSerializer(); 字符串 json = ser.Serialize(objectClass);

回答by Mironline

I not sure this a good solution , but if you use the Json.netlibrary, you can ignore some properties by adding [JsonIgnore]attribute.

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

回答by Laramie

This should solve it.

这应该解决它。

In the private SerializeValue method of JavaScriptSerializer in System.WebExtensions.dll, the __type is added to an internal dictionary if it can be resolved.

在 System.WebExtensions.dll 中 JavaScriptSerializer 的私有 SerializeValue 方法中,如果可以解析 __type 则添加到内部字典中。

From Reflector:

从反射器:

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

If the type can't be determined, serialization will still proceed, but the type will be ignored. The good news is that since anonymous types inherit getType() and the names returned are dynamically generated by the compiler, the TypeResolver returns null for ResolveTypeId and the "__type" attribute is subsequently ignored.

如果无法确定类型,序列化仍将继续,但类型将被忽略。好消息是,由于匿名类型继承了 getType() 并且返回的名称是由编译器动态生成的,因此 TypeResolver 为 ResolveTypeId 返回 null,随后忽略“__type”属性。

I also took John Morrison's advice with the internal constructor just in case, though using just this method, I was still getting __type properties in my JSON response.

为了以防万一,我还在内部构造函数中采纳了 John Morrison 的建议,尽管只使用了这种方法,但我的 JSON 响应中仍然有 __type 属性。

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

Note:I'm using an inherited JSON type converter that reads the XML Serialization attributes from serialized types to further compress the JSON. With thanks to CodeJournal. Works like a charm.

注意:我使用继承的 JSON 类型转换器从序列化类型读取 XML 序列化属性以进一步压缩 JSON。感谢CodeJournal。奇迹般有效。

回答by Stephen Kennedy

John's solution didn't work for me as the type I'm returning is in a seperate DLL. I have full control over that DLL but I can't construct my return type if the constructor is internal.

John 的解决方案对我不起作用,因为我返回的类型位于单独的 DLL 中。我可以完全控制那个 DLL,但是如果构造函数是内部的,我就不能构造我的返回类型。

I wondered if the return type being a public type in a library might even be the cause - I've been doing a lot of Ajax and not seen this one before.

我想知道返回类型是库中的公共类型是否可能是原因 - 我已经做了很多 Ajax 并且以前没有见过这个。

Quick tests:

快速测试:

  • Temporarily moved the return type declaration into App_Code. Still get __typeserialised.

  • Ditto and applied the protected internal constructor per JM. This worked (so he gets a vote).

  • 暂时将返回类型声明移至 App_Code。还是要__type连载。

  • 同上并根据 JM 应用受保护的内部构造函数。这奏效了(所以他得到了投票)。

Strangely I don't get __typewith a generic return type:

奇怪的是我没有得到__type一个通用的返回类型:

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

The solutionfor me, however, was to leave my return type in the DLL but change the WebMethod return type to object, i.e.

然而,我的解决方案是将我的返回类型保留在 DLL 中,但将 WebMethod 返回类型更改为 object,即

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

instead of

代替

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

回答by Jonathan Sayce

I've been trying some of these suggestions with a .NET 4 WCF service, and they don't seem to work - the JSON response still includes __type.

我一直在使用 .NET 4 WCF 服务尝试其中的一些建议,但它们似乎不起作用 - JSON 响应仍然包含 __type。

The easiest way I've discovered to remove the type-hinting is to change the endpoint behaviour from enableWebScript to webHttp.

我发现删除类型提示的最简单方法是将端点行为从 enableWebScript 更改为 webHttp。

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

The default enableWebScript behaviour is required if you're using an ASP.NET AJAX client, but if you're manipulating the JSON with JavaScript or jQuery then the webHttp behaviour is probably a better choice.

如果您使用的是 ASP.NET AJAX 客户端,则需要默认 enableWebScript 行为,但如果您使用 JavaScript 或 jQuery 操作 JSON,则 webHttp 行为可能是更好的选择。

回答by dlchambers

This is a bit of a hack, but this worked for me (using C#):

这有点hack,但这对我有用(使用C#):

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

Works with both [DataContract]and [DataContract(Namespace="")]

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

回答by Adam

Pass in null for the JavaScriptTypeResolver and the __type will not be serialized

为 JavaScriptTypeResolver 传入 null 并且 __type 不会被序列化

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

回答by Michael

A bit late to the thread but here goes.

线程有点晚了,但这里是。

We had the same issue when the property being added to the json string was a List<T>. What we did was add another property which was an array of T, something like.

当添加到 json 字符串的属性是 List<T> 时,我们遇到了同样的问题。我们所做的是添加另一个属性,它是一个 T 数组,类似于。

Before.

前。

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

After.

后。

public List<Person> People { get; set; }

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

While not an ideal solution, it does the trick.

虽然不是理想的解决方案,但它确实有效。

回答by Art Kg

In addition to John Morrison's advice on internalor protected internalconstructor in your DataContract class, which works amazingly well for web services and majority of WCF, you might need to make an additional change in your web.config file. Instead of <enableWebScript/>element use <webHttp/>for your endpointBehaviors, e.g.:

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

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