问题
I have a program that serializes an object and sends it over a network:
TcpClient client = new TcpClient();
client.ReceiveTimeout = 10000;
client.SendTimeout = 10000;
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
client.Connect(serverEndPoint);
BinaryFormatter binaryformatter = new BinaryFormatter();
NetworkStream networkStream = client.GetStream();
if (networkStream.CanWrite)
{
binaryformatter.Serialize(networkStream, kort);
}
And on the other side I receive and deserialize the code as such:
TcpClient tcpClient = (TcpClient)client;
tcpClient.SendTimeout = 10000;
tcpClient.ReceiveTimeout = 10000;
NetworkStream clientStream = tcpClient.GetStream();
try
{
if (clientStream.CanRead)
{
BinaryFormatter binaryformatter = new BinaryFormatter();
binaryformatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder();
Kort tempkort = (Kort)binaryformatter.Deserialize(clientStream);
SetImage(tempkort);
}
}
catch (SerializationException e)
{
MessageBox.Show("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
clientStream.Close();
tcpClient.Close();
}
But when I deserialized I got this error about an assembly missing:
"An unhandled exception of type
System.Runtime.Serialization.SerializationExceptionoccurred in Server.exe Additional information: Unable to find assembly 'Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
which I solved with this:
sealed class AllowAllAssemblyVersionsDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
String currentAssembly = Assembly.GetExecutingAssembly().FullName;
// In this case we are always using the current assembly
typeName = "Server.Kort";
assemblyName = currentAssembly;
// Get the type using the typeName and assemblyName
Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return typeToDeserialize;
}
}
But now that I try to do it, I keep getting an error that says:
"Object of type
Server.Kortcannot be converted to typeServer.Kort+kortvalör."
And I don't know how to fix it.
回答1:
The class Kort on the sending side must contain an instance of a nested type (perhaps an enum?) called kortvalör. And, since BinaryFormatter serializes public & private fields instead of properties, the nested type could be completely invisible to the outside world, but still get serialized.
For instance, I was able to reproduce your exception "Object of type Server.Kort cannot be converted to type Server.Kort+kortvalör" using your binder with the following class:
[Serializable]
public class Kort
{
// Private enum that is invisible to the outside world.
enum kortvalör
{
Zero,
One,
Two,
Three
}
kortvalör valör = kortvalör.Three;
public int Value
{
get
{
return (int)valör;
}
set
{
// Check to make sure the incoming value is in a valid range.
var newvalör = (kortvalör)value;
if (Enum.IsDefined(typeof(kortvalör), newvalör))
valör = newvalör;
else
valör = default(kortvalör);
}
}
}
When deserializing the class above, your binder will be called twice, once with the typeName for Kort -- and then once with the typename "MyClientNamespace.Kort+kortvalör". Since your binder ignores the incoming typeName and returns typeof(Kort), this fails.
You have a few options to solve this problem:
Extract your class
Kortinto a shared DLL and link it with both the sending and receiving applications. Then the problem goes away.Create duplicates of all types referenced by
Kortin both the sending and receiving applications -- including private nested types -- and remap the type names appropriately inside a smarter version of yourSerializationBinder. The article Advanced Binary Serialization: Deserializing an Object Into a Different Type Than the One It was Serialized Into has an example of how to do it.Consider using a different serialization format that serializes properties rather than private fields. BSON is one option. Protobuf-net is another.
来源:https://stackoverflow.com/questions/30196506/deserialization-with-binaryformatter