Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specific JSON settings per controller on ASP.NET MVC 6

I need specific JSON settings per controller in my ASP.NET MVC 6 webApi. I found this sample that works (I hope !) for MVC 5 : Force CamelCase on ASP.NET WebAPI Per Controller

using System;
using System.Linq;
using System.Web.Http.Controllers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Serialization;

public class CamelCaseControllerConfigAttribute : Attribute, IControllerConfiguration 
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        var formatter = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
        controllerSettings.Formatters.Remove(formatter);

        formatter = new JsonMediaTypeFormatter
        {
            SerializerSettings = {ContractResolver = new CamelCasePropertyNamesContractResolver()}
        };

        controllerSettings.Formatters.Add(formatter);

    }
}
like image 665
Karine Avatar asked May 02 '16 13:05

Karine


2 Answers

This class works fine :

using System;
using System.Linq;
using Newtonsoft.Json.Serialization;
using Microsoft.AspNet.Mvc.Filters;
using Newtonsoft.Json;
using Microsoft.AspNet.Mvc.Formatters;

namespace Teedl.Web.Infrastructure
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]

    public class MobileControllerConfiguratorAttribute : Attribute, IResourceFilter
    {
        private readonly JsonSerializerSettings serializerSettings;

        public MobileControllerConfiguratorAttribute()
        {
            serializerSettings = new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects,
                TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
                Binder = new TypeNameSerializationBinder("Teedl.Model.Mobile.{0}, Teedl.Model.ClientMobile")
        };
        }


        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            var mobileInputFormatter = new JsonInputFormatter(serializerSettings);
            var inputFormatter = context.InputFormatters.FirstOrDefault(frmtr => frmtr is JsonInputFormatter);
            if (inputFormatter != null)
            {
                context.InputFormatters.Remove(inputFormatter);
            }
            context.InputFormatters.Add(mobileInputFormatter);

            var mobileOutputFormatter = new JsonOutputFormatter(serializerSettings);
            var outputFormatter = context.OutputFormatters.FirstOrDefault(frmtr => frmtr is JsonOutputFormatter);
            if (outputFormatter != null)
            {
                context.OutputFormatters.Remove(outputFormatter);
            }
            context.OutputFormatters.Add(mobileOutputFormatter);
        }
    }
}

Use :

[Route("api/mobile/businessrequest")]
[Authorize]
[MobileControllerConfigurator]
public class MobileBusinessRequestController : BaseController
{
like image 179
Karine Avatar answered Oct 20 '22 22:10

Karine


You can use a return type of JsonResult on your controller action methods. In my case, I needed specific actions to return Pascal Case for certain legacy scenarios. The JsonResult object allows you to pass an optional parameter as the JsonSerializerSettings.

public JsonResult Get(string id)
{
    var data = _service.getData(id);

    return Json(data, new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver()
    });

}

To have more consistent controller method signatures I ended up creating an extension method:

public static JsonResult ToPascalCase(this Controller controller, object model)
{
    return controller.Json(model, new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver()
    });
}

Now I can simply call the extension method inside my controller like below:

public IActionResult Get(string id)
{
    var data = _service.getData(id);
    return this.ToPascalCase(data);
}
like image 36
Mike Lunn Avatar answered Oct 21 '22 00:10

Mike Lunn