Deserialization exception: Unable to find assembly - c#

I'm serializing some data like fields and custom class to create a binary data (byte array).
Then I want to Deserialize it back from binary data to fields and class.
But I get an exception. It would all work fine if these two methods would happen in same assembly - but its not.
I do Serialization in one assambly, and do the Deserialization in another one. And this is the excaption saying too:
Unable to find assembly 'MyAssamblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
NOTE 1: I have no issues with getting the fields back, only the classes causes them.
NOTE 2: I have this same class in both assemblies.

NOTE 2: I have this same class in both assemblies
No you don't. At least, not as far as the runtime is concerned. You have two different types that happen to have the same name. A type is defined by its assembly. Thus "SomeType in AssemblyA" is completely different to "SomeType in AssemblyB", even if they happen to have been compiled from the same source file.
BinaryFormatter works with type information, so this won't work. One option would be to move the type to a library dll that both the other projects reference - then it is only defined once, and it will be happy.
Another option is to work with a contract-based serializer (rather than a type-based serializer). This means that "classes that look similar enough" are fine, even if they are in different assemblies (and perhaps have different source, as long as it is "similar enough"). Examples of suitable serializers for this would include (plus a few others) XmlSerializer, DataContractSerializer (but not NetDataContractSerializer), JavaScriptSerializer, or protobuf-net if you want dense raw binary.

All the assemblies containing classes in the class hierarchy of the object you are deserializing must be present in the application in which you are performing this deserialization. They could be either explicitly referenced (if you need compile-time safety with those classes) or only placed in the bin folder of the application so that they could be resolved at runtime. If they are not explicitly referenced you will have to use reflection in order to read the values from the deserialized instance.

Related

Can I use a .NET attribute without depending on the assembly that defines it?

I am unclear about the rules regarding attributes and assembly dependencies.
Is it possible (and not a terrible idea) to annotate the types in an assembly with custom attributes from a NuGet package without introducing a run-time dependency on that NuGet package? Could clients use the types in the assembly without also needing to have the custom package's assemblies present?
I ask because My .NET application uses two packages:
A third party NuGet package called YamlDotNet for serializing types to YAML. It lets you control YAML serialization with custom attributes analogous to Microsoft's XML attributes (e.g. it has YamlIgnoreAttribute like MS' XmlIgnoreAttribute)
My own package, PackageA which does not depend upon YamlDotNet.
I want my app to serialize my types from PackageA using YamlDotNet. But they will not serialize correctly unless I do one of the following:
annotate the types in PackageA with YamlDotNet custom attributes
create annotated wrappers for PackageA types in the App to do the serialization for me.
I can do #2, but it would be easier to do #1. But I do not want to introduce a run-time dependency on YamlDotNet for all clients of PackageA. Ideally, I would like anybody using PackageA who also happens to be using YamlDotNet to get those attibutes for free and for them to be invisible to anyone else.
Is what I want possible?
Attributes are a compile-time feature, you will always need reference to YamlDotNet in order to use one of its types as compile-time type metadata, unless you are open to doing things like generating your model classes in run-time (which is quite probably way more troublesome than having a one extra package reference).
This is a general problem where using attribute-driven features of a serializer pollutes the target assembly and couples it with that serializer.
There are three ways to address this:
Accept this as a compromise
Move YamlDotNet-specific into a separate assembly
Have a separate serialization model
The first point should be quite clear - this is what you don't want and your first ssuggestion.
The second point could be creating YamlDotNet-specific type wrappers or type converters (if it supports such things) in a separate assembly so that the core assembly stays clean. This is your second suggestion, just with a twist of converters that may be more pleasant than wrapping everything from consumer perspective.
The third point is about creating DTOs/payloads in the core assembly so that you never have to use any serializer-specific attributes and the serialization just works out of the box. If you need to [YamlIgnore] properties, the model used for serialization probably also serves other purposes so this is basically just a separation of concerns. If you serialize your application model, you might find it impossible to provide backwards compatibility without affecting business logic at various places as a result.

XmlSerializer - the first deserialization is very slow

