派生类型的 ASP.NET ScriptService 反序列化问题
我有一个 ScriptService
Web 方法 (.NET 3.5),它采用抽象基本类型的单个参数:
[WebMethod(EnableSession=true)]
[ScriptMethod()]
public bool Test(Item item) { ... }
并且:
namespace Namespace {
public abstract class Item
{
public int id;
}
public class Group : Item
{
public Item[] items;
}
public class Instance : Item
{
public string whatever;
}
}
通常,当调用该方法时,item
将是Group
包含 Instance
和/或 Group
对象。我从 jQuery 调用此服务;我没有使用 Microsoft 客户端框架。调用其他方法工作正常。
问题:当我进行调用时,在调用我的方法之前就会引发异常。例如,如果我的调用是:
POST /WebService.asmx/Test HTTP/1.1
Content-Type: application/json; charset=UTF-8
Accept: application/json, text/javascript, */*
{"item":{"id":0,"__type":"Namespace.Group","items":[]}}
...我收到 InvalidOperationException
:
{"Message":"Operation is not valid due to the current state of the object.","StackTrace":" at System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject(IDictionary`2 dictionary, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeDictionary(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.InvalidOperationException"}
如果我删除 JSON 对象的 __type
成员或将其更改为 Namespace.Item
(并从 Item
中删除 abstract
修饰符),异常消失,但生成的反序列化对象显然有点无用。
我缺少什么?
I have a ScriptService
web method (.NET 3.5) which takes a single parameter of an abstract base type:
[WebMethod(EnableSession=true)]
[ScriptMethod()]
public bool Test(Item item) { ... }
And:
namespace Namespace {
public abstract class Item
{
public int id;
}
public class Group : Item
{
public Item[] items;
}
public class Instance : Item
{
public string whatever;
}
}
Usually, when the method is called, item
will be a Group
which contains Instance
and/or Group
objects. I'm calling this service from jQuery; I'm not using the Microsoft client-side framework. Calls to other methods work fine.
The problem: When I make the call, an exception is thrown before my method is even invoked. For example, if my call is:
POST /WebService.asmx/Test HTTP/1.1
Content-Type: application/json; charset=UTF-8
Accept: application/json, text/javascript, */*
{"item":{"id":0,"__type":"Namespace.Group","items":[]}}
...I get an InvalidOperationException
:
{"Message":"Operation is not valid due to the current state of the object.","StackTrace":" at System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject(IDictionary`2 dictionary, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeDictionary(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.InvalidOperationException"}
If I drop the __type
member of the JSON object or change it to Namespace.Item
(and remove the abstract
modifier from Item
), the exception goes away, but the resulting deserialized object is obviously kinda useless.
What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
啊哈!单击此问题右侧的相关链接,我发现 一个答案帮助我解决了这个问题。
GenerateScriptType
属性必须应用于 Web 服务类:如果没有这些属性,反序列化器将不知道我的派生类型。
Ah ha! Clicking around the related links on the right side of this question, I found an answer that helped me solve this problem.
The
GenerateScriptType
attribute must be applied to the web service class:Without these attributes, the deserializer doesn't know about my derived types.
我可以使用 Newtonsofts JsonConvert 解决这个问题,如下所示。
I could solve this using
Newtonsofts JsonConvert
as below.