FileHelpers DelimitedClassBuilder add fields after read - c#

I'm using the FileHelpers DelimitedClassBuilder to build a class based on metadata in a datatable. This way I can read any file known in the metadata. I read it as a stream and process each record individually. For further processing I want to add some fields to the data and then serialize it to JSON. It's the adding of fields part that doesn't work. The stream returns an object. I'm using a work-around. Serializing the object to JSON, de-serializing it to a dictionary, adding the fields and then serializing it to JSON again. I'm sure this can be done in a more efficient way. I tried converting it to a list but that doesn't work.
//build runtime class based on metadata
FD.DelimitedClassBuilder cb = new FD.DelimitedClassBuilder("ImportFile", "|");
cb.IgnoreFirstLines = 1;
foreach (DT.DataRow drMetadata in dtMetadata.Rows)
{
cb.AddField(drMetadata["EntityColumnName"].ToString(), typeof(string));
cb.LastField.FieldQuoted = true;
cb.LastField.QuoteMode = FH.QuoteMode.AlwaysQuoted;
cb.LastField.QuoteMultiline = FH.MultilineMode.AllowForBoth;
}
//create async filehelper engine for row by row processing
FH.FileHelperAsyncEngine fhe = new FH.FileHelperAsyncEngine(cb.CreateRecordClass());
using (fhe.BeginReadStream(file))
{
foreach(object record in fhe)
{
//convert object to list, doesn't work
//SG.List<object> blaat = (record as SG.IEnumerable<object>).Cast<object>().ToList();
//serialize record class to json
string json = JS.JsonConvert.SerializeObject(record, JS.Formatting.Indented);
//convert message to key-value dictionary
SG.IDictionary<string, string> values = JS.JsonConvert.DeserializeObject<SG.IDictionary<string, string>>(json);
values.Add("SourceSystem", messagesource);
values.Add("SourceType", messagetype);
string json2 = JS.JsonConvert.SerializeObject(values, JS.Formatting.Indented);
SY.Console.WriteLine(json2);
}
}
fhe.Close();

You can use a list of fields obtained via reflection on the record class. Then use Linq's ToDictionary to populate your values.
var recordClass = cb.CreateRecordClass();
List<FieldInfo> fields = recordClass.GetFields().ToList();
FileHelperAsyncEngine fhe = new FileHelperAsyncEngine(recordClass);
using (fhe.BeginReadStream(file))
{
foreach (var record in fhe)
{
IDictionary<string, object> values = fields.ToDictionary(x => x.Name, x => x.GetValue(record));
values.Add("SourceSystem", "messagesource");
values.Add("SourceType", "messagetype");
string json = JsonConvert.SerializeObject(values, Formatting.Indented);
Console.WriteLine(json);
}
}

Related

How to return a string array with complex structure in c#

for a legacy system, I need to return an object than have inside it a key value than it's the date, and inside have a body, any idea how to get the job done?
I need to return this array
{
"sellerId":"157747190185796800",
"data":
{
"2020-08-25":{ "sales":195000,"comission":25350},
"2020-08-26":{"sales":70500,"comission":9165},
"2020-08-27":{ "sales":51000,"comission":6630}
}
}
I'm trying with a json result and it works, but there's a problem with the key value date
Edit: I'm trying to make the suggestion of an dictionary, but, I don't know what I'm doing bad in this case. i try as an object too and doesn't work.
var lst = new List<Dictionary<string, JsonResult>>();
foreach (var item in listToReturn)
{
lst.Add(new Dictionary(item.DateFromStr, new JsonResult (new
{
sales = item.sales,
comission = item.Comission,
})));
}
I would create the JSON using anonymous objects, using a Dictionary for the sales data like this:
var resultToReturn = new
{
sellerId,
data = listToReturn.ToDictionary (
item => item.DateFromStr,
item => new
{
sales = item.Sales,
commission = item.Commission
}
)
};
Then you can serialize resultToReturn using your favorite serializer, or if you're using MVC, return it in a JsonResult.
Demo fiddle: https://dotnetfiddle.net/jZvoNo
Note: this solution assumes all the date values will be unique within the list, otherwise ToDictionary will throw an exception.

