|
I feel dumb asking, but maybe someone has done it already.
I get why it bombs, "$0.00" and convert to 0.00
I find it hard to believe that I have to write a complex custom type converter for this.
And in the CSV file , "$53.00",
public double SoldFor { get; set; }
Map(m => m.SoldFor).Index(25).Default(0.00).TypeConverterOption.NumberStyles(NumberStyles.Currency);
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
|
I'll give that a whirl
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
Wrote a TypeConverter, Took me awhile to understand how it works
I tried modifying the input text, with replace, but was not able to change it's value.
So I went with TryParse to generate a new double to send back, and just used substring to chop the $ off.
I bet the 2nd parse will fail now that I think about it. it should be TryParse as well.
public class PriceConverter<T> : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
var result = 0.00;
if (text.StartsWith("$"))
{
double.TryParse(text.Substring(1, text.Length - 1), out result);<br />
}
else
{
result = double.Parse(text);
}
return result;
}
}
And the map
Map(m => m.SoldFor).Index(25).TypeConverter<PriceConverter<double>>();
Hope this helps somebody in the future
If it ain't broke don't fix it
Discover my world at jkirkerx.com
modified 4-Sep-20 12:40pm.
|
|
|
|
|
jkirkerx wrote: Hope this helps somebody in the future Not if they thing about it. You declare the ConvertFromString with a return of object you then use var inside the method and call the method expecting a double . It would not pass revue!
Also you may want to cater for other currency symbols.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
It's my first type converter, and first time using CSVHelper. Didn't even know it existed till 2 days ago.
It didn't like a return value of double, so I left the object.
I will work on the currency system; or wait I have no way of knowing what marketplace the file is coming from, like Japan, UK which can be French, German, Spanish, English. String Array match.
It's not a program for sale, just for my use. You must think I will grow really fast and sell around the world, appreciate the lift in spirits there. Next markets I enter will be Canada and Malaysia. I can't afford to ship goods to Europe.
Appreciate the feedback seriously, I'll make those changes. But sticking with NoSQL.
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
I'm working on it, but really wanted to see some results today like my first database/collection write.
Thank God I only have the 2 CSV files to download. But Amazon allows for uploading Inventory, Prices, and shipping plans. Not sure about the format, probably CSV.
I know what I want to be able to do in this app, and the data I need to see. Using both marketplaces over the last 4 months has shown me that I don't have all the data I need to fill out a tax return, or show the state how much tax was collected. I can't account for all the inventory I purchased and sold. And I'm not a wiz with Excel, don't even know where to start with it. I don't even know how much money I made so I can pay myself. I've sold so much, that I don't have time to hand enter all the data. Just too many entries.
public class AmazonDateConverter<T> : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
var ci = CultureInfo.GetCultureInfo("en-us");
return DateTime.Parse(text, ci);
}
}
public class AmazonPriceConverter<T> : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
var result = 0.00;
if (text.StartsWith("$"))
{
double.TryParse(text.Substring(1, text.Length - 1), out result);
}
else
{
double.TryParse(text, out result);
}
return result;
}
}
public class EBayYesNoConverter<T> : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if (text.ToLower().Equals("yes"))
{
return true;
}
else if (text.ToLower().Equals("no"))
{
return false;
}
return false;
}
}
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
The IRS don't care.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
I was talking about my state and sales tax, they are brutal.
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
I'm stumped here. Writing a program for myself to keep track of Amazon and EBay sales. On this Ebay report, the first line is a string of comma's, and then the header. Some of the header columns are unquoted and some are quoted to represent text.
I don't know if the string comma's is a blank line, or what. And not sure how to tell CsvHelper about the quotes in the column names.
I guess the string of commas is a line, because the line has a line feed. That's solved.
My problem is the usual won't work issue. Guess I could edit the file and remove the commas and test to see if the column reads, No, the first column doesn't read and it doesn't have quotes. So it's the first line that's my issue.
I wonder why EBay put that line of commas in as the first line, must mean something.
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Sales Record Number,"Order Number","Buyer Username","Buyer Name","Buyer Email","Buyer Note","Buyer Address 1","Buyer Address 2","Buyer City","Buyer State","Buyer Zip","Buyer Country","Ship To Name","Ship To Phone","Ship To Address 1","Ship To Address 2","Ship To City","Ship To State","Ship To Zip","Ship To Country","Item Number",Item Title,"Custom Label","Sold Via Promoted Listings","Quantity","Sold For","Shipping And Handling","Seller Collected Tax","eBay Collected Tax","Electronic Waste Recycling Fee","Mattress Recycling Fee","Additional Fee","Total Price","eBay Collected Tax and Fees Included in Total","Payment Method","Sale Date","Paid On Date","Ship By Date","Minimum Estimated Delivery Date","Maximum Estimated Delivery Date","Shipped On Date","Feedback Left","Feedback Received","My Item Note","PayPal Transaction ID","Shipping Service","Tracking Number","Transaction ID","Variation Details","Global Shipping Program","Global Shipping Reference ID","Click And Collect","Click And Collect Reference Number","eBay Plus","Authenticity Verification Program","Authenticity Verification Status","Authenticity Verification Outcome Reason"
,"","","","","","","","","","","","","","","","","","","","",,"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
My map
Map(m => m.SalesRecordNumber).Name("Sales Record Number").Index(0);
Map(m => m.OrderNumber).Name("Order Number").Index(1);
Map(m => m.BuyerUsername).Name("Buyer Username").Index(2);
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
Are you sure it's not an artifact of your download process? How did you get teh data?
The first row of a CSV file can normally be one of three things:
1) A header row giving the column titles.
2) The first row of data
Or
3) A row indicating a "custom separator": "Sep=|" for example is used by Excel: Comma-separated values - Wikipedia[^]
I've never seen a valid CSV file with anything else as the top row.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I downloaded it again thinking the same thing.
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
I've seen one case in 30 years where the first TWO rows were headers. Yeah, it's not what anyone would call "standard", but there it was.
The first row was column types and the second row contained the column names.
|
|
|
|
|
Since you're mapping by index, you could skip the first two lines in the TextReader before you pass it to the CsvReader , and tell it there is no header:
using (TextReader reader = ...)
{
reader.ReadLine();
reader.ReadLine();
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.RegisterClassMap<FooMap>();
var records = csv.GetRecords<Foo>()
...
}
}
...
public class Foo
{
public string SalesRecordNumber { get; set; }
public int OrderNumber { get; set; }
public string BuyerUsername { get; set; }
}
public class FooMap : ClassMap<Foo>
{
public FooMap()
{
Map(m => m.SalesRecordNumber).Index(0);
Map(m => m.OrderNumber).Index(1);
Map(m => m.BuyerUsername).Index(2);
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I think I'll just write some code to dump the first line.
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
My guess is the line of comma's was an afterthought, and got added to "solve" some problem related to the inconsistent quote situation in the original title line; so now the title line is basically empty, and the column names appear in the first data row, which could be good enough for people reading the table on screen, not for a program trying to interpret it all.
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
|
|
|
|
|
Excel imports the first line as blank cells, then the header is on the 2nd line.
Amazon version is much nicer, and easier to work with.
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
I took the names out of the map. Then did the readline twice to skip the comma's and header, and turned off read header.
So I can read the file and populate the model now. Just need to fix the number conversions, everything in the model is a string now. But I'm 3 steps closer now. Thanks for all the help!
namespace MarketPlace.CsvParser
{
public class EBayCsvParser
{
public static async Task<List<EBayCsvImport>> Import_EBayOrderFile(string appPath)
{
var pOrders = new List<EBayCsvImport>();
try
{
using (var reader = new StreamReader(appPath))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.Delimiter = ",";
csv.Configuration.Encoding = Encoding.UTF8;
csv.Configuration.MissingFieldFound = null;
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.HeaderValidated = null;<br />
csv.Configuration.CultureInfo = CultureInfo.InvariantCulture;
csv.Configuration.TypeConverterOptionsCache.GetOptions(typeof(decimal)).NumberStyle = NumberStyles.AllowCurrencySymbol | NumberStyles.AllowThousands;
csv.Configuration.PrepareHeaderForMatch = (header, index) => header.ToLower();
csv.Configuration.RegisterClassMap<EBayCsvImportMap>();
reader.ReadLine();
reader.ReadLine();
csv.Read();<br />
pOrders = csv.GetRecords<EBayCsvImport>().ToList();
Console.Write(pOrders);
}
}
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
await Task.Delay(100);
return pOrders;
}
}
}
If it ain't broke don't fix it
Discover my world at jkirkerx.com
|
|
|
|
|
We seem to assume the big boys always know what they're doing. If the comas line up, it simply looks like 3 stabs at a header.
1) No quotes, no data.
2) Quotes and data.
3) Quotes, no data.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
Hey guys i'm trying to handle a server request by console app. I have a Listener class that implements a delegate and do some stuff when receive the request.
Now im getting calls by postman in localhost, and don't know how to implement to get server calls (idk if need other application for this like dotnet server or idk).
The calls is based in the appClientCode so i need to get only the client call can be more clients on but they din't notice about other calls.
How can i manage that? Code below.
Anyway thx.
Listener class:
<pre>using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace MyListener
{
public delegate byte[] ProcessDataDelegate(string data);
class MyListener
{
private const int HandlerThread = 2;
private readonly ProcessDataDelegate handler;
private readonly HttpListener listener;
public MyListener(HttpListener listener, string url, ProcessDataDelegate handler)
{
this.listener = listener;
this.handler = handler;
listener.Prefixes.Add(url);
}
public void Start()
{
if (listener.IsListening)
return;
listener.Start();
for (int i = 0; i < HandlerThread; i++)
{
listener.GetContextAsync().ContinueWith(ProcessRequestHandler);
}
}
public void Stop()
{
if (listener.IsListening)
listener.Stop();
}
private void ProcessRequestHandler(Task<HttpListenerContext> result)
{
try
{
if (!listener.IsListening)
return;
listener.GetContextAsync().ContinueWith(ProcessRequestHandler);
string request = new StreamReader(result.Result.Request.InputStream).ReadToEnd();
var responseBytes = handler.Invoke(request);
result.Result.Response.ContentLength64 = responseBytes.Length;
var output = result.Result.Response.OutputStream;
output.WriteAsync(responseBytes, 0, responseBytes.Length);
output.Close();
}
catch (Exception)
{
}
}
}
}
Main class (Console):
using System;
using System.Collections.Generic;
using System.Net;
namespace MyListener
{
class Program
{
static MyListener myListener;
static bool bussy = false;
static void Main(string[] args)
{
Console.WriteLine("Listening...");
StartListener("1");
Console.ReadKey();
}
public static void StartListener(string clientCode)
{
var httpListener = new HttpListener();
myListener = new MyListener(httpListener, string.Format("{0}{1}/", "http://127.0.0.1/", clientCode), ProcessYourResponse);
myListener.Start();
}
public static byte[] ProcessYourResponse(string requestParams)
{
if (bussy)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Call end[{0}]\n\n", DateTime.Now.ToString());
Console.ResetColor();
bussy = false;
return new byte[0];
}
Dictionary<string, string> responseData = MakeNewDictionaryFromResponse(requestParams);
bussy = true;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("New call [{0}]:", DateTime.Now.ToString()) ;
Console.ResetColor();
Console.WriteLine("Key Value");
Console.WriteLine("=====================================================================================");
foreach (KeyValuePair<string, string> entry in responseData)
{
Console.WriteLine("{0}{1}{2}",entry.Key.PadRight(16), " ".PadRight(30),entry.Value);
}
return new byte[0];
}
private static Dictionary<string, string> MakeNewDictionaryFromResponse(string requestParams)
{
string[] splitParams = requestParams.Split('&');
Dictionary<string, string> aux = new Dictionary<string, string>();
foreach (var item in splitParams)
{
string[] tmp = item.Split('=');
aux.Add(tmp[0], tmp[1]);
}
return aux;
}
}
}
|
|
|
|
|
Quote: I have a Listener class that implements a delegate and do some stuff when receive the request. If this is a fresh project, I would recommend moving to a more web-development framework to write more secure, stable, and scalable apps; such as with ASP.NET Core. With ASP.NET Core, you can just specify a single Controller and let it handle your requests for you. On top of that, you get several benefits:
- Parsing of the HTTP request/response.
- Security features and authentication.
- Caching support
- Publishing/hosting support with leading cloud hosting platforms
If you really want to handle the low-level details of the HTTP protocol (which, I again suggest not to), then I think you have got it working.
Quote: Now im getting calls by postman in localhost, and don't know how to implement to get server calls (idk if need other application for this like dotnet server or idk). Your application is already on a server; localhost. If you want to move it to something like www.yourdomain.com , then that is more about the deployment of the application. Deploy it to a hosting platform and apply your domain name to it.
Quote: The calls is based in the appClientCode so i need to get only the client call can be more clients on but they din't notice about other calls. Although I have not checked your code by running it, but your code "should" spawn a new thread for each request and handle the requests in an isolated manner. That shouldn't be an issue.
Once again, go with ASP.NET Core, and you can write an ASP.NET Core API that provides the HTTP access to your clients and server and makes it easier to work with HTTP protocol.
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
Hello all,
I'm just learning to use C# Inheritance.
It is quite clear to me (I've worked with C++ in the past).
I've a problem with two classes.
So, imagine a base class, which contain a sub-class; the sub-class is used to collect data.
I used a sub-class because I need to write and read it from a disk, using a XmlSerializer.
The base class has the needed public Save/Load members, that serialize the sub-class.
I now have to Inherit the base class multiple times; the only differnece in the derived classes is the sub-class, that have a slightly different format for each derived class.
I created few derived classes, re-definind into them the sub-class wth the keyboard "new".
Unfortunately, everytime I call the Save/Load members (defined in the base class) from the derived classes, these methods actually save ansd load the sub-class defined into the base class, not the one defined into the calling derived class.
What I'm doing wrong?
Here below an excerpt of my code, with the definition of the two classes (heavily simplified, of course):
public class BaseClass
{
public class Data
{
public int data1 = 1;
public int data2 = 1;
public string Data3 = "BaseString";
}
public Data data = new Data();
public bool Save(string Filename)
{
var xs = new XmlSerializer(Data.GetType());
using (TextWriter sw = new StreamWriter(Filename))
{
xs.Serialize(sw, Obj);
}
return File.Exists(Filename);
}
public static T Load<T>(Filename)
{
Object rslt;
var xs = new XmlSerializer(typeof(T));
using (var sr = new StreamReader(FileName))
{
rslt = (T)xs.Deserialize(sr);
}
return (T)rslt;
}
}
public DerivedClass : BaseClass
{
public new class Data
{
public int data1 = 2;
public int data2 = 2;
public string Data3 = "DerivedString";
public int Data4 = 2;
}
public new Data data = new Data();
}
Now, using them as follows gives me the error that the base class Data are saved:
DerivedClass MyClass = new DerivedClass();
MyClass.Save("Test.xml");
Any clue?
I know this is probably quite trivial, but please help me.
Thank you in advance.
Ciao,
Giovanni
|
|
|
|
|
Members declared with new will not be visible to the base class. When code in the base class looks for the Data member, it will use its own member, not the "shadowed" member declared by the derived class.
Members which are meant to be overridden in a derived class must be marked as virtual , and overridden properly in the derived class.
Knowing When to Use Override and New Keywords - C# Programming Guide | Microsoft Docs[^]
However, a nested class cannot be marked as "virtual". Instead, you will need to inherit from it. You will also need to use a constructor to overwrite the default field values.
public class BaseClass
{
public class Data
{
public int data1 = 1;
public int data2 = 1;
public string data3 = "BaseString";
}
public Data Value { get; }
public BaseClass()
{
Value = new Data();
}
}
public class DerivedClass : BaseClass
{
public class DerivedData : BaseClass.Data
{
public int data4 = 2;
public DerivedData()
{
data1 = 2;
data2 = 2;
data3 = "DerivedString";
}
}
public DerivedClass()
{
Value = new DerivedData();
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hllo,
Thank you very much for the answer, Richard.
Now everything is clear, and sound logic.
I will modify my code as for you suggestions.
Regards,
Giovanni
|
|
|
|
|
See if Richard's excellent response, and this code ... gives you some ideas:
using System;
using System.IO;
using System.Xml.Serialization;
namespace TextToClasses
{
public class BaseClass
{
public class Data
{
public int Data1;
public int Data2;
public string Data3;
public Data()
{
}
public Data(int data1, int data2, string data3)
{
Data1 = data1;
Data2 = data2;
Data3 = data3;
}
}
public Data TheData;
public bool Save(string Filename, Data data)
{
var xs = new XmlSerializer(data.GetType());
using (TextWriter sw = new StreamWriter(Filename))
{
xs.Serialize(sw, data);
}
return File.Exists(Filename);
}
public Data Load(string Filename, Type type)
{
Data rslt;
var xs = new XmlSerializer(type);
using (var sr = new StreamReader(Filename))
{
rslt = (Data) xs.Deserialize(sr);
}
return rslt;
}
}
public class DerivedClass : BaseClass
{
public class DerivedData : BaseClass.Data
{
public int Data4;
public DerivedData()
{
}
public DerivedData(int data4, int data1, int data2, string data3) : base(data1, data2, data3)
{
Data4 = data4;
}
}
}
} Sample usage:
BaseClass bc = new BaseClass();
bc.TheData = new BaseClass.Data(1,1,"BaseString");
bc.Save(@"C:\Users\test_user\Desktop\Basedata.xml", bc.TheData);
var bcdata = bc.Load(@"C:\Users\test_user\Desktop\Basedata.xml", bc.TheData.GetType());
DerivedClass dc = new DerivedClass();
dc.TheData = new DerivedClass.DerivedData(4, 2, 2, "DerivedString");
dc.Save(@"C:\Users\test_user\Desktop\Deriveddata.xml", dc.TheData);
var dcdata = dc.Load(@"C:\Users\test_user\Desktop\Deriveddata.xml", dc.TheData.GetType());
I am sure this can be improved
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|