4

Note I don't believe this is a duplicate of this question. in which the objective is to deserialise a model using a non-default constructor, whereas I need my custom deserialiser, not the model, to instantiate using its non-default constructor, injecting some dependency set up in the API statup. I tried the JsonConstructor anyway, but it still produced the same error.

Newtonsoft.Json.JsonException: No parameterless constructor defined for 'Domain.UserProjector'.


I'm working on an API that should allow the consumer to dictate resource projections based on some query string parameters. I though it'd be easiest handling it during JSON serialisation.

The model

I decorate my model with the custom serialiser.

[JsonConverter(typeof(CustomProjector))]
public class SomeDTO { /* members */ }

The converter

I implement my custom serialiser, injecting the required HttpContext.

public class CustomProjector : JsonConverter
{
    public CustomProjector(IHttpContextAccessor httpContext)
    {
        /* IHttpContextAccessor is already set up in the dependency container. Then get the requirements from the query string. */
    }

    /* JsonConverter implementation */
}

The API method

And all I have to do is return the result.

public IActionResult GetSomething(int id)
{
    SomeDTO something = domain.GetSomething(id);

    return this.Ok(somthing);
}

Unfortunately this doesn't work because JsonConverter implementations need default constructors, and an error is thrown due to the paramaterised constructor in CustomProjector, producing an error:

Newtonsoft.Json.JsonException: No parameterless constructor defined for 'Domain.UserProjector'.


A possible solution is to simply provide CustomProjector with the query string and do the convertion manually.

The model

No decoration required.

public class SomeDTO { /* members */ }

The converter

HttpContext is replaced by the query string, since I'm going to instantiate it manually.

public class CustomProjector : JsonConverter
{
    public CustomProjector(string queryString)
    {
        /* Get requirements from query string. */
    }

    /* JsonConverter implementation */
}

The API method

Instantiate the converter, and use it convert, before returning the result.

public IActionResult GetSomething(int id)
{
    SomeDTO something = domain.GetSomething(id);

    CustomProjector projector = new CustomProjector(this.Request.QueryString.Value);
    string somethingSerialised = JsonConvert.SerializeObject(something, projector);

    return this.Ok(somethingSerialised);
}

or

Pass the individual query string parameters to the constructor, but this is essentially the same as the option above.

The model

public class CustomProjector : JsonConverter
{
    public CustomProjector(string reqParam1, string reqParam2)
    {
        /* Use requirements provided. */
    }

    /* JsonConverter implementation */
}

The API method

public IActionResult GetSomething(int id, string reqParam1, string reqParam2)
{
    SomeDTO something = domain.GetSomething(id);

    CustomProjector projector = new CustomProjector(reqParam1, reqParam2);
    string somethingSerialised = JsonConvert.SerializeObject(something, projector);

    return this.Ok(somethingSerialised);
}

I would like to avoid these solutions as it requires API methods to include the parameters and requires that each method converts the results manually, or the returned data will be incorrect.


Is there something I can change to make it work the way I want? Perhaps something to do with DI? Perhaps a different serialiser?

Much appreciated!

Community
  • 1
  • 1
that0th3rGuy
  • 1,356
  • 1
  • 15
  • 19
  • 1
    Possible duplicate of [JSON.net: how to deserialize without using the default constructor?](http://stackoverflow.com/questions/23017716/json-net-how-to-deserialize-without-using-the-default-constructor) – Metro Smurf Feb 16 '17 at 18:27
  • I believe this is essentially the same question as [JSON.net: how to deserialize without using the default constructor?](http://stackoverflow.com/questions/23017716/). In other words, you would create a `JsonSerializerSettings` with an instance of your converter passing in the `IHttpContextAccessor` as the .ctor parameter and pass the converter to the Json deserializer with the `JsonSerializerSettings`. – Metro Smurf Feb 16 '17 at 18:30
  • 1
    Thank you for your responses, however, as I noted in the edit, I do not believe this is a duplicate, the difference being non-default instantiation of a deserialisation target object vs. non-default instantiation of the custom deserialiser itself. – that0th3rGuy Feb 17 '17 at 04:33
  • Furthermore, it's definitely possible doing it all manually -- constructing the converter, passing the query string, returning the result -- but I was hoping to avoid the manuality, and instead decorate models with their deserialisers and injecting the required parameters, so the framework handles everything. – that0th3rGuy Feb 17 '17 at 04:42

0 Answers0