Serialization problem - c#

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.

Related

C# .Net 3.5 : Extracting and binding Metadata to a file

Introduction
I am trying to make a compression application. The current obstacle I am facing is that whenever I try to compress my file I take a byte array from the file and apply compression algorithm on the byte array itself because of which the metadata of file is lost.
Question
Is there any method by which I can extract the metadata of a file on compression and later on extraction attach the metadata to the extracted file?
Visual Studio : VS2008
Framework : .Net 3.5
Solutions I found:
I have seen in many articles that they say we can use Windows Property System but even after reading the article I have no clue as to how can I implement it.
This website has explained with the code but they didn't give any download link for the DLL.
From this Stackoverflow answer I got this code:-
//creates new class of oledocumentproperties
var doc = new OleDocumentPropertiesClass();
//open your selected file
doc.Open(#"C:\Users\ABC\Desktop\Test\1.jpg", false, dsoFileOpenOptions.dsoOptionDefault);
//you can set properties with summaryproperties.nameOfProperty = value; for example
doc.SummaryProperties.Company = "lol"; //Line 8 : Shows error
doc.SummaryProperties.Author = "me";
//after making changes, you need to use this line to save them
doc.Save();
I get the following error on Line 8
The name is not valid. (Exception from HRESULT: 0x800300FC (STG_E_INVALIDNAME))
Are you sure that the Company property exists in your file metadata?
Try using a known existing property in the metadata of the file you're trying to access, as the ones that are used in the example may just not exist.
As for saving the properties, you can access some basic global ones like CreationTime and LastAccessTime from the System.IO.FileInfo object.
This article seems to describe a method through which you can get more specific properties from files, such as the Camera and CameraManufacturer properties (that isn't identical to the one from the StackOverflow question) like so:
using System;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using Microsoft.WindowsAPICodePack.Shell;
using System.Diagnostics;
class Program {
void getProperty() {
var cameraModel = GetValue(picture.Properties.
GetProperty(SystemProperties.System.Photo.CameraModel));
}
}
with GetValue being:
private static string GetValue(IShellProperty value)
{
if (value == null || value.ValueAsObject == null)
{
return String.Empty;
}
return value.ValueAsObject.ToString();
}

StackExchange.Precompilation - How can I unit test precompilation diagnostics?

Background
I'm using StackExchange.Precompilation to implement aspect-oriented programming in C#. See my repository on GitHub.
The basic idea is that client code will be able to place custom attributes on members, and the precompiler will perform syntax transformations on any members with those attributes. A simple example is the NonNullAttribute I created. When NonNullAttribute is placed on a parameter p, the precompiler will insert
if (Object.Equals(p, null)) throw new ArgumentNullException(nameof(p));
at the beginning of the method body.
Diagnostics are awesome...
I would like to make it difficult to use these attributes incorrectly. The best way I have found (aside from intuitive design) is to create compile-time Diagnostics for invalid or illogical uses of attributes.
For example, NonNullAttribute does not make sense to use on value-typed members. (Even for nullable value-types, because if you wanted to guarantee they weren't null then a non-nullable type should be used instead.) Creating a Diagnostic is a great way to inform the user of this error, without crashing the build like an exception.
...but how do I test them?
Diagnostics are a great way to highlight errors, but I also want to make sure my diagnostic creating code does not have errors. I would like to be able to set up a unit test that can precompile a code sample like this
public class TestClass {
public void ShouldCreateDiagnostic([NonNull] int n) { }
}
and confirm that the correct diagnostic is created (or in some cases that no diagnostics have been created).
Can anyone familiar with StackExchange.Precompilation give me some guidance on this?
Solution:
The answer given by #m0sa was incredibly helpful. There are a lot of details to the implementation, so here is the unit test actually looks like (using NUnit 3). Note the using static for SyntaxFactory, this removes a lot of clutter in the syntax tree construction.
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using NUnit.Framework;
using StackExchange.Precompilation;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace MyPrecompiler.Tests {
[TestFixture]
public class NonNull_CompilationDiagnosticsTest {
[Test]
public void NonNullAttribute_CreatesDiagnosticIfAppliedToValueTypeParameter() {
var context = new BeforeCompileContext {
Compilation = TestCompilation_NonNullOnValueTypeParameter(),
Diagnostics = new List<Diagnostic>()
};
ICompileModule module = new MyPrecompiler.MyModule();
module.BeforeCompile(context);
var diagnostic = context.Diagnostics.SingleOrDefault();
Assert.NotNull(diagnostic);
Assert.AreEqual("MyPrecompiler: Invalid attribute usage",
diagnostic.Descriptor.Title.ToString()); //Must use ToString() because Title is a LocalizeableString
}
//Make sure there are spaces before the member name, parameter names, and parameter types.
private CSharpCompilation TestCompilation_NonNullOnValueTypeParameter() {
return CreateCompilation(
MethodDeclaration(ParseTypeName("void"), Identifier(" TestMethod"))
.AddParameterListParameters(
Parameter(Identifier(" param1"))
.WithType(ParseTypeName(" int"))
.AddAttributeLists(AttributeList()
.AddAttributes(Attribute(ParseName("NonNull"))))));
}
//Make sure to include Using directives
private CSharpCompilation CreateCompilation(params MemberDeclarationSyntax[] members) {
return CSharpCompilation.Create("TestAssembly")
.AddReferences(References)
.AddSyntaxTrees(CSharpSyntaxTree.Create(CompilationUnit()
.AddUsings(UsingDirective(ParseName(" Traction")))
.AddMembers(ClassDeclaration(Identifier(" TestClass"))
.AddMembers(members))));
}
private string runtimePath = #"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\";
private MetadataReference[] References =>
new[] {
MetadataReference.CreateFromFile(runtimePath + "mscorlib.dll"),
MetadataReference.CreateFromFile(runtimePath + "System.dll"),
MetadataReference.CreateFromFile(runtimePath + "System.Core.dll"),
MetadataReference.CreateFromFile(typeof(NonNullAttribute).Assembly.Location)
};
}
}
I figure you want to add you diagnostics before the actual emit / compilation, so the steps would be:
create your CSharpCompilation, make sure it has no diagnostic errors before going further
create an BeforeCompileContext, and populate it with the compilation and an empty List<Diagnostic>
create an instance of your ICompileModule and call ICompileModule.BeforeCompile with the context from step 2
check that it contains the required Diagnostic

XmlReader is declared in a different Assembly even though System.Xml is referenced?

I am a student studying Computer Engineering in University, and I am trying to develop an application that will read an rss feed from a certain url, then display the titles and links of each item in the feed as a notification whenever a the feed on the url is updated.
Well, I am actually at the very beginning, and I am working on this project for learning purposes, following some tutorials etc.
My plan was to use System.ServiceModel.Syndication library to read the rss feed from the url using the SyndicationFeed object and its methods. But whenever I try to use that I get a strange error. The error is as follows
--- CS0012: The type 'XmlReader' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xml, Version=5.0.5.0',Culture=neutral, PublicKeyToken='7cec85d7bea7798e'.
Here is the part of code that this error is shown:
public void GetFeed()
{
// Create an xml reader that will read rss data from the given url
var xmlReader = XmlReader.Create(rssUrl);
syndicationFeed = SyndicationFeed.Load(xmlReader);
}
The part where I create the xmlReader has no errors, I also have the following assembly referenced, 'System.Xml'.
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel.Syndication;
using System.Xml; // Here is the System.Xml
Also, trying to add a refenrence to the said library (System.Xml) by right clicking and selecting 'Add Reference' just gives me another error, telling me that I cannot refenrence 'System.Xml' as it is already being referenced by the build system.
I tried using other classes from the System.ServiceModel.Syndication namespace to ensure that the problem is not with the assembly, and every other class, method, etc. worked without errors. For example, I am able to write this and get no error:
SyndicationItem item = new SyndicationItem();
item.Title = new TextSyndicationContent("Me");
item.Links.Add(new SyndicationLink() { Uri = new Uri("http://somesite.con") });
item.PublishDate = DateTime.Now;
I get no errors on the above piece of code. I don't get errors when I use XmlReader like this for example:
var reader = XmlReader.Create(rssUrl);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Attribute:
// Some code here
break;
// Some more cases here......
}
}
I get no errors here about the XmlReader either. I only get the error when passing an instance of XmlReader to a SyndicationFeed.Load(XmlReader instance) method.
// This always gives me error!!!
syndicationFeed = SyndicationFeed.Load(xmlReader);
I have been trying to solve this problem for quite a while now, nearly 6 hours, I searched on the web, referenced different versions of System.ServiceModel.Syndication.dll, trying to find Syndication packages on Nuget package manager. Nothing worked. I am asking this question here as a last resort, and any help would be greatly appreciated.
UWP apps use the Windows Runtime class Windows.Web.Syndication.SyndicationFeed rather than .Net's System.ServiceModel.Syndication.
Windows.Web.Syndication.SyndicationFeed doesn't have an XmlReader constructor. Generally you'll create a SyndicationClient and then call RetrieveFeedAsync(url) to get the SyndicationFeed.
See How to access a web feed (XAML) for a full walkthrough.

Suggestion for ServiceStack.NET

The suggested way of using ServiceStack.NET with Silverlight is to use the Linked-Project addon. This enables two synchronous Projects and their sources, one for Silverlight, one for .NET 3.5+.
But when it comes to validation, this gets a bit annoying.
ServiceStack is using FluentValidation, which is cool. But it has changed the namespace.
So I end up with:
using MyNamespace.Model;
// HERE ----------------------------
#if SILVERLIGHT
using FluentValidation;
#else
using ServiceStack.FluentValidation;
#endif
//TO HERE------------------------
namespace HR.RoBP.Contracts.Validators.Model
{
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(r => r.Name).NotEmpty().NotNull();
}
}
}
This is not much, but it gets really annoing when writing a new validator each time. I often forget it, compile, have errors, fix it.
I know there is something changed in FluentValidation on ServiceStack.NET.
But must it be in a seperate Namespace?
I think its in the interest of servicestack to keep code files clean.
But using the the same validation on client and server forces me to do this.
If there is a elegant way to fix this issue, I would love to hear about it.
You unfortunately can't set a project-wide namespace alias. You could however try to write a template for your validator class that has that boilerplate code built in, and you can easily click Add -> New Item -> Your Validator Template.

Unable to serialize the session state... [Updated!]

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

Categories

Resources