Deserialization not working across projects - c#

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.

Related

VS 2015 C# AsyncExtension.cs not found

I haven't been able to find any information on this online. I'm debugging an console application, trying to step through some code. When I go to step over I get a source not found error. It says "AsyncExtension.cs not found" and then gives me some details. It says "You need to find AsyncExtension.cs to view the source for the current call stack frame". I'm working in VS2015. I'm assuming something async is happening behind the scenes, its erroring at some point but can't give me the specific details because it can't find the assembly containing AsyncExtension. But I don't know what this is, where to get it, etc. The code in particular I'm trying to step over is below. But I seem to get this at various points, and even when debugging other projects under the same solution.
Line of code:
var newObject = JsonConvert.DeserializeObject<HIDPMessage>(message.ToString());
HIDPMessage:
public class HIDPMessage
{
public string version { get; set; }
[Newtonsoft.Json.JsonProperty]
public string header { get; set; }
[Newtonsoft.Json.JsonProperty]
private Data Data { get; set; }
}
Not sure what you are trying to do but the code you have provided would not normally have any references to anything called AsyncExtension.cs. However your attempt to deserialize message could cause a JsonReaderException.
I'm guessing that "message" is some object that contains properties in common with HIDPMessage type and that you are trying to extract those into a new object, if so message.ToString(), unless overridden will just return the name of the type.
You need to serialize the object to a json string and use the json string instead of message.ToString();
Thanks for the input guys, you were right my code for deserializing was a little off. It turns out this app was built using VS2017 and some components from the Azure SDK were missing. I tried a manual install of the SDK but it wouldn't work - upgrading to 2017 fixed it, but I'm kinda surprised I had to upgrade just to get it to work.
I appreciate the feedback on the serialization stuff as well. This is a new-ish area for me and I'm still learning.

Json.NET deserialise to interface implementation

I'm trying to use Json.NET to serialise a class for transfer via an http request. This is a client server test program that shares some common class files. Those files are an interface (ITestCase) and the implementations of this interface (TestPicture, TestVideo).
Serialising and deserialising testCase below within the same application works fine, presumably because the Json.NET code is all contained within the one assembly. When I serialise testCase, send it to the server, then try to deserialise, I get the error
"Error resolving type specified in JSON 'com.test.testcases.TestPicture, Graphics Tester'. Path '$type', line 2, position 61"
with an Inner Exception of type JsonSerializationException with message
"Could not load assembly 'Graphics Tester'."
In the Json.NET documentation, when the Json is generated the $type value is "$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests". The second parameter seems to reference the relevant classes by namespace, rather than by project name (namely Graphics Tester) as it is happening in my instance.
Given that both projects share the requisite classes and that the files are in the same namespace, why is Json.NET looking for the assembly rather than the class itself?
Below is the skeleton of my code; details are ommited as they don't assist with the problem. Shown is the interface, and the two implementations of that interface. Also shown are the serialisation and deserialisation operations, and the resulting Json.
ITestCase testCase = new TestPicture("test.jpg")
string json = JsonConvert.SerializeObject(testCase, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
});
ITestCase instance = JsonConvert.DeserializeObject<ITestCase>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
});
//value in variable json after serialisation
//{
// "$type": "com.test.testcases.TestPicture, Graphics Tester",
// "filename": "test.jpg",
// "testPoints": null
//}
Individual class files:
namespace com.test.testcases
{
interface ITestCase
{
void Run();
bool Verify();
}
}
namespace com.test.testcases
{
class TestPicture : ITestCase {}
}
namespace com.test.testcases
{
class TestVideo : ITestCase {}
}
My Solution:
A simpler solution existed than I expected. It wasn't optimal, but it certainly works. I'd class it more as a workaround or a hack. By altering the Project Properties and setting the assembly name to be the same in both projects, it will find the classes that were already included in the project, and thus create the objects specified by the Json string.
The $type encodes the fully-qualified type name, which will differ between the Client and Server if they're not using the same project to define these types (i.e. if each defines the type by itself rather than referencing a common assembly).
In your case, in the client the fully-qualified name is com.test.testcases.TestPicture, Graphics Tester, but when this gets to the server the server can't find any assembly called Graphics Tester.
You can solve this in one of two ways:
Define a common assembly for serializable types, and reference it from both client and server.
Define the types separately both in the client and the server, and customize Json.NET's type resolving by providing a custom SerializationBinder to JsonSerializerSettings.Binder, where you could implement your own logic.

