asp.net - serialize - web api asp net return json
¿Cómo implementar la serialización JSON personalizada desde el servicio web ASP.NET? (5)
No me cite en este trabajo con certeza, pero creo que esto es lo que está buscando.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public XmlDocument GetXmlDocument()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(_xmlString);
return xmlDoc;
}
¿Qué opciones hay para la serialización al devolver instancias de clases personalizadas desde un servicio web?
Tenemos algunas clases con varias propiedades de clase de recopilación infantil, 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 mediante 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 manera más detallada de lo que se desearía si se quisiera limitar la cantidad de tráfico.
Actualmente, para las clases que se devuelven hemos agregado convertidores personalizados de JavaScript que manejan la serialización JSON, y los hemos agregado al web.config como se muestra a continuación:
<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 personalizado 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?
Seguir
@marxidad:
Estamos utilizando la clase DataContractJsonSerializer en otras aplicaciones, sin embargo, no he podido averiguar cómo aplicarlo a estos servicios. Aquí hay un ejemplo de cómo se configuran los servicios:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
Los WebMethods son llamados por javascript y devuelven datos serializados en JSON. ¿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.
Actualizar
Bueno, no pudimos encontrar ninguna forma de cambiar el JavaScriptSerializer de fábrica, excepto para crear JavaScriptConverters individuales como se indicó anteriormente.
Lo que hicimos en ese extremo para evitar tener que crear un convertidor separado fue crear un JavaScriptConverter genérico. Añadimos una interfaz vacía a las clases que queríamos manejar y SupportedTypes, que se llama en el inicio del servicio web, usa la reflexión para encontrar cualquier tipo que implemente la 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, por lo que el tipo se almacena en caché, y es probable que 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 <> en sí 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 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 al servicio web, la deserialización se rompe, porque no pueden ser la entrada se trata como una lista de diccionarios de cadenas / objetos, que pueden No se convertirá en una lista de la 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 hace el trabajo por nosotros sin crear una tonelada de clases de conversión personalizadas.
Puede usar System.Runtime.Serialization.Json.
Clase DataContractJsonSerializer
en el ensamblado System.ServiceModel.Web.dll
.
Si usa .NET 3.x (o puede), un servicio WCF será su mejor opción.
Puede controlar selectivamente qué propiedades se serializan al cliente con el atributo [DataMember]. WCF también permite un control más detallado sobre la serialización JSON y la deserialización, si lo desea.
Este es un buen ejemplo para comenzar: http://blogs.msdn.com/kaevans/archive/2007/09/04/using-wcf-json-linq-and-ajax-passing-complex-types-to-wcf -services-with-json-encoding.aspx
Si no usa clases generadas por código, puede decorar sus propiedades con ScriptIgnoreAttribute para decirle al serializador que ignore ciertas propiedades. La serialización Xml tiene un atributo similar.
Por supuesto, no puede usar este enfoque si desea devolver algunas propiedades de una clase en una llamada de método de servicio y diferentes propiedades de la misma clase en una llamada de método de servicio diferente. Si desea hacer eso, devuelva un tipo anónimo en el método de servicio.
[WebMethod]
[ScriptMethod]
public object GimmieData()
{
var dalEntity = dal.GimmieEntity(); //However yours works...
return new
{
id = dalEntity.Id,
description = dalEntity.Desc
};
}
Al serializador no le importa el tipo de objeto que le envíe, ya que simplemente lo convierte en texto.
También creo que podría implementar ISerializable en su entidad de datos (como una clase parcial si tiene entidades de datos genéricas) para obtener un control detallado sobre el proceso de serialización, pero no lo he intentado.
Sé que este hilo ha estado en silencio por un tiempo, pero pensé que ofrecería que si anulas la propiedad SupportedTypes de JavaScriptConverter en tu convertidor personalizado, puedes agregar los tipos que deberían usar el convertidor. Esto podría entrar en un archivo de configuración si es necesario. De esta forma, no necesitarías un convertidor personalizado para cada clase.
Traté de crear un convertidor genérico pero no pude encontrar la manera de identificarlo en el web.config. Me encantaría saber si alguien más lo ha logrado.
Tuve la idea al tratar de resolver el problema anterior y tropecé con el "Serializador JSON .NET más preciso" de Nick Berardi (google it).
Trabajó para mi:)
Gracias a todos.