【问题标题】:WebAPI serializer serializes base class instead of kludgy child classWebAPI 序列化器序列化基类而不是 kludgy 子类
【发布时间】:2015-04-15 21:43:54
【问题描述】:

我需要的类被序列化为 Web 服务响应主体。

问题是,来自基类的属性会随之序列化,而我无法为该服务提供这些属性。

我需要阻止这些属性仅在这个子类上序列化。所以我尝试使用new 隐藏属性,但基类属性仍在被序列化(即“Hello, world”在生成的 http 响应正文中):

public class MyBaseClass
{
    public string MyProperty { get { return "Hello, world"; } }
}

public class MyChildClass : MyBaseClass
{
    [XmlIgnore]
    [JsonIgnore]
    public new string MyProperty { get; set; }
}

这通过以下方式返回:

return myHttpRequestMessage.CreateResponse(myStatusCode, myChildClassInstance);

两个问题

  • 那是怎么回事?为什么不通过装饰来尊重子类?
  • 还有其他方法可以实现我想要实现的目标(防止装饰属性被序列化?

我知道这是一团糟,但在我有时间解决更深层次的问题(即强制这种继承的操作)之前,这就是我必须解决的问题。

【问题讨论】:

  • 如何初始化子类的实例?
  • [Serializable] 你的班级声明?
  • 您的测试用例是为 Json.Net 重现的,但不是为 DataContractJsonSerializer 重现的,它优先序列化子属性而不是父属性。这有帮助吗?
  • 假设您使用的是 Json.NET,这可能是相关的:stackoverflow.com/questions/27887787/…
  • 我正在使用默认的序列化程序,我认为它使用 json.net 用于 json 和 datacontractserializer 用于 xml。两者都需要支持。我先测试json,我没有专门尝试过xml。 @dbc 这就是你在说的吗?那如果是xml就好了? @robert 只是var childInstance = new ChildClass()。没什么特别的。

标签: c# serialization asp.net-web-api json.net datacontractserializer


【解决方案1】:

JSON

如果您使用 JSON.NET(这是 Web.API 中的默认 JSON 序列化程序),那么您可能需要使用自定义 ContractResolver。这个question 的答案有一个很好的例子来创建这种类型的类。在以下示例中,我将使用其中一个答案中的IgnorableSerializerContractResolver

现在你可以在Global.asax注册了:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new IgnorableSerializerContractResolver()
    .Ignore<MyBaseClass>(x => x.MyProperty);

如果您已经在使用某些合约解析器(例如 CamelCasePropertyNamesContractResolver),那么您需要以某种方式组合它们。

XML

我不知道您使用的是哪种类型的 XML 序列化(DataContractSerializerXmlSerializer),但据我所知,DataContractSerializer 不允许在运行时排除属性。您将需要使用XmlSerializer。您可以为每种类型设置自定义序列化程序:

var xmlOver = new XmlAttributeOverrides();
var xmlAttr = new XmlAttributes { XmlIgnore = true };
xmlOver.Add(typeof(MyBaseClass), "MyProperty", xmlAttr);

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.SetSerializer<MyChildClass>(new XmlSerializer(typeof(MyChildClass), xmlOver));

简单的方法

如果您有权访问您的MyBaseClass 并允许进行一些更改,那么您可以使用Data 属性解决您的问题:

[DataContract]
public class MyBaseClass
{
    public string MyProperty { get; set; }
}

[DataContract]
public class MyChildClass : MyBaseClass
{
    [DataMember]
    public string MyProperty2 { get; set; }
}

在这种情况下,您可以使用默认序列化程序(JSON.NET 用于 JSON,DataContractSerializer 用于 XML),它将自动为您解决。请注意,您必须DataContract 添加到MyBaseClass,否则 XML 序列化将失败。

【讨论】:

  • 您是否需要 XML 的相同功能?
  • 我愿意。我明天回到办公室时会试试这个。
【解决方案2】:

为了忽略基类中的属性,您可以在派生类中覆盖该属性并用JsonIgnoreAttribute 装饰它:

public class MyBaseClass
{
    public virtual string MyProperty { get { return "Hello, world"; } }
}

public class MyChildClass : MyBaseClass
{
    [JsonIgnore]
    public override string MyProperty { get; }
}

你得到一个空的 json 对象序列化它:

Debug.Assert(Newtonsoft.Json.JsonConvert.SerializeObject(new MyChildClass()) == "{}");

【讨论】:

    猜你喜欢
    • 2014-10-16
    • 1970-01-01
    • 2017-05-16
    • 1970-01-01
    • 2016-05-22
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多