I have a model in my WebAPI application, written in .NET 4.0 that has a property of type System.Net.Mime.ContentType
, like this:
[Serializable]
public class FileData
{
private ContentType contentType;
private long size;
private string name;
public ContentType ContentType
{
get { return contentType; }
set { contentType = value; }
}
...
/* same getter/setter logic for the other fields */
}
The model resides in a separate assembly from my web project.
So, the client sends me a JSON message that I need to convert to this class:
{
"size": 12345,
"contentType": "image/png",
"name": "avatar.png"
}
In order to tell Json.NET how to convert the ContentType
I have registered a custom JsonConverter
that I have written for the purpose:
JsonFormatter.SerializerSettings.Converters.Add(new ContentTypeJsonConverter());
In the above code I am referring to the global JsonFormatter
obeject for the WebApi application.
Thus, when the client sends me the JSON, I am expecting the controller to properly parse the message.
Unfortunately, it fails with an error :
"Could not cast or convert from System.String to System.Net.Mime.ContentType."
I know I can work this around by adding the following code to my FileData
class:
public class FileData
{
...
[JsonConverter(typeof(ContentTypeJsonConverter))]
public ContentType ContentType { /* Getter and Setter */ }
}
but the problem is that I must not introduce dependencies to JSON.NET in the assembly where the FileData
type resides.
Is there any way to trigger the proper deserialization of the contentType
member without altering the FileData
class?
In addition to the above I also tried what Brian Rogers suggested:
JsonFormatter.SerializerSettings.ContractResolver = new CustomResolver();
with the following CustomResolver
implementation:
class CustomResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (objectType == typeof(ContentType))
{
contract.Converter = new ContentTypeJsonConverter();
}
return contract;
}
}
The result was still the same.
The following works for me (Web API 2).
Model:
[Serializable]
public class FileData
{
private ContentType contentType;
public ContentType ContentType
{
get { return contentType; }
set { contentType = value; }
}
}
Custom JSON converter:
public class ContentTypeJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ContentType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return new ContentType((string)reader.Value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((ContentType)value).ToString());
}
}
Converter registration (WebApiConfig.cs
):
public static void Register(HttpConfiguration config)
{
...
config
.Formatters
.JsonFormatter
.SerializerSettings
.Converters
.Add(new ContentTypeJsonConverter());
}
Controller:
public class TestController : ApiController
{
public IHttpActionResult Post(FileData data)
{
return this.Ok(data);
}
}
Request:
POST /api/test HTTP/1.1
Content-Type: application/json
Host: localhost:48278
Content-Length: 36
{
"contentType": "image/png"
}
Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?ZDpcd29ya1xUb0REXGFwaVx0ZXN0?=
X-Powered-By: ASP.NET
Date: Mon, 25 Jul 2016 07:06:02 GMT
Content-Length: 27
{"contentType":"image/png"}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With