小弟刚刚学会C#的网络传输,也刚刚学会C#的对象序列化,小弟想把这两项合起来做能够在socket流上进行对象序列化和反序列化,但是在运行中总是出现异常“Unable to find assembly 'myPro, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null'.”这个问题要怎么解决?
这是服务器端的代码(监听部分的代码就不加了)
class Client
    {
        TcpClient m_tcp;
        public Client(TcpClient t)
        {
            m_tcp = t;
        }
        public void communicate()
        {
            NetworkStream ns = m_tcp.GetStream();
            IFormatter formatter = new BinaryFormatter();
            while (true)
            {
                MyClass myClass;
                try
                {
                    if ((myClass = (MyClass)formatter.Deserialize(ns)) == null)
                    {
                        Console.WriteLine("disconnected");
                        break;
                    }
                }
                catch (Exception exc)
                {
                    Console.WriteLine("missing " + exc.ToString());
                    break;
                }
                Console.WriteLine(myClass.name);
                myClass.name = myClass.name.ToUpper();
                myClass.gender = myClass.gender.ToUpper();
                try
                {
                    formatter.Serialize(ns, myClass);
                }
                catch
                {
                    Console.WriteLine("missing");
                    break;
                }
            }
            ns.Close();
        }
    }
MyClass那个类    [Serializable]
    class MyClass
    {
        public string name;
        public string gender;
    }
客户端的代码    class Program
    {
        static void Main(string[] args)
        {
            TcpClient tcpClient = new TcpClient();
            tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 13000);
            NetworkStream ns = tcpClient.GetStream();
            IFormatter formatter = new BinaryFormatter();
            while (true)
            {
                MyClass myClass = new MyClass();
                myClass.name = "zhaohad";
                myClass.gender = "male";
                try
                {
                    formatter.Serialize(ns, myClass);
                }
                catch (Exception exc)
                {
                    Console.WriteLine("missing " + exc.ToString());
                    break;
                }
                try
                {
                    myClass = (MyClass)formatter.Deserialize(ns);
                }
                catch (Exception exc)
                {
                    Console.WriteLine("missing " + exc.ToString());
                    break;
                }
            }
            ns.Close();
        }
    }
小弟调了两天了!一直没能解决,请给位大牛门帮帮小弟

