Closed adamdriscoll closed 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:
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
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.
Great! I think we can close this then? :smile:
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 IResponseProcessor
s, 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 IResponseFormatterFactory
s like DefaultResponseFormatterFactory which has access to the NancyContext
(but also implements the same "get the first ISerializer
supporting application/json), and IResponseProcessor
s. 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.
@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.
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?