如何从ASP.NET Web服务实现自定义JSON序列化?
从WebService返回自定义类的实例时,有哪些序列化选项?
我们有一些具有许多子集合类属性的类以及根据用法设置或不设置的其他属性。 这些对象是从用ScriptService属性装饰的ASP.NET .asmx WebService返回的,因此当由各种WebMethods返回时,通过JSON序列化进行序列化。
问题在于,开箱即用的序列化会返回所有公共属性,无论它们是否被使用,以及以比所需的更加冗长的方式返回类名和其他信息,如果您想限制交通。
目前,对于返回的类,我们添加了处理JSON序列化的自定义JavaScript转换器,并将它们添加到web.config中,如下所示:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="CustomClassConverter" type="Namespace.CustomClassConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
但是这需要每个班级的自定义转换器。 有没有其他的方式来改变开箱即用的JSON序列化,或者通过扩展服务,创建一个自定义序列化器或类似的东西?
跟进
@marxidad:
我们在其他应用程序中使用DataContractJsonSerializer类,但是我一直无法弄清楚如何将它应用到这些服务。 以下是如何设置服务的示例:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
WebMethods由javascript调用并返回以JSON序列化的数据。 我们能够改变序列化的唯一方法是使用上面提到的JavaScript转换器?
有没有办法告诉WebService使用自定义DataContractJsonSerializer? 无论是通过web.config配置,使用属性装饰服务等?
更新
那么,除了像上面那样创建单独的JavaScriptConverters外,我们找不到任何方式来切换开箱即用的JavaScriptSerializer。
我们在这方面做了什么来防止创建一个单独的转换器,就是创建了一个通用的JavaScriptConverter。 我们为我们想要处理的类添加了一个空接口,并且在Web服务启动时调用的SupportedTypes使用反射来查找实现接口类型的任何类型,如下所示:
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;
}
}
}
}
}
}
实际的实现有点不同,因此类型被缓存,我们可能会重构它以使用自定义属性而不是空的接口。
但是,在处理自定义集合时,我们碰到了一个稍微不同的问题。 这些通常只是扩展通用列表,但是使用自定义类而不是List <>本身,因为在集合类中通常存在自定义逻辑,排序等。
问题是JavaScriptConverter的Serialize方法返回一个字典,该字典被序列化为JSON作为具有关联类型的名称值对,而列表作为数组返回。 所以收集类不能使用转换器轻松地序列化。 这个解决方案仅仅是在转换器的SupportedTypes中不包括这些类型,并且它们完全作为列表序列化。
因此,序列化可以起作用,但是当您尝试以另一种方式将这些对象作为Web服务调用的参数传递时,反序列化会中断,因为它们不能作为输入被视为字符串/对象字典的列表,不会被转换为集合包含的任何自定义类的列表。 我们可以找到处理这个问题的唯一方法是创建一个泛型类,它是一个字符串/对象字典列表,然后将该列表转换为适当的自定义集合类,然后更改任何Web服务参数以使用泛型类。
我确信这里存在大量的问题和违反“最佳实践”的情况,但是它为我们完成了工作,而无需创建大量的自定义转换器类。
如果您不使用代码生成的类,则可以使用ScriptIgnoreAttribute修饰您的属性,以通知序列化程序忽略某些属性。 Xml序列化具有类似的属性。
当然,如果要在一个服务方法调用中返回一个类的某些属性,并在不同的服务方法调用中返回同一个类的不同属性,则不能使用此方法。 如果你想这样做,请在服务方法中返回一个匿名类型。
[WebMethod]
[ScriptMethod]
public object GimmieData()
{
var dalEntity = dal.GimmieEntity(); //However yours works...
return new
{
id = dalEntity.Id,
description = dalEntity.Desc
};
}
序列化器可以不关心发送给它的对象的类型,因为它只是将它转换为文本。
我也相信你可以在你的数据实体上实现ISerializable(如果你有代码生成的数据实体,它是一个部分类)来获得对序列化过程的细粒度控制,但是我没有尝试过。
我知道这个线程已经安静了一段时间,但我想我会提供,如果您在自定义转换器中覆盖JavaScriptConverter的SupportedTypes属性,则可以添加应使用转换器的类型。 这可能会在必要时进入配置文件。 这样你就不需要为每个班级定制一个转换器。
我试图创建一个通用转换器,但无法弄清楚如何在web.config中识别它。 想知道是否有其他人管理它。
我在尝试解决上述问题时得到了这个想法,并偶然发现了Nick Berardi的“创建更精确的JSON .NET序列化程序”(google it)。
为我工作:)
谢谢大家。
如果您使用.NET 3.x(或可以),WCF服务将是您最好的选择。
您可以选择性地使用[DataMember]属性控制将哪些属性序列化到客户端。 如果您愿意,WCF还可以对JSON序列化和反序列化进行更精细的控制。
这是一个很好的例子:http://blogs.msdn.com/kaevans/archive/2007/09/04/using-wcf-json-linq-and-ajax-passing-complex-types-to-wcf -Services与 - JSON-encoding.aspx
链接地址: http://www.djcxy.com/p/56653.html上一篇: How to implement custom JSON serialization from ASP.NET web service?
下一篇: Setting a default ErrorMessage for a custom ASP.NET MVC ValidationAttribute