I'm forced to use GET requests to pass complex objects to my application.
How can I deserialize a querystring like this:
?people[andy]=12&people[bob]=43&people[charlie]=53&items=89&items=123&x=zulu
into a custom object like this?
public class myClass {
public Dictionary<string, int> people { get; set; }
public int[] items { get; set; }
public string x { get; set; }
}
Is there a better (more sophisticated) way to do this besides splitting it by & and looping through the results to manually set each value?
Any pointers / guidance would be greatly appreciated.
If you have control over the sending side of the application, I strongly suggest you use a different encoding method to make parsing easier. I would just JSON encode the entire object, and then URIencode the JSON if it must be in the query_string.
There are often fairly small (on the order of 2K characters) limits to the size of URIs including the query_string. If you are forced to use HTTP, depending on your use case and whether you have control over this, POST may be preferable.
See this question for some methods of deserializing JSON:
C# deserialize dynamic JSON
Related
I have this JSON:
{
"response":
{
"data":
[
{
"start":1,
"subjects":["A"]
},
{
"start":3,
"subjects":["B"]
},
{
"start":2,
"subjects":["C"]
}
]
}
}
And I want to get only the "subject" data from the object with it's "start" value to be the smallest one that is greater than 1.3, which in this case would be C. Would anybody happen to know how such a thing can be achieved using C#?
I want to extend a bit on the other answers and shed more light into the subject.
A JSON -- JavaScript Object Notation - is just a way to move data "on a wire". Inside .NET, you shouldn't really consider your object to be a JSON, although you may colloquially refer to a data structure as such.
Having said that, what is a JSON "inside" .NET? It's your call. You can, for instance treat it as a string, but you will have a hard time doing this operation of finding a specific node based on certain parameters/rules.
Since a JSON is a tree-like structure, you could build your on data structure or use the many available on the web. This is great if you are learning the workings of the language and programming in general, bad if you are doing this professionally because you will probably be reinventing the wheel. And parsing the JSON is not a easy thing to do (again, good exercise).
So, the most time-effective way of doing? You have two options:
Use a dynamic object to represent your JSON data. A dynamic is a "extension" to .NET (actually, an extension to the CLR, that is called DLR) which lets you create objects that doesn't have classes (they can be considered to be "untyped", or, better, to use duck typing).
Use a typed structure that you defined to hold your data. This is the canonical, object-oriented, .NET way of doing it, but there's a trade-off in declaring classes and typing everything, which is costly in terms of time. The payoff is that you get better intellisense, performance (DLR objects are slower than traditional objects) and more safe code.
To go with the first approach, you can refer to #YouneS answer. You need to add a dependency to your project, Newtonsoft.Json (a nuget), and call deserialize to convert the JSON string to a dynamic object. As you can see from his answer, you can access properties in this object as you would access then on a JavaScript language. But you'll also realize that you have no intellisense and things such as myObj.unexistentField = "asd" will be allowed. That is the nature of dynamic typed objects.
The second approach is to declare all types. Again, this is time consuming and on many cases you'll prefer not to do it. Refer to Microsoft Docs to get more insight.
You should first create your data contracts, as below (forgive me for any typos, I'm not compiling the code).
[DataContract]
class DataItem
{
[DataMember]
public string Start { get; set; }
[DataMember]
public string[] Subjects { get; set; }
}
[DataContract]
class ResponseItem
{
[DataMember]
public DateItem[] Data { get; set; }
}
[DataContract]
class ResponseContract
{
[DataMember]
public ResponseItem Response { get; set; }
}
Once you have all those data structures declared, deserialize your json to it:
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var deserializer = new DataContractJsonSerializer(typeof(ResponseContract));
return (T)deserializer.ReadObject(ms);
}
The code above may seem a bit complicated, but follow a bit of .NET / BCL standards. The DataContractJsonSerializer work only with streams, so you need to open a stream that contains your string. So you create a memory stream with all the bytes from the json string.
You can also use Newtonsoft to do that, which is much simpler but, of course, still requires that extra dependency:
DataContract contract = JsonConvert.DeserializeObject<DataContract>(output);
If you use this approach you don't need the annotations (all those DataMember and DataContract) on your classes, making code a bit more clean. I very much prefer using this approach than DataContractJsonSerializer, but it's your call.
I've talked a lot about serializing and deserializing objects, but your question was, "How do I find a certain node?". All the discussion above was just a prerequisite.
There are, again and as usual, a few ways of achieving what you want:
#YouneS answer. It's very straightforward and achieves what you are looking for.
Use the second approach above, and then use your typed object to get what you want. For instance:
var contract = JsonConvert.DeserializeObject<DataContract>(output);
var query = from dataItem in contract.Response.Data
where dataItem.Start > 1.3
order by dataItem.Start;
var item = query.FirstOrNull();
Which will return the first item which, since it's ordered, should be the smallest. Remember to test the result for null.
You can use a feature from Newtonsoft that enables to directly find the node you want. Refer to the documentation. A warning, it's a bit advanced and probably overkill for simple cases.
You can make it work with something like the following code :
// Dynamic object that will hold your Deserialized json string
dynamic myObj = JsonConvert.DeserializeObject<dynamic>(YOUR-JSON-STRING);
// Will hold the value you are looking for
string[] mySubjectValue = "";
// Looking for your subject value
foreach(var o in myObj.response.data) {
if(o.start > 1.3)
mySubjectValue = o.subjects;
}
I am trying to get around that C# prefers to have classes generated (I know they are easy to generate, but currently my format and parameters are changing a lot due to development in both client and server end).
Example of what I most often find when I try to find out to deserialize is that you first have to know the exact structure - then build a class - and then you can refer to it later on (it's fine, but it's just not what I would like to do):
Json format 1:
[{"FirstName":"Bob","LastName":"Johnson"},{"FirstName":"Dan","LastName":"Rather"}]
public class People
{
public string FirstName { get; set; }
public string LastName { get; set;}
}
public List<People> peopleList;
. . . // (same as first example)
//Change the deserialize code to type <List<Class>>
peopleList = deserial.Deserialize<List<People>>(response);
That of course is easy as long as the reply doesn't change format, if for example the reply changes to a nested field :
Json format 2:
[{"FirstName":"Bob","LastName":"Johnson"},{"data":{"nestedfield1"
:"ewr"} }]
I would of course have to change the class to represent that, but at the moment we are moving back and forth in formats and I would somehow like if there was a way where I could try to access json elements directly in the string?
For example, like I can do in Python:
mystring1 = reply ["firstName"] mystring2 = reply ["data"]["nestedfield1"]
Is there any way to achieve this in C#? It would speed up development rapidly if there was a way of accessing it without first referencing the output in the code to then once again reference the class variable that was created when referencing it.
And note it's for rapid development, not necessarily for the final implementation where I can see advantages by doing the class approach.
Another way of asking was maybe can it serialize taking any format (as long as its JSON) and dynamically build up a struct where I can access it with named keys and not as class variables?
to deserialize json without using classes you can use using Newtonsoft.Json
here's the code:
using System;
using Newtonsoft.Json;
using System.Text;
public class Program
{
public static void Main()
{
var myJSONString = "[{\"FirstName\":\"Bob\",\"LastName\":\"Johnson\"},{\"FirstName\":\"Dan\",\"LastName\":\"Rather\"}]";
dynamic obj = JsonConvert.DeserializeObject<dynamic>(myJSONString);
Console.WriteLine(obj[0].FirstName);
}
}
The obj will perform the same way you use when generating classes,
it can take any json string and deserialize into dynamic object regardless of structure of the json. Keep in mind that you won't get VS intellisense support.
UPDATE
Here's fiddle:
https://dotnetfiddle.net/xeLDpK
We have a scenario where we need to calculate multiple fee components & share between Pre & Post stages of a Plugin. So we created the object like this.
class FeeCalculation
{
public string TotalFee { get; set; }
public string FilingFee { get; set; }
public string LegalFee { get; set; }
public string RecordFee { get; set; }
}
So far we have used single fee component & shared variable worked nicely. When tried to assign the whole object - the result is not fruitful.
context.SharedVariables.Add("fees", fcObject);
Is there a way to achieve this expected result?
The plugin infrastructure must be able to serialize/deserialize the objects that are in your SharedVariables collection. It has no knowledge of custom types like the FeeCalculation class and therefore cannot serialize it.
Use primitive types, common .NET types (e.g. a List of decimals should work) or CRM types (Entity, Money etc.). It's good to note that the SharedVariables collection is a key value pair collection. So, why not just add items to it with keys like "TotalFee", "FilingFee" etc?
I was trying to share an IEnumerable<Guid>, but collections like List did not work.
Of course you can always serialize to string, but your plugin code really shouldn't have to deal with serialization of common types.
After some trial and error, I ended up using arrays, i.e. Guid[].
This question already has answers here:
How do I turn a C# object into a JSON string in .NET?
(15 answers)
Closed 6 years ago.
I'm working on a point system for my twitch chat bot in C#. I need to save a list of users with their amount of points and hours to a local .txt file like this:
users : ???
username : ???
nick : string
points : int
hours : int
username : ???
nick : string
points : int
hours : int
username : ???
nick : string
points : int
hours : int
I'm trying to create a .NET Object to serialize to a JSON string and write this to my .txt file but I'm stuck here.
I figure users needs to be an Array of some sort but what do I do with username? I don't think JSON supports custom types?
Thanks for your time,
X3ntr
First we need to create a model. This model needs to match the structure of the JSON. There are a couple of ways to create this model.
Probably the best and safest way is to write it manualy. If you are using vs2015 you can also copy the json and paste it as class.
You can find this option here:
Another option is to use a website like http://json2csharp.com/ here you can paste the JSON and this will also generate classes for your JSON. Keep in mind that these generator are not 100% accurate so you might have to change some properties your self.
Ones we got the model we can use a lib like JSON.net to Deserialize our JSON. On the website is also some extra documentation on how to use JSON.net
var userList = JsonConvert.DeserializeObject<List<UserModel>>(users); //Users being the json as text.
Remember that if you miss a property in you model this will not always throw an error. So make sure that all properties got serialize correctly.
Serializing is as simple as Deserializing.
string json = JsonConvert.SerializeObject(model);
File.WriteAllText("C:\json.txt",json);
Optional is adding an encoding when writing the json.
File.WriteAllText("C:\json.txt",json,Encoding.UTF8);
I'll take a shot at it.
First up we'll need a model for our user:
public class User
{
public Guid Id { get; set; }
public string Username { get; set; }
public string NickName { get; set; }
public int Points { get ;set; }
public int Hours { get; set; }
}
Then in your main method, or wherever you deal with your users:
List<User> users = new List<User>();
Notice that I've added an Id property. Even though your usernames might very well be unique, it's always good practice to have some sort of property whose entire job is to just be the Id. This property should never change throughout the lifetime of the user. Where username might change one day, the Id will always stay the same.
Anyways, now to turn your list into Json:
string myJsonString = JsonConvert.SerializeObject(users, Formatting.Indented);
Et voila! Your list of users is now in a tidy Json string. The above line of code is from JSON.NET, you can get it as a Nuget package. The full qualification is Newtonsoft.Json.JsonConvert. You can pretty much trust JSON.NET to handle almost anything you throw at it, especially for a simple User class like you're going to be throwing at it.
Hope this helps get you started.
Extending on from this question, I'm trying to pass a complex object containing a collection of complex objects to an ASP.NET Web API controller action method, but I'm having trouble finding the correct format to use for my input object in the request. Continuing the example from Christopher Johnson's question (and removing some fields for simplicty), if I change his PhoneRequest object to contain a collection of phone numbers...
public class PhoneRequest
{
public string[] PhoneNumbers { get; set; }
public string State { get; set; }
}
...and I either pass the parameter as a URL encoded query string:
/api/phonenumber?id[0][State]=UT&id[0][PhoneNumbers][0]=555-1234567
...or POST it as a html form encoded (Content-Type: application/x-www-form-urlencoded) request body:
[0][State]=UT&[0][PhoneNumbers][0]=555-1234567
...then everything works great. But If I change PhoneNumbers from a collection of strings to a collection of a new PhoneNumber type...
public class PhoneRequest
{
public PhoneNumber[] PhoneNumbers { get; set; }
public string State { get; set; }
}
public class PhoneNumber
{
string AreaCode { get; set; }
string Number { get; set; }
}
...and I pass the object in what appears to me to be the logical way, given the previous result...
id[0][State]=UT&id[0][PhoneNumbers][0][AreaCode]=555&id[0][PhoneNumbers][0][Number]=1234567
...or again as a html form post body...
[0][State]=UT&[0][PhoneNumbers][0][AreaCode]=555&[0][PhoneNumbers][0][Number]=1234567
...then it still makes an attempt to bind it, and gets into my action method, but the model only contains State, and the phone number is this weird ComplexUriAndFormObject thing. Here's a copy-paste from my debugger Watch:
phoneRequest {ComplexUriAndFormObject.Models.PhoneRequest[1]}
[0] {ComplexUriAndFormObject.Models.PhoneRequest}
PhoneNumbers {ComplexUriAndFormObject.Models.PhoneNumber[1]}
[0] {ComplexUriAndFormObject.Models.PhoneNumber}
AreaCode null
Number null
State "UT"
Is there some way to specify this object correctly using this format? Or have I exceeded the limit of what ASP.NET Web API's built in model binders are able to do?
Note: Please don't say "just use POST" or "just use JSON/XML/Whatever as your Content-Type"... If I was able to do that, I would.
Until now, no built-in Web API model binders including derived FromUri and FromBody attributes support passing a complex object that contains any property of non-primitive class types (excluding the System.String) with query strings. I had the similar issues and have created a unique and advanced custom model binder, the FieldValueModelBinder class, to work on a target object hierarchy having generic list or array collections. I can use the pure query string type of source data without imbedding any JSON or XML structure into it. The model binder can be used as easy as the FromUri and FromBody attributes. It also works effectively for transferring query string data in both URI and request body.
Please read my article and download source code I have just posted using this link. You can also run the test app from the download source for your input string, model, and results. I hope that this is the right solution you need.