I am a noob to Nancy. I have been using it as a framework to produce a REST API. I am familiar with Json.NET so I've been playing with the Nancy.Serialization.JsonNet
package.
My goal: to customize the behavior (i.e. change the settings) of the JsonNetSerializer
and JsonNetBodyDeserializer
.
Specifically I'd like to incorporate the following settings...
var settings = new JsonSerializerSettings { Formatting = Formatting.Indented };
settings.Converters.Add( new StringEnumConverter { AllowIntegerValues = false, CamelCaseText = true } );
I wanted to perform this customization using the builtin TinyIoC container to avoid the inheritance chain and limit potential issues arising from any changes in the Nancy.Serialization.JsonNet
package.
NOTE: As a temporary workaround, I have leveraged inheritance to create CustomJsonNetSerializer
and CustomJsonNetBodyDeserializer
.
I have tried several approaches to incorporate this configuration at least for the JsonNetSerializer
. I've not tried configuring the JsonNetBodyDeserializer
using the TinyIoC yet. I imagine it will be done similarly. All the work I've tried is in my CustomNancyBootstrapper
(which inherits from DefaultNancyBootstrapper
).
Most successful approach so far: override ConfigureApplicationContainer
protected override void ConfigureApplicationContainer( TinyIoCContainer container )
{
base.ConfigureApplicationContainer( container );
// probably don't need both registrations, and I've tried only keeping one or the other
var settings = new JsonSerializerSettings { Formatting = Formatting.Indented };
settings.Converters.Add( new StringEnumConverter { AllowIntegerValues = false, CamelCaseText = true } );
container.Register( new JsonNetSerializer( JsonSerializer.CreateDefault( settings ) ) );
container.Register<ISerializer>( new JsonNetSerializer( JsonSerializer.CreateDefault( settings ) ) );
}
I have traced the code and watched the JsonNetSerializer(JsonSerializer serializer)
constructor in the JsonNet package.
Potential problem: I noticed the constructor is called twice. I did not expect this behavior.
The first time everything is just right - my customization is added and registered properly. But, then the second time happens and the types are re-registered, without the settings customization. The re-registration appears to replace the original registration losing my settings customization.
The call stack the second time the constructor is called shows that it is called during GetEngine
and GetEngineInternal
which seems to try to build a NancyEngine
(I am using the self-host package so this happens in program.cs -- using(var host = new NancyHost(uri))
).
Seems like I either need to tell Nancy not to do something or I need to hook in to a later part in the chain.
Any help would be appreciated.
Typically the way to solve this in Nancy is to implement your own JSON Serializer like so:
Here you can override all the settings.
Then you can register it, I do this by using
IRegistrations
Q: How does this approach differ from creating CustomJsonNetSerializer inheriting from JsonNetSerializer and then registering it in ConfigureApplicationContainer (container.Register( typeof(JsonNetSerializer), typeof(CustomJsonNetSerializer) )?
A: The JsonSerializer is the implementation if json.net for Nancy, this is the recommended method we define on the readme on github:
https://github.com/NancyFx/Nancy.Serialization.JsonNet#customization
The class you mention is the serialization of an object to JSON, there is another which handles deserialization, both of which utilize JsonSerializer internally:
https://github.com/NancyFx/Nancy.Serialization.JsonNet/blob/master/src/Nancy.Serialization.JsonNet/JsonNetSerializer.cs#L10
Using this method makes the implementation settings consistent anywhere that the JsonSerializer is used.
Q: can I correctly infer from the approach you've outlined that I would no longer need to explicitly register CustomJsonSerializer in the ConfigureApplicationContainer override in my CustomNancyBootstrapper?
A: The method I've done for registering is just a cleaner abstraction for registering dependencies, rather than making one giant Bootstrapper, you can create a few smaller specific classes.
Yes using my method means you do not need to register in the bootstrapper.