Same problem as in #694 (default DateParseHandling settings lead to loss of original string value), different solution proposed.
I wanted to write a custom converter to convert my class to/from string (and I need the _exact string_ value even if it looks like datetime). Unfortunately, inside of ReadJson the value is already processed as DateTime, it's too late to set DateParseHandling.None as it cannot be re-read (forward-only) and it is not possible to recover its original string form.
I don't know of any way to configure DateParseHandling.None to be used selectively with my converter only, and not for entire json I'm reading.
I think the easiest way to solve the problem without breaking compatibility would be to provide original string value as a new property of JsonReader (RawValue?) - alongside Path, LinePosition etc.
public override object ReadJson(JsonReader jsonReader, Type type, object obj, JsonSerializer serializer)
{
jsonReader.DateParseHandling = DateParseHandling.None;
// - too late for that - parsing is already done for current token
return new MyClass(jsonReader.Value.ToString());
// - corrupted string for inputs like "2012-01-01T20:44:55+07:00" due to timezone loss
return new MyClass(JToken.Load(jsonReader).ToString());
// - same
return new MyClass(JRaw.Create(jsonReader).ToString());
// - same
return new MyClass(jsonReader.RawValue);
// - this would be awesome
}
This behaviour is absolutely bonkers. @JamesNK has been closing these issues on the grounds of backwards compatibility, which is understandable. Look's like the only way forward would be a fork.
Why can't you set DateParseHandling on the JsonReader before you start serializing?
Can I do it once for all deserializations of MyClass? If yes - could you give me some pointer how to achieve that?
I want it to deserialize the same way without having to remember to set DateParseHandling.None every time I do it - I want to reuse this class in many places (for sensitive user strings) without risking damaging the values by mistake.
I need a possibility to tell Json.NET to always use raw string value when deserializing MyClass - after all it's the class (or more specifically its converter) that knows how to ReadJson and I think ability to use original unmodified value belongs to that knowledge internal to the class/converter.
Use JsonConvert.DefaultSettings + DateParseHandling.None
But how can I tell Json.NET to always use DateParseHandling.None with my converter?
I know I can pass settings to DeserializeObject, but I would need to do it every time I call the method, which is exactly what I don't want to do for reasons explained above. I need some solution to empower my converter to access raw string regardless of settings passed to DeserializeObject.
This is shocking!
For anyone else stumbling on this...
public class MyConverter : JsonConverter<MyType>
{
:
public override MyType ReadJson(JsonReader reader, Type objectType, MyType existingValue, bool hasExistingValue, JsonSerializer serializer)
{
// Disable converting strings to date objects
**reader.DateParseHandling = DateParseHandling.None;**
:
}
:
}
After this, reader.TokenType will be JToken.String and not JToken.Date. Same with reader.Value.
For anyone else stumbling on this...
public class MyConverter : JsonConverter<MyType> { : public override MyType ReadJson(JsonReader reader, Type objectType, MyType existingValue, bool hasExistingValue, JsonSerializer serializer) { // Disable converting strings to date objects **reader.DateParseHandling = DateParseHandling.None;** : } : }After this, reader.TokenType will be JToken.String and not JToken.Date. Same with reader.Value.
Having the same problem. Unfortunately the solution above does not seem to work. Setting DateParseHandling seems to be to late and has no effect.
I know this issue is already closed but wanted to mention I'm running into same issue.
For the overall JSON string, I'd like to use DateParseHandling.DateTime or DateParseHandling.DateTimeOffset. However, for a specific type that handles dates in a custom way, for which I have a custom converter, I'd like to be able to always parse the raw string (skip the automatic date parsing) regardless of the general serialization settings.
The context is ASP.NET Core 3.1 application where I'm using DateTime for properties on the API models that have date and time component and my custom date-related type (contains a date with no time part) for some properties. So, I want to have the automatic date parse handling for the DateTime types but not for my custom type. I have one set of serialization settings configured via services.AddControllers().AddNewtonsoftJson(options => ... ).
For this particular case, it would be nice to have access within one of the JsonConverter.ReadJson(...) overloads (even if it's a new method to preserve backward compatibility of existing methods) to the original text before date handling logic parsed it. In my case, my custom converter inherits the generic JsonConverter<T>, not JsonConverter.
Specifically for the JsonTextReader, it seems this value is available internally in the private _stringReference but only made available via public JsonReader.Value for the current token when date parse handling is disabled or unsuccessful:
https://github.com/JamesNK/Newtonsoft.Json/blob/6b9f467e817854532ea31e6c08abe47c53ac8b5c/Src/Newtonsoft.Json/JsonTextReader.cs#L202-L240
I'm not sure what all the ramifications would be for exposing _stringReference through a public property that returns System.String given all the different token types and use cases of token handling. I also realize the base class JsonReader is what's provided to custom converters, e.g. in ReadJson but the reference above is to derived type JsonTextReader.
If it makes sense on JsonReader to expose the raw string that was read to create the token, not just current token JsonReader.Value, that would be ideal. However, even if this only makes sense in the context of JsonTextReader specifically, I could do a check like reader is JsonTextReader inside custom converter.
For reference, here is the top level call to Json.NET from ASP.NET Core for deserializing request body JSON string:
https://github.com/dotnet/aspnetcore/blob/271ebe019823e8e6a751429cd350c2db76ebab05/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs#L178
A totally different approach to achieving this goal, rather than exposing JsonReader._stringReference, could be to allow adjusting the DateParseHandling settings for certain output types from deserialization process. This may be a bit tricky though since the JsonReader parsing of the string happens before, and independently, of any process to convert to output/target type.
I am facing the same issue
I faced a similar issue, I needed the raw value of a field in my custom converter.
I asked them to add the function JsonReader.ReadRawValue, but nobody replied.
However, I sorted it out myself:
You can find the code on stackoverflow here:
Where is JsonReader.ReadRawValue?
Most helpful comment
But how can I tell Json.NET to always use
DateParseHandling.Nonewith my converter?I know I can pass settings to
DeserializeObject, but I would need to do it every time I call the method, which is exactly what I don't want to do for reasons explained above. I need some solution to empower my converter to access raw string regardless of settings passed toDeserializeObject.