Why do I get "Unexpected character encountered while parsing value" when using Newtonsoft.Json.DeserializeObject with a string?

I'm getting the mentioned error when trying to DeserializeObject() into a list of strings.
ResultSet is fine and making a string as:
string sRetVal_Json = new JavaScriptSerializer().Serialize(ResultSet);
also works fine.
The resultant string, e.g., is:
sRetVal_Json = "[{\"CUSTNUM\":\"8690\"}]"
Here is a code snip:
var ResultSet = (from cms in MASadminE.MOM_CMS
where cms.ORDER == sOrdNum
select new
{
cms.CUSTNUM
});
List<string> list = new List<string>();
string sRetVal_Json = new JavaScriptSerializer().Serialize(ResultSet);
if (sRetVal_Json != "[]") // got > 0 records
{
list = JsonConvert.DeserializeObject<List<string>>(sRetVal_Json);
}
You're trying to deserialize a serialized list of anonymously-typed objects to a list of strings. The parser chokes when it hits the colon after the first property name. I don't think there's a way to use NewtonSoft to deserialize to a list of an anonymous type. You can deserialize to a Dictionary<string, string>, though:
Dictionary<string, string>> dict = JsonConvert.DeserializeObject<Dictionary<string, string>>>(sRetVal_Json);
It doesn't make sense to serialize and then deserialize to get your list of strings. You still have the same problem and you're just doing unecessary processing.
Change your projection to just select the value if that is all you want. Then ToList() it if there are any items in the sequence:
var ResultSet = (from cms in MASadminE.MOM_CMS
where cms.ORDER == sOrdNum
select cms.CUSTNUM);
if(ResultSet.Any())
{
List<string> custnums = ResultSet.ToList();
}
The issue is that the ResultSet here is actually the "dynamic" type because you created an anonymous class when you did
select new
{
cms.CUSTNUM
}
Thus there are 2 ways to do this. Either change your select to select back cms.CUSTNUM directly to get a list of strings (but JSON won't have CUSTNUM as a property) or you create a class that will support you here.
1.
var ResultSet = (from cms in MASadminE.MOM_CMS
where cms.ORDER == sOrdNum
select cms.CUSTNUM).ToList();
(Then you can use List< string > here)
2.
public class MyData
{
public string CUSTNUM { get; set; }
}
var ResultSet = (from cms in MASadminE.MOM_CMS
where cms.ORDER == sOrdNum
select new MyData
{
CUSTNUM = cms.CUSTNUM
});
List<MyData> list = new List<MyData>();
string sRetVal_Json = new JavaScriptSerializer().Serialize(ResultSet);
if (sRetVal_Json != "[]") // got > 0 records
{
list = JsonConvert.DeserializeObject<List<MyData>>(sRetVal_Json);
}

Parsing JSON response from StreamBuilder C#

I'm getting a JSON response back from another website and then building the response from a StreamReader:-
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
response = streamReader.ReadToEnd();
}
The result I'm getting is:-
string response = "{\"d\":\"[{\\\"Animal\\\":\\\"Cat\\\",\\\"Noise\\\":\\\"Meow\\\"},{\\\"Animal\\\":\\\"Dog\\\",\\\"Noise\\\":\\\"Woof\\\"}]\"}";
I've then used the JsonConvert.DeserializeObject(response) to deserialise and then I'm then trying to loop through the results to read the values.. but it's not working whatever I try
dynamic jObj = JsonConvert.DeserializeObject(response);
var arr = jObj; //Tried var arr = jObj.d;
#foreach (var item in arr)
{
….
}
Error: Target type System.Collections.IEnumerable is not a value type or a non-abstract class.
Parameter name: targetType
Your JSON response contains a d property, which value is an array wrapped into string itself.
So, you should parse a d content separately into array, Json.Linq solution is below
string response = "{\"d\":\"[{\\\"Animal\\\":\\\"Cat\\\",\\\"Noise\\\":\\\"Meow\\\"},{\\\"Animal\\\":\\\"Dog\\\",\\\"Noise\\\":\\\"Woof\\\"}]\"}";
var json = JObject.Parse(response);
var array = json["d"];
foreach (var item in JArray.Parse(array.ToString()))
{
Console.WriteLine(item["Animal"]);
}
Solution with deserialization to dynamic object
dynamic json = JsonConvert.DeserializeObject(response);
var array = json?.d;
foreach (var item in JsonConvert.DeserializeObject(array?.ToString()))
{
Console.WriteLine(item?.Animal);
}
It allows you to parse the response without any changes to source JSON
If you printed response, you would see that jObj.d is not an array, but a string. In fact, it looks like the string representation of an array of objects.
It seems that the "d"'s value contains another JSON data. If it is correct and you don't want to touch the JSON format, here is the solution:
string response = "{\"d\":\"[{\\\"Animal\\\":\\\"Cat\\\",\\\"Noise\\\":\\\"Meow\\\"},{\\\"Animal\\\":\\\"Dog\\\",\\\"Noise\\\":\\\"Woof\\\"}]\"}";
dynamic jObj = JsonConvert.DeserializeObject(response);
var arr = JsonConvert.DeserializeObject<D[]>((jObj.d).Value);
foreach (var item in arr)
{
}
........
public class D
{
public string Animal { get; set; }
public string Noise { get; set; }
}

