Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSonConverter not firing for property of my model in a C# WebAPI

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.

like image 340
Ivaylo Slavov Avatar asked Oct 30 '22 23:10

Ivaylo Slavov


1 Answers

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"}
like image 99
Darin Dimitrov Avatar answered Nov 15 '22 06:11

Darin Dimitrov