解决方案 »

  1. 你的myclass是不是在服务器和客户端各有一份呢?这样的话序列化和反序列化的时候就会导致错误的两个方案:第一:将myclass和序列化和反序列化的功能封装成DLL,分别加入服务器和客户端。第二:。Net二进制序列化支持自己提供一个借口对象,来定义序列化的程序集名称。
      

  2. myPro是个啥,你先建成发出和发回的数据流的大小,接受的是否正确
      


  3. 两端的MyClass类是直接复制过去的,完全一样的!
    第一种方法不会做。
    第二种方法没明白。能不能给个简单的例子或者给个有关的连接
      


  4. 无论你怎么复制,myclass位于不同的程序集。序列化将导致错误等我找代码
      


  5. myPro是我的工程名
    这个工程是我本来先用字符串传输测试成功后改成的序列化的传输你说的“先建成发出和发回的数据流的大小”这是什么意思?
      

  6. /// <summary>
            /// 反序列化TcpMessage对象
            /// </summary>
            /// <param name="Msg"></param>
            /// <returns></returns>
            //  采用二进制序列化取代了XML序列化,二进制体积小,速度快,但是有一定的限定条件
            public static TcpMsg GetMessage_(byte[] Msg)
            {
                try
                {
                    using (MemoryStream memStream = new MemoryStream(Msg))
                    {
                        BinaryFormatter brFormatter = new BinaryFormatter();
                        // 就是下面的接口
                        brFormatter.Binder = new ConvertAssemblyBinder();
                        TcpMsg tm = (TcpMsg)brFormatter.Deserialize(memStream);                    //XmlSerializer xs = new XmlSerializer(typeof(TcpMsg));
                        //TcpMsg tm        = xs.Deserialize(memStream) as TcpMsg;
                        return tm;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
            }/// <summary>
        /// 控制将序列化对象绑定到类型的过程(通过此接口自己修改序列化后的程序集和命名空间即可)
        /// </summary>
        public sealed class ConvertAssemblyBinder : SerializationBinder
        {
            /// <summary>
            /// 控制二进制序列化类型转换
            /// </summary>
            /// <param name="assemblyName"></param>
            /// <param name="typeName"></param>
            /// <returns></returns>
            // 在序列化过程中,格式化程序传输创建正确类型和版本的对象的实例所需的信息。
            // 此信息通常包括对象的完整类型名称和程序集名称。
            // 程序集名称包含程序集的名称、版本和强名称(请参见具有强名称的程序集)散列。
            // 默认情况下,反序列化将使用此信息创建等同对象的实例(安全策略所限制的任何程序集加载属于例外)。
            // 因为类已经在程序集之间移动或者因为在服务器和客户端上要求类的不同版本,有些用户需要控制要加载哪些类。
            // 这是一个抽象基类。所有联编程序都扩展此类。
            // 给继承者的说明 从 SerializationBinder 继承时,必须重写以下成员:BindToType。         // 由于服务器和客户端共同使用同一个类型,进行数据传递,但是服务器和客户端的同一类型处于不同的
            // 程序集,需要在反序列化的时候,提供强制类型转换
            public override Type BindToType(string assemblyName, string typeName)
            {
                // 取得当前的程序集名称,取得传递过来,类型名称不修改,都是"TestPro.CSFTcpMsg"
                string strCurAssembly = Assembly.GetExecutingAssembly().FullName;            // 返回当前对应的类型
                Type CurType = Type.GetType(String.Format("{0}, {1}", typeName, strCurAssembly));
                return CurType;
            }
        }
      

  7. 我试着去重新改了下程序,我不知道我是不是理解对了
    这是我改过的代码
            public void communicate()
            {
                NetworkStream ns = m_tcp.GetStream();
                //IFormatter formatter = new BinaryFormatter();
                while (true)
                {
                    byte[] buf;
                    MyClass myClass;
                    try
                    {
                        buf = new byte[1024];
                        ns.Read(buf, 0, 1024);
                        MemoryStream memStream = new MemoryStream(buf);
                        BinaryFormatter bf = new BinaryFormatter();
                        bf.Binder = new ConvertAssemblyBinder();
                        myClass = (MyClass)bf.Deserialize(memStream);
                        /*if ((myClass = (MyClass)formatter.Deserialize(ns)) == null)
                        {
                            Console.WriteLine("disconnected");
                            break;
                        }*/
                    }
                    catch (Exception exc)
                    {
                        Console.WriteLine("missing " + exc.ToString());
                        break;
                    }
                    Console.WriteLine(myClass.name);
                    myClass.name = myClass.name.ToUpper();
                    myClass.gender = myClass.gender.ToUpper();
                    try
                    {
                        formatter.Serialize(ns, myClass);
                    }
                    catch
                    {
                        Console.WriteLine("missing");
                        break;
                    }
                }
                ns.Close();
            }
    ConvertAssemblyBinder跟你给我的那个一摸一样,但是问题未能解决
      

  8. 错误是不是由myClass = (MyClass)bf.Deserialize(memStream);引起的?
      

  9. 你参考一下:http://topic.csdn.net/u/20110518/11/563453bc-a508-4cd0-9aca-a7b9142096e0.html另外看看如下代码的返回值是不是你要的程序集版本和名称
    public override Type BindToType(string assemblyName, string typeName)
            {
                // 取得当前的程序集名称,取得传递过来,类型名称不修改,都是"TestPro.CSFTcpMsg"
                string strCurAssembly = Assembly.GetExecutingAssembly().FullName;            // 返回当前对应的类型
                Type CurType = Type.GetType(String.Format("{0}, {1}", typeName, strCurAssembly));
                return CurType;
            }
      

  10. 问题解决了!感谢各位!要把需要序列化的类专门写成一个dll,然后客户端和服务器端都要引用这个dll,通过引用的这个dll才能进行序列化对象的网络传播参考1
    http://topic.csdn.net/u/20100428/21/d36073ab-5731-4259-bb37-876ae154ad45.html?seed=913911487&r=73858327#r_73858327参考2
    http://topic.csdn.net/u/20110518/11/563453bc-a508-4cd0-9aca-a7b9142096e0.html问题解决
      

类似问题 »