Web API: 无法序列化内容类型的响应正文

Web API: Failed to serialize the response body for content type

我正在使用 ASP.NET MVC 5 Web Api。

我有很多 api 的现有应用程序。 最近我实现了自定义 JsonConverter,它将根据时区转换日期。

public class CustomInfoConverter : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(CustomType);
    }
    public override bool CanRead
    {
        get
        {
            return false;
        }
    }
    public override bool CanWrite
    {
        get
        {
            return true;
        }
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var customType = (CustomType)value;
        if (customType == null || null== customType.TimeZone) return;
        //DateTime currentDateTime = customType.Date??DateTime.Now;
        DateTime currentDateTime = DateTime.SpecifyKind(customType.Date ?? DateTime.Now, DateTimeKind.Unspecified);

        DateTime userDateTime = TimeZoneInfo.ConvertTimeFromUtc(currentDateTime, customType.TimeZone);
        customType.Date = userDateTime;
        JsonSerializer innerSerializer = new JsonSerializer();
        foreach (var converter in serializer.Converters.Where(c => !(c is CustomInfoConverter)))
        {
            innerSerializer.Converters.Add(converter);
        }
        innerSerializer.Serialize(writer, customType);


    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }


}

在实施此自定义 JsonConverter 之后,所有 api 都在工作,除了一个 api,它抛出以下异常

{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Token PropertyName in state Property would result in an invalid JSON object. Path 'Data.Forms[0]'.","ExceptionType":"Newtonsoft.Json.JsonWriterException","StackTrace":" at Newtonsoft.Json.JsonWriter.AutoComplete(JsonToken tokenBeingWritten)\r\n at Newtonsoft.Json.JsonWriter.InternalWritePropertyName(String name)\r\n at Newtonsoft.Json.JsonTextWriter.WritePropertyName(String name, Boolean escape)\r\n at Newtonsoft.Json.Serialization.JsonProperty.WritePropertyName(JsonWriter writer)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at System.Web.Http.WebHost.HttpControllerHandler.d__1b.MoveNext()"}}

您可以参考这篇了解更多详情。

问题似乎是,在某些情况下,您从 WriteJson() 返回时没有写任何东西,特别是当 customType.TimeZone == null:

    var customType = (CustomType)value;
    if (customType == null || null== customType.TimeZone) return;

这样做会导致无效的 JSON 对象,因为 属性 name 已经被调用者写入,导致:

{
    "customType":
}

尝试执行此操作会导致您看到异常。

相反,您需要防止 属性 本身被序列化。然而,这在转换器中是不可能的,它需要在包含类型中完成。

为了避免用空值序列化 属性,您应该在 serializer settings 中或在 属性 本身上设置 NullValueHandling = NullValueHandling.Ignore

public class ContainerClass
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public CustomType CustomType { get; set; }
}

要防止在 TimeZone 属性 为 null 时序列化您的 属性,您应该通过向包含类型添加 ShouldSerializeXXX() 方法来使用 conditional property serialization ,其中 XXX 与您的 属性 姓名完全匹配:

public class ContainerClass
{
    public CustomType CustomType { get; set; }

    public bool ShouldSerializeCustomType()
    {
        return CustomType != null && CustomType.TimeZone != null;
    }
}