How to parse JSON with Newtonsoft?

I created an ASP.NET Application, where I have to parse a csv file with a json structure.
The csv file itself is structured like:
{"Instance":"abc","Date":"2019-06-03T00:00:02.056Z","Identification":"someFunction","Type":"DurationInMs","Value":"5","iserror":"False""}
I get the jsonCsvData as a string and tried to parse it. Then I want to save some of the elements of this json object into a db.
public IActionResult ReadJsonCsvData(string jsonCsvData)
{
Console.WriteLine("ReadJsonCsvData");
ChartData chartData = new ChartData();
var lines = jsonCsvData.Split("\n");
foreach (var line in lines)
{
var values = JObject.Parse(line);
var first = string.Concat(values["Instance"]); //Output for first: ""
}
}
The problem now is, that the variable first is an empty string. The result should be (like in the json structure example above) "abc".
Thank you in advance!
I don't know if it will help but here is my solution (remove one of " at the end of your Json).
I use the "Jobject" to parse Json as I want. Import this two reference.
using Newtonsoft.Json.Linq;
using Newtonsoft;
Then you have to create your JObject :
JObject o = JObject.Parse(myJsonString);
Then to retrieve specifics data, you just have to search in your object just like you do with a dictionary with key :
instanceFromJson = o["Instance"].ToString;
dateFromJson = o["Date"].ToString;
If you have a table in your "instance" json object you can retrieve all data from this list just like that :
foreach (var item in o["Instance"]["tabFromInstanceObject"])
{
MyList.Add(item);
}

set props value from text field, and convert it into a list of JSON objects and store in a file

I am trying to get data from web form and convert properties into a list of json objects through json.net, first time a list of object is stored in a file. But next time, instead of appending data into list it creates new list. So how can I add it in same list. Here is my code
public List<StudentProps> GetProps(StudentProps p)
{
List<StudentProps> s = new List<StudentProps>();
s.Add(p);
return s;
}
public void GetStudent(StudentProps p)
{
var json = JsonConvert.SerializeObject(GetProps(p), Formatting.Indented);
String FilePath = #"C:\Users\Haseeb\Desktop\Test.json";
File.AppendAllText(FilePath, json + Environment.NewLine);
var ReadFile = File.ReadAllText(FilePath);
// List<StudentProps> props = JsonConvert.DeserializeObject<List<StudentProps>>(ReadFile).ToList();
}

Categories

Resources