I am going crazy... I am missing something and I can't see what?!?!
I have created a property called "GAME_SETTINGS" inside the gameSparks admin area and have included this in it:
{
"AppVersionIOS": 1,
"AppVersionAndroid": 1
}
I am then trying to retrieve it inside Unity like this:
new GameSparks.Api.Requests.GetPropertyRequest().SetPropertyShortCode("GAME_SETTINGS").Send((response) => {
if (!response.HasErrors) {
Debug.Log("Setting Achieved: "+response.JSONString);
} else {
Debug.Log("Error Getting Settings");
}
});
I can see that I am getting the settings in my Debug.Log:
Setting Achieved: {"#class":".GetPropertyResponse","property":{"AppVersionIOS":1,"AppVersionAndroid":1},"requestId":"XXXXXXXXXXXXXXX","scriptData":null}
My question is though... How do I get the properties AppVersionIOS and AppVersionAndroid inside an Dictionary so I can call on them from other scripts...
Really hoping for help in this matter and thanks in advance :-)
I actually work for GameSparks and noticed your question so set up an account to answer you.
The property values returned in the JSON are of nullable type : https://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
Best practice is to parse the values before they are cached in a Dictionary or otherwise.
The following code should allow you to get those properties, then you may store them in a dictionary as you see fit.
public void GetProperties()
{
new GameSparks.Api.Requests.GetPropertyRequest()
.SetPropertyShortCode("GAME_SETTINGS")
.Send((response) =>
{
if (!response.HasErrors)
{
print(response.JSONString);
int androidProperty = (int)response.Property.GetInt("AppVersionAndroid");
int IOSProperty = (int)response.Property.GetInt("AppVersionIOS");
print("AndroidProperty:" + androidProperty);
print("IOSProperty:" + IOSProperty);
}
else
{
Debug.LogWarning(response.JSONString);
}
});
}
Hopefully this solves your problem. If you have any other questions please feel free to head to our website and log a ticket with us.
Regards, Patrick.
Notice: This answer assumes that the API doesn't have a way of converting this into a nice object which you can easily manipulate / parse, so it converts it itself using some class. It's however very likely that your API offers such a function somewhere, so you'd be better be looking in the documentation again. I guess it's somewhere near https://api.gamesparks.net/#getpropertyrequest .
You have the JSON document already, all you have to do is parse it. That'd be easier in a JavaScript file than in C#, but you can also use the JsonUtils class there, see http://docs.unity3d.com/Manual/JSONSerialization.html . Let http://json2csharp.com/ convert that JSON to a class layout for you and you get
public class Property
{
public int AppVersionIOS { get; set; }
public int AppVersionAndroid { get; set; }
}
public class RootObject
{
public string __invalid_name__#class { get; set; }
public Property property { get; set; }
public string requestId { get; set; }
public object scriptData { get; set; }
}
Now just take the string and serialize it into an RootObject.
new GameSparks.Api.Requests.GetPropertyRequest().SetPropertyShortCode("GAME_SETTINGS").Send((response) => {
if (!response.HasErrors) {
Debug.Log("Setting Achieved: "+response.JSONString);
//Serialization
var info = JsonUtility.FromJson<RootObject>(response.JSONString);
//Print the AppVersionIOS property
Debug.Log("App Version iOS: " + info.Property.AppVersionIOS);
} else {
Debug.Log("Error Getting Settings");
}
});
You might need some mofication in the data types of your class (e.g. make object scriptData to string scriptData if there can be an actual string in it), but that should be it. Have fun.
Related
For school homework I'm supposed to work out a class diagram in C#. Everything went smoothly, but I'm struggling with the constructor for the Track part.
So I think I have to convert a SectionTypes -> Section to put it in the LinkedList, but this doesn't seem logical to me, or am I missing something? Should I convert it in any way or is my overall code for Section wrong?
Here is the class diagram
Here is the part of Section:
namespace Model
{
public enum SectionTypes { Straight, LeftCorner, RightCorner, StartGrid, Finish }
internal class Section
{
public SectionTypes SectionType { get; set; }
}
}
And finally here is where I'm trying to make the constructor, Track:
namespace Model
{
internal class Track
{
public string Name { get; set; }
public LinkedList<Section> Sections { get; set; }
public Track(string name, SectionTypes[] sections)
{
Name = name;
// set Sections here
}
}
}
The error that I get is CS1503, when I try to add anything to Sections in the front, which means the types aren't the same.
Thanks for reading, and thank you for helping in advance!
Here's what I did. By the way, I renamed the SectionTypes enumeration to SectionType (that way, it reads SectionType.Finish, not SectionTypes.Finish).
First I created the enum the same as you:
public enum SectionType
{
Straight,
LeftCorner,
RightCorner,
StartGrid,
Finish,
}
and the Section class pretty much the same way:
public class Section
{
public SectionType SectionType { get; set; }
}
I'm not sure why the class diagram is laid out the way it is, but you need to translate a SectionType to a Section in order to get it to work. That's pretty easy; a Section is a pretty stupid/simple wrapper around a single SectionType. So, things end up looking like:
public class Track
{
public string Name { get; set; }
public LinkedList<Section> Sections { get; set; } = new LinkedList<Section>();
public Track(string name, SectionType[] sections)
{
Name = name;
foreach (var section in sections)
{
Sections.AddLast(new Section { SectionType = section });
}
}
}
Note that I construct the Sections LinkedList. It can either be done the way I show, or it could be done in the constructor. But, the magic is to convert the incoming SectionType[] sections into a collection of Section type. I'm sure that there is a way to do this with LINQ (though I don't have a lot of experience with the LinkedList collection). But, doing it explicitly like this makes it more clear.
I'm only at chapter 5 in "Essential C#" and not sure if i understand the difference correctly. I tried to make the model below to test one instance of everything in the properties chapter - and it works - but is the example acceptable use of the two ways one can implement properties or are there better ways?
using MarkdownSharp; // StackOverflow's md processor
public class Article
{
public string Headline { get; set; }
public string Content
{
get
{
return _content;
}
set
{
var md = new Markdown();
var html = md.Transform(value);
_content = html;
}
}
private string _content;
public DateTime Published { get; set; } = DateTime.Now;
}
This question may be better suited for codereview.stackexchange, although it's perhaps too tiny a snippet and to vague a question for that.
Personally, I shy away from magic properties that act in surprising ways. It tends to make for APIs that can be hard to use because they are surprising, even if they are somehow “clever” under the hood. You have a property where you set a different value than the one you get out. One thing where this can break would be the += operator, which suddenly would work in very weird ways with your Content property.
I'd probably go with something like
public class Article
{
private string content;
private string renderedContent;
public string Headline { get; set; }
public string Content
{
get { return content; }
set
{
content = value;
renderedContent = null; // reset cached rendered content
}
}
public string RenderedContent
{
get
{
if (renderedContent == null)
{
renderedContent = new Markdown().Transform(content);
}
return renderedContent;
}
}
public DateTime Published { get; set; } = DateTime.Now;
}
As for whether to use field-backed properties, or auto-properties, or computed properties ... that's up to you to decide based on what the property is supposed to do. Auto-properties are fine for simply storing and retrieving a value, e.g. Published or Headline here. You need the explicit backing field as soon as you do something more than just reading or writing it in the getter and setter, as shown here in Content. RenderedContent could be just a computed property, but I chose to cache the value after initial conversion because you kinda do the same. This pattern here doesn't convert the Markdown until it's actually needed, though.
I have been agonizing over this problem for a few days now and have no hope left. I'm still in the early stages of learning C#, so excuse me if my explanations or understanding are lacking.
My scenario is that I have a need to access an API and download the data as JSON then deserialize it into a class. At the moment, things work as they should, however every variable is defined as String which means I need to convert and manipulate data that should be int/double on the fly constantly as the API can give "N/A" for these data. The impression I get is relying on everything being string is bad practice.
So how should I implement it? I need to be able to store the data as the correct type while keeping in mind that it could be wrong.
Example of properties with wrong type
public string Title { get; set; }
public string Year { get; set; } // Wanted int. Often has an end year "2010-2014"
public string Metascore { get; set; } // Wanted double. Could be "N/A"
The only way I can imagine solving this is by having two classes: the first one being the original string-only class, then having the second being an almost identical class with the desired properties that uses the data from the original then converts it.
My problem with that is that the class already has a few dozen properties, so duplicating it seems nearly as wasteful as the original problem. Regardless, I would like to know an alternative for future use anyway.
EDIT:
Found a similar question here, though unfortunately it didn't help.
you can deserialize the json to JObject and than load it your self
public class RootObject
{
public RootObject(JObject obj)
{
Title = obj["Title"].ToString();
var year = obj["year"].ToString();
Year = year == "N/A" ? 0 : int.Parse(year);
var metascore = obj["Metascore"].ToString();
Metascore = metascore == "N/A" ? 0 : int.Parse(metascore);
}
public string Title { get; set; }
public int Year { get; set; }
public double Metascore { get; set; }
}
static void Main(string[] args)
{
string json = "{\"Title\":\"test\",\"year\":\"2012\",\"Metascore\":\"N/A\"}";
RootObject root = new RootObject(JObject.Parse(json));
}
I am working with an API that returns data in JSON format (as far as I can tell, this is my first time working with a true API or JSON). I read a bunch about working with JSON in C#, and eventually got the Newtonsoft.Json library. Unfortunately, I am having a hard time converting the response I am receiving into a C# class following the examples that exist in the Newtonsoft documentation.
Here is an example of the data returned by this API:
{"name":{"id":1,"name":"name","pID":1,"revisionDate":1390580000000}}
And heres what I have so far:
public class apiDataObject
{
public long id {get; set;}
public string name { get; set; }
public int pID { get; set; }
public long revisionDate { get; set; }
}
public long getID()
{
try
{
data = WebRequest.Create(baseURL);
retData = data.GetResponse().GetResponseStream();
}
catch (Exception exception)
{
outputBox.AppendText(Environment.NewLine + exception.ToString());
}
retDataReader = new StreamReader(retData);
returnedData = retDataReader.ReadToEnd();
outputBox.AppendText(returnedData);
apiDataObject test = new apiDataObject();
JsonConvert.PopulateObject(returnedData, test);
return test.id;
}
I have also tried replacing the JsonConvert.PopulateObject(returnedData, test) with:
apiDataObject test = JsonConvert.DeserializeObject<apiDataObject>(returnedData)
The problem is that my "test" object is always empty after the code finishes. I have stepped through the code, and everything works great until I get to the lines where the test object is created, and supposedly populated. I also tried the inbuilt Microsoft libraries and had the exact same issue. I am honestly stumped, I have spent 2 or 3 hours looking at these few lines of code and tons of documentation and samples of the Newtonsoft.Json library, but simply cant figure out where I've gone wrong here. Any help would be greatly appreciated.
From the JSON you posted, its actually a dictionary type: I changed your method to show you, I tested it out and it works.
public long GetID()
{
var testDict = new Dictionary<string, apiDataObject>();
var returnedData = "{\"name\":{\"id\":1,\"name\":\"name\",\"pID\":1,\"revisionDate\":1390580000000}}";
JsonConvert.PopulateObject(returnedData, testDict);
return testDict["name"].id;
}
Running your original code throws an exception telling you that it doesn't know what to do with the first "name".
Just in case anyone ever comes across this in a search, I figured out an alternative solution to working with this type of data as well. The Newtonsoft.Json library contains a function called DeserializeObject. So for the sample data of:
{"name":{"id":1,"name":"name","pID":1,"revisionDate":1390580000000}}
You can create an object that looks like:
public class Name
{
public int id { get; set; }
public string name { get; set; }
public int pID { get; set; }
public long revisionDate { get; set; }
}
public class RootObject
{
public Name name { get; set; }
}
and then use:
JsonConvert.DeserializeObject<RootObject>(returnedData);
to convert the json into the object without having to use a dictionary.
This is probably "common knowledge", considering the object code can easily be created using the json2csharp converter someone linked earlier, but I was unable to find any direct explanation about when to use the DeserializeObject function or why it should be used versus PopulateObject.
I've had a look at a few threads but what I'm aiming for I can't seem to find.
I have the following JSON strings returned:
On success:
{"success":{"username":"key"}}
On Error:
{"error":{"type":101,"address":"/","description":"link button not pressed"}}
I need to be able to de-serialize these into a class and determine whether I've got an error or a success message to carry on doing it. Any ideas on how to achieve this?
thanks,
Adam
No need to declare a lot of tiny classes. dynamic keyword can help here.
dynamic jObj = JObject.Parse(json);
if (jObj.error!= null)
{
string error = jObj.error.description.ToString();
}
else
{
string key = jObj.success.username.ToString();
}
One option is to use http://nuget.org/packages/newtonsoft.json - you can either create your own custom class to deserialize into or use dynamic as the target type.
var result = JsonConvert.DeserializeObject<Result>(jsonString);
class Result
{
public SuccessResult success { get; set; }
public ErrorResult error { get; set; }
}
class SuccessResult
{
public string username { get; set; }
}
class ErrorResult
{
public int type { get; set; }
public string address { get; set; }
public string description { get; set; }
}
If you need just to check for success, it is possible to just check result.StartsWith("{\"success\":") to avoid unnecessary parsing. But this should only be done if you have guarantee that the JSON string will always be exactly like this (no extra whitespaces etc.) - so it is usually only appropriate if you own the JSON generation yourself.
This answer covers most options, including rolling your own parser and using JSON.Net:
Parse JSON in C#
You could also just write a regex if the format is going to be that simple...