派生类型的 ASP.NET ScriptService 反序列化问题

发布于 2024-09-25 05:01:40 字数 2651 浏览 1 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒绊 2024-10-02 05:01:40

啊哈!单击此问题右侧的相关链接,我发现 一个答案帮助我解决了这个问题。

GenerateScriptType 属性必须应用于 Web 服务类:

[WebService( ... )]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
[GenerateScriptType(typeof(Group))]
[GenerateScriptType(typeof(Instance))]
public class WebService : System.Web.Services.WebService
{
    [WebMethod(EnableSession=true)]
    [ScriptMethod()]
    public bool Test(Item item) { ... }
}

如果没有这些属性,反序列化器将不知道我的派生类型。

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:

[WebService( ... )]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
[GenerateScriptType(typeof(Group))]
[GenerateScriptType(typeof(Instance))]
public class WebService : System.Web.Services.WebService
{
    [WebMethod(EnableSession=true)]
    [ScriptMethod()]
    public bool Test(Item item) { ... }
}

Without these attributes, the deserializer doesn't know about my derived types.

海螺姑娘 2024-10-02 05:01:40

我可以使用 Newtonsofts JsonConvert 解决这个问题,如下所示。

[System.Web.Services.WebMethod]      
public static void MyAjaxCallingMethod(object inputs)
    {           
    string stingDataFromAjaxCall = JsonConvert.SerializeObject(inputs);
            MyObject myObj = JsonConvert.DeserializeObject<MyObject>(stingDataFromAjaxCall);
            ....}

I could solve this using Newtonsofts JsonConvert as below.

[System.Web.Services.WebMethod]      
public static void MyAjaxCallingMethod(object inputs)
    {           
    string stingDataFromAjaxCall = JsonConvert.SerializeObject(inputs);
            MyObject myObj = JsonConvert.DeserializeObject<MyObject>(stingDataFromAjaxCall);
            ....}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文