如何在SignalR中使用适当的大小写传递复杂对象

本文关键字:大小写 对象 复杂 SignalR | 更新日期: 2023-09-27 18:21:59

我的c#中有一个类似这样的复杂类:

public class Channel
{
    public int Id { get; set; }
    public string ChannelName { get; set; }
    public Dictionary<int, Question> Questions { get; set; }
    public Dictionary<int, ChatMessage> ChatMessages { get; set; }
    public Dictionary<int, User> Users { get; set; }
    public bool IsAdmin { get; set; }
    public int TimeLeft { get; set; }
}

要将其传递给我的客户,我需要:Clients.Caller.CheckVersion(ChannelInstance);

我的问题是,当我在客户端上收到对象时,它仍然会有CamelCasing,而不是CamelCassing。有没有什么方法可以做到这一点,这样SignalR就会自动将我的对象转换为具有适当可变大小写的对象?

我知道这是一件很琐碎的事情,但我发现在我的javascript:中定义这样的类很烦人

function Channel() {
    this.Id;
    this.ChannelName;
    this.etc;
}

当这看起来更正确的JavaScript时:

function Channel() {
    this.id;
    this.channelName;
    this.etc;
}

有什么办法可以做到这一点吗?还是我只能将就着用奇怪的CamelCasing?

如何在SignalR中使用适当的大小写传递复杂对象

正如Rob Segerink在这个答案中所说,在不破坏SignalR的情况下,显然不可能更改全局JsonSerializerSettings。快速搜索源会发现它有时会执行new JsonSerializer(),有时会执行JsonSerializer.CreateDefault(),这可能至少导致了部分问题。

也就是说,您可以根据自己的需要采用SignalR Typenamehandling问题中的技巧,特别是覆盖Json.NET的行为,并使用以下合同解析器,仅对标记有特定属性的类型或标记有特定特性的程序集中使用驼色大小写

public sealed class ConditionalCamelCaseContractResolver : IContractResolver
{
    readonly static IContractResolver defaultContractResolver;
    readonly static IContractResolver camelCaseContractResolver;
    readonly static ConcurrentDictionary<Type, bool> camelCaseTable;
    static Func<Type, bool> isCamelCase;
    // Use a static constructor for lazy initialization.
    static ConditionalCamelCaseContractResolver()
    {
        defaultContractResolver = new JsonSerializer().ContractResolver; // This seems to be the only way to access the global singleton default contract resolver.
        camelCaseContractResolver = new CamelCasePropertyNamesContractResolver();
        camelCaseTable = new ConcurrentDictionary<Type, bool>();
        isCamelCase = (t) => GetIsCamelCase(t);
    }
    static bool GetIsCamelCase(Type objectType)
    {
        if (objectType.Assembly.GetCustomAttributes<JsonCamelCaseAttribute>().Any())
            return true;
        if (objectType.GetCustomAttributes<JsonCamelCaseAttribute>(true).Any())
            return true;
        foreach (var type in objectType.GetInterfaces())
            if (type.GetCustomAttributes<JsonCamelCaseAttribute>(true).Any())
                return true;
        return false;
    }
    static bool IsCamelCase(Type objectType)
    {
        var code = Type.GetTypeCode(objectType);
        if (code != TypeCode.Object && code != TypeCode.Empty)
            return false;
        return camelCaseTable.GetOrAdd(objectType, isCamelCase);
    }
    #region IContractResolver Members
    public JsonContract ResolveContract(Type type)
    {
        return IsCamelCase(type) ? camelCaseContractResolver.ResolveContract(type) : defaultContractResolver.ResolveContract(type);
    }
    #endregion
}
[System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Interface)]
public class JsonCamelCaseAttribute : System.Attribute
{
    public JsonCamelCaseAttribute()
    {
    }
}

接下来,用这个属性标记您的程序集、类型或接口,以启用驼色外壳:

[assembly: MyNamespace.JsonCamelCaseAttribute]

最后,使用以下设置,使用该问题中显示的技术安装合同解析器:

public static class ConverterSettings
{
    public static JsonSerializer GetSerializer()
    {
        return JsonSerializer.Create(new JsonSerializerSettings()
        {
            ContractResolver = new ConditionalCamelCaseContractResolver()
        });
    }
}

由于SignalR自己的内部类型不会被如此标记,它们将继续使用默认设置进行序列化。

注意-测试了各种测试用例,但没有SignalR本身,因为我目前还没有安装它。

不,当您使用JsonSerializerSettings类更改服务器上的默认JSON.net序列化设置时,SignalRjquery客户端将停止工作,因为它希望使用默认JSON.net序列化设置序列化服务器消息。我相信在版本3中,他们会改变这一点。

我知道这是一个老问题,但这个快速解决方案可能会帮助遇到这个问题的人。它过去确实帮助过我。

DataContractDataMember属性可能正是您的a想要的,以您想要的方式序列化您的类,并且仍然保持C#中的大写字母。

你的课是这样的:

[DataContract]
public class Channel
{
    [DataMember(Name = "id")]
    public int Id { get; set; }
    [DataMember(Name = "channelName")]
    public string ChannelName { get; set; }
    [DataMember(Name = "questions")]
    public Dictionary<int, Question> Questions { get; set; }
    
    ...
}

这将按照您想要的方式序列化它。