C# json deserialiser how to set property - c#

My code is:
namespace RTT_API
{
class routepoint
{
public string description { get; set; }
public string TIPLOC { get { return TIPLOC; } set { SetStationRef(); } }
public string publicTime { get; set; }
public Guid StationRef { get; set; }
public void SetStationRef()
{
SqlCommand comStationRef = new SqlCommand("select uniqueref from station where tiploc=#tiploc", Globals.RTTConn);
comStationRef.Parameters.Add("#tiploc");
comStationRef.Parameters["#tiploc"].Value = TIPLOC;
SqlDataReader rdrStationRef = comStationRef.ExecuteReader();
if (rdrStationRef.HasRows == true)
{
rdrStationRef.Read();
StationRef = rdrStationRef.GetGuid(1);
rdrStationRef.Close();
}
else
{
rdrStationRef.Close();
comStationRef.CommandText="Insert into station(tiploc) values (#tiploc)";
comStationRef.ExecuteNonQuery();
}
rdrStationRef.Close();
}
}
}
I would appreciate help with the following:
If I try to debug the TIPLOC value I receive a Stackoverflow error. It worked OK when the definition was only:
public string TIPLOC { get; set; }
The SetStationRef method doesn't run when the value is set
The TIPLOC value is set by a JSON deserialise command. Is using a custom 'set' method the correct way to set the StationRef value? I tried putting code in the class constructor but it looks like the constructor runs before the JSON deserialise sets the properties? I'm new to C# so trying not to get into any bad practices to start with.
Thanks

This line
public string TIPLOC { get { return TIPLOC; } set { SetStationRef(); } }
will return TIPLOC indefinitely because it is calling itself. Calling return TIPLOC will call the getter of TIPLOC and its just going to keep doing that until it overflows the stack. When you debug the debugger will try and retrieve the value of the property and will get stuck in that loop.
set { SetStationRef(); } also ignores the value. I assume you want to call SetStationRef(value);. In the setter of a property the value the user is trying to set gets passed in as a local variable called value
From the overall look I think what you are trying to achieve is something along the lines of
private string tiploc;
public string TIPLOC
{
get
{
if(tiploc == null)
{
tiplock = GetValueFromDatabase(); // Replace this to retrieve the value
}
tiploc;
}
set
{
SetStationRef(value);
tiploc = value;
}
}

My original three questions were:
If I try to debug the TIPLOC value I receive a Stackoverflow error
The SetStationRef method doesn't run when the value is set -
The TIPLOC value is set by a JSON deserialise command. Is using a custom 'set' method the correct way to set the StationRef value? I tried putting code in the class constructor but it looks like the constructor runs before the JSON deserialise sets the properties? I'm new to C# so trying not to get into any bad practices to start with.
Question 1 was answered by Ben and his help enabled me to find a solution to questions 2 and 3 so a lot of credit is due to him.
I've only added a separate answer because the custom accessor needs to be defined on the StationRef and not the Tiploc (the Tiploc is set by the Deserialisation code) as follows:
public string tiploc { get; set; }
public Guid StationRef
{
get
{
if (stationRef == Guid.Empty)
{
stationRef = Globals.GetStationRef(tiploc);
}
return stationRef;
}
set
{
stationRef = value;
}
}

Related

Update method in web API: How to know which fields to update?

I have a typical web API with a couple of PUT/UPDATE endpoints. These endpoints simply call the underlying service, and do the update.
The service layer, has the typical signature such as Object Update(Object object). What I then do is I basically run the following pseudo code:
var dbobject = _db.Object.Find(object.Id);
dbobject.Field1 = object.Field1;
dbobject.Field2 = object.Field2;
// continue for all fields
_db.SaveChanges();
return GetObjectById(object.Id);
However, this provides a challenge for me.
Lets say we have a consumer of our API. This consumer calls my PUT endpoint (/api/Object/{id}), and the payload is the updated Object.
However, lets say that the object we put don't know about example Field4, then this value would be NULL after the update has been run.
My question is:
What do you do about all those fields the payload does NOT contain?
How do you handle not setting values to NULL you don't expect to be
NULL afterwards?
As one of the possible ways, here can be used mix of NotifyPropertyChanged with automapper
The Idea is to store in DTO object which fields exactly was set, and which stays filled with default value. And use collected data in mapping.
For example DTO object will be
public class Dto
{
private List<string> Changed = new List<string>();
public bool IsChanged(string field) => Changed.Contains(field);
private int _age;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
// IMPORTANT: field name should fit main object field name
Changed.Add("Name");
}
}
public int Age
{
get { return _age; }
set
{
_age = value;
Changed.Add("Age");
}
}
}
I used Next class for test
public class Human
{
public string Name { get; set; } = "DEFAULT";
public int Age { get; set; } = -1;
}
and automapper configuration will looks like
cfg.CreateMap<Dto, Human>()
.ForAllMembers(s=> s.Condition(d=>d.IsChanged(s.DestinationMember.Name)));
This is a simple example. But it still doesn't prevent to use function IsChanged for some complex/specific logic, use not just a strings but Expressions / MethodInfo, or add custom attributes and use them in automapper configuration (DestinationMember is MethodInfo)
Append
Instead of complex DTO object the information about passed field you can get from Request.Properties in your controller (key ms_querynamevaluepairs value of type Dictionary<string, string>).

