I have ASP.Net site. I have JSON string that need to exported to physical CSV file.
private String JsonToCsv(string jsonData, string delimiter)
{
try
{
StringWriter swObj = new StringWriter();
using (var csv = new CsvWriter(swObj))
{
csv.Configuration.SkipEmptyRecords = true;
csv.Configuration.WillThrowOnMissingField = false;
csv.Configuration.Delimiter = delimiter;
using (var dt = jsonStringToTable(jsonData))
{
foreach (DataColumn col in dt.Columns)
{
csv.WriteField(col.ColumnName);
}
csv.NextRecord();
foreach(DataRow row in dt.Rows)
{
for (var i = 0; i < dt.Columns.Count; i++)
{
csv.WriteField(row[i]);
}
csv.NextRecord();
}
}
}
return swObj.ToString();
}
catch (Exception ex)
{
//handle exception
return null;
}
}
private DataTable jsonStringToTable(string jsonContent)
{
DataTable dt = JsonConvert.DeserializeObject<DataTable>(jsonContent);
return dt;
}
public HttpResponseMessage ExportToCSV(string jsonData)
{
string csv = JsonToCsv(jsonData, ",");
HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.OK);
res.Content = new StringContent(csv);
res.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
res.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "export.csv" };
return res;
}
But neither I am getting any exception nor CSV file is getting any data.
The Export.csv is located in the root folder.
How do I export the JSON & auto download the file??
It seems you do have an error, that you are suppressing in your catch.
Your first error is in that your jsonContent is not actually json. You have a variable assignment jsonContent = [...] in your sample. the section [...] is your actual json.
to handle that, you need only compose it better, by not having it assign to a variable (recommended approach), or handle instances here with jsonContent.Split(new [] {'='}).Last(). (a declarative vs imperative approach/strategy).
Also, you are attempting to deserialize into an incorrect type, for it does not reflect your json data structure.
although there are other manners to convert and process one string to another. I do agree the proper thing to do here is to deserialize your object (or not serialize beforehand - recommended).
I'm providing a sample Console Application for you to review two implementations of handle a JsonToCsv operation.
dynamic (imperative)
and providing a Type and using System.Reflection on that type. (declarative to the Json.Convert.DeserializeObject<T>() method, imperative afterward)
there is a dependency on NewtonSoft.Json Assembly (Install it via NuGet package) in this implementation; it reflects your provided code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.Reflection;
using Newtonsoft;
namespace JsonToCsvTests
{
using Newtonsoft.Json;
using System.IO;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
TestJsonToCsv();
Console.ReadLine();
}
static void TestJsonToCsv()
{
string jsonData = #"jsonData = [
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:06:25.083"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
},
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:12:02.497"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
},
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:13:48.013"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
}]";
Console.WriteLine("...using System.Dynamic and casts");
Console.WriteLine();
Console.WriteLine(JsonToCsv(jsonData, ","));
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("...using a provided StrongType with System.Reflection.");
Console.WriteLine();
Console.WriteLine(JsonToCsv<JsonData>(jsonData, ","));
}
static private string JsonToCsv(string jsonContent, string delimiter)
{
var data = jsonStringToTable(jsonContent);
var headers = ((IEnumerable<dynamic>)((IEnumerable<dynamic>)data).First()).Select((prop) => prop.Name).ToArray();
var csvList = new List<string>
{
string.Join(delimiter, headers.Select((prop) => string.Format(#"""{0}""", prop)).ToArray())
};
var lines = ((IEnumerable<dynamic>)data)
.Select(row => row)
.Cast<IEnumerable<dynamic>>()
.Select((instance) => string.Join(delimiter, instance.Select((v) => string.Format(#"""{0}""", v.Value))))
.ToArray();
csvList.AddRange(lines);
return string.Join(Environment.NewLine, csvList );
}
static private string JsonToCsv<T>(string jsonContent, string delimiter) where T : class
{
var data = jsonStringToTable<T>(jsonContent);
var properties = data.First().GetType().GetProperties();
var lines = string.Join(Environment.NewLine,
string.Join(delimiter, properties.Select((propInfo) => string.Format(#"""{0}""", propInfo.Name))),
string.Join(Environment.NewLine, data.Select((row) => string.Join(delimiter, properties.Select((propInfo) => string.Format(#"""{0}""", propInfo.GetValue(row)))))));
return lines;
}
static private dynamic jsonStringToTable(string jsonContent)
{
var json = jsonContent.Split(new[] { '=' }).Last();
return JsonConvert.DeserializeObject<dynamic>(json);
}
static private IEnumerable<T> jsonStringToTable<T>(string jsonContent) where T : class
{
var json = jsonContent.Split(new[] { '=' }).Last();
return JsonConvert.DeserializeObject<IEnumerable<T>>(json);
}
public class JsonData
{
public string DocumentName { get; set; }
public DateTime ActionDate { get; set; }
public string ActionType { get; set; }
public string ActionPerformedBy { get; set; }
}
}
}
Console.Output
...using System.Dynamic and casts
"DocumentName","ActionDate","ActionType","ActionPerformedBy"
"Test Document","9/25/2015 4:06:25 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:12:02 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:13:48 PM","View","Sreeja SJ"
...using a provided StrongType with System.Reflection.
"DocumentName","ActionDate","ActionType","ActionPerformedBy"
"Test Document","9/25/2015 4:06:25 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:12:02 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:13:48 PM","View","Sreeja SJ"
This is what i use to generate CSV file on my ASP.NET Website
public static class CSVUtils
{
public static void AddCsvLine(bool isFrenchSeparator, StringBuilder csv, params object[] values)
{
foreach (var value in values)
{
csv.Append('"').Append(value).Append('"');
if (isFrenchSeparator)
{
csv.Append(';');
}
else
{
csv.Append(',');
}
}
csv.Append('\r'); // AppendLine() adds a double line break with UTF32Encoding
}
}
public FileContentResult ExportCSV()
{
StringBuilder csv = new StringBuilder();
CSVUtils.AddCsvLine(false, csv, "Field1", "Field2", "Field3");
CSVUtils.AddCsvLine(false, csv, "value1", "value2", "value3");
return this.File(new UTF32Encoding().GetBytes(csv.ToString()), "text/csv", "myfile.csv");
}
I basically call the ExportCSV action from my website, on a button click for example and it downloads the file. Make sure to clean your JSON beforehand from all coma otherwise it would mess your CSV file.
EDIT: Specifically for JSON, you'd also have to anti-slash every " otherwise it would mess the StringBuilder i guess
Related
I understand that this question have been asked many times (1, 2 & 3) but I just don't understand how to apply it in my case. I have tried playing around for hours but I cannot get it right.
I have variables in the form of List<string>where each list contain datas that have line breaks between them/multiline data. Then I called an event that would export these datas in a CSV file. Below is my code.
savestate.cs - class where I initialized the variables
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>();
public static List<string> rtb2_list = new List<string>();
public static List<string> rtb3_list = new List<string>();
public static List<string> rtb4_list = new List<string>();
}
Form1.cs - The event
public void Savetocsv()
{
Type s = typeof(Savestate);
FieldInfo[] fields = s.GetFields(BindingFlags.Public | BindingFlags.Static);
StringBuilder csvdata = new StringBuilder();
string header = String.Join(",", fields.Select(f => f.Name).ToArray());
csvdata.AppendLine(header);
string rtb1 = String.Join(",", Savestate.rtb1_list.ToArray());
string rtb2 = String.Join(",", Savestate.rtb2_list.ToArray());
string rtb3 = String.Join(",", Savestate.rtb3_list.ToArray());
string rtb4 = String.Join(",", Savestate.rtb4_list.ToArray());
string newlinestring = string.Format("{0}; {1}; {2}; {3}", rtb1, rtb2, rtb3, rtb4);
csvdata.AppendLine(newlinestring);
string filepath = #"C:\new.csv";
File.WriteAllText(filepath, csvdata.ToString());
}
However when I opened the CSV file, the words are all over the place. For example I wrote hi then a new line then I wrote bye. This is the actual output and this is my intended output.Hope that I can get help.
To insert line breaks in csv file you need to surround string with double quotes, so desired output is generated by following code :
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>() { "hi1", "bye1" };
public static List<string> rtb2_list = new List<string>() { "hi2", "bye2" };
public static List<string> rtb3_list = new List<string>() { "hi3", "bye3" };
public static List<string> rtb4_list = new List<string>() { "hi4", "bye4" };
}
public static void Savetocsv()
{
Type s = typeof(Savestate);
FieldInfo[] fields = s.GetFields(BindingFlags.Public | BindingFlags.Static);
StringBuilder csvdata = new StringBuilder();
string header = String.Join(",", fields.Select(f => f.Name).ToArray());
csvdata.AppendLine(header);
string rtb1 = String.Join("\n", Savestate.rtb1_list.ToArray());
string rtb2 = String.Join("\n", Savestate.rtb2_list.ToArray());
string rtb3 = String.Join("\n", Savestate.rtb3_list.ToArray());
string rtb4 = String.Join("\n", Savestate.rtb4_list.ToArray());
string newlinestring = string.Format("\"{0}\",\" {1}\",\" {2}\",\" {3}\"", #rtb1, #rtb2, #rtb3, #rtb4);
csvdata.AppendLine(newlinestring);
string filepath = #"new.csv";
File.WriteAllText(filepath, csvdata.ToString());
}
Output file:
I suggest using CsvHelper Nuget Package when dealing with CSV, then try doing the following, I added an extension method to print each rtb list as one string:
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>() { "hi", "bye" };
public static List<string> rtb2_list = new List<string>() { "hi", "bye" };
public static List<string> rtb3_list = new List<string>() { "hi", "bye" };
public static List<string> rtb4_list = new List<string>() { "hi", "bye" };
}
public static class SavestateExtensions
{
public static string GetRtbListAsString(this IEnumerable<string> rtb_list)
{
StringBuilder str = new StringBuilder();
foreach (var value in rtb_list)
{
str.AppendLine(value);
}
return str.ToString();
}
}
Then use the CsvWriter from CSVHelper:
using (var writer = new StreamWriter("file.csv"))
{
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.Encoding = Encoding.UTF8;
csvWriter.WriteField("rtb1_list ");
csvWriter.WriteField("rtb2_list ");
csvWriter.WriteField("rtb3_list ");
csvWriter.WriteField("rtb4_list ");
csvWriter.NextRecord();
csvWriter.WriteField(Savestate.rtb1_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb2_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb3_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb4_list.GetRtbListAsString());
csvWriter.NextRecord();
}
}
The output should be as the following:
I have write a C# Program to Generate "Json" File for Eway Bill Uploading
My Json Format is :- (Its not working When I upload in EwayBill)
Please help me,how to do this
[{"Supply Type":"Outward","Sub Type":"Export","Doc Type":"Tax Invoice","Doc No":"PK/18/0015","Doc Date":"16/02/2018 00:00:00","From_OtherPartyName":"KH Exports India Private Limited Glove Division","From_GSTIN":"33AAACR1714R1ZA","From_Address1":"142/1,Trunk Road","From_Address2":"Perumugai","From_Place":"Vellore","From_Pin Code":"632009","From_State":"Tamil Nadu","To_OtherPartyName":"K H EXPORTS INDIA PRIVATE LIMITED","To_GSTIN":"33AAACR1714R1ZA","To_Address1":"GLOVE DIVISION, GODOWN","To_Address2":"NEW NO. 24, KUMARAPPA STREET,","To_Place":"Chennai","To_Pin Code":"600003","To_State":"Tamil Nadu","Product":"FINISHED LEATHER GLOVES FOR LADIES","Description":"","HSN":"42032920","Unit":"PAIRS","Qty":"25","Assessable Value":"678","Tax Rate (S+C+I+Cess)":"9+9+0+0","CGST Amount":"6102","SGST Amount":"6102","IGST Amount":"0","CESS Amount":"0","Trans Mode":"Road","Distance (Km)":"115","Trans Name":"","Trans ID":"","Trans DocNo":"","Trans Date":"","Vehicle No":"TN23CB8274","Errors List":""}]
The below json is working fine (I get this json from eway bill website)
{
"version":"1.0.0123",
"billLists":[{
"userGstin":"29BQSPA3829E124",
"supplyType":"O",
"subSupplyType":1,
"docType":"INV",
"docNo":"1234",
"docDate":"04/03/2017",
"fromGstin":"29BQSPA3829E124",
"fromTrdName":"HUKKERI PVT LTD",
"fromAddr1":"OLD AIRPORT ROAD",
"fromAddr2":"OLD AIRPORT ROAD",
"fromPlace":"BANGALORE",
"fromPincode":560090,
"fromStateCode":29,
"toGstin":"29AAACG0569P1Z3",
"toTrdName":"AMBUJA PVT LTD",
"toAddr1":"MG ROAD",
"toAddr2":"MG ROAD",
"toPlace":"BANGALORE",
"toPincode":560090,
"toStateCode":29,
"totalValue":678,
"cgstValue":6102,
"sgstValue":6102,
"igstValue":0,
"cessValue":0,
"transMode":1,
"transDistance":567,
"transporterName":"",
"transporterId":"",
"transDocNo":"",
"transDocDate":"",
"vehicleNo":"KA12KA1234",
"itemList":[{
"itemNo":1,
"productName":"STEEL",
"productDesc":"STEEL",
"hsnCode":26180000,
"quantity":0,
"qtyUnit":"KGS",
"taxableAmount":678,
"sgstRate":9,
"cgstRate":9,
"igstRate":0,
"cessRate":0
}
]
}
]
}
I have tried below but its not solved...please check this code...
public bool WriteJason(DataTable dt, string path)
{
try
{
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<Dictionary<string, string>> rows = new List<Dictionary<string, string>>();
Dictionary<string, string> row = null;
foreach (DataRow dr in dt.Rows)
{
row = new Dictionary<string, string>();
foreach (DataColumn col in dt.Columns)
{
row.Add(col.ColumnName.Trim().ToString(), Convert.ToString(dr[col]));
}
rows.Add(row);
}
string jsonstring = serializer.Serialize(rows);
using (var file = new StreamWriter(path, false))
{
file.Write(jsonstring);
file.Close();
file.Dispose();
}
return true;
}
catch { return false; }
}
As #mcy mentionned in a comment, you'll have an easier time using Json.NET.
To expand a little on this idea, I would personally take this approach:
Define a model that matches your Json-structure:
private class JsonModel
{
public string Version { get; set; }
public IList<JsonBillModel> BillLists { get; set; } = new List<JsonBillModel>();
}
private class JsonBillModel
{
public string UserGstin { get; set; }
public string SupplyType { get; set; }
public int SubSupplyType { get; set; }
public string DocType { get; set; }
//...
}
Create an instance of your model
var model = new JsonModel
{
Version = "1.0.0123",
BillLists =
{
new JsonBillModel
{
UserGstin = "29BQSPA3829E124",
SupplyType = "O",
SubSupplyType = 1,
DocType = "INV"
//...
}
}
};
Serialze your model to Json using Json.NET:
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
var json = JsonConvert.SerializeObject(model, serializerSettings);
File.WriteAllText(path, json);
The reason we create an instance of JsonSerializerSettings with a CamelCasePropertyNamesContractResolver contract resolver is that our model would otherwise generate PascalCase keys in our Json (since our model is written in a PascalCase-format. If this sounds confusing, try leaving out the ContractResolver-line and see the result for yourself.
Write a test to ensure that your Json output matches your desired output, using your favourite testing library.
Sidenote: you can also use Json.NET to convert json into an instance of your model.
var model = JsonConvert.DeserializeObject<JsonModel>(json);
You have 2 option to create a JSON file.
using text editor like notepad
using online tools like JSON parser
Create a file from the JSON URL
if you want full process it provide in Learning Container.
I am using JSON.NET and C# 5. I need to serialize/de-serialize list of objects into line delimited json. http://en.wikipedia.org/wiki/Line_Delimited_JSON. Example,
{"some":"thing1"}
{"some":"thing2"}
{"some":"thing3"}
and
{"kind": "person", "fullName": "John Doe", "age": 22, "gender": "Male", "citiesLived": [{ "place": "Seattle", "numberOfYears": 5}, {"place": "Stockholm", "numberOfYears": 6}]}
{"kind": "person", "fullName": "Jane Austen", "age": 24, "gender": "Female", "citiesLived": [{"place": "Los Angeles", "numberOfYears": 2}, {"place": "Tokyo", "numberOfYears": 2}]}
Why I needed because its Google BigQuery requirement https://cloud.google.com/bigquery/preparing-data-for-bigquery
Update: One way I found is that serialize each object seperataly and join in the end with new-line.
You can do so by manually parsing your JSON using JsonTextReader and setting the SupportMultipleContent flag to true.
If we look at your first example, and create a POCO called Foo:
public class Foo
{
[JsonProperty("some")]
public string Some { get; set; }
}
This is how we parse it:
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var jsonReader = new JsonTextReader(new StringReader(json))
{
SupportMultipleContent = true // This is important!
};
var jsonSerializer = new JsonSerializer();
while (jsonReader.Read())
{
Foo foo = jsonSerializer.Deserialize<Foo>(jsonReader);
}
If you want list of items as result simply add each item to a list inside the while loop to your list.
listOfFoo.Add(jsonSerializer.Deserialize<Foo>(jsonReader));
Note: with Json.Net 10.0.4 and later same code also supports comma separated JSON entries see How to deserialize dodgy JSON (with improperly quoted strings, and missing brackets)?)
To implement with .NET 5 (C# 9) and the System.Text.Json.JsonSerializer class, and for "big" data, I wrote code for streaming processing.
Using the System.IO.Pipelines extension package, this is quite efficient.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
static readonly byte[] NewLineChars = {(byte)'\r', (byte)'\n'};
static readonly byte[] WhiteSpaceChars = {(byte)'\r', (byte)'\n', (byte)' ', (byte)'\t'};
private static async Task Main()
{
JsonSerializerOptions jsonOptions = new(JsonSerializerDefaults.Web);
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var pipeReader = PipeReader.Create(contentStream);
await foreach (var foo in ReadItemsAsync<Foo>(pipeReader, jsonOptions))
{
Console.WriteLine($"foo: {foo.Some}");
}
}
static async IAsyncEnumerable<TValue> ReadItemsAsync<TValue>(PipeReader pipeReader, JsonSerializerOptions jsonOptions = null)
{
while (true)
{
var result = await pipeReader.ReadAsync();
var buffer = result.Buffer;
bool isCompleted = result.IsCompleted;
SequencePosition bufferPosition = buffer.Start;
while (true)
{
var(value, advanceSequence) = TryReadNextItem<TValue>(buffer, ref bufferPosition, isCompleted, jsonOptions);
if (value != null)
{
yield return value;
}
if (advanceSequence)
{
pipeReader.AdvanceTo(bufferPosition, buffer.End); //advance our position in the pipe
break;
}
}
if (isCompleted)
yield break;
}
}
static (TValue, bool) TryReadNextItem<TValue>(ReadOnlySequence<byte> sequence, ref SequencePosition sequencePosition, bool isCompleted, JsonSerializerOptions jsonOptions)
{
var reader = new SequenceReader<byte>(sequence.Slice(sequencePosition));
while (!reader.End) // loop until we've come to the end or read an item
{
if (reader.TryReadToAny(out ReadOnlySpan<byte> itemBytes, NewLineChars, advancePastDelimiter: true))
{
sequencePosition = reader.Position;
if (itemBytes.TrimStart(WhiteSpaceChars).IsEmpty)
{
continue;
}
return (JsonSerializer.Deserialize<TValue>(itemBytes, jsonOptions), false);
}
else if (isCompleted)
{
// read last item
var remainingReader = sequence.Slice(reader.Position);
ReadOnlySpan<byte> remainingSpan = remainingReader.IsSingleSegment ? remainingReader.First.Span : remainingReader.ToArray();
reader.Advance(remainingReader.Length); // advance reader to the end
sequencePosition = reader.Position;
if (!remainingSpan.TrimStart(WhiteSpaceChars).IsEmpty)
{
return (JsonSerializer.Deserialize<TValue>(remainingSpan, jsonOptions), true);
}
else
{
return (default, true);
}
}
else
{
// no more items in sequence
break;
}
}
// PipeReader needs to read more
return (default, true);
}
}
public class Foo
{
public string Some
{
get;
set;
}
}
Run at https://dotnetfiddle.net/M5cNo1
I'm sure its very straightforward but I am struggling to figure out how to write an array to file using CSVHelper.
I have a class for example
public class Test
{
public Test()
{
data = new float[]{0,1,2,3,4};
}
public float[] data{get;set;}
}
i would like the data to be written with each array value in a separate cell. I have a custom converter below which is instead providing one cell with all the values in it.
What am I doing wrong?
public class DataArrayConverter<T> : ITypeConverter
{
public string ConvertToString(TypeConverterOptions options, object value)
{
var data = (T[])value;
var s = string.Join(",", data);
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
throw new NotImplementedException();
}
public bool CanConvertFrom(Type type)
{
return type == typeof(string);
}
public bool CanConvertTo(Type type)
{
return type == typeof(string);
}
}
To further detail the answer from Josh Close, here what you need to do to write any IEnumerable (including arrays and generic lists) in a recent version (anything above 3.0) of CsvHelper!
Here the class under test:
public class Test
{
public int[] Data { get; set; }
public Test()
{
Data = new int[] { 0, 1, 2, 3, 4 };
}
}
And a method to show how this can be saved:
static void Main()
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
var list = new List<Test>
{
new Test()
};
csv.Configuration.HasHeaderRecord = false;
csv.WriteRecords(list);
writer.Flush();
}
}
The important configuration here is csv.Configuration.HasHeaderRecord = false;. Only with this configuration you will be able to see the data in the csv file.
Further details can be found in the related unit test cases from CsvHelper.
In case you are looking for a solution to store properties of type IEnumerable with different amounts of elements, the following example might be of any help:
using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CsvHelperSpike
{
class Program
{
static void Main(string[] args)
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
csv.Configuration.Delimiter = ";";
var list = new List<AnotherTest>
{
new AnotherTest("Before String") { Tags = new List<string> { "One", "Two", "Three" }, After="After String" },
new AnotherTest("This is still before") {After="after again", Tags=new List<string>{ "Six", "seven","eight", "nine"} }
};
csv.Configuration.RegisterClassMap<TestIndexMap>();
csv.WriteRecords(list);
writer.Flush();
}
using(var reader = new StreamReader("db.csv"))
using(var csv = new CsvReader(reader))
{
csv.Configuration.IncludePrivateMembers = true;
csv.Configuration.RegisterClassMap<TestIndexMap>();
var result = csv.GetRecords<AnotherTest>().ToList();
}
}
private class AnotherTest
{
public string Before { get; private set; }
public string After { get; set; }
public List<string> Tags { get; set; }
public AnotherTest() { }
public AnotherTest(string before)
{
this.Before = before;
}
}
private sealed class TestIndexMap : ClassMap<AnotherTest>
{
public TestIndexMap()
{
Map(m => m.Before).Index(0);
Map(m => m.After).Index(1);
Map(m => m.Tags).Index(2);
}
}
}
}
By using the ClassMap it is possible to enable HasHeaderRecord (the default) again. It is important to note here, that this solution will only work, if the collection with different amounts of elements is the last property. Otherwise the collection needs to have a fixed amount of elements and the ClassMap needs to be adapted accordingly.
This example also shows how to handle properties with a private set. For this to work it is important to use the csv.Configuration.IncludePrivateMembers = true; configuration and have a default constructor on your class.
Unfortunately, it doesn't work like that. Since you are returning , in the converter, it will quote the field, as that is a part of a single field.
Currently the only way to accomplish what you want is to write manually, which isn't too horrible.
foreach( var test in list )
{
foreach( var item in test.Data )
{
csvWriter.WriteField( item );
}
csvWriter.NextRecord();
}
Update
Version 3 has support for reading and writing IEnumerable properties.
Is there easier way to convert telerik orm entity list to csv format?
The following simple static class will help you in this task. Note that it will create a .csv file, which contains the values of the entity's properties without taking into account the navigation properties:
public static partial class EntitiesExporter
{
public static void ExportEntityList<T>(string fileLocation, IEnumerable<T> entityList, string seperator = " , ")
{
string content = CreateFileContent<T>(entityList, seperator);
SaveContentToFile(fileLocation, content);
}
private static string CreateFileContent<T>(IEnumerable<T> entityList, string seperator)
{
StringBuilder result = new StringBuilder();
List<PropertyInfo> properties = new List<PropertyInfo>();
foreach (PropertyInfo item in typeof(T).GetProperties())
{
if (item.CanWrite)
{
properties.Add(item);
}
}
foreach (T row in entityList)
{
var values = properties.Select(p => p.GetValue(row, null));
var line = string.Join(seperator, values);
result.AppendLine(line);
}
return result.ToString();
}
private static void SaveContentToFile(string fileLocation, string content)
{
using (StreamWriter writer = File.CreateText(fileLocation))
{
writer.Write(content);
writer.Close();
}
}
}
You can consume the class like this in your code:
using (EntitiesModel dbContext = new EntitiesModel())
{
IQueryable<Category> cats = dbContext.Categories;
string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string fileLocation = Path.Combine(appDir, "test.csv");
EntitiesExporter.ExportEntityList<Category>(fileLocation, cats);
}
I hope this helps.