Pregunta

Tengo un método ScriptService web (.NET 3.5), que toma un único parámetro de un tipo de base abstracta:

[WebMethod(EnableSession=true)]
[ScriptMethod()]
public bool Test(Item item) { ... }

Y:

namespace Namespace {
public abstract class Item
{
    public int id;
}

public class Group : Item
{
    public Item[] items;
}

public class Instance : Item
{
    public string whatever;
}
}

Por lo general, cuando se llama al método, item será un Group que contiene Instance y / o Group objetos. Voy a llamar a este servicio desde jQuery; No estoy usando el marco del lado del cliente Microsoft. Las llamadas a otros métodos bien el trabajo.

El problema: Cuando hago la llamada, se produce una excepción antes de que mi método es incluso invoca. Por ejemplo, si mi llamada es:

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":[]}}

... me sale 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 me cae el miembro __type del objeto JSON o cambiarla a Namespace.Item (y eliminar el modificador abstract de Item), la excepción desaparece, pero el objeto deserializado resultante es obviamente un poco inútil.

¿Qué me falta?

¿Fue útil?

Solución

Ah, ja! Al hacer clic en torno a los enlaces relacionados en el lado derecho de esta pregunta, he encontrado una respuesta que me ayudó a resolver este problema.

El atributo GenerateScriptType se debe aplicar a la clase de servicio 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) { ... }
}

Sin estos atributos, el deserializer no sabe nada de mis tipos derivados.

Otros consejos

Me podría resolver esto utilizando Newtonsofts JsonConvert como a continuación.

[System.Web.Services.WebMethod]      
public static void MyAjaxCallingMethod(object inputs)
    {           
    string stingDataFromAjaxCall = JsonConvert.SerializeObject(inputs);
            MyObject myObj = JsonConvert.DeserializeObject<MyObject>(stingDataFromAjaxCall);
            ....}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top