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

69
每个从ScriptServiceWebMethod返回的对象都被包装成一个JSON对象,其中数据存储在名为d的属性中。这是可以接受的。但我不想将额外的__type属性提供给客户端,因为我使用jQuery进行手动处理。
有可能实现吗?

ASP.NET 3.5 SP1,C#服务器端 jQuery客户端,执行$.ajax调用 - Robert
这些解决方案都没有对我起作用,我的响应中仍然有__type。有人有更多的解决方案吗? - Alma
17个回答

1

不要使用[Serializable]属性。

以下代码就可以实现:

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


它输出一个JSON,其中所有键都有转义引号(\") - 这必须在客户端处理。为了避免这种情况(双重JSON格式化),请参见https://dev59.com/cXA75IYBdhLWcg3w1sz2#3079326。您还必须使用`System.Web.Script.Serialization`命名空间,该命名空间位于`System.Web.Extensions.dll`中。 - Alex P.

1
这是一个解决方法。
    [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);
    }

0

这应该解决它。

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

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

如果无法确定类型,则序列化仍将继续进行,但将忽略该类型。好消息是,由于匿名类型继承了getType()并且编译器动态生成返回的名称,因此TypeResolver对ResolveTypeId返回null,随后忽略“__type”属性。
我还采纳了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;
    }
}

注意:我正在使用继承的JSON类型转换器,该转换器从序列化类型中读取XML序列化属性以进一步压缩JSON。感谢CodeJournal。非常好用。


为什么他们会认为在你完成更改之后修改自定义序列化是个好主意呢? 我使用的是ASP.NET 2.0,这里没有var关键字。你知道是否有类似的方法吗? - Groxx

0

除了 @sean 的回答使用 JavaScriptSerializer 之外。

当使用 JavaScriptSerializer 并标记方法的 ResponseFormat = WebMessageFormat.Json 时,生成的响应会进行两次 JSON 编码,而且如果生成的响应是 string 类型,它将被放置在双引号之间。

为了避免这种情况,可以使用 这个优秀答案 中提供的解决方案来将内容类型定义为 JSON(覆盖)并流式传输 JavaScriptSerializer 的二进制结果。

来自上述答案的代码示例:

public Stream GetCurrentCart()
{
    //Code ommited
    var j = new { Content = response.Content, Display=response.Display,
                  SubTotal=response.SubTotal};
    var s = new JavaScriptSerializer();
    string jsonClient = s.Serialize(j);
    WebOperationContext.Current.OutgoingResponse.ContentType =
        "application/json; charset=utf-8";
    return new MemoryStream(Encoding.UTF8.GetBytes(jsonClient));
}

JavaScriptSerializer位于System.Web.Script.Serialization命名空间中,该命名空间在System.Web.Extensions.dll中找到,但默认情况下未被引用。


0

您可以创建自己的返回类型来发送响应。同时,在发送响应时,使用对象作为返回类型。因此,_type属性将被忽略。


0
var settings = new DataContractJsonSerializerSettings();
settings.EmitTypeInformation = EmitTypeInformation.Never;
DataContractJsonSerializer serializerInput = new DataContractJsonSerializer(typeof(Person), settings);
var ms = new MemoryStream();
serializerInput.WriteObject(ms, personObj);
string newRequest = Encoding.UTF8.GetString(ms.ToArray());

-7

这有点取巧,但对我来说有效(使用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="")]两种方式


6
我-1,因为建议某人这样做是如此糟糕,以至于不说比说话更好。 - Baptiste Pernet
1
这是什么编程语言:s =(带有“__type”:“clsname”属性的JSON字符串)?? - Darko Romanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接