Static vs Non-Static Classes - c#

This is what my code looks like in my public Form1()
while (accessReader.Read())
{
for (int i = 0; i < count; i++)
{
string urlpart2= accessReader.GetValue(i).ToString();
WebRequest request = WebRequest.Create("urlpart1" + urlpart2+ "urlpart3");
string json;
var response = request.GetResponse();
request.ContentType = "application/json; charset=utf-8";
using (var streamr = new StreamReader(response.GetResponseStream()))
{
json = streamr.ReadToEnd();
List<MyObject> list = JsonConvert.DeserializeObject<List<MyObject>>(json);
var date = MyObject.Start;
//MessageBox.Show(date.ToString());
This is my class representing the different variables my json string returns
public class MyObject
{
public int Type { get; set; }
public string Country { get; set; }
public string Channel { get; set; }
public string Code { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
This is what a json string will return, the only difference that will change is maybe type, code, start, and end. - I want the Start and End Values.
[{"Type":1,"Country":"CA","Channel":"","Code":"1EZ","Start":"2014-10-24T00:00:00","End":"2015-10-23T00:00:00"},{"Type":2,"Country":"","Channel":"","Code":"UAD","Start":"2014-10-24T00:00:00","End":"2017-10-23T00:00:00"},{"Type":2,"Country":"","Channel":"","Code":"TPQ","Start":"2014-10-24T00:00:00","End":"2017-10-23T00:00:00"},{"Type":3,"Country":"","Channel":"","Code":"SVC_PRIORITY","Start":"2014-10-24T00:00:00","End":"2017-10-23T00:00:00"}]
I am fairly new to programming and I have run into an error I do not really understand 'An object reference is required for the nonstatic field, method, or property'.
Also I created this class within my Form1.cs as opposed to creating a new class in my Project Solution (if that matters?)

You try to access MyObject.Start like it would be a static property or field. However it's a instance field and basically you need to get a instance to access the field.
MyObject obj = list[0];
var date = obj.Start;
The field List<MyObject> list = ... contains all data which got deserialized from the json file ( And none if no data exists in the json file! ).
I guess you want to access all data of the json file, in this case i would prefer iterating through the objects via a foreach loop.
foreach (MyObject item in list) { .... }

The problem is with line var date = MyObject.Start; You have created a list of MyObjects. To access them you have to use list indexes i.e. var first = list[0] returns first element. Then you can get required date as: first.Start
In order to process every entry of your list you can use foreach loop as follows:
foreach (var obj in list) {
// use obj.Start, obj.End values
}

Related

Trying to use reflection to concatenate lists of objects

I have below class
public class HydronicEquipment
{
public List<LibraryHydronicEquipment> Source { get; set; }
public List<LibraryHydronicEquipment> Distribution { get; set; }
public List<LibraryHydronicEquipment> Terminals { get; set; }
}
and then i have the below class for "libraryHydronicEquipment"
public class LibraryHydronicEquipment : IEquipmentRedundancy
{
public string Name { get; set; }
public RedundancyStatus RedundancyStatus { get; set; }
public EquipmentRedundancy EquipmentRedundancy { get; set; }
}
I am trying to concatenate the list of "LibraryHydronicEquipment" objects available from all three properties (i.e) from source, distribution and terminal and General concatenate method will looks like as this below
var source = hydronicEquipment.Source;
var distribution = hydronicEquipment.Distribution;
var teriminals = hydronicEquipment.Terminals;
Source.Concat(Distribution).Concat(Terminals)
I am trying to achieve the same using reflection and the code looks like as below
foreach (var (systemName, hydronicEquipment) in hydronicSystemEquipment)
{
bool isFirstSystem = true;
var equipmentList = new List<string> { "Source", "Distribution", "Terminals" };
var redundancyequipmentList = GetRedundancyEquipment(hydronicEquipment, equipmentList);
}
and the method GetRedundancyEquipment is looks like below
private static IEnumerable<IEquipmentRedundancy> GetRedundancyEquipment(HydronicEquipment hydronicEquipment, List<string> equipmentList)
{
IEnumerable<IEquipmentRedundancy> equipmentRedundancies = new List<IEquipmentRedundancy>();
dynamic equipmentResults = null;
foreach(var equipment in equipmentList)
{
var componentList = hydronicEquipment.GetType().GetProperty(equipment).GetValue(hydronicEquipment, null) as IEnumerable<IEquipmentRedundancy>;
equipmentResults = equipmentRedundancies.Concat(componentList);
}
return equipmentResults;
}
The problem here is even though i have Source is having list of objects and Distribution is having list of objects, the equipmentResults is giving only one object instead of list of concatenated objects.
I am trying to return the IEnumerable<IEquipmentRedundancy> at the end using reflection method but it seems not working with the above code.
Could any one please let me know how can i achieve this, Many thanks in advance.
GetRedundancyEquipment should preserve your values instead of reassign the reference with each iteration. Here's the fixed version:
private static IEnumerable<IEquipmentRedundancy> GetRedundancyEquipment(HydronicEquipment hydronicEquipment, List<string> equipmentList)
{
IEnumerable<IEquipmentRedundancy> equipmentRedundancies = new List<IEquipmentRedundancy>();
var equipmentResults = new List<IEquipmentRedundancy>();
foreach (var equipment in equipmentList)
{
var componentList = hydronicEquipment.GetType().GetProperty(equipment).GetValue(hydronicEquipment, null) as IEnumerable<IEquipmentRedundancy>;
equipmentResults.AddRange(equipmentRedundancies.Concat(componentList));
}
return equipmentResults;
}
If we look at what you're doing in GetRedundancyEquipment() it becomes clear.
First you create equipmentRedundancies = new List<IEquipmentRedundancy>();
Then you never modify equipmentRedundancies - e.g. via Add(). It remains an empty list until it goes out of scope and is garbage collected.
In a loop you then repeatedly make this assignment equipmentResults = equipmentRedundancies.Concat(componentList);
That is to say: Assign to equipmentResults the concatenation of componentList to equipmentRedundancies.
Note that Concat() is a lazily evaluated linq method. When you actually enumerate it results are produced. It doesn't modify anything, it's more like a description of how to produce a sequence.
So each time through the loop you're assigning a new IEnumerable that describes a concatentaion of an empty list followed by the property that you retrieved with reflection to equipmentResults. Then at the end you return the final one of these concatenations of an empty list and retrieved property.
If you want all of them together, you should concatenate each of them to the result of the previous concatenation, not to an empty list.

How to store multiple items in IDictionary?

I have this IDictionary declaration: IDictionary<string, string> trace;
Inside of it I want save a list of element returned by a json deserialization, actually I do this like:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
foreach (var trace in item.trace.context.context)
{
trace["context"] = JsonConvert.SerializeObject(trace);
}
}
Now this code working good but save only the last item of the iteration, this 'cause when I iterate over the item the date, type etc... are replaced, but I want store the item not replace it in each new iteration.
How can do this with IDictionary?
Note that: trace.x is the name of the class that deserialize the json.
Further question: Maybe the use of IDictionary is not a good idea for achieve this?
Looks like you'd be better off using a dedicated class, something like this:
public class TraceInfo
{
public string Date { get; set; }
public string Type { get; set; }
public List<string> ContextItems { get; set; }
}
Then for every value in obj, create a TraceInfo object using new TraceInfo() and set its properties.
You can then store them in a List<TraceInfo> or in a Dictionary<string, TraceInfo>, the choice is yours.

c# is there a method to serialize to UrlEncoded?

I want to use facebook's API and i find it hard to convert objects to urlEncoded.
so, for now i have something like:
string postData = JsonConvert.SerializeObject(req);
postData = postData.Replace(#"\", "");
postData = HttpUtility.UrlEncode(postData);
byte[] data = Encoding.UTF8.GetBytes(postData);
string facebookUrl = "https://graph.facebook.com/v2.5/";
problem is that facebook doesn't accept jsons but UrlEncoded data, as it seems, correct me if im wrong.
So, Im pretty sure converting objects to UrlEncoded string is impossbile in .Net 4.5.1 because I've tried to use some of the answers for this questions that are while ago they are not working for me.
for example:
var result = new List<string>();
foreach (var property in TypeDescriptor.GetProperties(req))
{
result.Add(property.Name + "=" + property.GetValue(req));
}
postData = string.Join("&", result);
but .Name and .GetValue aren't defined at all.
Would like to get some help with that, TIA.
Objects i use:
internal sealed class FacebookValidationRequest
{
public string access_token;
public fbReq[] batch;
public string method;
public string format;
public int pretty;
public int suppress_http_code;
public string debug;
public FacebookValidationRequest(string appId, string userToken)
{
access_token = userToken;
batch = new[]
{
//test code
new fbReq("GET", "me"),
new fbReq("GET", "me/friends?limit=50") //,
//new fbReq("GET", "app?access_token=" + userToken)
};
method = "post";
format = "json";
pretty = 0;
suppress_http_code = 1;
debug = "all";
}
}
internal sealed class fbReq
{
public string method;
public string relative_url;
public fbReq(string m, string url)
{
method = m;
relative_url = url;
}
}
FacebookValidationRequest req = new FacebookValidationRequest(appToken, userToken);
Also, took the token for the facebook debugger site
how facebook wants to object to look like after encoding:
access_token=mytoken&batch=%5B%7B%22method%22%3A%22GET%22%2C%20%22relative_url%22%3A%22me%22%7D%2C%7B%22method%22%3A%22GET%22%2C%20%22relative_url%22%3A%22me%2Ffriends%3Flimit%3D50%22%7D%5D&debug=all&fields=id%2Cname&format=json&method=post&pretty=0&suppress_http_code=1
Seems to me that the easiest way to do this is with Attributes to describe your properties, just like how the .Net Json's DataContract system does it. Basically, you assign an attribute to each property you want serialized, and make that attribute contain the name to serialize it as. I don't think you want to get into the mess of actually writing your own DataContractSerializer, though, so it might be easier to simply create your own Property class and a simple serializer using reflection.
The attribute class:
[AttributeUsage(AttributeTargets.Property)]
public sealed class UrlEncodeAttribute : System.Attribute
{
public String Name { get; private set; }
public UrlEncodeAttribute(String name)
{
this.Name = name;
}
}
Then, to apply to your data class... put the attributes on all properties:
internal sealed class FacebookValidationRequest
{
[UrlEncodeAttribute("access_token")]
public String AccessToken { get; set; }
[UrlEncodeAttribute("method")]
public String Method { get; set; }
[UrlEncodeAttribute("format")]
public String Format { get; set; }
[UrlEncodeAttribute("pretty")]
public Int32 Pretty { get; set; }
[UrlEncodeAttribute("suppress_http_code")]
public Int32 SuppressHttpCode { get; set; }
[UrlEncodeAttribute("debug")]
public string Debug { get; set; }
public fbReq[] Batch { get; set; }
[UrlEncodeAttribute("batch")]
public String BatchString
{
get
{
// put your json serialization code here to return
// the contents of Batch as json string.
}
}
}
As you see, Batch does not have the UrlEncodeAttribute, while its string representation BatchString does. Its get is what will be called by the serializer, so you can put the conversion code in there.
Also note that thanks to the text names you give in the attributes, your properties don't need to have the names you actually get in the serialization, which looks much cleaner in my opinion. C#'s own serialization to xml and json works in the same way.
Now, let's take a look at the actual serialization, using reflection to get those properties:
public static String Serialize(Object obj, Boolean includeEmpty)
{
// go over the properties, see which ones have a UrlEncodeAttribute, and process them.
StringBuilder sb = new StringBuilder();
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
object[] attrs = p.GetCustomAttributes(true);
foreach (Object attr in attrs)
{
UrlEncodeAttribute fldAttr = attr as UrlEncodeAttribute;
if (attr == null)
continue;
String objectName = fldAttr.Name;
Object objectDataObj = p.GetValue(obj, null);
String objectData = objectDataObj == null ? String.Empty : objectDataObj.ToString();
if (objectData.Length > 0 || includeEmpty)
{
objectData = HttpUtility.UrlEncode(objectData);
objectName= HttpUtility.UrlEncode(objectName);
if (sb.Length > 0)
sb.Append("&");
sb.Append(objectName).Append("=").Append(objectData);
}
break; // Only handle one UrlEncodeAttribute per property.
}
}
return sb.ToString();
}
A more advanced version of this could be made by including a serialization method property in the UrlEncodeAttribute class (probably best done with an enum), so you can simply specify to serialize the array on the fly using json. You'll obviously need to put the actual json converter into the Serialize function then. I thought using the getter on a dummy property as preparation method was simpler, here.
Obviously, calling it is simply this: (assuming here the Serialize() function is in a class called UrlEncodeSerializer)
FacebookValidationRequest fbreq = new FacebookValidationRequest();
// fill your data into fbreq here
// ...
// includeEmpty is set to true for testing here, but normally in
// UrlEncoded any missing property is just seen as empty anyway, so
// there should be no real difference.
String serialized = UrlEncodeSerializer.Serialize(fbreq, true);

Error when deserializing JSON to Object

I need to convert JSON data that I get from a REST API and convert them to CSV for some analytic. The problem is that the JSON data do not necessarily follow the same content, so I can't define a type for mapping. This has become a challenge that is taking too much of my time. I have already created some code, but of course it is not working as it throws exception on this line
var data = JsonConvert.DeserializeObject<List<object>>(jsonData);
The error is:
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[System.Object]' because the type
requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'data', line 2, position 10.
please let me know what I can do to get this going.
A sample of data would be like this, the fields of data can change very often, for example a new field can be added the next day, so I don't have the liberty to create a .Net class to map the data.
{
"data": [
{
"ID": "5367ab140026875f70677ab277501bfa",
"name": "Happiness Initiatives - Flow of Communication/Process & Efficiency",
"objCode": "PROJ",
"percentComplete": 100.0,
"plannedCompletionDate": "2014-08-22T17:00:00:000-0400",
"plannedStartDate": "2014-05-05T09:00:00:000-0400",
"priority": 1,
"projectedCompletionDate": "2014-12-05T08:10:21:555-0500",
"status": "CPL"
},
{
"ID": "555f452900c8b845238716dd033cf71b",
"name": "UX Personalization Think Tank and Product Strategy",
"objCode": "PROJ",
"percentComplete": 0.0,
"plannedCompletionDate": "2015-12-01T09:00:00:000-0500",
"plannedStartDate": "2015-05-22T09:00:00:000-0400",
"priority": 1,
"projectedCompletionDate": "2016-01-04T09:00:00:000-0500",
"status": "APR"
},
{
"ID": "528b92020051ab208aef09a4740b1fe9",
"name": "SCL Health System - full Sitecore implementation (Task groups with SOW totals in Planned hours - do not bill time here)",
"objCode": "PROJ",
"percentComplete": 100.0,
"plannedCompletionDate": "2016-04-08T17:00:00:000-0400",
"plannedStartDate": "2013-11-04T09:00:00:000-0500",
"priority": 1,
"projectedCompletionDate": "2013-12-12T22:30:00:000-0500",
"status": "CPL"
}
]
}
namespace BusinessLogic
{
public class JsonToCsv
{
public string ToCsv(string jsonData, string datasetName)
{
var data = JsonConvert.DeserializeObject<List<object>>(jsonData);
DataTable table = ToDataTable(data);
StringBuilder result = new StringBuilder();
for (int i = 0; i < table.Columns.Count; i++)
{
result.Append(table.Columns[i].ColumnName);
result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
}
foreach (DataRow row in table.Rows)
{
for (int i = 0; i < table.Columns.Count; i++)
{
result.Append(row[i].ToString());
result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
}
}
return result.ToString().TrimEnd(new char[] {'\r', '\n'});
}
private DataTable ToDataTable<T>( IList<T> data )
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0 ; i < props.Count ; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0 ; i < values.Length ; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
}
}
The real issue here is that you are trying to deserialize into a List<object> but your JSON actually represents a single object containing a data property which then contains a list of objects. That is why you are getting this error. Json.Net can't deserialize a single object into a list. I think what you really want to do is define a container class like this:
class Root
{
public List<Dictionary<string, object>> Data { get; set;}
}
Then deserialize like this:
var data = JsonConvert.DeserializeObject<Root>(jsonData).Data;
You will then end up with a list of dictionaries, where each dictionary represents one item in the JSON array. The dictionary key-value pairs are the dynamic values in each item. You can then work with these as you would with any other dictionary. For example, here is how you would dump out all the data:
foreach (var dict in data)
{
foreach (var kvp in dict)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}
Console.WriteLine();
}
Fiddle: https://dotnetfiddle.net/6UaKhJ
What you're looking for is the dynamic type. Though unrelated, this answer contains much of the information on how you'll be able to iterate through the changing properties on your object.
You will need to add some additional work to figure out how to handle your result when it is an array versus a single object as your error shows us. However, this is a good first step for you.
Basically, a dynamic object is a Dictionary, much like how a JSON object is treated in JavaScript. You just need to iterate through each of the KeyValuePair objects within the main object and go through their properties.
var data = JsonConvert.DeserializeObject<dynamic>(jsonData);
var rows = new List<string>();
// Go through the overall object, and get each item in
// the array, or property in a single object.
foreach (KeyValuePair<string, object> item in data)
{
dynamic obj = item.Value;
var row = "";
// Perhaps add a check here to see if there are more
// properties (if it is an item in an array). If not
// then you are working with a single object, and each
// item is a property itself.
foreach (KeyValuePair<string, object> prop in obj)
{
// Very dummy way to demo adding to a CSV
string += prop.Value.ToString() + ",";
}
rows.Add(string);
}
This is far from a complete example, but we don't have enough information to go on to help you finish what you're trying to do.
You are trying to deserialize into a List but your JSON actually represents a single object containing a data property containing list of objects. That is why you are getting this error. Json.Net can't deserialize a single object into a list.
Please try this:Create a class which contain single property on datatype Object and pass this class for deserialization.
class Parent
{
public object Data { get; set;}
}
Then deserialize like this:
var output = JsonConvert.DeserializeObject<Parent>(jsonData);
Try using this class instead of Object
public class Datum
{
public string ID { get; set; }
public string name { get; set; }
public string objCode { get; set; }
public double percentComplete { get; set; }
public string plannedCompletionDate { get; set; }
public string plannedStartDate { get; set; }
public int priority { get; set; }
public string projectedCompletionDate { get; set; }
public string status { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
Change to this:
var data = JsonConvert.DeserializeObject<RootObject>(jsonData);
If your data is dynamic so try a dynamic list:
using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d=jss.Deserialize<dynamic>(str);
Since you're trying to deserialize an object type into a list type, it won't deseralize directly.
You can do this:
var data = JsonConvert.DeserializeObject<ObjectDataList>(jsonData);
var rows = new List<DeserializedData>();
foreach (dynamic item in data)
{
var newData = new DeserializedData();
foreach (dynamic prop in item)
{
var row = new KeyValuePair<string, string>
(prop.Name.ToString(), prop.Value.ToString());
newData.Add(row);
}
rows.Add(newData);
}
Here are new classes
//class for key value type data
class DeserializedData
{
List<KeyValuePair<string, string>> NewData =
new List<KeyValuePair<string, string>>();
internal void Add(KeyValuePair<string, string> row)
{
NewData.Add(row);
}
}
[DataContract]
class ObjectDataList
{
[DataMember(Name ="data")]
List<object> Data { get; set; }
public IEnumerator<object> GetEnumerator()
{
foreach (var d in Data)
{
yield return d;
}
}
}
As far as I can tell, more recent versions of Newtonsoft can actually do this now, no additional work required.
I was working with the binary version however, and this did still have the issue - I had a test where you could configure to use binary or json, and the json version worked just fine, but the binary complained about not getting an array type.
I started using the BsonDataReader for this, and was looking through the properties and methods on it to see how I could best look at the contents, and lo and behold, this had a property called:
reader.ReadRootValueAsArray
Setting this to 'true' did the trick.

Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'

I am testing my Web API. Mocking the data I have this:
var objs = ((JArray)JsonConvert.DeserializeObject("{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}")).Values<JObject>();
Which gives me the error:
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'
The thing is it was working. I must have changed something, but I don't know what.
My intent is to convert this JSON object to a list of .NET objects called Print which has the fields:
PrintId
Header
TX
CompnayRef
Just make a class and deserialize it.
public class Print
{
public int PrintId { get; set; }
public string Header { get; set; }
public string TC { get; set; }
public string CompanyRef { get; set; }
}
Print printObj = JsonConvert.DeserializeObject<Print>(yourJson);
printObj.PrintId = //...
As the message says, your object is JObject so don't cast it to JArray. Try this:
var objs = JsonConvert.DeserializeObject("{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}");
Update To get a collection List<Print>, your JSON needs to be an array. Try this (I made your JSON an array and added a second object):
string json = "[{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}"
+ ",{ \"PrintId\":20,\"Header\":\"header2\",\"TC\":\"tc2\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}]";
var objs = JsonConvert.DeserializeObject<List<Print>>(json);
//The loop is only for testing. Replace it with your code.
foreach(Print p in objs){
Console.WriteLine("PrintId: " + p.PrintId);
Console.WriteLine("Header: " + p.Header);
Console.WriteLine("TC: " + p.TC);
Console.WriteLine("CompanyRef: " + p.CompanyRef);
Console.WriteLine("==============================");
}
public class Print
{
public int PrintId { get; set; }
public string Header { get; set; }
public string TC { get; set; }
public string CompanyRef { get; set; }
}
Here is a fiddle.
Simply because { } is a jobject notation, to make it a jarray just put square brackets around it e.g. [{ }]. So in your case, just putting these two chars fixes the problem.
var objs = ((JArray)JsonConvert.DeserializeObject("[{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}]")).Values<JObject>();
you can try here
https://dotnetfiddle.net/RmgGw8
Note: You said it was working before. So this string input probably is a result of a serialization. You did not have a problem before, because your input was always an array with multiple items until this one. And your serializer is probably producing a single object (output starting with '{') instead of an array (output starting with '[') for single item arrays.
serializing List with single object as JSON object not JSON array
For me I was putting empty string as an object which caused the issue, I switched to "{}" which fixed my issue

Categories