6

My application requires the (almost default) JSON serialization settings:

services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            });

For one controller only, I need to use a different naming strategy for both input (where I use model binding with [FromBody] myComplexObject and output with

options.SerializerSettings.ContractResolver = new DefaultContractResolver();

My question is virtually identical to Web API: Configure JSON serializer settings on action or controller level with the exception that I'm asking for AspNet Core 2.2+, in which IControllerConfiguration is no longer existent.

The Core 2.1+ equivalent question has a response here: Configure input/output formatters on controllers with ASP.NET Core 2.1

The answers there appear slightly fragmented or incomplete - it's hard to imagine that there is no easier way to achieve this. Would anyone have an idea on how to use a DefaultContractResolver for all input and output within a single controller?

3 Answers 3

9

The answer you link works well enough, but you can extend it further by wrapping it in an attribute that you can apply to any action or controller. For example:

public class JsonConfigFilterAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is ObjectResult objectResult)
        {
            var serializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver()
            };

            var jsonFormatter = new JsonOutputFormatter(
                serializerSettings, 
                ArrayPool<char>.Shared);

            objectResult.Formatters.Add(jsonFormatter);
        }

        base.OnResultExecuting(context);
    }
}

And just add it to action methods or controllers:

[JsonConfigFilter]
public ActionResult<Foo> SomeAction()
{
    return new Foo
    {
        Bar = "hello"
    };
}
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks @DavidG - that won't take care of the input formatter for [FromBody] object though, or would it? I thought that is the missing piece in the original question as well.
Hmm you may be right. In that case you may be better off with a custom model binder.
@ExternalUse Have you tried the input side of this? I don't think the JSON input formatter cares too much about the case inside of the request, so it should work with SomeProperty and someProperty without any changes. It also works with SOMePRoperTY - if you provide multiple variations in the JSON the last one wins.
The answer provided works fine (thank you!); it is worth making a note of @KirkLarkin 's comment above. The input filter does indeed appear to ignore the casing.
.NET Core version of the action filter: stackoverflow.com/a/73866496/379279
|
1

For Global Setting in Startup.cs, having installed Newtonsoft.json, you will have this

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

For Individual Controller, you can override the global setting below

 public JsonResult GetStates()
    {
        var model = new List<StateObject>();
        if (!string.IsNullOrEmpty(id))
        {
            var schedule = _settingsService.GetStates().ToList();
            return Json(new SelectList(schedule, "StateCode", "Name"), new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
        }
        else
            return Json(new SelectList(model, "StateCode", "Name"), new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
    }

Let me know if this solves your problem, or you need further Assitance.

2 Comments

Thanks @Samuel, that takes care of the Output problem but not about ModelBinding on a POST with a [FromBody] object parameter. The global setting in the Startup class is not an option since for most other controllers, the default setting is correct. Only one controller requires a DefaultContractResolver
This kind of solved the issue. But for each request $id is getting appended. For example, for first request $id starts with 1, but for all subsequent requests $id starts with 27,55... stackoverflow.com/questions/59832635/… Can anybody help me here?
1

Just override Json() in your controller

public class MyController : Controller
{
    public override JsonResult Json(object data)
    {
        return base.Json(data, new JsonSerializerSettings {
            // set whataever options you want
        });
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.