Unable to use 'dynamic' with Json.Net and Universal Apps - c#

I have the following code
var client = new HttpClient();
var url = new Uri("https://someuri/someresource", UriKind.Absolute);
var response = await client.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject(content) as dynamic;
As per what I see when I debug the code, everything is completed successfully; i.e., the above returns the expected JSON, and json object has the expected properties... let's assume it is:
{ "current_page": 1, "total_pages": 7, "items": [ ... ] }
However, when I do json.current_page, I get the following exception:
'object' does not contain a definition for 'current_page' and no
extension method 'current_page' accepting a first argument of type
'object' could be found (are you missing a using directive or an
assembly reference?)
Does anyone has an ides on what's going wrong here?
P.S. I tried it with both types of Universal Apps, Windows 8.1 and Windows Phone 8.1.
P.S. Same code works with a Console application, but not Universal Apps.

You are getting an object with no defined properties on it and you need to parse it first. You can use System.Web.Helpers.Json class as follows
dynamic data = Json.Decode(json);
As I can see you are using newtonsoft so you can achieve the same using Parse as follows
dynamic d = JObject.Parse(#"{ ""current_page"": 1, ""total_pages"": 7}");
Console.WriteLine(d.current_page);

I recently ran into the same issue and saw that you had opened an issue on GitHub.
This is the answer:
UWP apps use the PCL259 assembly and it doesn't support dynamic. A dedicated assembly will probably be added in the future but not anytime in the next couple of releases.
- JamesNK

Related

Error CS0433: The type 'JsonValue' exists in both 'System.Json, Version=2.0.5.0' and 'Xamarin.Auth' (CS0433)

I'm trying to create an app in Visual studio for mac with Xamarin.Forms. In this app I'm using Xamarin.Auth to store some user details. Now I want to add a connection with an API by using JSON. I added System.Json and added my code. But the problem is I get the error:
Error CS0433: The type 'JsonValue' exists in both 'System.Json,
Version=2.0.5.0' and 'Xamarin.Auth' (CS0433).
I removed and added Xamarin.Auth to the project. I removed the OBJ and BIN folders while visual studio was closed, started VS, cleaned the solution, rebuild the solution and tried it again but still the same error. I can't seem to find out what the problem is.
I'm not quite sure if it will help but here is one snippet of code where the error occurs, I know the function does not return anything at the moment but I'm just trying to figure out how to do JSON/API calls and get the code to compile without errors:
public class DBhandler
{
public async Task<List<Object>> GetItemsFromApiASync(Type callingClass, string apiDir, string apiFile)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(ApiAddress + apiDir + apiFile));
request.ContentType = "application/json";
request.Method = "Get";
using (WebResponse response = await request.GetResponseAsync())
{
using (Stream stream = response.GetResponseStream())
{
System.Json.JsonValue jsonDoc = await Task.Run(() => System.Json.JsonObject.Load(stream));
object[] parametersArray = new object[] { jsonDoc };
MethodInfo methodInfo = callingClass.GetMethod("ConvertApiResultToObject");
methodInfo.Invoke(methodInfo, parametersArray);
}
}
return null;
}
I encountered the same problem when creating a Xamarin Android project that referenced Xamarin.Auth and a few other NuGet packages and the Facebook Xamarin component. I was able to simply remove System.Json from my project's references, and then my project was able to compile and run.
All of a sudden I did remember how to solve this: I was helped by the comments on the question(thanks #Tcraft, #DiegoRafaelSouza). I added System.Json to the references on the different platforms(I use a shared project, so on project.IOS and project.Android). Right clicked on properties and ticked Local Copy. Then I added an alias SystemJsonAlias. And used using SystemJsonAlias = System.Json in all my .cs files where needed.
Perhaps this helps someone else.

Reading JSON data throws runtime exception

According to NewtonSoft's documentation, this code:
string props = "{\"lot\":\"TEST\",\"mhd\":\"2016-06-17\"}";
dynamic json = JsonConvert.DeserializeObject(props);
string s = json.mhd;
should work, but I get a RunTimeBinderException when I try it. I have Micrsoft.CSharp referenced and the compile works (it is a runtime error). I am compiling against .NET 4.0, using NewtonSoft version 7.
I tried accessing as json["mhd"], which works fine.
Am I missing something?
The json object is a JObject, so to get the value you need do:
string s = (string)json["mhd"];
I try this case in Newtonsoft.Json 3.5.8 version ,I get this error.
When I upgrade Newtonsoft.Json package version to 4.5.1 it works .
I think it has bug on older version.
#Candide pointed out what was wrong with your example, but if you still want to use json.mhd syntax and have real dynamic object to work with you can do it.
Try to deserialize it using the ExpandoObjectConverter:
var converter = new ExpandoObjectConverter();
dynamic json = JsonConvert.DeserializeObject<ExpandoObject>(props, converter);

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.

(MfA) - Name property on CollectionDataContractAttribute on Dictionary type is ignored

Please note I am posting this QA here to help others and as a partner to bug report 11881 on the Xamarin.Android Bugzilla area. As a result the type described below is for demonstration purposes only. I have posted an initial answer, also making reference to the same bug report, but hopefully at some point this question can be 'answered' with 'this has been fixed in version x.y'.
I have a following type shared between Mono for Android and Windows RT sources:
[CollectionDataContract(Name = "MyDictionary",
Namespace = "http://foo.bar/schema",
ItemName = "pair",
KeyName = "mykey",
ValueName = "myvalue")]
public class MyDictionary : Dictionary<string, string>
{
}
This is read from our Web API (running on Asp.Net Web API, Framework 4.5) as XML which looks like this:
<MyDictionary
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://foo.bar/schema">
<pair>
<mykey>message1</mykey>
<myvalue>Hello</myvalue>
<pair>
<pair>
<mykey>message2</mykey>
<myvalue>World</myvalue>
<pair>
</MyDictionary>
When using the class as described above, this XML deserializes correctly on Windows, Windows Phone and Win-RT platforms.
However, on Mono for Android builds I get
System.Runtime.Serialization.SerializationException: Expected element 'ArrayOfpair' in namespace 'http://foo.bar/schema', but found Element node 'MyDictionary' in namespace 'http://foo.bar/schema'.
What have I done wrong?
Assuming I hadn't done anything wrong - I wrote an NUnitLight unit test to test whether an instance of MyDictionary would be serialized correctly by the Mono for Android implementation of the DataContractSerializer:
public string Serialize(object o)
{
DataContractSerializer ser = new DataContractSerializer(o.GetType());
using (var ms = new MemoryStream())
{
ser.WriteObject(ms, o);
return Encoding.Default.GetString(ms.ToArray());
}
}
[Test]
public void ShouldSerializeDictionaryCorrectlyAndDeserialize()
{
MyDictionary dict = new MyDictionary();
dict["message1"] = "hello";
dict["message2"] = "world";
var s = Serialize(dict);
Assert.That(s, Is.StringStarting("<MyDictionary"));
}
The unit test fails, with the output string starting 'ArrayOfpair' and not 'MyDictionary', which would be consistent with the original behaviour where deserialization of the correct XML fails because it doesn't start 'ArrayOfpair'.
This is, therefore, a good candidate for a bug in the Mono for Android implementation of the DataContractSerializer (I have reported the bug here) - but until that bug is both confirmed and fixed, a workaround will be needed. In my case I have shared codebase issues (Android, Windows and Monotouch) to contend with and so I don't want to just rewrite this type for Android. If I come up with a decent workaround, I'll post it on this answer.
Please note - I don't yet know if this also applies to Monotouch - we don't yet have a complete enough build of our component to run the same test, so it might do, I just don't know.

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