problème de désérialisation ASP.NET ScriptService avec des types dérivés
-
26-09-2019 - |
Question
I ai un procédé de bande de ScriptService
(NET 3.5) qui prend un paramètre unique d'un type de base abstraite:
[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;
}
}
En général, lorsque la méthode est appelée, item
sera un Group
qui contient Instance
et / ou des objets Group
. J'appelle ce service de jQuery; Je ne suis pas en utilisant le cadre côté client Microsoft. Les appels à d'autres méthodes de travail bien.
Le problème: Quand je fais l'appel, une exception est levée avant que ma méthode est même invoqué. Par exemple, si mon appel est:
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":[]}}
... Je reçois un 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"}
Si je laisse tomber l'élément __type
de l'objet JSON ou modifier à Namespace.Item
(et supprimer le modificateur de abstract
de Item
), l'exception disparaît, mais le résultat objet désérialisé est évidemment un peu inutile.
Qu'est-ce que je manque?
La solution
Ah ha! En cliquant autour des liens connexes sur le côté droit de cette question, j'ai trouvé une réponse qui m'a aidé à résoudre ce problème.
L'attribut GenerateScriptType
doit être appliqué à la classe de service 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) { ... }
}
Sans ces attributs, le désérialiseur ne connaît pas mes types dérivés.
Autres conseils
Je pourrais résoudre ce en utilisant Newtonsofts JsonConvert
comme ci-dessous.
[System.Web.Services.WebMethod]
public static void MyAjaxCallingMethod(object inputs)
{
string stingDataFromAjaxCall = JsonConvert.SerializeObject(inputs);
MyObject myObj = JsonConvert.DeserializeObject<MyObject>(stingDataFromAjaxCall);
....}