Invalid Resx file. Could not load type error why?

I'm getting designer error on code:
The Component i'm willing to define a List of properties for:
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace TestProjectForProperty.Test
{
public class MyTreeView : TreeView
{
private List<TypeDescriptorBase> _descriptorsAvailable = new List<TypeDescriptorBase>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<TypeDescriptorBase> DescriptorsAvailable
{
get { return _descriptorsAvailable; }
set { _descriptorsAvailable = value; }
}
}
}
The Descriptor itself:
using System;
namespace TestProjectForProperty.Test
{
[Serializable]
public class TypeDescriptorBase
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
I am getting the following error if i try to use the component for example on a form and add any items on the property sheet or in the component's constructor to the DescriptorsAvailable property
Error 1 Invalid Resx file. Could not load type
System.Collections.Generic.List`1[[TestProjectForProperty.Test.TypeDescriptorBase,
TestProjectForProperty, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089 which is used in the .RESX file.
Ensure that the necessary references have been added to your project.
Line 134, position 5. ...\visual studio
2010\Projects\TestProjectForProperty\TestProjectForProperty\Form1.resx 134 5 TestProjectForProperty
In the Resx file there is data field with base64 encoded stuff inside when this error is present.
I have been searching for an answer, but the best i got is to restart everything, it didn't help me, do you guys have any suggestions? I'm using .net 4 client and visual studio 2010
In my experience, this is due to a change of version of a referenced library, or a change of the lib itself, which contains the backing type of a property you have defined in your user control. The solution is to "force" the visual studio designer to re-initialize it's designer code for that type, and not expect to retrieve a "canned" version of it from the .resx file of the control.
1) Delete the offending data section in the .resx file of your control. This will be a section in the xml of the .resx file associated with your user control, which has a node: <data></data> - the name attribute will be set to whatever you've named that object in the properties of whatever you added this type to. The <data>/data> section contains a base64 encoded string that is the encoded form of the name and version of the library the type comes from. This is where the problem ism, because it now contains an encoded version of the library and/or version number you are no longer referencing in order to include the type. Delete the entire <data>/data> section, from opening to closing tag, save the change and close the file. Now the "artifact" is gone.
2) Now find the place in the designer file for your control, where the type is instantiated; this is initialization code generated for you by visual studio, and it is the place that is expecting to load a "canned" definition of the type from the base64 encoded string contained within the .resx file. The line will look something like this:
this.myCtrlFoo.MyPropertyFroo = ((MyNamespaceFoo.MyTypeFoo)(resources.GetObject("myCtrlFoo.MyPropertyFroo")));
...now just replace the resources.GetObjec call with the instantiation of a new instance of the appropriate type like so:
this.myCtrlFoo.MyPropertyFroo = ((MyNamespaceFoo.MyTypeFoo)(new MyNamespaceFoo.MyTypeFoo()));
...now save the change to the file, close it, rebuild, and everything should now build & run OK.
Put the MyTreeView and TypeDescriptorBase classes into another project and reference it from your GUI project will resolve the issues.
I'm not sure why exactly the problem occurs - I guess it has something to do with the way the serializing process is generating the base64 string for the DescriptorsAvailable Property. Maybe somebody else can give us some insight.
I've struggled quite a bit with this; I have three user controls that all expose the same non-designer property, but for some reason, any change to two of the three would instantly cause the next build to fail with this same issue. This is in VS 2015.
I wound up having to add the following two attributes to the property that kept expanding in the resx file, and it hasn't occurred since. It works for me because they're not available in the designer anyway.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
For me, this error occured when I used a custom class as a property for the user control. When I switched from property to traditional get- and set- methods, the error disappeared. I guess this is because properties are already compiled at design-time, so when you build the whole project, a new version of the custom class is compiled which is separate from the one of the control, and the reference is broken.
For me, with the custom class Inventory, all I had to do was to switch from this property-based approach:
public Inventory Resources {get;set;}
to this method-based approach:
private Inventory resources;
public Inventory getResources() { return resources; }
public void setResources(Inventory newResources) { resources = newResources; }
I hope this helps someone, as I've been spending some hours on figuring it out.
In my case I've got the error : "error MSB3103: Invalid Resx file. The specified module could not be found" executed in a light windows container based on mcr.microsoft.com/powershell instead of mcr.microsoft.com/windows:1909 (was working fine on 1909).
The error was on a ressource icon that was compressed with PNG inside.
It can be checked by opening the ressource on visual studio : Project > Properties > Ressources.resx, select icons, double click on the icon, check the end of the title that is either "..,BMP]" or "...,PNG]").
Updating the icon with an uncompressed format solve the "Invalid Resx file" issue.
I stumbled across this question today whilst looking for the solution to a similar issue.
Unfortunately none of the above worked for me, however my issue turned out to be that I had different versions of the .NET Framework for different projects. For example;
Project A - .NET Framework 4.7.2
Project B - .NET Framework 4
Where Project B was referencing Project A. Solution was simply to change the .NET Framework version of Project B to 4.7.2 (in my case) and hey presto the issue was resolved.
A shame Visual Studio doesn't provide a more helpful error message in this case, but something to look out for!

Unable to compile code output because of some reference assembly goofups

My issue goes like this:
There is a project called myframework. It has some extension methods defined in it as follows:
namespace myframework
{
public static class Helpers
{
public static bool ContainsAll(this string obj, string[])
{
return true;
}
}
}
It also has some other stuff like interfaces, etc, etc.
There is a second class I generate via System.CodeDom classes. The generated output is somewhat like this:
using myframework;
public class A: IMyFrameworkInterface
{
public void foo()
{
string s ="HELLO";
if(s.ContainsAll(some_arr))
return;
}
//More methods defined...
}
The compiler options I pass which is created prior to the actual compile call references the correct assemblies
var cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("myframework.dll");
The code compilation modules are written in a different project. The particular class responsible for this also nicely gives us access to a list of CompilerError object via which we can learn the result of compilation.
Issue1: When I tried this in an asp.net project the compiler threw error saying it could not find metadata file myframework.dll (despite it being referenced in the project).
Issue2: When I tried it with a windows forms project. It gave a different error. This time saying that string does not contain definition for ContainsAll()
How to solve these two specific problems?
Found out the answer to this after a bit digging up. I was using .net framework 3.5. The codedom compiler apis targets v2.0 of the framework by default. Hence, you have to manually specify the correct framework:
var cp = new CompilerParameters(
new Dictionary<string,string>() { {"CompilerVersion", "v3.5"} });
For the compilation to work within an asp.net environment you'd have to actually point the references to the correct location. Hence you'd have to do something like follows:
cp.ReferencedAssemblies.Add(
HttpContext.Current.Server.MapPath(
"bin\\myframework.dll"));
My references:
http://blogs.msdn.com/b/lukeh/archive/2007/07/11/c-3-0-and-codedom.aspx
.Net 3.5 CodeDom Compiler generating odd errors
And comments in the question's post. :)

Attempt by method 'System.Web.Helpers.Json..cctor()' to access method 'System.Web.Helpers.Json.CreateSerializer()' failed

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.

Categories

Resources