I am trying to send an object over tcpclient from the server to a client and i get an error . First, here is the pack class :
[Serializable()]
public class pack
{
public int a;
}
here is the server's sending code(it's namespace is WindowsFormsApplication1) :
pack pachet = new pack();
pachet.a = 3;
IFormatter bformatter = new BinaryFormatter();
NetworkStream ntstream = tcpClient.GetStream();
bformatter.Serialize(ntstream, pachet);
and the client's 'translation' code(it's namespace is WindowsFormsApplication2) :
NetworkStream strm = client.GetStream();
IFormatter bformatter = new BinaryFormatter();
pack nettmp = (pack)bformatter.Deserialize(strm);
and the error is :
serializationException was unhandeled. Unable to find assembly 'WindowsFormsApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Can someone tell me what the problem is?
Well, as the error message says, your server can't find the WindowsFormsApplication1 assembly.
Do you have it on the client side? You won't be able to use binary deserialization if you don't have the all the assemblies containing the types to be deserialized.
Note that the namespaces are irrelevant - and you won't be able to deserialize an object just because you've got a type with the same name in a client assembly. The assembly name is embedded in the serialization data.
(Personally I'm not terribly keen on using the default .NET binary serialization to start with, as it's pretty fragile in terms of backward and forward versioning, but that's a different matter. If you're interested in alternatives, you might want to look at text based formats such as XML, YAML and JSON, or binary formats such as Thrift and Protocol Buffers.)
For this issue you need to compile and assemble a DLL Library, then add it as a reference to both projects. Just remember, all the classes in the DLL library must be [Serializable].
You need to add reference to WindowsFormsApplication1 to the client. Or better yet, add a separate assembly for classes which are common for both the client and the server.
I found a great tut on how to serialize by transforming an object first into an xml then into a string ! http://www.dotnetjohn.com/articles.aspx?articleid=173
Related
I'm trying to serialize my custom control's final state.
Reason is I do bunch of stuff to obtain final state, but its takes too much time and source during run-time, and I don't have any other way to go. So I want to do it once, serialize it and use serialized form as a template to avoid waste of sources.
Important thing for me is to serialize Region data of related object. But following code causes exception. I'm new to serialization stuff so please explain your ideas.
FileStream stream = new FileStream(#"C:\Serialized_t1.Data", FileMode.Create);
BinaryFormatter processor = new BinaryFormatter();
processor.Serialize(stream, object1);
stream.Close();
Note: Class of related custom control marked like this:
[Serializable]
[Designer(typeof(TControllDesigner))]
public class TControl: UserControl
Note 2 : Exception is
{"Type 'System.Windows.Forms.UserControl' in Assembly 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable."}
Note 3/Edit :
I noticed that GraphicPath or Region causes exception during serialization, so should I need different approach or what ?
How can I save and load List of SlimDX.DirectInput.Joystick to/from a file?
I tried
using (Stream stream = File.Open("joys.xml", FileMode.Create))
{
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(stream, usedsticks);
}
but I got an exception:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Typ SlimDX.DirectInput.Joystick v sestavení SlimDX, Version=4.0.13.43, Culture=neutral, PublicKeyToken=b1b0c32fd1ffe4f9 není označen jako serializovatelný.
I don't speak Czech, but I suppose "Typ SlimDX.DirectInput.Joystick není označen jako serializovatelný." means "type SlimDX.DirectInput.Joystick isn't serializable". That means that SlimDX.DirectInput.Joystick simply cannot be instantiated via deserialization.
The object class you are trying to serialize must be marked as serializable. See the relevant question about the SerializableAttribute class - What is [Serializable] and when should I use it?
Considering the original problem, normally you're supposed to write your own serializable classes for saving. You should instantiate SlimDX.DirectInput.Joystick (or any) objects in a usual way using loaded data afterwards.
In order to save your object into a file you could choose a suitable file format.
For instance, JSON - Turn C# object into a JSON string in .NET 4
I'm trying to make a board game framework that loads in each game as their own plugin classes (through dependency injection). Each 'game' would then be it's own DLL. Thus the plugin handles loading in the correct resource for a 'pawn' in a game, the proper image for the game board, any special logic the game needs, etc.
My proposed folder structure is
game.exe
plugins/
/plugin1
/textures
plugin1.dll
/plugin2
/textures
plugin2.dll
When you start a game, I have you use a filemanager to load the proper dll (will be refined in the future), and as other clients connect to you, it makes them load the plugin on their side too, or fail to connect if you don't also have a dll for that game.
An example of the code for loading is below:
Assembly assembly = Assembly.LoadFile(openPlugin.FileName);
string fullTypeName = "TestPlugin.TestPlugin";
Type dllType = assembly.GetType(fullTypeName);
IPlugin myType = (IPlugin)Activator.CreateInstance(dllType);
I'm using the hard coded string for the type name for now, but that will eventually change.
To play with other people, there is a network architecture that primarily consists of using binary serialization of objects. The problem is when I unserialize an object of a class that was in a plugin dll, the system wants to reload the dll from file. When it trys to reload it, it follows normal rules and looks for the dll in the directory of the exe (This all works if I move the plugin dll to the main directory).
Here is a sample of the binary serialization if it helps
public Stream SerializeObject(object obj)
{
Stream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
return stream;
}
/// <summary>
/// Deserializes Objects
/// </summary>
/// <param name="stream">Stream containing the binary objects</param>
public T DeserializeObject<T>(byte[] data)
{
Stream stream = new MemoryStream(data);
IRemotingFormatter formatter = new BinaryFormatter();
return (T)formatter.Deserialize(stream);
}
I wish I could make it less open ended, but what can I do to solve this and keep the directory structure I want?
- Make some form of custom loader to search recursively through plugins/ ?
- Choose a different method for binary serialization?
- When I 'load', am I not doing it properly for the class is loaded into 'memory' for future uses?
I'm welcome to architectural changes if you read this and go 'why the heck is he doing it that way??' :)
1) Use Assembly assembly = Assembly.LoadFrom("dllPath"); instead of Assembly.LoadFile()
2) As your plugins have different names, you can put them into one directory and define the path in app.config to this dir.
3)It's probably good idea to load Dlls in other than main AppDomain so you can unload them without to restart your application, see my example here
I have created a phonebook application and it works fine after a awhile i liked to make an upgrade for my application and i started from scratch i didn't inherit it from my old class,and i successes too ,my request
"I want to migrate my contacts from the old application to the
new one"
,so i made an adapter class for this reason in my new application with the following code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace PhoneBook
{
class Adapter
{
PhoneRecord PhRecord; //the new application object
CTeleRecord TelRecord; //the old application object
string fileName;
public Adapter(string filename)
{
fileName = filename;
}
public void convert()
{
PhRecord = new PhoneRecord();
TelRecord = new CTeleRecord();
FileStream OpFileSt = new FileStream(fileName, FileMode.Open,FileAccess.Read);
BinaryFormatter readBin = new BinaryFormatter();
for (; ; )
{
try
{
TelRecord.ResetTheObject();
TelRecord = (CTeleRecord)readBin.Deserialize(OpFileSt);
PhRecord.SetName = TelRecord.GetName;
PhRecord.SetHomeNumber = TelRecord.GetHomeNumber;
PhRecord.SetMobileNumber = TelRecord.GetMobileNumber;
PhRecord.SetWorkNumber = TelRecord.GetWorkNumber;
PhRecord.SetSpecialNumber = TelRecord.GetSpecialNumber;
PhRecord.SetEmail = TelRecord.GetEmail;
PhRecord.SetNotes = TelRecord.GetNotes;
PhBookContainer.phBookItems.Add(PhRecord);
}
catch (IOException xxx)
{
MessageBox.Show(xxx.Message);
}
catch (ArgumentException tt)
{
MessageBox.Show(tt.Message);
}
//if end of file is reached
catch (SerializationException x)
{
MessageBox.Show(x.Message + x.Source);
break;
}
}
OpFileSt.Close();
PhBookContainer.Save(#"d:\MyPhBook.pbf");
}
}
}
the problem is when i try to read the file ctreated by my old application i receive serialization exception with this message
"Unalel to find assembly 'PhoneBook,Version=1.0.0.0,Culture=neutral,PublicK eyToken=null"
and the source of exception is mscorlib.
when i read the same file with my old application (Which is the origin of the file) i have no problem and i don't know what to do to make my adapter class work.
When the class is serialised, it includes the assembly information of the class.
It does this so the deserializer knows what type of class to create with the serialised data.
The problem is that while the two classes may seem to be identical, they are not because they are in different assemblies.
The recommended way to do this is to always put serializable classes in a class library. Then in your situation V2.0 of your application can reference the V1.0 assembly, and then you can deserialize the objects.
If your V1.0 classes aren't in a class library (e.g. they're embedded in an executable), you can build your V2.0 classes in a class library, and add functionality to your V1.0 app to transform classes to V2.0 classes.
Post any questions you might have as comments.
Hope this helps.
BinaryFormatter is not very tolerant to assembly changes. I long ago reached the conclusion that it is OK (just about) for transport, but not good for any kind of storage - it is just too brittle.
In short, I would use another serializer - but contract-based, not type-based (so any type with the same cnotract can share the data):
in many cases XmlSerializer will do; it has some limitations (public types and members), but it works generally
with .NET 3.0, DataContractSerializer is useful
or if you want something outside of the code libs, protobuf-net is very fast and efficient
Of those, only DataContractSerializer will currently support "graph" mode (rather than trees).
If you have existing data that you're fighting, I would be sorely tempted to use the old code (or something very close to it) to re-write the data in a contract-based form. Although you say you've only just created it, so maybe this isn't a problem.
As previously stated the file contains the fully qualified assembly name of your class, which has changed in your new project. If you your assembly, class name and namespaces match, you can set the Assembly format to simple on the formatter:
BinaryFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
This use LoadWithPartialName when the formatter tries to load this type. See MSDN for more info.
You could also write a serialization binder to resolve the differences.
I am trying to store some objects in the session (which is using a StateServer), but I am getting the error "System.Web.HttpException: Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode"
I know what the error message means, but I can't work out why. All of the classes I am using are marked as Serializable, and I am able to Serialize and Deserialize the object to and from XML using:
System.IO.StringReader stringReader = new System.IO.StringReader(xml);
System.Xml.XmlTextReader xmlTextReader = new System.Xml.XmlTextReader(stringReader);
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Parts));
Parts obj = ((Parts)(xmlSerializer.Deserialize(xmlTextReader)));
This works, and will Serialize as well using:
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(this.GetType());
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
xmlSerializer.Serialize(memoryStream, this);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
System.IO.StreamReader streamReader = new System.IO.StreamReader(memoryStream);
return streamReader.ReadToEnd();
But the error is thrown when trying to store it in the Session.
Does anyone have any ideas what may be causing this behaviour?
EDIT:
I have just discovered that this line is causing the error (having removed everything and re-included it)
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("RecordReference", typeof(RecordReference), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
[System.Xml.Serialization.XmlElementAttribute("PartContainer", typeof(PartContainer), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public object Item
{
get
{
return this.itemField;
}
set
{
this.itemField = value;
}
}
If I set this "Item" property to "new RecordReference()", then the error occurs. If it is null, it's fine.
So now, the question is, why can't the StateServer cope with this? It serializes fine when serializing to XML...
EDIT...
Type 'System.Xml.XmlElement' in Assembly 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
.....Are we saying that the Xml objects in C# aren't serializable?! Does anyone else think this verges on the insane?
In the stack trace you should see a SerializationException that will mention which class it's unable to serialize...
[SerializationException: Type 'SomethingOrOther' in Assembly 'SomethingElse' ...
Note that the state server uses binary serialization not XML serialization.
So I have found the answer to the question, but I'm not happy about it.
Basically, some of the classes I'm using contain XMLElements and XMLNodes (they're automatically generated using svcutil). For whatever reason, but it thinks it needs them.
Neither of these XML classes are serializable!! Am I the only one who finds this to be a complete failing of these objects? So to get this set of classes into the session, I've got to serialize them down to a string, and then store that in the session, which is in turn serializing it. So I'm serializing it in order for it to be serialized.....!?
Not sure I'm happy with that, but that was the cause of my problems.
Don't use ever use InProc. It is as reliable as the weather or a room mate paying their share of the rent on time. You never know when it is going to just drop out.
InProc uses available RAM resources. It will get recycled if the machine needs the RAM resources for other tasks of more priority. So the session info could last the 20 minutes or what ever you set it for. Or it could last 2 minutes when you're expecting 20. Just like the weather you never know. It all works great in Dev where the machine is not busy. Then live, people are getting free stuff off the shopping cart because they are being charged 0 dollars to Paypal.
If you are going to use Session information then State Server is the easiest and most pain free way. It is almost bullet proof also. I have used it for years with zero issues. You can rebuild your app, deploy it and the users don't loose the session info and keep right on like nothing ever happened. Plus you can't cluster in other web servers if you are using InProc. You can with StateServer with no hassle because it is made for that. As far as objects being non serializabe, just wrap them in an object that is. For instance DataTables are non-serializabe but a DataSet is serializable.
for objects or a complex class then you need to add in you own serialision attributes to the class.
So for MyClass do something like this
[Serializable]
public class MyClass : ISerializable
{
bool TorF=true;
string str="Save me";
public MyClass() {//need a constructor for your access}
#region Serialisation
//read in data
public MyClass(SerializationInfo info, StreamingContext context)
{
TorF=(bool)info.GetValue("TorF",typeof(bool));
str=(string)info.GetValue("str",typeof(string));
}
//write out data
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("TorF", TorF);
info.AddValue("str", str);
}
}
The biggest thing is to ensure that your web.config has your session state mode set as 'InProc'. Based on the error message you are receiving, simply changing that should fix it. If you still encounter issues, make sure that any events are marked as non-serializable.
As stevemegson said, find out which class threw the SerializationException.
[SerializationException: Type 'SomethingOrOther' in Assembly 'SomethingElse' ...
Find that "SomethingOrOther" class in your code and make sure it is serializable.
Making a class serializable in C#:
[Serializable]_
public class PayeeData
{
...
}
Making a class serializable in VB.NET:
<Serializable()> _
Public Class PayeeData
...
End Class
For your specific query about XML serialization, see this MSDN article:
XML Serialization in the .NET Framework