【问题标题】:How to pass complex objects in SignalR with proper casing?如何使用适当的大小写在 SignalR 中传递复杂对象?
【发布时间】:2016-02-16 06:19:49
【问题描述】:

我的 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,而不是 camelCasing。有没有办法做到这一点,所以 SignalR 会自动将我的对象转换为具有适当可变大小写的对象?

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

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

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

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

有什么办法可以做到这一点,还是我只需要使用奇怪的 CamelCasing?

【问题讨论】:

    标签: javascript c# signalr


    【解决方案1】:

    正如 Rob Segerink 在 this answer 中所说,显然不可能在不破坏 SignalR 的情况下更改全局 JsonSerializerSettings。快速的search of the source 显示它有时会出现new JsonSerializer(),有时会出现JsonSerializer.CreateDefault(),这可能至少导致了部分问题。

    话虽如此,您也许可以根据您的需要采用问题SignalR Typenamehandling 中的技巧,特别是覆盖Json.NET 的行为并仅对标有特定属性的类型使用驼峰式大小写,或者在标有特定属性的程序集中,使用以下contract resolver

    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]
    

    最后,使用that question 中显示的技术,使用以下设置安装合约解析器:

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

    由于 SignalR 自身的内部类型不会如此标记,所以会继续使用默认设置进行序列化。

    注意 - 使用各种测试用例进行测试,但不是 SignalR 本身,因为我目前没有安装它。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        DataContractDataMember 属性可能正是您想要以您想要的方式序列化您的类并在 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; }
            
            ...
        }
        

        这将按照您想要的方式对其进行序列化。

        【讨论】:

          猜你喜欢
          • 2013-06-25
          • 2019-08-26
          • 1970-01-01
          • 2014-01-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-10
          相关资源
          最近更新 更多