asp.net - 如何从 ASP.NET Web 服务实现自定义 JSON 序列化?

标签 asp.net web-services json serialization

从 WebService 返回自定义类的实例时,有哪些序列化选项?

我们有一些类具有许多子集合类属性以及其他属性,这些属性可能会或可能不会根据使用情况进行设置。这些对象从用 ScriptService 属性修饰的 ASP.NET .asmx WebService 返回,因此在由各种 WebMethod 返回时通过 JSON 序列化进行序列化。

问题在于开箱即用的序列化返回所有公共(public)属性,无论是否使用它们,并且以比您想要限制的方式更详细的方式返回类名和其他信息流量。

目前,对于返回的类,我们添加了处理 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。我们向想要处理的类添加了一个空接口(interface),并且在 Web 服务启动时调用的 SupportedTypes 使用反射来查找实现该接口(interface)的任何类型,如下所示:

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;
          }
        }
      }
    }
  }
}

实际的实现有点不同,因此类型会被缓存,我们可能会重构它以使用自定义属性而不是空接口(interface)。

但是,我们在处理自定义集合时遇到了稍微不同的问题。这些通常只是扩展通用列表,但使用自定义类而不是 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在您的数据实体上(如果您有代码生成的数据实体,则作为分部类)以获得对序列化过程的细粒度控制,但我还没有尝试过。

关于asp.net - 如何从 ASP.NET Web 服务实现自定义 JSON 序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/159704/

相关文章:

c# - 如何排序和排名并选择唯一值?

javascript - 根据 javascript 中的模式验证 json

javascript - 如何使用 ng-repeat 显示带有条件的 json 数组?

jquery - ASP.net MVC 3 导航 Accordion 图像路径

.net - 是什么原因导致这个 "Invalid length for a Base-64 char array"

asp.net - 为什么 IE 无法从 Response.Write 服务器我的 CSV 文件?

JAVA-EE7/javax.ws.rs : Injection of EJB in REST-Resource

javascript - 自定义绑定(bind) (knockout.js) 以根据其他 <select> 更新 <select>

java - 在基于 Java 的 Web 服务中使用代理获取网页

javascript - JSON 属性最佳实践