NancyFx / Nancy.Serialization.JsonNet

NewtonSoft.Json serializer for Nancy
MIT License
39 stars 32 forks source link

JsonSerializerSettings per request? #21

Closed adamdriscoll closed 9 years ago

adamdriscoll commented 9 years ago

I'm attempting to change the serializer settings per request. Right now I'm trying to register a custom JsonSerializer in ConfgureRequestContainer based on header values but this doesn't seem to work. The construct is never called. If I register in ConfigureApplicationContainer, it works fine but I can't query the header. I'm assuming the composition happens before this.

Anyone have any ideas?

jonorossi commented 9 years ago

Hey @adamdriscoll, I'm looking at doing something very similar. I'm trying to pick a custom Nancy.ISerializer based on the request. I'm trying to make my API return compact JSON for API clients (using Accept: application/json variants) and indented JSON for browsers and curl by default (but still returning Content-Type: application/json). I realised I needed to use ISerializer to access the StreamWriter because I want to write an extra new line at the end so that the output doesn't run into the next command in the terminal, but I too can't work out any way to do this based on the current request.

I found these two classes that seem to cache the ISerializers:

khellang commented 9 years ago

Why would you use the container for this? You could just create a separate instance with the settings you need? This sounds like a case for a response processor. Take a look at https://github.com/NancyFx/Nancy/blob/0f7deb47dea34cdde541bbbf808a77bc2d79168e/src/Nancy/Responses/Negotiation/JsonProcessor.cs

jonorossi commented 9 years ago

Sorry @adamdriscoll for hijacking your thread. Thanks @khellang, I had seen IResponseProcessor and JsonProcessor but I had missed that the Process method was the one creating the JsonResponse and picking an ISerializer. I've been able to write a custom IResponseProcessor and ISerializer to achieve what I'm after and ensure they are the only ones in NancyInternalConfiguration. I only forked JsonNetSerializer because I needed to modify the pretty print behaviour to append a new line to the stream in the Serialize method.

khellang commented 9 years ago

Great! I think we can close this then? :smile:

jonorossi commented 9 years ago

For anyone else trying to do the same thing, if you follow what I wrote above make sure not to use Response.AsJson as that extension method doesn't go via IResponseProcessors, it directly calls the first ISerializer from the container that supports application/json. It also caches the ISerializer it found in a static field.

I am wondering why there are IResponseFormatterFactorys like DefaultResponseFormatterFactory which has access to the NancyContext (but also implements the same "get the first ISerializer supporting application/json), and IResponseProcessors. If I wanted to implement versioning using a IResponseProcessor I assume I'd also have to stay clear of Response.AsJson. This is probably something I should bring up on the Nancy issue tracker, rather than talking anymore on the JSON.NET integration one.

djonasdev commented 6 years ago

@jonorossi Do you already have a clean solution how to use a ISerializer per request? I have made an Extension method:

    public static Response AsJson<TModel>(this IResponseFormatter formatter, TModel model, ISerializer serializer, HttpStatusCode statusCode = HttpStatusCode.OK)
    {
        JsonResponse<TModel> jsonResponse = new JsonResponse<TModel>(model, serializer);
        jsonResponse.StatusCode = statusCode;
        return jsonResponse;
    }

My custom ISerialzer always return false when calling CanSerialize so it is only used when I add it manual.