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

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

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

40

我发现如果我将我的类的默认构造函数设置为除public以外的任何其他访问修饰符,它将不会序列化__type:ClassName 部分。

您可能希望将默认构造函数声明为protected internal ClassName() { }


1
如果您无法将其设置为非公共,并且您的对象来自不同的程序集,那么是否有任何解决方案?我很长一段时间没有__type,现在它偶尔会出现,即使我已经定义了自己的JavaScriptConverter :/ - Groxx
@Catch22:它如何将响应JSON对象中的数据量减半?有多少个对象和你的__type有多长? - Naor
9
@Naor:我的JS对象包含一个数组,其中有大约1000个简单对象,每个对象有两个属性(ID、Name)。然后,如果添加if__type=namespace.name(1000次),那么传输的数据量大约会翻倍。 - Catch22
1
这对我不起作用。有人可以发布一些示例代码吗? - Andrew Gee
1
对我来说也不起作用...仍然有这个__type属性。 - Mr. Pumpkin
显示剩余3条评论

25

由于我返回的类型在一个单独的DLL中,所以John的解决方案对我无效。我对那个DLL有完全的控制,但如果构造函数是internal,就不能构造我的返回类型。

我想知道返回类型是否是库中的公共类型甚至可能是原因-我一直在做很多Ajax,以前没有看到过这种情况。

快速测试:

  • 将返回类型声明临时移动到App_Code中。仍然会得到__type序列化。

  • 重复上述步骤并按JM的建议应用protected internal构造函数。这个方法可行(所以他得到了一票)。

奇怪的是,使用泛型返回类型时我不会得到__type

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

对我来说 解决方案 是保留DLL中的返回类型,但将 WebMethod 的返回类型更改为 object,即:

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

而不是

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

16

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

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

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

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


2
这是我在 .Net 4 Web 服务中唯一有效的方法。非常有用,谢谢。 - vlad259
太棒了,这种方式同时删除了“d”关键字。非常感谢。 - Domi.Zhang
1
我还必须显式设置消息格式:[WebGet(ResponseFormat = WebMessageFormat.Json)] - andersh
我在从enableWebScript切换到webHttp后,还必须指定defaultOutgoingResponseFormat="Json"automaticFormatSelectionEnabled="true" - WynandB
这对我有用,但是/jsdebug现在丢失了。如果您正在使用asp:ScriptManager生成js存根,则不好。 - Yasin Kilicdere

12

如果你正在使用ServiceStack.Text JSON序列化器,你只需要:

JsConfig.ExcludeTypeInfo = true;

这个功能在 v2.28 版本中自动添加回来了,但上面的代码将其排除在序列化之外。你也可以通过 Type 来更改此行为:

JsConfig<Type>.ExcludeTypeInfo = true;

5
我认为我已经找到了神秘出现“__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类作为参数,调用另一个方法MyMethodB()返回的JSON中就会添加__type。

即使它们是不同的方法!!

我的理论如下:

  1. 编写这样的Web服务时,Microsoft的代码会自动为您连接JSON序列化/反序列化行为,因为您使用了正确的属性,例如[WebMethod]和[ScriptService]。
  2. 当此自动魔法Microsoft代码执行时,它找到了一个以Cat类作为参数的方法。
  3. 它想...哦...好吧...既然我将从JSON接收到一个Cat对象....因此...如果我曾经从当前Web服务类中的任何方法以JSON形式返回Cat对象...我将给它一个__type属性,以便在反序列化回C#时容易识别。
  4. Nyah-hahahaha...

重要的收获笔记

通过避免将相关类(在我的情况下是Cat)作为WebMethods中的任何参数来避免在生成的JSON中出现__type属性。因此,在上面的代码中,只需尝试修改MyMethodA()以删除Cat参数即可。这将导致__type属性被生成。


1
这也是我的问题。我有一个函数,它以类作为参数,另一个函数返回它。一旦我删除了以类为输入的函数,__type就消失了。所以对于我来说,我将创建两个版本的任何需要双向传递的类,一个用于请求,一个用于响应。这样我就不会得到额外的__type开销了。 - eselk

4

以下是我的建议,虽然有些晚:正如其他人所提到的,似乎有两种方法可以防止 "__type" 属性:

a) 保护无参数构造函数

b) 避免将类作为参数传递给 Web 方法

如果您永远不需要将类作为参数传递,则可以将构造函数设置为 "protected internal"。如果您需要创建一个空对象,则添加一个工厂方法或者其他带有虚拟参数的构造函数。

但是,如果您需要将类作为参数传递给 Web 方法,则会发现,如果无参数构造函数受到保护(即 ajax 调用失败,可能是因为传入的 json 数据无法反序列化成您的类),这将无法工作。

这正是我的问题,所以我不得不使用 (a) 和 (b) 的组合:保护无参数构造函数,并创建一个仅用于 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
    ...
}

3

如果JavaScriptTypeResolver传入null,则不会序列化__type。

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

尝试了以上所有解决方案,仍然对我无效。 - tom_mai78101

2

除了John Morrison关于DataContract类中< strong>内部或< strong>受保护的内部构造函数的建议,这个建议非常适用于Web服务和大多数WCF操作,你可能需要在web.config文件中做出额外的更改。 为了使您的端点行为生效,请使用<webHttp/>元素而不是<enableWebScript/>元素,例如:

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

2

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


是的,Mironline是一个很好的解决方案。我个人使用它,并且认为忽略属性的最佳选项是[jsonIngore],感谢它。 - Dhaval Patel

1
有点晚了,但是还是来解决下这个问题。
当要添加到 JSON 字符串的属性是 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 { }
}

虽然不是理想的解决方案,但它能解决问题。


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