SignalR .NET Core camelCase JSON Contract Resolver

不羁岁月 提交于 2019-12-04 02:50:25

Based on this issue from the SignalR Core repository, there is no native way of doing this as of right now, but you can create a custom contract resolver as indicated in this comment on an old SignalR issue.

Since that thread is for SignalR 2.2.0, let's make it work for SignalR Core.

using System;
using System.Reflection;
using Microsoft.AspNetCore.SignalR.Infrastructure;
using Newtonsoft.Json.Serialization;

    public class SignalRContractResolver : IContractResolver
    {
        private readonly Assembly _assembly;
        private readonly IContractResolver _camelCaseContractResolver;
        private readonly IContractResolver _defaultContractSerializer;

        public SignalRContractResolver()
        {
            _defaultContractSerializer = new DefaultContractResolver();
            _camelCaseContractResolver = new CamelCasePropertyNamesContractResolver();
            _assembly = typeof(Connection).GetTypeInfo().Assembly;
        }


        public JsonContract ResolveContract(Type type)
        {
            if (type.GetTypeInfo().Assembly.Equals(_assembly))
                return _defaultContractSerializer.ResolveContract(type);

            return _camelCaseContractResolver.ResolveContract(type);
        }

    }

What happens here is that you cannot use the camel case contract resolver for the SignalR internals, because it would break the communication with the client.

So every time we resolve a contract in the ResolveContract method we have to check the assembly of the type currently resolved and check wether it is SignalR internal. If not, then we can resolve the contract using camel case.

At this point, we need to register this contract resolver in the framework.

public void ConfigureServices(IServiceCollection services)
    {
        var settings = new JsonSerializerSettings();
        settings.ContractResolver = new SignalRContractResolver();

        var serializer = JsonSerializer.Create(settings);

        services.Add(new ServiceDescriptor(typeof(JsonSerializer), 
                                           provider => serializer,
                                           ServiceLifetime.Transient));

        // register other services like SignalR, MVC and custom services
     }

Best of luck!

Let me quote the answer of anurse on GitHub:

Since the protocols are pluggable, the options were moved to a different location because you may choose not to use JSON at all. Now you set them in the .AddJsonProtocol extension method in ConfigureServices, like this:

services.AddSignalR()
.AddJsonProtocol(options => {
    // Edit or replace 'options.PayloadSerializerSettings' here!
});

As of the first final alpha release of signalR core (1.0.0-alpha1-final), you can get camel case like the code snippet below natively:

services.AddSignalR(option =>
{
    option.JsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});

In fact, you can also employ any customized resolver instead of CamelCasePropertyNamesContractResolver.

In SignalR 3.0 you can do this with the following statement, as described in the Microsoft Docs

services.AddSignalR()
  .AddNewtonsoftJsonProtocol(
    options =>
      options.PayloadSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()
  );

with ASP.NET Core 3.0 and SignalR 3.0, this is what works:

services.AddSignalR()
   .AddJsonProtocol(options =>
   {
       options.PayloadSerializerOptions.PropertyNamingPolicy = null; 
   });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!