2

I'm running an WebAPI OData v4 service and I don't want null values to be emitted. For example, when I request a User object, the following is returned:

"value": [
{
  "FirstName": "John",
  "LastName": "Smith",
  "EmailAddress": "john@smith.com",
  "PasswordHash": null,
  "PhoneNumber": "11234567890",
  "Website": null,
  "Id": "dac9706a-8497-404c-bb5a-ca1024cf213b"
}

Since the PasswordHash and Website fields are null, I'd like them to not be included in the output. I've tried the following lines in the application's Register block, but none of them work:

config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
config.Formatters.JsonFormatter.SerializerSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;

Below is the full contents of the Register method. I'm using the Newtonsoft Json package to handle the JSON serialization.

public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "UploadComplete",
            routeTemplate: "UploadFiles/Complete",
            defaults: new { controller = "UploadFiles", action = "Complete" }
        );

        var builder = new ODataConventionModelBuilder();

        builder.EntitySet<Address>("Addresses");
        builder.EntitySet<Assignment>("Assignments");
        builder.EntitySet<Course>("Courses");
        builder.EntitySet<File>("Files");
        builder.EntitySet<UploadFile>("UploadFiles");
        builder.EntitySet<Organization>("Organizations");
        builder.EntitySet<Submission>("Submissions");
        builder.EntitySet<Term>("Terms");
        builder.EntitySet<User>("Users");

        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: null,
            model: builder.GetEdmModel());

        // Neither of these lines work.
        config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
        config.Formatters.JsonFormatter.SerializerSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
        config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    }
pwnsauce
  • 151
  • 2
  • 8
  • 1
    I think you can derive from ODataEntityTypeSerializer.cs, and remove the "null" property from the `Properties` in ODataEntry. – Sam Xu Oct 19 '15 at 01:48

2 Answers2

4

Thanks Brian Rogers for pointing me in the right direction, I ended up overriding ODataEntityTypeSerializer like so:

public override ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
{
    ODataEntry entry = base.CreateEntry(selectExpandNode, entityInstanceContext);

    // Remove any properties which are null.
    List<ODataProperty> properties = new List<ODataProperty>();
    foreach (ODataProperty property in entry.Properties)
    {
        if (property.Value != null)
        {
            properties.Add(property);
        }
    }

    entry.Properties = properties;
    return entry;
}

And then I used code from RaghuRam-Nadiminti's answer to implement a CustomSerializerProvider class which I could then use in Register.

Community
  • 1
  • 1
pwnsauce
  • 151
  • 2
  • 8
2

Although Web API iteself uses the Json.Net serializer, the MediaTypeFormatter for Web API OData uses its own internal serializer which is not Json.Net. Therefore, changing the Json.Net serializer settings in the configuration will not have any effect on OData. However, it does appear that you can implement your own ODataSerializerProvider and ODataDeserializerProvider classes to get OData to use Json.Net. See JSON.NET as a WebAPI 2 OData serializer vs ODataMediaTypeFormatter for a starting point.

Community
  • 1
  • 1
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300