Creating a Parse class to handle parsing of file being read in - c#

I wrote a parse class trying to handle parsing the data from a string array into it's appropriate value. I am trying to test this program to see if it will print out the value parse.open, and it is not. It is printing up 0's for the moment (which isn't accurate), until i could figure out why it's not showing what I need.
while (!r.EndOfStream)
{
ParseFileRead parse = new ParseFileRead();
string line = r.ReadLine();
//Send this to Parse class
string [] values = line.Split(',');
//parse records
Console.WriteLine(values[6]); //This is printing the accurate value for parse.open
ParseFileRead.Parse(values);
Console.WriteLine(parse.open); //This is not printing the accurate value
}
Console.Read();
vWriteFile.Close();
And here is my ParseFileRead class:
public class ParseFileRead
{
public int open { get; set; }
public int buy { get; set; }
public int sell { get; set; }
public double settleMM { get; set; }
public string account { get; set; }
public string underlying { get; set; }
public string symbol { get; set; }
public static void Parse(string[] arr)
{
ParseFileRead parse = new ParseFileRead();
parse.account = arr[0];
parse.underlying = arr[12];
parse.symbol = arr[1];
parse.open = Convert.ToInt32(arr[6]);
parse.buy = Convert.ToInt32(arr[7]);
parse.sell = Convert.ToInt32(arr[8]);
parse.settleMM = Convert.ToDouble(arr[10]);
}
}

This is actually correct.
The default value for an uninitialized int is 0.
You are creating a new instance of your ParseFileRead class which will have a value of 0 for open. You then check your parsed value to make sure it's reading in correctly using Console.WriteLine(values[6]);.
Next, you try to parse your values using the Parse function of your ParseFileRead class; which is a void function so it has no return value.
Inside your Parse function you have: ParseFileRead parse = new ParseFileRead(); which creates yet another new instance of your class with a value of 0 for open. This particular instance is never used anywhere and is not the same as the values of the properties created with your initial instance of ParseFileRead
If you put a Console.Write in your Parse function, I'm sure that you will see it being parsed correctly.
So you have 2 options:
Set the properties of your ParseFileRead inside the Parse class without creating a new instance of ParseFileRead
Return the newly created ParseFileRead instance out of your Parse function.
Or a 3rd Option, which is probably best as suggested by Plutonix:
/*Parse class*/
public class ParseFileRead
{
public int open { get; set; }
public int buy { get; set; }
public int sell { get; set; }
public double settleMM { get; set; }
public string account { get; set; }
public string underlying { get; set; }
public string symbol { get; set; }
public ParseFileRead(string[] arr)
{
this.account = arr[0];
this.underlying = arr[12];
this.symbol = arr[1];
this.open = Convert.ToInt32(arr[6]);
this.buy = Convert.ToInt32(arr[7]);
this.sell = Convert.ToInt32(arr[8]);
this.settleMM = Convert.ToDouble(arr[10]);
}
}
/*Parsing code*/
while (!r.EndOfStream)
{
string line = r.ReadLine();
//Send this to Parse class
string [] values = line.Split(',');
//parse records
Console.WriteLine(values[6]); //This is printing the accurate value for parse.open
ParseFileRead parse = new ParseFileRead(values);
Console.WriteLine(parse.open); //This is not printing the accurate value
}

Related

Accept a list of objects from form data in ASP.NET Core

I am currently struggling to accept a list of objects from FormData in ASP.NET Core.
The project looks like this:
I have a class called Stavka (English: Item).
public class Stavka
{
public string naziv { get; set; }
public double cenaPoJedinici { get; set; }
public string jedinicaMere { get; set; }
public int kolicina { get; set; }
public Stavka(string naziv, double cenaPoJedinici, string jedinicaMere, int kolicina)
{
this.naziv = naziv;
this.cenaPoJedinici = cenaPoJedinici;
this.jedinicaMere = jedinicaMere;
this.kolicina = kolicina;
}
public Stavka()
{
}
}
I have a class called Faktura (English: Bill) which has a variable called Stavke (English: Items) that is a list containing the Stavka objects.
public class Faktura
{
public int Id { get; set; }
public string pibStart { get; set; }
public string pibEnd { get; set; }
public DateTime datumGen { get; set; }
public DateTime datumRok { get; set; }
public List<Stavka> stavke { get; set;}
public double cena { get; set; }
public string tip { get; set; }
public Faktura(int id, string pibStart, string pibEnd, DateTime datumGen, DateTime datumRok, List<Stavka> stavke, string tip)
{
Id = id;
this.pibStart = pibStart;
this.pibEnd = pibEnd;
this.datumGen = datumGen;
this.datumRok = datumRok;
this.stavke = stavke;
this.tip = tip;
double sumCena = 0;
foreach(Stavka s in stavke)
{
sumCena += s.kolicina * s.cenaPoJedinici;
}
this.cena = sumCena;
}
public Faktura()
{
}
I want to create a new Faktura object and add it to a list within my Controller. I tried to do this with the following code:
[HttpPost("dodajFakturu")]
public IActionResult dodajFakturu([FromForm]string pibStart, [FromForm]string pibEnd,[FromForm]DateTime datumStart, [FromForm]DateTime datumEnd,[FromForm]List<Stavka> stavkeLis, [FromForm]string tip)
{
int id = lst.OrderByDescending(p => p.Id).First().Id + 1;
Faktura f = new Faktura(id, pibStart,pibEnd, datumStart,datumEnd,stavkeLis,tip);
lst.Add(f);
return Ok(SveFakture());
}
And yet, when i post the request (in Swagger/Postman), the variable stavkeLis (which accepts the JSON array) is always empty:
This is certainly because i fundamentally misunderstood the way in which NET Core accepts these variables.
Is there some other way to send a list of objects through form data?
this way you have is currect, but if its not maybe because simple code problem but way that you right the code can be better or you can say develop your code as Below:
// StavkaBody => I Mean All Body In One Json
public async Task<IActionResult> MethodName([FromForm] string
StavkaBody)
{
YourObjectType object = new YourObjectType();
// this will be Populate All Json To Single object And
// You dont Need To Add some Constructors For Done this
JsonConvert.PopulateObject(StavkaBody, objec);
// Example Usage
Console.WriteLine(object.Name);
}
in Here I`ve Used The Newtonsoft.Json For this And Its Make Your Model So Much Simpler.
I Hope Its Helps

Convert value to int

I am trying to convert a value from a CSV file using CsvHelper. The value itself is an integer but the value inside the csv contains a whitespace e.g. "0 " or "12 ".
How can I get it to work now? On StackOverFlow I found this thread but the trimming doesn't apply to the binding. According to a comment from the creator of this library it should since V2.9.0.
How do you ignore Whitespace when using CsvHelper, CsvReader.Read()?
I try to read my CSV in this way:
using (TextReader reader = new StreamReader(datei))
{
CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
configuration.BadDataFound = null;
configuration.TrimOptions = TrimOptions.Trim;
using (var csv = new CsvReader(reader, configuration))
{
ArtikeldatenLieferant = csv.GetRecords<AllnetArtikel>().ToList();
}
}
Edit:
This is one line of my CSV which results in this issue:
Nr.;ALLNET-Artikelnummer;Hersteller-Artikelnummer;Hersteller;Produktbezeichnung;EAN Nummer;Kategorieebene1;Kategorieebene2;Kategorieebene3;HEK;Artikelzustand;UVP;Produktbeschreibung;Gewicht;Lagerbestand
9234;193301;AL-MSUC-SUF-S;Audiocodes Live;Audiocodes Live - AL-MSUC-SUF-S;;Telekommunikation;Voice over IP;Voice over IP - Gateway Support;2739,13;neu;3043,48;"AudioCodes Live non-recurring setup fee, for each customer site with up to 500 users. Includes delivery, Planning and Design consulting service, Implementation service (configuration and basic verification) for AudioCodes hardware or software, and cutover support into production for a single event. Does not include Project Management.;0,001;0
Edit2: Here is the AllnetArtikel class.
public class AllnetArtikel
{
[Name("Nr.")]
public string Nr { get; set; } = string.Empty;
[Name("ALLNET-Artikelnummer")]
public string AllnetArtiNr{ get; set; } = string.Empty;
[Name("Hersteller-Artikelnummer")]
public string HerstellerArtiNr{ get; set; } = string.Empty;
[Name("Hersteller")]
public string Hersteller{ get; set; } = string.Empty;
[Name("Produktbezeichnung")]
public string Produktbezeichnung{ get; set; } = string.Empty;
[Name("EAN Nummer")]
public string EAN{ get; set; } = string.Empty;
[Name("Kategorieebene1")]
public string Kategorie1{ get; set; } = string.Empty;
[Name("Kategorieebene2")]
public string Kategorie2{ get; set; } = string.Empty;
[Name("Kategorieebene3")]
public string Kategorie3{ get; set; } = string.Empty;
[Name("HEK")]
public decimal HEK{ get; set; }
[Name("Artikelzustand")]
public string Zustand{ get; set; } = string.Empty;
[Name("UVP")]
public decimal UVP{ get; set; }
[Name("Produktbeschreibung")]
public string Produktbeschreibung{ get; set; } = string.Empty;
[Name("Gewicht")]
[Default(-1)]
public decimal Gewicht{ get; set; }
[Name("Lagerbestand")]
public int Lagerbestand { get; set; }
}
Final Update
The issue ended up being a quote in a field and the quote was not escaped or the field contained in quotes. ;"AudioCodes ... Management.;. Since the quote was a part of the data that was needed, the solution was to change the configuration mode to NoEscape. This mode will ignore quotes and escape characters.
configuration.Mode = CsvMode.NoEscape;
Update
Any string that works with int.Parse should work with CsvHelper. For instance int.Parse("0 ") == 0. Since having extra whitespace is not an issue and it works when you change your integer field to string, I'm going to take a guess that your issue is actually with an empty value. CsvHelper is unable to convert any empty values into an int. If that is the case, you have two choices.
Either turn your integer field into a Nullable<int>
void Main()
{
CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
using (var reader = new StringReader("Id;Name\n1;Joe\n;Jenny"))
using (var csv = new CsvReader(reader, configuration))
{
var records = csv.GetRecords<Foo>().ToList().Dump();
}
}
public class Foo
{
public int? Id { get; set; }
public string Name { get; set; }
}
Or give your integer field a default value.
void Main()
{
CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
using (var reader = new StringReader("Id;Name\n1;Joe\n;Jenny"))
using (var csv = new CsvReader(reader, configuration))
{
var records = csv.GetRecords<Foo>().ToList().Dump();
}
}
public class Foo
{
[Default(0)]
public int Id { get; set; }
public string Name { get; set; }
}
Original
Are you sure you aren't getting an exception for something else? I can put in as many spaces after the number as I want and it still reads it correctly.
void Main()
{
CsvConfiguration configuration = new CsvConfiguration(CultureInfo.GetCultureInfo("de-DE"));
using (var reader = new StringReader("Id;Name\n1 ;Joe\n10 ;Jenny"))
using (var csv = new CsvReader(reader, configuration))
{
var records = csv.GetRecords<Foo>().ToList();
}
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}

Removing header from a formatted string

I have a formatted log file I'm trying to parse; the file is divided in sections with an header and the data inside each section is formatted with JSON like follows. Link to an extract of the log file here
[UnityCrossThreadLogger]1/8/2019 7:49:19 PM
==> Deck.GetDeckLists(112):
{
"jsonrpc": "2.0",
"method": "Deck.GetDeckLists",
"params": {},
"id": "112"
}
My issue here is manipulating the whole string in a way I get to the section I want and there strip the meaningless data and parse the remaining through Newtonsoft JSON. For now I'm cutting everything I don't need using this function, since the log file is in chronological order and only the latest occurrence of the entry is needed:
//Cut the whole log to the last entry
private static string CutLog(string fromWhereToCut)
{
string log = GetLog();
//In this case fromWhereToCut would be "Deck.GetDeckLists"
string s = log.Substring(log.LastIndexOf(fromWhereToCut));
return s;
}
The problem is the fact it leaves the header in place I need to remove before deserializing the JSON and it's prone to breaking because the name of the sections aren't that unique and they could be repeated further down as non-header titles (as can be seen in my example). Furthermore I don't know how to stop at the end of the section I need before another one begins.
I thought RegEx could be used but this seems way to big even for a RegEx and maybe there's a better solution.
If the Log is the same as the one found in PasteBin, this deserializes fine.
I'm using a support class (JSON_Logs) to contain the extracted data.
The JSON is read from a file in this simulation.
Reading the structure of the data, the most probable candidate to identify the start of the actual data, is the recurring string "Deck.GetDeckLists". In the parsing method it's assigned to a variable called excludedSection.
The data starts right after the last one of those string. I'm using logFile.LastIndexOf(excludedSection) to find the index of the last of these entries, then use this index to identify the first data structure.
JsonConvert.DeserializeObject is then used to deserialize the data into a List of class objects.
I didn't find any problem during the deserialization process.
string searchString = "Deck.GetDeckLists";
List<JSON_Logs.Header> jsonLogs = ParseJsonLog(searchString, "JSON_Logs.txt");
private List<JSON_Logs.Header> ParseJsonLog(string excludedSection, string fileName)
{
string logFile = File.ReadAllText(fileName);
int refIndex = logFile.LastIndexOf(excludedSection);
logFile = logFile.Substring(logFile.IndexOf("[", refIndex));
return JsonConvert.DeserializeObject<List<JSON_Logs.Header>>(logFile);
}
Support class:
public class JSON_Logs
{
public class Header
{
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
public string format { get; set; }
public string resourceId { get; set; }
public int deckTileId { get; set; }
public MainDeck[] mainDeck { get; set; }
public object[] sideboard { get; set; }
public DateTime lastUpdated { get; set; }
public bool lockedForUse { get; set; }
public bool lockedForEdit { get; set; }
public bool isValid { get; set; }
}
public class MainDeck
{
public string id { get; set; }
public int quantity { get; set; }
}
}
I hope this is what you need. :) Actually, regex finds json in all sections, but I included getting only last section (matches[matches.Count - 1]). Since JToken doesn't have TryParse method, you have to use try/catch:
static void ParseLog()
{
var s = File.ReadAllText(#"C:\log.json");
var pattern =
#"(?s)(?'header'\[\w+\]\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}\s(A|P)M\r\n" +
#"<?==>?.+?\r\n)" +
#"(?'body'.+?)(?=$|\[\w+\]\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}\s(A|P)M)";
var matches = Regex.Matches(s, pattern);
if (matches.Count > 0)
{
JToken last_json = null;
try
{
var text = matches[matches.Count - 1].Groups["body"].Value;
last_json = JToken.Parse(text);
WriteLine(last_json.ToString());
}
catch (Exception ex) { WriteLine(ex.ToString()); }
}
else
{
WriteLine("No matches found");
}
}

infinite loop stackoverflow list of objects exception

i have this code:
public List<CsvUserData> CsvUserList = new List<CsvUserData>();
public CsvUserData()
{
readCSV(#"C:\userdata.csv");
}
public string CSVEmailEditText { get; set; }
public string CSVNameEditText { get; set; }
public string CSVAddressEditText { get; set; }
public string CSVPostnumEditText { get; set; }
public string CSVCityEditText { get; set; }
public string CSVPhoneEditText { get; set; }
public string CSVCommentEditText { get; set; }
public string SelectPage { get; set; }
private void readCSV(string location)
{
var reader = new StreamReader(File.OpenRead(location));
string line;
string[] values;
while (!reader.EndOfStream)
{
line = reader.ReadLine();
values = line.Split(',');
CsvUserList.Add
(
new CsvUserData
{
CSVEmailEditText = values[0],
CSVNameEditText = values[1],
CSVAddressEditText = values[2],
CSVPostnumEditText = values[3],
CSVCityEditText = values[4],
CSVPhoneEditText = values[5],
}
);
}
}
I am trying to read csv file into list that consists of objects named CsvUserData, the class definition is displayed above. Once the class is instantiated my program is getting into infinite loop eventually resulting in stackoverflow exception once the list memory is full, even though my csv file only has one row of data. Can someone help me and explain why is this happening?
Let’s see:
Create a new CsvUserData object, call the constructor.
readCSV(#"C:\userdata.csv");
Inside readCSV: Open file, and iterate over the lines.
For each line: new CsvUserData { … }
Go to 1.
So you end up creating new CsvUserData objects from within the constructor of the CsvUserData type. So this will repeat forever.
You probably meant to make the readCSV method static or something, and only call it once. There is really no reason why it should be called from the constructor. And the constructor shouldn’t really open a file and create stuff based on the file; that’s far too much work for a constructor.

How to iterate through Observable collection?

Hi guys i want to ask that i have a Class with properties like following:
public class VLANSPropertyClass
{
public string vname { get; set; }
public int S_No { get; set; }
public string vid { get; set; }
public string ip { get; set; }
public string vports { get; set; }
}
I created an ObservableCollection as follows:
public ObservableCollection<VLANSPropertyClass> vlan { get; set; }
vlan = new ObservableCollection<VLANSPropertyClass>();
I am adding all these values in a datagrid:
void AddVlans()
{
var serial = new VLANSPropertyClass();
serial.S_No = vlan.Count + 1;
Console.WriteLine(serial.S_No);
serial.vname = VlanName;
Console.WriteLine(serial.vname);
serial.vid = VlanID;
Console.WriteLine(serial.vid);
serial.ip = VlanIP1 + "." + VlanIP2 + "." + VlanIP3 + "." + VlanIP4;
Console.WriteLine(serial.ip);
serial.vports = SelectedVlanPort;
vlan.Add(serial);
}
The display looks like following image:
Now i want go through each row and read its values.I tried following but didnt work
foreach(VLANSPropertyClass v in vlan)
{
Console.WriteLine(v);
Console.WriteLine();
}
Kindly tell me the possible way of reading values from ObservableCollection/Datagrid.Any help would be highly appreciable.
You can change your class to this...
public class VLANSPropertyClass
{
public string vname { get; set; }
public int S_No { get; set; }
public string vid { get; set; }
public string ip { get; set; }
public string vports { get; set; }
public override string ToString()
{
return String.Format("Name: {0}, Serial {1}", vname, S_No);
}
}
This change includes an override to the ToString method. It will be called whenever the framework needs a string representation of your class.
ToString is the major formatting method in the .NET Framework. It
converts an object to its string representation so that it is suitable
for display. (For information about formatting support in the .NET
Framework, see Formatting Types.)
source: http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx
Using an override to ToString will let you do this Console.WriteLine(v); with expected results.
When you loop through an ObservableCollection<>, accessing it through index returns a complete instance/item of the collection in form of the string, you now need to reference this string using index or property(in case its a user defined type(class)) in order to access the real content, in my case i am doing this to access temp property of an item of the collection mess.
mess[mj_key][mn_key][0].Temp.ToString()
here i have 3 dimensions, avoid it for now, just understand that 0 index returns string object, i then access temperature using .Temp
Hope it Helps!

Categories