• EasyNetQ 不同框架序列化反序列化问题


    当.net core 项目给.net framework 用easynetq发送信息的时候。出现异常,例如以string对象为例。抛出异常:“Could not load assembly 'System.Private.CoreLib'”

    因为:.net core 的string 对象是在System.Private.CoreLib程序集下,System.String命名空间下;而.net framework的string对象是在mscorlib程序集下,System.String命名空间下

    easynetq反序列化对象前,会拿到当前对象的类型,拿到类型之后会从对应的程序集去加载,而.net framework当然没有System.Private.CoreLib.dll,所以失败。

    解决办法:替换ITypeNameSerializer组件  官方替换各种组件方法

    源码地址

    关键源码(版本6.3.1):

      private static Type GetTypeFromTypeNameKey(TypeNameKey typeNameKey)
            {
                var assemblyName = typeNameKey.AssemblyName;
                var typeName = typeNameKey.TypeName;
    
                if (assemblyName != null)
                {
                    var assembly = Assembly.Load(new AssemblyName(assemblyName));
                    if (assembly == null)
                    {
                        throw new EasyNetQException($"Could not load assembly '{assemblyName}'");
                    }
    
                    var type = assembly.GetType(typeName);
                    if (type == null)
                    {
                        // if generic type, try manually parsing the type arguments for the case of dynamically loaded assemblies
                        // example generic typeName format: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
                        if (typeName.IndexOf('`') >= 0)
                        {
                            try
                            {
                                type = GetGenericTypeFromTypeName(typeName, assembly);
                            }
                            catch (Exception ex)
                            {
                                throw new EasyNetQException($"Could not find type '{typeName}' in assembly '{assembly.FullName}'", ex);
                            }
                        }
    
                        if (type == null)
                        {
                            throw new EasyNetQException($"Could not find type '{typeName}' in assembly '{assembly.FullName}'");
                        }
                    }
    
                    return type;
                }
    
                return Type.GetType(typeName);
            }
    View Code

    只要在源码中做兼容代码就行。

    下面是兼容代码整个类(其实只是增加了一个if判断,暂时可以这样写,以后类型多了不好这样写),以及easynetq组件替换方式。

        public class MyTypeNameSerializer : ITypeNameSerializer
        {
            private readonly ConcurrentDictionary<Type, string> serializedTypes = new ConcurrentDictionary<Type, string>();
            private readonly ConcurrentDictionary<string, Type> deSerializedTypes = new ConcurrentDictionary<string, Type>();
    
            /// <inheritdoc />
            public string Serialize(Type type)
            {
    
                return serializedTypes.GetOrAdd(type, t =>
                {
                    var typeName = RemoveAssemblyDetails(t.AssemblyQualifiedName);
                    if (typeName.Length > 255)
                    {
                        throw new EasyNetQException($"The serialized name of type '{t.Name}' exceeds the AMQP maximum short string length of 255 characters");
                    }
                    return typeName;
                });
            }
    
            /// <inheritdoc />
            public Type DeSerialize(string typeName)
            {
                return deSerializedTypes.GetOrAdd(typeName, t =>
                {
                    var typeNameKey = SplitFullyQualifiedTypeName(t);
                    return GetTypeFromTypeNameKey(typeNameKey);
                });
            }
    
            private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
            {
                var builder = new StringBuilder(fullyQualifiedTypeName.Length);
    
                // loop through the type name and filter out qualified assembly details from nested type names
                var writingAssemblyName = false;
                var skippingAssemblyDetails = false;
                foreach (var character in fullyQualifiedTypeName)
                {
                    switch (character)
                    {
                        case '[':
                            writingAssemblyName = false;
                            skippingAssemblyDetails = false;
                            builder.Append(character);
                            break;
                        case ']':
                            writingAssemblyName = false;
                            skippingAssemblyDetails = false;
                            builder.Append(character);
                            break;
                        case ',':
                            if (!writingAssemblyName)
                            {
                                writingAssemblyName = true;
                                builder.Append(character);
                            }
                            else
                            {
                                skippingAssemblyDetails = true;
                            }
                            break;
                        default:
                            if (!skippingAssemblyDetails)
                            {
                                builder.Append(character);
                            }
                            break;
                    }
                }
    
                return builder.ToString();
            }
    
            private static TypeNameKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName)
            {
                var assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
    
                string typeName;
                string assemblyName;
    
                if (assemblyDelimiterIndex != null)
                {
                    typeName = fullyQualifiedTypeName.Trim(0, assemblyDelimiterIndex.GetValueOrDefault());
                    assemblyName = fullyQualifiedTypeName.Trim(assemblyDelimiterIndex.GetValueOrDefault() + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.GetValueOrDefault() - 1);
                }
                else
                {
                    typeName = fullyQualifiedTypeName;
                    assemblyName = null;
                }
    
                return new TypeNameKey(assemblyName, typeName);
            }
    
            private static Type GetTypeFromTypeNameKey(TypeNameKey typeNameKey)
            {
                var assemblyName = typeNameKey.AssemblyName;
                var typeName = typeNameKey.TypeName;
    
                if (assemblyName == "System.Private.CoreLib" && typeName == "System.String")
                {
                    return typeof(string);
                }
    
                if (assemblyName != null)
                {
                    //#if NETFX
                    //                // look, I don't like using obsolete methods as much as you do but this is the only way
                    //                // Assembly.Load won't check the GAC for a partial name
                    //#pragma warning disable 618,612
                    var assembly = Assembly.LoadWithPartialName(assemblyName);
                    //#pragma warning restore 618,612
                    //#else
                    //                var assembly = Assembly.Load(new AssemblyName(assemblyName));
                    //#endif
    
                    //#if NETFX
                    if (assembly == null)
                    {
                        // will find assemblies loaded with Assembly.LoadFile outside of the main directory
                        var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
                        foreach (var a in loadedAssemblies)
                        {
                            // check for both full name or partial name match
                            if (a.FullName == assemblyName || a.GetName().Name == assemblyName)
                            {
                                assembly = a;
                                break;
                            }
                        }
                    }
                    //#endif
                    if (assembly == null)
                    {
                        throw new EasyNetQException($"Could not load assembly '{assemblyName}'");
                    }
    
                    var type = assembly.GetType(typeName);
                    if (type == null)
                    {
                        // if generic type, try manually parsing the type arguments for the case of dynamically loaded assemblies
                        // example generic typeName format: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
                        if (typeName.IndexOf('`') >= 0)
                        {
                            try
                            {
                                type = GetGenericTypeFromTypeName(typeName, assembly);
                            }
                            catch (Exception ex)
                            {
                                throw new EasyNetQException($"Could not find type '{typeName}' in assembly '{assembly.FullName}'", ex);
                            }
                        }
    
                        if (type == null)
                        {
                            throw new EasyNetQException($"Could not find type '{typeName}' in assembly '{assembly.FullName}'");
                        }
                    }
    
                    return type;
                }
    
                return Type.GetType(typeName);
            }
    
            private static Type GetGenericTypeFromTypeName(string typeName, Assembly assembly)
            {
                Type type = null;
                var openBracketIndex = typeName.IndexOf('[');
                if (openBracketIndex >= 0)
                {
                    var genericTypeDefName = typeName.Substring(0, openBracketIndex);
                    var genericTypeDef = assembly.GetType(genericTypeDefName);
                    if (genericTypeDef != null)
                    {
                        var genericTypeArguments = new List<Type>();
                        var scope = 0;
                        var typeArgStartIndex = 0;
                        var endIndex = typeName.Length - 1;
                        for (var i = openBracketIndex + 1; i < endIndex; ++i)
                        {
                            var current = typeName[i];
                            switch (current)
                            {
                                case '[':
                                    if (scope == 0)
                                    {
                                        typeArgStartIndex = i + 1;
                                    }
                                    ++scope;
                                    break;
                                case ']':
                                    --scope;
                                    if (scope == 0)
                                    {
                                        var typeArgAssemblyQualifiedName = typeName.Substring(typeArgStartIndex, i - typeArgStartIndex);
                                        var typeNameKey = SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName);
                                        genericTypeArguments.Add(GetTypeFromTypeNameKey(typeNameKey));
                                    }
                                    break;
                            }
                        }
    
                        type = genericTypeDef.MakeGenericType(genericTypeArguments.ToArray());
                    }
                }
    
                return type;
            }
    
            private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName)
            {
                // we need to get the first comma following all surrounded in brackets because of generic types
                // e.g. System.Collections.Generic.Dictionary`2[[System.String, mscorlib,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
                var scope = 0;
                for (var i = 0; i < fullyQualifiedTypeName.Length; i++)
                {
                    var current = fullyQualifiedTypeName[i];
                    switch (current)
                    {
                        case '[':
                            scope++;
                            break;
                        case ']':
                            scope--;
                            break;
                        case ',':
                            if (scope == 0)
                            {
                                return i;
                            }
                            break;
                    }
                }
    
                return null;
            }
    
            private readonly struct TypeNameKey
            {
                public string AssemblyName { get; }
                public string TypeName { get; }
    
                public TypeNameKey(string assemblyName, string typeName)
                {
                    AssemblyName = assemblyName;
                    TypeName = typeName;
                }
            }
        }
    View Code
     var bus = RabbitHutch.CreateBus(connectString, serviceRegister => serviceRegister.Register<ITypeNameSerializer, MyTypeNameSerializer>());

    这样就结束了。

  • 相关阅读:
    [基础]RHEL6下LINUX服务器批量部署
    delphi 连接 c++ builder 生成obj文件
    Delphi基本图像处理代码
    Delphi 版本号(D1到XE6),发现一个delphi.wikia.com网站
    Delphi常用排序
    Delphi中用Webbrowser加载百度地图滚轮失效(ApplicationEvents里使用IsChild提前判断是哪个控件的消息)
    判断连个单链表是否交叉,并找到交叉点
    窗体自适应屏幕分辨率
    Zlib压缩算法在Java与Delphi间交互实现(压缩XML交互)
    开机自动启动程序的几种方法
  • 原文地址:https://www.cnblogs.com/TeemoHQ/p/14627896.html
Copyright © 2020-2023  润新知