我们有一些类包含多个子集合类属性以及根据用途可能设置或不设置的其他属性.这些对象从ASP.NET .asmx WebService返回,并使用ScriptService属性进行装饰,所以通过各种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配置,使用属性装饰服务等?
更新
那么我们找不到任何方法来切换开箱即用的JavaScriptSerializer,除了如上创建单独的JavaScriptConverter.
我们在这方面做了什么,以防止创建一个单独的转换器是创建一个通用的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服务参数以使用泛型类.
我相信这里有很多问题和违反“最佳实践”的问题,但是我们完成了这项工作,而不需要创建大量的自定义转换器类.