问题描述
这是我必须使用的模型的简化版本:
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; }
}
事实证明这是行不通的,因为当时 被调用,阅读器已经前进到日期字符串并将其标记为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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!