问题
I am serializing/deserializing a class that has a property of type System.Text.Encoding with Json.Net. Trying out a simple test, my class serialized without any issue:
public class TestClass {
public Encoding TheEncoding { get; set; }
}
var testClass = new TestClass { TheEncoding = Encoding.UTF8 };
var json = JsonConvert.SerializeObject( testClass, Formatting.Indented );
var obj = JsonConvert.DeserializeObject<TestClass>( json );
Serializes to:
{
"TheEncoding": {
"BodyName": "utf-8",
"EncodingName": "Unicode (UTF-8)",
"HeaderName": "utf-8",
"WebName": "utf-8",
"WindowsCodePage": 1200,
"IsBrowserDisplay": true,
"IsBrowserSave": true,
"IsMailNewsDisplay": true,
"IsMailNewsSave": true,
"IsSingleByte": false,
"EncoderFallback": {
"DefaultString": "?",
"MaxCharCount": 1
},
"DecoderFallback": {
"DefaultString": "?",
"MaxCharCount": 1
},
"IsReadOnly": true,
"CodePage": 65001
}
}
However, when deserializing, I got an exception:
Could not create an instance of type System.Text.Encoding. Type is an interface or abstract class and cannot be instantiated. Path 'TheEncoding.BodyName', line 3, position 16.
I was able to get past this issue by creating a custom converter that handles the System.Text.Encoding type:
public class JsonEncodingConverter : JsonConverter {
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) {
// Serialize as the BodyName.
serializer.Serialize( writer, ( value as Encoding ).BodyName );
}
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) {
// Already good to go.
return existingValue;
}
public override bool CanConvert( Type objectType ) {
return ( typeof ( Encoding ).IsAssignableFrom( objectType ) );
}
}
var testClass = new TestClass { TheEncoding = Encoding.UTF8 };
var json = JsonConvert.SerializeObject( testClass, Formatting.Indented, new JsonEncodingConverter() );
var obj = JsonConvert.DeserializeObject<TestClass>( json , new JsonEncodingConverter() );
Serializing with the custom converter now produces:
{
"TheEncoding": "utf-8"
}
And this JSON can be successfully round-tripped back to the original object when deserialized with the custom converter.
I'm new to Json.Net, and I have a strong feeling that I'm doing this the hard way! Surely there is a better and less involved way to handle System.Text.Encoding?
回答1:
Use [DataContract]
and [DataMember]
attributes to explicity set which properties will be serialized on your TestClass
objects.
- Omit the
[DataMember]
attribute from yourTheEncoding
property. - Create a helper property which gets serialized as "utf-8" (depending on the value of
TheEncoding
). Include the[DataMember]
attribute on this property.
For example:
[DataContract]
public class TestClass
{
public Encoding TheEncoding { get; set; }
[DataMember]
public string TheEncodingName
{
get
{
if (this.TheEncoding == System.Text.Encoding.UTF8)
return "utf-8";
// TODO: More possibilities
}
set
{
if (value == "utf-8")
this.TheEncoding = System.Text.Encoding.UTF8;
// TODO: More possibilities
}
}
}
When serialized, TheEncoding
will be skipped and TheEncodingName
will be serialized instead.
回答2:
I think the better way to approach this problem is to figure out exactly what properties do you need on your JSON object?
Server side there's no reason to include all of the properties from the Encoding
object because you already have access to it at run time as part of the .NET framework.
On the client I can't imagine why you would need all of the properties from the Encoding
object.
It might be more intuitive to just send the EncodingName
or BodyName
and from that you can determine what encoding object to use on the server.
As an example, if I were to send some JSON to the server specifying utf-8
I would know to use Encoding.UTF8
.
来源:https://stackoverflow.com/questions/16866632/is-there-a-better-way-to-handle-encoding-values-with-json-net