How to retrieve property from GameSparks inside Unity

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.

Convert json data into datatable

I tried using json.net for converting json data into datatable, but am not able to solve, am newbie with json
code i tried:
string json = JsonConvert.SerializeObject(friend);
friends_info finfo = JsonConvert.DeserializeObject<friends_info>(json);
public class friends_info
{
public friends_info()
{
}
public string name_; // Backing field
public string name
{
get { return name_; } // Getter
set { name_ = value; } // Setter
}
public string id_; // Backing field
public string id
{
get { return id_; } // Getter
set { id_ = value; } // Setter
}
}
where string json="{"data":[{"name":"Angelina Jovy","id":"100000599264453"},{"name":"Luvbhie Rose May Aviles","id":"100001102845189"},{"name":"Nainy Ahuja","id":"100001103300515"},{"name":"Sabrina Reis","id":"100008357430263"}],"paging":{"next":"https://graph.facebook.com/v1.0/1539545690/friends?access_token=CAAGjOBYUDq0BAAFnIgfyfvMftE1ImSEfZCK7R7NdFYw5lnKuddHwqqlm20DTuZCjEeUh2hzMD0KAJpY1ozq3aPuh9nQUHBrXtG0Qu2sd6RwotUQtYj9jtGcMlJEzZCCBLLH8CZBSNQIZAzC2ASOxkYf3JCfwGZA7XSzF5y2iPVDWRCfrl8C4rZAZBzkJiaJwytVvSintYLRfySaunO81fAei&limit=5000&offset=5000&__after_id=enc_AewuVVCxM4Iz1IuazCHob3SZku3BDZ6NeU054UtCU_gc0QDAm2g2VNM__lcbuJNDtm9RmHLU-QCQifFun9H__Zqs"}}"
The class you're deserializing to must match the JSON string.
public class MyData
{
public friends_info[] data { get; set; }
public object paging { get; set; } // you can probably omit this
}
With that deserializing the given JSON string should work.
MyData myData = JsonConvert.DeserializeObject<MyData>(json);
friends_info finfo = myData.data;
Apart from that I'd very much suggest that you look into the C# basics again. Even that little code you posted violates the typical coding conventions.
i m not sure but i think your string is not in correct format it should be like this.
"{'data':[{'name':'Angelina Jovy','id':'100000599264453'},{'name':'Luvbhie Rose May Aviles','id':'100001102845189'},{'name':'Nainy Ahuja','id':'100001103300515'},{'name':'Sabrina Reis','id':'100008357430263'}],'paging':{'next':'https://graph.facebook.com/v1.0/1539545690/friends?access_token=CAAGjOBYUDq0BAAFnIgfyfvMftE1ImSEfZCK7R7NdFYw5lnKuddHwqqlm20DTuZCjEeUh2hzMD0KAJpY1ozq3aPuh9nQUHBrXtG0Qu2sd6RwotUQtYj9jtGcMlJEzZCCBLLH8CZBSNQIZAzC2ASOxkYf3JCfwGZA7XSzF5y2iPVDWRCfrl8C4rZAZBzkJiaJwytVvSintYLRfySaunO81fAei&limit=5000&offset=5000&__after_id=enc_AewuVVCxM4Iz1IuazCHob3SZku3BDZ6NeU054UtCU_gc0QDAm2g2VNM__lcbuJNDtm9RmHLU-QCQifFun9H__Zqs'}}";
if your json string is in correct format then #bstenzel suggestion should work fine.
Thanx

System.StackOverflowException on BlogEngine.NET

