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.
Related
I'd like to use C#'s reflection and custom attributes to simplify registering a series of types with a central management class (i.e. it provides static methods taking a string key and invoking/retrieving the proper method/parameter for the associated type). Looking at other questions here and a couple places elsewhere, it seems like the best way of doing so is to simply iterate through all public types of the assembly -- since it's intended to be a library -- and check if each type has the proper attribute before adding the relevant values to the underlying Dictionaries. The reflection and iteration will definitely be slow, but I can live with it since it should only occur once.
Unfortunately, I can't figure out how to get an attribute from a type. For methods and assemblies, I can use CustomAttributeExtensions.GetCustomAttribute<MyAttribute>(base) from System.Reflection.Extensions, but that doesn't provide an overload for Type; the same for Assembly.GetCustomAttribute(Assembly, Type) and the .IsDefined(...) methods used in this question. Other suggestions use methods on the Type itself that, from the documentation, seem to be loaded from mscorelib.dll, but it didn't seem to be showing up in Intellisense even after adding the reference and I'm not sure how that .dll interacts with .NET Standard, anyway (as in, does it reduce the ability to run on arbitrary platforms at all?)
Am I missing something obvious, or is it really this hard to get an Attribute back off of a Type?
Try typeof(YourType).GetTypeInfo().GetCustomAttributes();
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.
I'm developing a MAF application which, in a DLL contains a class. The problem is, when one of the methods exposed by one of the AddIns uses this class. Example:
class A
{
Property_1
Property_2
Method_X()
}
And my AddIn has a method which use class A
MyAddIn.Set(class A);
So, with this, where must I place the DLL in the pipeline? Or how should I proceed with this scenario?
When the proyect start, the warnings of the AddInStore.Update() method throws messages like: unable to connect a part of a canalization...
So, there is an article this which says "There are many other capabilities MAF provides such as versioning, passing collections and WPF visuals, passing non-serializable types, etc.". But I can't find an example.
EDIT:
Thanks to Panos for this link about the restrictions on contracts. And after more research I've found this article which, through the Paint.NET proyect, shows how to use data types in the host without referencing.
After reading both sources, I know that this is what I'm looking for. But I can't understand it yet.
As a final petition, can someone please provide me code example? Just to finally get it.
Thanks.
You should study these guidelines on what types are allowed in the contracts assembly.
Basically you should not reference the dll you mention in the pipeline (contracts, adapters and views) because this way you can leak types from the host to the add-in. This means that you will lose versioning because all pipeline segments are referencing the same assembly. What this means is that if the add-in is referencing v.1 of the assembly and the contract is referencing v.2, both versions will be loaded and an InvalidCasrtException will be thrown.
A solution to this is to create an interface based on class A and make it a contract. Then your add-in can provide the implementation. Thiw way you will not lose versioning.
Regards,
Panos
I am currently building an emulator in C#/Silverlight. Because we are emulating a particular software domain, we have domain-level classes (Cube, CubeSet, BaseApp, etc.) that we have to implement within the scope of our emulator. Additionally, these domain-level classes have to be available to the application developer because they are accessible to applications which will be emulated.
So what we have is a .dll which is a compilation of just the domain-level classes, and then within the emulator implementation itself we have a package of the same domain-level classes.
The goal is to dynamically instantiate the application object, which is doable, and then call a sequence of that application's methods to carry out the emulation. However, in calling one of the methods, we have to pass in a domain-level object which is instantiated within the emulator implementation. We have to call AssociateCubes (which takes a CubeSet parameter) on the dynamically instantiated application. When I try to do that dynamically, I'm getting an InvalidCastException which (amusingly enough) says that a "CubeSet" object cannot be cast as a "CubeSet" object. An example of the code being used to dynamically access the application is:
Object o = Activator.CreateInstance(appType);
MethodInfo AssocCubes = o.GetType().GetMethod("AssociateCubes");
AssocCubes.Invoke(o, new object[] { Cubes });
where Cubes is of type CubeSet in the emulator, and the appType is as given by the user.
Is there any way to force some sort of link between the two so that the compiler recognizes that in reality the same class, or is it that the two classes are completely distinct and cannot be associated in such a way to allow an object of one type to be cast as the other.
One solution I have considered is simply defining a method to manually copy the contents of one object to an instance in the emulator, but the problem therein is that the application developer can define their own methods for the application class to be used as helper methods.
I may not have explained everything completely, so I can offer any clarifications that may help expose a potential solution.
The InvalidCastException only shows last portion of full class name for convinience, but types are compared on full identity: Full Name (including namespaces) and assembly it is coming from (which may have strong name if signed).
Consider using Unit Testing framework for "mocking" objects. Or at least read on how such frameworks wrap classes.
The real fix is to use testable class hierarchies. Often using interfaces instaed of concreate classes help to solve this type if issues.
I don't want to discount the previous answer given, but I have found a solution as I described in the comment I wrote.
What I do instead is pull the domain layer out of the emulator project and compile it separately as a DLL. Now that DLL is referenced in the emulator and the separate applications, so when the types are loaded dynamically they are considered to be the same type after all.
I serialize some configuration objects and store the result bytes within a database.
new BinaryFormatter().Serialize(memoryStream, instance);
Convert.ToBase64String(memoryStream.ToArray());
These objects will be deserialized later.
new BinaryFormatter().Deserialize(memoryStream);
It's possible, that the Application has some new assembly versions at the time of deserialization. In general it works well, but sometimes I get a file load exception:
"The located assembly's manifest definition does not match the assembly reference.". The assemblies work all with strong naming, can that be the problem and how could I avoid this problem?
Thanks for help
Absolutely, using BinaryFormatter with database (i.e. long-term) storage is a bad idea; BinaryFormatter has two three big faults (by default):
it includes type metadata (shucks if you move/rename your types... this can mean strong name/versioning too)
it includes field names (fields are private details!)
it is .NET specific (which is a pain if you ever want to use anything else)
My blog post here raises two specific issues with this - obfuscation and automatically implemented properties... I won't repeat the text here, but you may find it interesting.
I recommend the use of a contract based serialization. XmlSerializer or DataContractSerializer would suffice normally. If you want small efficient binary, then protobuf-net might be of interest. Unlike BinaryFormatter, the binary from this is portable between implementations, extensible (for new fields), etc. And it is quicker and smaller, too.
I think WCF might be your best bet. It can handle passing unknown fields through to it's consumer even if it doesn't know how to deserialize them.
Example:
Service A: Knows about version 2 of the Widget class which has a Description field
Service B: Knows about version 1 of the Widget class which doesn't have a Description field
Service C: Knows about version 2 of the Widget class which has a Description field
If service A calls service B passing a Widget object and then service B calls service C passing on the same Widget object then service C will get the Description field as it was passed from service A. Service B won't have any Description field but when it deserializes it and re-serializes it it will just pass the Description field through without knowing what it is.
So, you could use WCF services with in-proc communication.
See this link for more on versioning wcf contracts.