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
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 ?
I am encountering a problem with Json.NET (version 6.0.5) that leaves me a bit puzzled.
One of my classes that gets to be serialized looks something like this:
[JsonConstructor]
public MyContainerClass(IEnumerable<AbstractBaseClass> myDerivedUnitClasses)
{
if (myDerivedUnitClasses == null)
{
Units = ImmutableHashSet.Create<object>();
}
else
{
Units = myDerivedUnitClasses.ToImmutableHashSet();
}
}
public IEnumerable<AbstractBaseClass> Units { get; private set; }
Using Json.Convert with TypeNameHandling set to TypeNameHandling.Auto serializes this without problems. The serialized JSON includes the expected $type-qualifier for the property: "System.Collections.Immutable.ImmutableHashSet`1[[AbstractBaseClass, MyLibrary]], System.Collections.Immutable"
I got one project in my Solution where I serialize the data structure and another one where I deserialize it using Json.Convert (deserialization also using automatic type name handling). Deserialization fails with this error: Error resolving type specified in JSON System.Collections.Immutable.ImmutableHashSet`1[[AbstractBaseClass, MyLibrary]], System.Collections.Immutable
Using the source of Json.NET I traced the error back to the DefaultSerializationBinder calling assembly.GetType(string name) and getting null as result.
So far so bad. Here comes the part that leaves me especially puzzled right now: When I deserialize the JSON in the same code block where I serialize my data structure everything works perfectly fine (using the same code that I use in the other project).
Thank you for your help.
Turns out there was an assembly binding problem regarding the assembly containing AbstractBaseClass in the one project. I used fuslogvw.exe of the Visual Studio Tools while debugging to check for errors and noted that the directories that were searched were not the ones I was expecting and did not contain the assembly file.
My solution was to subscribe to the AppDomain.CurrentDomain.AssemblyResolve-event prior to deserialization and then manually load the assembly from the correct path via Assembly.LoadFrom in the event handler.
I'm currently trying to learn proper unit-test. So now I'm trying to write unit-tests for a class that should map data from an XML-File to the proper objects. Of course all functionality of the class is dependent on the existence of the corresponding XML-file. The XML-file is loaded in the constructor of the class.
I'm using C# with NUnit. So far I've got two tests:
[Test]
public void ShouldAllowInstanceToBeCreatedWhenXMLFileIsPresent()
{
if (File.Exists(SettingsReader.XML_SETTINGS_PATH))
{
SettingsReader settingsReader = new SettingsReader();
Assert.AreNotEqual(null, settingsReader);
}
}
[Test]
[ExpectedException("Telekanzlei.Clientmanager.XMLDataLayer.XMLFileNotFoundException")]
public void ShouldThrowExceptionWhenXMLFileIsNotPresent()
{
if (!File.Exists(SettingsReader.XML_SETTINGS_PATH))
{
SettingsReader settingsReader = new SettingsReader();
}
else
throw new XMLFileNotFoundException();
}
I'm not sure if checking the existence of the file in the test is a proper way to go, so any suggestions on those test are welcome too. But my question is, how to proceed with the following tests. Obviously all following tests are going to fail, if the XML-file is not present.
So do I assume that the XML-file is present, while keeping in mind, that a failing test could just mean that it's not? That wouldn't seem right to me.
Is there a general pattern, to handle a problem like this?
Thx for any help
edit: rewrote the second test, as it was failing if the file was actually present...
edit2: May it is helping to tell you, what the SettingsReader actually does. So far it looks like this:
public class SettingsReader
{
public static readonly string XML_SETTINGS_PATH = "C:\\Telekanzlei\\Clientmanager_2.0\\Settings.xml";
public XElement RootXElement { get; private set; }
public SettingsReader()
{
if (!File.Exists(XML_SETTINGS_PATH))
throw new XMLFileNotFoundException();
using (var fs = File.OpenRead(XML_SETTINGS_PATH))
{
RootXElement = XElement.Load(fs);
}
}
}
I'm not sure, but I guess a StreamReader wouldn't be the way to go here, would it?
The problem is not with your unit tests but with the design of the class. I'd suggest refactoring the class so it doesn't open the file but instead operates on a stream. Then your unit tests could simply replace a file stream for a memory stream - simples! :)
public class SettingsReader()
{
public SettingsReader(System.IO.StreamReader reader)
{
// read contents of stream...
}
}
// In production code:
new SettingsReader(new StreamReader(File.Open("settings.xml")));
// In unit test:
new SettingsReader(new StringReader("<settings>dummy settings</settings>"));
Remember, opening a file and parsing settings data are two very different concerns.
If you must I suggest you use SetUp method to copy or verify that the file exist.
I suggest making sure the file is present by adding it to the test project and marking it as "copy always" once you get that working there is no need to re-check it.
If you have a lot of tests that require external files perhaps you should use MsTest - it has an attribute called DeploymentItem that makes sure that the file is copied to the same location as the test.
Consider rewriting code so dependencies can be passed in or somehow else stubbed for the code you want to unit-test.
I.e. pass something like "IMySettingsFileProvider" instance to SettingsReader constructor where IMySettingsFileProvider.SettingsXml returns some setting stream. This way you can mock IMySettingsFileProvider interface for the test instead of requiring file to be present on disk.
One option is to put this at the top of the test fixture. Then the tests will only be valid when the file exists.
[SetUp]
public void Setup()
{
Assume.That(File.Exists(SettingsReader.XML_SETTINGS_PATH));
}
I am using System.Web.Helpers.Json to deserialize some JSON into dynamic in NET 4. The following line fails with this error: TypeInitializationException: Attempt by method 'System.Web.Helpers.Json..cctor()' to access method 'System.Web.Helpers.Json.CreateSerializer()' failed.
var json = Json.Decode(response);
The response is lengthy but valid JSON. What could be the matter here? I have tried LINQPad with a short handcrafted JSON and it worked. Is this a configuration issue of some sort?
[EDIT]
Here is the actual sample JSON. It appears the content is pretty much irrelevant. When this is run in a brand new Console application or LINQPad, it works as expected. But if you try to run the same code from a brand new Windows Forms application, it barfs with the above error.
var json = Json.Decode("{\"r\":{\"0\":{\"id\":\"2\"},\"1\":{\"id\":\"33\"}}}");
[EDIT2]
Actually, it turns out this has nothing to do with project types. The exception is thrown if the project is being debugged. If it is simply run, the exception does not occur. Strange, eh?
I forgot about this question and I found my answer in the meantime. I think it was somewhere on Microsoft's Connect site but I am not sure. So let's share it now.
Basically, in order to workaround this problem you need to make sure "Enable the Visual Studio hosting process" is unchecked in your project's settings under Debug. I am not sure why it's happening but this is definitely a way to "fix" it. I stopped searching for answers once I found out about this. It was good enough for me.
This can also happen if you are running in a partial trust.
Check the exception description here for possible reasons.
I don't know if this will apply to you, since you are not running in a web context, but this is what that link describes:
This exception is thrown in situations such as the following:
A private, protected, or internal method that would not be accessible from normal compiled code is accessed from partially
trusted code by using reflection.
A security-critical method is accessed from transparent code.
The access level of a method in a class library has changed, and one or more assemblies that reference the library have not been
recompiled.
There is problem in the inbuilt json class.
If you want to achieve this in alternate way, please use the below code:
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new DynamicJavaScriptConverter[] { new DynamicJavaScriptConverter() });
var result = WrapObject(serializer.DeserializeObject(value)); // here you will have result.
private object WrapObject(object value)
{
IDictionary<string, object> values = value as IDictionary<string, object>;
if (values != null)
{
return new DynamicJsonObject(values);
}
object[] arrayValues = value as object[];
if (arrayValues != null)
{
return new DynamicJsonArray(arrayValues);
}
return value;
}
Further to Roland's answer: some assembly mismatches listed can be fixed in the AssemblyInfo.cs file.
The offending line in my AssemblyInfo was this:
[assembly: AllowPartiallyTrustedCallers]
Removing this allowed me to access the public property (on a public class) that I was trying to set from another assembly that had dynamically loaded this assembly.
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.