I am using BlogEngine.NET and need to set the BlogId to a specific Guid (blogIdstr). I can't seem to figure out how to change it from the default blogId. This is the code I have at the moment but it is giving me a StackOverflowException...
These two are in the base class...
public virtual TKey Id { get; set; }
public Guid BlogId
{
get
{
return BlogId; <-- Stack Overflow
}
set
{
string blogIdstr = "FCA96EFB-D51C-4C41-9F85-3EEB9C50BDE7";
Guid blogIdGuid = Guid.Empty;
blogIdGuid = Guid.Parse(blogIdstr);
}
}
And this one is in blog.cs...
public override Guid Id
{
get { return base.Id; }
set
{
base.Id = value;
base.BlogId = value;
}
}
How can I set the blogId and avoid the StackOverflowException? Thanks in advance.
For the first one, in BlogId, you're returning BlogId, which fires the Getter that returns... BlogId. Boom, stack overflow. Return blogIdGuid in your public getter instead of BlogId.
I'm guessing the second one is related to the first, but without more code I can't tell offhand.
Edit: Whoops, misread the code. Yeah, use a backing class-level property called _blogId and set that in the setter and return it in the getter.
You just need to introduce a backing variable
private Guid _blogId; and be sure to set that field in your set method
public Guid BlogId
{
get
{
return _blogId;
}
set
{
string blogIdstr = "FCA96EFB-D51C-4C41-9F85-3EEB9C50BDE7";
Guid blogIdGuid = Guid.Empty;
blogIdGuid = Guid.Parse(blogIdstr);
_blogId = value;
}
}
Your get method is calling itself, and your set method is essentially issuing a no-op by setting a value local to the method. You need a backing field for your property if you want to do something inside of the getter and setter:
private Guid _blogId;
public Guid BlogId
{
get
{
return _blogId;
}
set
{
//some operation against value here, Validate(value), etc.
_blogId = value;
}
}
If you have no action to take in the getter/setter, you can use an auto property, which will generate the backing field for you:
public Guid BlogId { get; set; }
What you can't do, and what it appears you're really trying to do here, is pass a different type into a property - to do that you'd need a method on the class, i.e.:
public bool TrySetBlogId(string newId)
{
Guid id;
var stringIsGuid = Guid.TryParse(newId, out id);
if (stringIsGuid)
{
BlogId = id;
}
return stringIsGuid;
}

Attributes of properties in MetadataType are ignored by EntLib Validation

It's an EntLib-Validator-issue again. I'm playing with EntLib 5.0 in C# and .Net 4.0 on XP pro.
I have some business objects (partial classes) generated by T4 templates. So I decided to put their validation attributes in buddy-classes by using MetadataTypeAttribute as definitely recommended by the documentation of entLib 5.0 (msdn).
But the Validator object I get from the ValidatorFactory doesn't know about the validation attributes, defined in the metadata-class.
The business object is defined like this:
[MetadataType(typeof(PatientMetadata))]
public partial class Patient
{
private string _Name;
private int _DiagnosisCount;
public int DiagnosisCount
{
get
{
return _DiagnosisCount;
}
set
{
if (value != _DiagnosisCount)
{
_DiagnosisCount = value;
}
}
}
public string Name
{
get
{
return _Name;
}
set
{
if (value != _Name)
{
_Name = value;
}
}
}
}
And the metadata class like this, according to documentation:
public class PatientMetadata
{
[RangeValidator(4)]
public int DiagnosisCount { get; set; }
[StringLengthValidator(64, ErrorMessage = "Name must not exceed 64 chars.")]
public string Name { get; set; }
}
If I know try to do validation this way:
var factory = ValidationFactory.DefaultCompositeValidatorFactory;
var validator = factory.CreateValidator<Patient>();
...then watching into validator (during debugging) already says, that it's just an AndCompositeValidator without any children validators.
Again, if I put the validation attributes right in the Patient class, it works perfectly.
By now, I have no real idea, what I'm missing here, since I think doing everything according to the docs.
Thanks in advance to you guys!
The property names of the metadata class must match the property names of the main class.
In your case your metadata class should look like:
public class PatientMetadata
{
[RangeValidator(0, RangeBoundaryType.Inclusive, 10, RangeBoundaryType.Ignore)]
public int DiagnosisCount { get; set; }
[StringLengthValidator(6, ErrorMessage = "Name must not exceed 6 chars.")]
public string Name { get; set; }
}
Also, the docs indicate the accepted approach is to declare all return types as object. However, the docs also talk about using properties but in their example use fields so take it under advisement. :)

Categories

Resources