NancyFx / Nancy.Serialization.JsonNet

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

Custom serializer doesn't run #55

Closed sakopov closed 7 years ago

sakopov commented 7 years ago
    public sealed class CustomJsonSerializer : JsonSerializer
    {
        public CustomJsonSerializer()
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver();
            NullValueHandling = NullValueHandling.Ignore;
            DefaultValueHandling = DefaultValueHandling.Ignore;
        }
    }
    public class CustomApiBootstrapper : DefaultNancyBootstrapper
    {
        protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
        {
            base.ConfigureRequestContainer(container, context);

            container.Register<JsonSerializer, CustomJsonSerializer>();
        }
    }

The CustomJsonSerializer constructor never executes. The JSON response still has null properties.

{
  "data": {
    "application": "myApp",
    "version": "1.0",
    "links": {
      "self": {
        "href": "/api"
      }
    }
  },
  "message": null,
  "status": "success"
}

What's missing?

thecodejunkie commented 7 years ago

Nancy consumes 'ISerializer' instances. You need to implement that in order for Nancy to discover and use it

sakopov commented 7 years ago

That breaks it even more.

Added to bootstrap.

container.Register<ISerializer, JsonNetSerializer>();
container.Register<JsonSerializer, CustomJsonSerializer>();

The JSON looks like:

{
  "Data": {
    "Application": "myApp",
    "Version": "1.0",
    "Links": {
      "self": {
        "Href": "/api"
      }
    }
  },
  "Message": null,
  "Status": "success"
}

Lost camel casing, null values are not ignored.

Also noticed that JSON.Net version that's referenced by Nancy.Serialization.JsonNet is very, very old.

sakopov commented 7 years ago

It seems like i'm having problems with everything that Nancy is supposed to magically pick up and run. (i.e. I'm using FluentValidation with Nancy which also had the same problem until i explicitly added it to dependency registration). So this makes me wonder if the problem is in how i'm running Nancy? I'm using Topshelf and Nancy.Hosting.Self to host it in a windows service.

Update 1 Tried this package on another Nancy API project hosted using OWIN. As soon as i introduced a custom serializer with settings as show in previous post, I noticed that Nancy stopped applying default serialization rules but it also never applied mine. I also never had to explicitly add any registration to see this behavior when running on OWIN. So different hosting types definitely have a profound effect. Second day wasted on this and I feel completely stumped.

Update 2 Oh God, I was adding registrations by overriding the ConfigureRequestContainer instead of ConfigureApplicationContainer.

protected override void ConfigureApplicationContainer(TinyIoCContainer container)
        {
            base.ConfigureApplicationContainer(container);

            container.Register<ISerializer, JsonNetSerializer>();
            container.Register<IBodyDeserializer, JsonNetBodyDeserializer>();
            container.Register<JsonSerializer, CustomJsonSerializer>();
        }

This is working! Rookie mistake. Sorry I'm new to Nancy :(

ryanulit commented 7 years ago

@sakopov that registration is literally the ONLY way it will work for me using the Nancy.Bootstrappers.Autofac bootstrapper on a 64 bit windows machine. Thank you.

YuriGal commented 4 years ago

@ryanulit I know it's been a while but could you please show an example how custom JsonSerializer is configured in Nancy.Bootstrappers.Autofac bootstrapper ?

ryanulit commented 4 years ago

@YuriGal here's what worked for me, but this is 2+ years old so there may be a better way now:

public class ApiBootstrapper : AutofacNancyBootstrapper
{
    protected override void ConfigureApplicationContainer(ILifetimeScope existingContainer)
    {
        base.ConfigureApplicationContainer(existingContainer);

        existingContainer.Update(builder =>
        {
            builder.RegisterType<JsonNetSerializer>().As<ISerializer>();
            builder.RegisterType<JsonNetBodyDeserializer>().As<IBodyDeserializer>();
            builder.RegisterType<CustomJsonSerializer>().As<JsonSerializer>();
        });
    }
}

And the CustomJsonSerializer class:

public class CustomJsonSerializer : JsonSerializer
{
    public CustomJsonSerializer()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver();
        NullValueHandling = NullValueHandling.Ignore;
        Converters.Add(new StringEnumConverter(true));
    }
}

And here's my packages.config for version references:

<package id="Nancy" version="1.4.5" targetFramework="net471" />
<package id="Nancy.Bootstrappers.Autofac" version="1.4.1" targetFramework="net471" />
<package id="Nancy.Serialization.JsonNet" version="1.4.1" targetFramework="net471" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net471" />
YuriGal commented 4 years ago

@ryanulit Thank you so much for the prompt response! I figured it as far as builder.RegisterType( ) but was missing the .As( ) part. Thanks again!