I have a solution with two projects; an asp.net MVC application, and a class library. Let's call them project MVC and project CLS.
In the project CLS, there are two different versions (V1 and V2) of an XSD file that I have used to create two serializable classes with the same name, but under different namespaces (V1 and V2) using xsd2code.
In the MVC project, when the user uploads an XML file, the CLS.dll is used to deserialize the XML into an object. When the XML file is of type V1, the deserialization is very fast, but the XSD file for the V2 version is a lot more complex, and the deserialization can take up to a couple of minutes, only the first time (it's very fast afterwards, until the application is run again).
I used the Sgen.exe tool to create a serializer assembly (CLS.XmlSerializers.dll) for the CLS.V2 type in order to eliminate the first-time creation of the assembly on the fly, and therefore improving the performance.
I have successfully managed to add the Sgen Task to the Post Build events, and the assembly CLS.XmlSerializers.dll is created every time I build the project. Also, I have used the unit test code in this post to make sure the assembly is loaded, and it does. The test passes susscessfully.
However, still, the first time the XML file is deserialized, it takes a long time. So, something still should be wrong. But, I don't know what. Please help.
UPDATE:
I used Fuslogvw.exe as was suggested in the comments, and I can see that the CLS.XmlSerializers.dll is being loaded successfully. Then, how come the first time the XML file is deserialized it takes around one minute, but every time after that takes less than a second?
UPDATE 2:
One of the differences between the two XSD files is that the second one (V2) has a reference to a very big XSD file that containes definitions of some xs:enumeration types that are used in the main file. And, that's the reason the deserialization took a long time. Since all I need to do is to deserialize the XML files into objects and do not need to validate the values of the attributes and elements against those enumerations, I ended up removing the reference to that XSD file, and replacing all the enumeration types with their base types (in this case, xs:string). Now, V2 is deserialized as fast as V1, and I don't even need to use Sgen.exe. I guess Sgen.exe only helps in situations where you need to deserialize a very large XML file. In my case, the XML files are always very small, but the desrialization is (was) complex.
In order to increase performance of XML serialization, assemblies are dynamically generated each time XmlSerializer is instantiated for the first time for a specific type. It happens only once in the application lifetime, but that makes its first usage slow.
When you instantiate an XmlSerializer you have to pass the Type of the objects that you will attempt to serialize and deserialize with that serializer instance. The serializer examines all public fields and properties of the Type to learn about which types an instance references at runtime. It then proceeds to create C# code for a set of classes to handle serialization and deserialization using the classes in the System.CodeDOM namespace. During this process, the XmlSerializer checks the reflected type for XML serialization attributes to customize the created classes to the XML format definition. These classes are then compiled into a temporary assembly and called by the Serialize() and Deserialize() methods to perform the XML to object conversions.
Full Content: Troubleshooting Common Problems with the XmlSerializer
More Info: XmlSerializer Constructor Performance Issues
It is a known issue of x64 jit compiler, it can be very slow in some cases. That's why you have much better performance when running the deserializtion the second time when code is already compiled.
Try to use .net 4.6 or higher, it features a new version of x64 jit compiler (RyuJIT). If it is not possible to update .net version then take a look at this thread.

Cast Exception between objects loaded from the same assembly in different locations

I'm trying to use a supplied DLL that load the same dependent DLL from two different locations.
In the supplier deployment the two locations conicide, but not in mine.
When code runs I have a class cast exception:
Unable to cast [A]Type to [B]Type
The error is the same occurred to the op in StackOverflow question Different location of assemblies stoped the type casting.
The two types are the same type loaded from the two different locations of the DLL (the same physical file copied in two directories).
I've tried to use Strong Name with signature of the double DLL, but it did not work.
Is there a way I can tell CLR to treat the two types as the same type?
I'm pretty sure this isn't allowed for a lot of reasons.
First off, let's say you have 2 assemblies. The first defines Animal and has a descendant called Dog. The second defines Animal. Both assemblies use the same namespace.
During runtime what happens when you declare var B = new Dog();? Should the code swap the second assembly's version of Animal in there or not?
What if you declare var A = new Animal();? IMHO, the code should simply implode to prevent it.
From a security perspective you would absolutely not want someone to simply link in another assembly that defines the same namespace as your library to swap out a particular class.
Point is, by linking to both physical assemblies containing the exact same types you are introducing a huge problem that there is no real way to solve. Change your code to work the same way as the supplier.

Serializing IronPython Objects Which Inherit From CLR Types

This may be a bit of a weird question, but is there any reliable way to serialize IronPython objects whose classes extend CLR types?
For instance:
class Foo(System.Collections.Generic.List[str]):
def Test(self):
print "test!"
System.Collections.Generic.List<string> is serializable with Pickle, as it implements the ISerializable interface, but emitted subclasses of serializable CLR types seem to not work, and i get ImportError: No module named Generic in mscorlib, Version=4 when running pickle.dumps(Foo()).
Additionally, running the usual Formatter.Serialize(stream, object) gives me:
SystemError: Type 'IronPython.NewTypes.System.Collections.Generic.List`1_4$4' in Assembly Snippets.scripting, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
How can I implement serialization of IronPython objects when running in an embedded C# environment?
I don't know if it is what you are after, but you could consider the python version of protobuf (here)? I haven't tested it specifically on ironpython, mind. This has the added advantage that there are also C# implementations that may help, while keeping it platform independent. When possible I want to get protobuf-net to support DLR types, but that is a big job.
As a side note, personally I'd recommend having a dedicated DTO type rather than trying to extend the inbuilt types.
Quote from clrtype metaclasses
IronPython doesn’t support Reflection
based APIs or custom attributes today
because IronPython doesn’t emit a
custom CLR types for every Python
class. Instead, it typically shares a
single CLR type across many Python
classes. For example, all three of
these Python classes share a single
underlying CLR type.
class shop(object):
pass
class cheese_shop(shop):
def have_cheese(self, cheese_type):
return False
class argument_clinic(object):
def is_right_room(self, room=12):
return "I've told you once"
import clr
print clr.GetClrType(shop).FullName
print clr.GetClrType(cheese_shop).FullName
print clr.GetClrType(argument_clinic).FullName
Even though cheese_shop inherits from
shop and argument_clinic inherits from
object, all three classes share the
same underlying CLR type
I haven't tried, but maybe you can solve this issue with manual serialization via serialization surrogates.

C# Reading Serialized Objects between Applications

I have two different applications and I am using GroupLab Networking to communicate between them. The idea is there is a shared dictionary and when something changes in this shared dictionary, the other application gets a notification. The notification part works. Here is the problem. I have the following code in the first application.
TouchInfo t = new TouchInfo();
int.TryParse(txtXCoord.Text, out t.X);
int.TryParse(txtYCoord.Text, out t.Y);
this.sharedDictionary1["/pointOne"] = t;
Where TouchInfo is a struct. This object stored in the shared dictionary can be accessed by both applications. The code looks like this:
TouchInfo val = (TouchInfo)this.sharedDictionary1["/pointOne"]
While this code works in the application that created the object. I get the following error in the second:
{Unserializable object: problem: System.Runtime.Serialization.SerializationException: Unable to find assembly 'NetworkingTestProgramOne, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
I realize this problem is because the serialization also stores the assembly information of the program that serialized it. But I do need it to communicate across different programs. How do I make this work?
Have you got TouchInfo declared in two different assemblies? That's a bad idea - you should have one common assembly containing the types required by both applications.
Personally I'd try to avoid the default .NET binary serialization anyway, preferring something more controllable - I'm biased towards Google Protocol Buffers for various reasons. Does GroupLab Networking require "normal" binary serialization?
As an aside, I'd also try to avoid using mutable structs if at all possible.
You need to declare the struct in an assembly that is shared by both applications. The structure should be something like this:
MyApp.Shared
MyApp.ProgramOne
MyApp.ProgramTwo
Both programs reference Shared. Then they'll be able to serialize/deserialize appropriately.
In the past i've used a SerializationBinder to translate a requested type into the equivalent type available in the current app domain.
Sadly, I don't know anything about GroupLab.Networking, so I'm not sure if you can access or override the routines that do the serialization.
An alternate approach might be to use the AppDomain.CurrentDomain.AssemblyResolve event. Assign it a delegate and use that to redirect to a valid assembly containing the type.

Categories