¿Qué opciones hay para la serialización al devolver instancias de clases personalizadas desde un servicio web?¿Cómo implementar la serialización JSON personalizada desde el servicio web ASP.NET?
Tenemos algunas clases con varias propiedades de clase de colección secundaria, así como otras propiedades que pueden configurarse o no según el uso. Estos objetos se devuelven desde un ASP.NET .asmx WebService decorado con el atributo ScriptService, por lo que se serializan a través de la serialización JSON cuando los devuelven varios WebMethods.
El problema es que la serialización lista para usar devuelve todas las propiedades públicas, independientemente de si se usan o no, así como el nombre de la clase y otra información de una manera más detallada de lo que se desearía si quisiera limitar la cantidad de tráfico.
Actualmente, para ser devueltos a las clases que hemos añadido convertidores JavaScript personalizadas que manejan el serializtion JSON, e incluirlos en el web.config de la siguiente manera:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="CustomClassConverter" type="Namespace.CustomClassConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
Pero esto requiere un convertidor de medida para cada clase . ¿Hay alguna otra forma de cambiar la serialización JSON de fábrica, ya sea extendiendo el servicio, creando un serializador personalizado o similar?
Seguimiento
@marxidad:
Estamos utilizando la clase DataContractJsonSerializer en otras aplicaciones, sin embargo, han sido incapaces de encontrar la manera de aplicarla a estos servicios. Aquí está un ejemplo de cómo son los servicios de set-up:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
webMethods son llamados por javascript y datos serializados en JSON retorno. ¿El único método que hemos podido cambiar la serialización es usar los convertidores de JavaScript como se mencionó anteriormente?
¿Hay alguna manera de decirle al WebService que use un DataContractJsonSerializer personalizado? Ya sea por la configuración web.config, decorando el servicio con atributos, etc.
actualización
Bueno, no pudimos encontrar ninguna manera de cambiar la de la caja JavaScriptSerializer a excepción de la creación de JavaScriptConverters individuales que el anterior.
Lo que hicimos con ese fin para evitar tener que crear un convertidor separado fue crear un JavaScriptConverter genérico. Hemos añadido una interfaz vacía a las clases que queríamos ocupó y los SupportedTypes que se llama el servicio web puesta en marcha utiliza la reflexión para encontrar tipos que implementan el tipo de interfaz de la siguiente manera:
public override IEnumerable<Type> SupportedTypes
{
get
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder;
if (dynamicAssemblyCheck == null)
{
foreach (Type type in assembly.GetExportedTypes())
{
if (typeof(ICustomClass).IsAssignableFrom(type))
{
yield return type;
}
}
}
}
}
}
La implementación real es un poco diferente para que el tipo esté en caché, y probablemente lo refaccionaremos para usar atributos personalizados en lugar de una interfaz vacía.
Sin embargo, con esto, nos encontramos con un problema ligeramente diferente cuando se trata de colecciones personalizadas. Por lo general, estos solo extienden una lista genérica, pero las clases personalizadas se usan en lugar de la Lista <> misma porque generalmente hay una lógica personalizada, clasificación, etc. en las clases de colección.
El problema es que el método Serialize para un JavaScriptConverter devuelve un diccionario que se serializa en JSON como pares de nombre y valor con el tipo asociado, mientras que una lista se devuelve como una matriz. Por lo tanto, las clases de recopilación no se podían serializar fácilmente con el convertidor. La solución para esto fue simplemente no incluir esos tipos en SupportedTypes del convertidor y se serializaron perfectamente como listas.
Entonces, la serialización funciona, pero cuando intenta pasar estos objetos de otra manera como un parámetro para una llamada de servicio web, la deserialización se rompe, porque no pueden ser la entrada se trata como una lista de cadena/objeto diccionarios, que no se pueden convertir a una lista de cualquier clase personalizada que contenga la colección. La única forma que podemos encontrar para resolver esto es crear una clase genérica que sea una lista de diccionarios de cadenas/objetos que luego convierta la lista a la clase de recopilación personalizada adecuada y luego cambiar los parámetros del servicio web para usar la clase genérica. .
Estoy seguro de que hay un montón de problemas y violaciones de las "mejores prácticas" aquí, pero nos hace el trabajo sin crear un montón de clases de conversión personalizadas.
El servicio web está decorado con el atributo ScriptService, por lo que devuelve JSON de forma predeterminada, por lo que el atributo ScriptMethod no es necesario. –