Web API change JSON parser

不问归期 提交于 2021-02-11 00:09:15

问题


I am trying to change the JSON parser in my web API project.

I have followed the following tutorials:

https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/custom-formatters?view=aspnetcore-2.2

https://www.youtube.com/watch?v=tNzgXjqqIjI

https://weblog.west-wind.com/posts/2012/Mar/09/Using-an-alternate-JSON-Serializer-in-ASPNET-Web-API

I now have the following code:

public class MyJsonFormatter : MediaTypeFormatter
    {
        public MyJsonFormatter()
        {
            base.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
        {
            return null;
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            return null;
        }

        public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        {
            base.SetDefaultContentHeaders(type, headers, mediaType);
        }

        public override bool CanReadType(Type type)
        {
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }

        public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
        {
            return base.GetPerRequestFormatterInstance(type, request, mediaType);
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            return null;
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
        {
            return null;
        }

        public override IRequiredMemberSelector RequiredMemberSelector { get => base.RequiredMemberSelector; set => base.RequiredMemberSelector = value; }
    }   



public static void Register(HttpConfiguration config)
{
    ///Other stuff...
    GlobalConfiguration.Configuration.Formatters.Clear();
    GlobalConfiguration.Configuration.Formatters.Insert(0, new MyJsonFormatter());          
}

My issue is that whatever I do, JSON gets parsed and it seems to ignore my code - I can throw exceptions in the read or write methods and nothing will happen, break points do not get hit etc.

I know this formatter is being added as only the content types in my class are visible and if I set CanReadType to return false then nothing gets parsed.

My question is, how can I make the code execute my overrides?


回答1:


Update how the formatter is registered

public static class WebApiConfig {

    public static void Register(HttpConfiguration config) {

        // Other stuff...

        var jsonFormatter = new MyJsonFormatter();
        config.Formatters.Clear();
        config.Formatters.Insert(0, jsonFormatter);

        //...
    }
}

Making sure the suggested syntax is followed in Startup or where ever the application is started.

// configure Web Api
GlobalConfiguration.Configure(WebApiConfig.Register);

There is also the process of content negotiation as suggested in the following article

Supporting only JSON in ASP.NET Web API – the right way

Adapting it to your example, it would look like

public class JsonContentNegotiator : IContentNegotiator {
    MediaTypeHeaderValue mediaType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
    private readonly MyJsonFormatter _jsonFormatter;

    public JsonContentNegotiator(MyJsonFormatter formatter) {
        _jsonFormatter = formatter;
    }

    public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) {
        var result = new ContentNegotiationResult(_jsonFormatter, mediaType);
        return result;
    }
}

And registered against your HttpConfiguration

var jsonFormatter = new MyJsonFormatter();

config.Formatters.Clear();
config.Formatters.Insert(0, jsonFormatter);

//update content negotiation
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));

Finally one piece of information to note is that the framework did tightly couple its JSON formatting to its own JsonMediaTypeFormatter

/// <summary>
/// Gets the <see cref="MediaTypeFormatter"/> to use for Json.
/// </summary>
public JsonMediaTypeFormatter JsonFormatter
{
    get { return Items.OfType<JsonMediaTypeFormatter>().FirstOrDefault(); }
}

Reference source

So depending on how much of the pipeline actually depends on the existence of an instance of JsonMediaTypeFormatter, it would probably affect JSON related formatting.

If it is in fact a problem then my suggestion would be to derive from JsonMediaTypeFormatter and override its members as needed.

public class MyJsonFormatter : JsonMediaTypeFormatter {

    //... removed for brevity

}

But that might bring with it, its own problems depending on what that base class is coupled to.




回答2:


You need to register your formatter in the startup config.



来源:https://stackoverflow.com/questions/54203063/web-api-change-json-parser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!