如何防止单个对象属性在是字符串时转换为 DateTime [英] How to prevent a single object property from being converted to a DateTime when it is a string
问题描述
这是我必须使用的模型的简化版本:
Here is a simplified version of the model I have to work with:
class InputModel
{
public string Name { get; set; }
public object Value { get; set; }
}
以及控制器的相关部分:
And the relevant parts of the controller:
class Controller : ApiController
{
[HttpPut]
public async Task<IHttpActionResult> Update([FromBody]InputModel model)
{
//implementation
}
}
InputModel 类的 Value 属性可以是任何类型,它是哪种类型只有稍后知道,在模型被发送到的一段遗留代码中,我无法控制.
the Value property of the InputModel class could be of any type, and which type it will be is only known later on, in a piece of legacy code the model is sent to and that i have no control over.
我遇到的问题是请求正文中的以下 json:
The problem I have occurs with the following json in the request body:
{
"name": "X",
"value": "2001-10-17T13:55:11.123"
}
默认行为是解析此 json,以便将 Value 属性转换为 DateTime.然而,DateTimes 的处理方式与遗留代码中的字符串非常不同,处理后数据会丢失(例如:当持久化到数据库时,毫秒部分被删除).因此,当稍后请求相同的值时,返回的值为2001-10-17T13:55:11"(缺少毫秒).
The default behavior is to parse this json so that the Value property gets converted to a DateTime. DateTimes however are handled very differently from strings in the legacy code and data is lost after handling it (for example: the millisecond part is removed when persisting to the database). So when the same value is later requested, the returned value is "2001-10-17T13:55:11" (milliseconds missing).
当然我可以通过在我的 web api 配置中全局设置来解决这个问题:
Of course I can fix this by globally setting this in my web api configuration:
httpConfiguration.Formatters.JsonFormatter.SerializationSettings.DateParseHandling = DateParseHandling.None;
但这样做也会禁用解析 DateTimes 的其他方法和控制器中的模型,这些模型具有需要默认行为的模型.
But doing so disables parsing DateTimes also for models in other methods and controllers that have models for which the default behavior is wanted.
我正在寻找类似于以下(虚构的)代码:
What I'm looking for is something like the following (imaginary) code:
class InputModel
{
public string Name { get; set; }
[JsonSerializerSettings(DateParseHandling = DateParseHandling.None)]
public object Value { get; set; }
}
但我不知道如何实现这一点.任何帮助将不胜感激.
But I can't find out how to achieve this. Any help would be greatly appreciated.
推荐答案
可以做的是添加一个 自定义 JsonConverter
到 InputModel
类型以临时切换 JsonReader.DateParseHandling
到 None
:
What one can do is to add a custom JsonConverter
to the InputModel
type to temporarily toggle JsonReader.DateParseHandling
to None
:
[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
class InputModel
{
public string Name { get; set; }
public object Value { get; set; }
}
public class DateParseHandlingConverter : JsonConverter
{
readonly DateParseHandling dateParseHandling;
public DateParseHandlingConverter(DateParseHandling dateParseHandling)
{
this.dateParseHandling = dateParseHandling;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var old = reader.DateParseHandling;
try
{
reader.DateParseHandling = dateParseHandling;
existingValue = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
serializer.Populate(reader, existingValue);
return existingValue;
}
finally
{
reader.DateParseHandling = old;
}
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
请注意,如果要反序列化的 JSON 包含嵌套数组或对象,则所有递归包含的值都将使用 DateParseHandling.None
进行解析.
Note that, if the JSON to be deserialized contains nested arrays or objects, all recursively contained values will be parsed with DateParseHandling.None
.
有人可能会问,为什么不直接在属性中添加一个转换器,像这样?
One might ask, why not add a converter directly to the property, like so?
class InputModel
{
public string Name { get; set; }
[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
public object Value { get; set; }
}
事实证明这是行不通的,因为当时 JsonConverter.ReadJson()
被调用,阅读器已经前进到日期字符串并将其标记为DateTime
. 因此转换器必须应用于包含类型.
It turns out that this does not work because, at the time JsonConverter.ReadJson()
is called, the reader has already advanced to the date string and tokenized it as a DateTime
. Thus the converter must be applied to the containing type.
这篇关于如何防止单个对象属性在是字符串时转换为 DateTime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!