Convert IEnumerable to CSV
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
I have an IEnumerable
of a view model that I need to convert to CSV and send back as a file response. I have written it out quite manually and I'm just seeking code review and suggestions on a more elegant solution, or alternatively if this looks acceptable, confirmation of that:
public ActionResult ExportBasicReads(string nmi, DateTime fromDate, DateTime toDate)
var reads = _dataService.GetBasicReads(nmi, fromDate, toDate)
.Where(r => r.CurrentReadQuality != ReadQuality.Estimate)
.OrderBy(r => r.CurrentReadDate)
.ThenBy(r => r.DeviceKey)
.ThenBy(r => r.ValidationCode);
StringBuilder csv = new StringBuilder();
csv.AppendLine("Read Date,Device : Suffix,Read,Quality,Tran Code,Service Order,Previous Read Date,Previous Read,Previous Quality," +
"Previous Tran Code,Dial Diff,Quantity,UOM,Dial Factor,Direction,Validation,From Date,To Date,Kwh,Avg Daily Load,Profile Name," +
"Profle Area,Reading Timestamp,Update Date,ChangedBy,ChangeType,ChangeComment");
reads.ForEach(x => csv.AppendLine(
string.Format("0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22," +
"23,24,25,26,27",
x.CurrentReadDate,
x.DeviceKey,
x.Suffix,
x.CurrentReadRawValue,
x.CurrentReadQualityDesc,
x.CurrentReadTransactionCode,
x.CurrentServiceOrder,
x.PreviousReadDate,
x.PreviousReadRawValue,
x.PreviousReadQualityDesc,
x.PreviousReadTransactionCode,
x.DialDifference,
x.Quantity,
x.UOMDesc,
x.Multiplier,
x.DirectionDesc,
x.ValidationDesc,
x.EffectiveFromDateTime,
x.EffectiveToDateTime,
x.Kwh,
x.AverageDailyLoad,
x.ProfileName,
x.ProfileArea,
x.EffectiveFromDateTime,
x.UpdateTimestamp,
x.ChangedBy,
x.ChangeType,
x.ChangeComment
)
));
return File(Encoding.ASCII.GetBytes(csv.ToString()), "text/csv", "BasicReadsExport.csv");
c# mvc csv asp.net
add a comment |Â
up vote
5
down vote
favorite
I have an IEnumerable
of a view model that I need to convert to CSV and send back as a file response. I have written it out quite manually and I'm just seeking code review and suggestions on a more elegant solution, or alternatively if this looks acceptable, confirmation of that:
public ActionResult ExportBasicReads(string nmi, DateTime fromDate, DateTime toDate)
var reads = _dataService.GetBasicReads(nmi, fromDate, toDate)
.Where(r => r.CurrentReadQuality != ReadQuality.Estimate)
.OrderBy(r => r.CurrentReadDate)
.ThenBy(r => r.DeviceKey)
.ThenBy(r => r.ValidationCode);
StringBuilder csv = new StringBuilder();
csv.AppendLine("Read Date,Device : Suffix,Read,Quality,Tran Code,Service Order,Previous Read Date,Previous Read,Previous Quality," +
"Previous Tran Code,Dial Diff,Quantity,UOM,Dial Factor,Direction,Validation,From Date,To Date,Kwh,Avg Daily Load,Profile Name," +
"Profle Area,Reading Timestamp,Update Date,ChangedBy,ChangeType,ChangeComment");
reads.ForEach(x => csv.AppendLine(
string.Format("0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22," +
"23,24,25,26,27",
x.CurrentReadDate,
x.DeviceKey,
x.Suffix,
x.CurrentReadRawValue,
x.CurrentReadQualityDesc,
x.CurrentReadTransactionCode,
x.CurrentServiceOrder,
x.PreviousReadDate,
x.PreviousReadRawValue,
x.PreviousReadQualityDesc,
x.PreviousReadTransactionCode,
x.DialDifference,
x.Quantity,
x.UOMDesc,
x.Multiplier,
x.DirectionDesc,
x.ValidationDesc,
x.EffectiveFromDateTime,
x.EffectiveToDateTime,
x.Kwh,
x.AverageDailyLoad,
x.ProfileName,
x.ProfileArea,
x.EffectiveFromDateTime,
x.UpdateTimestamp,
x.ChangedBy,
x.ChangeType,
x.ChangeComment
)
));
return File(Encoding.ASCII.GetBytes(csv.ToString()), "text/csv", "BasicReadsExport.csv");
c# mvc csv asp.net
2
You can use string interpolation instead ofstring.Format()
?
â vasily.sib
Jun 22 at 5:37
2
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
1
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called.ToCsv()
: docs.servicestack.net/csv-format
â Jesse C. Slicer
Jun 22 at 14:35
1
thestring.Format
is awfully hard to follow given the large number of parameters. I would suggest something like$"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.
â Zer0
Jun 23 at 4:09
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
I have an IEnumerable
of a view model that I need to convert to CSV and send back as a file response. I have written it out quite manually and I'm just seeking code review and suggestions on a more elegant solution, or alternatively if this looks acceptable, confirmation of that:
public ActionResult ExportBasicReads(string nmi, DateTime fromDate, DateTime toDate)
var reads = _dataService.GetBasicReads(nmi, fromDate, toDate)
.Where(r => r.CurrentReadQuality != ReadQuality.Estimate)
.OrderBy(r => r.CurrentReadDate)
.ThenBy(r => r.DeviceKey)
.ThenBy(r => r.ValidationCode);
StringBuilder csv = new StringBuilder();
csv.AppendLine("Read Date,Device : Suffix,Read,Quality,Tran Code,Service Order,Previous Read Date,Previous Read,Previous Quality," +
"Previous Tran Code,Dial Diff,Quantity,UOM,Dial Factor,Direction,Validation,From Date,To Date,Kwh,Avg Daily Load,Profile Name," +
"Profle Area,Reading Timestamp,Update Date,ChangedBy,ChangeType,ChangeComment");
reads.ForEach(x => csv.AppendLine(
string.Format("0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22," +
"23,24,25,26,27",
x.CurrentReadDate,
x.DeviceKey,
x.Suffix,
x.CurrentReadRawValue,
x.CurrentReadQualityDesc,
x.CurrentReadTransactionCode,
x.CurrentServiceOrder,
x.PreviousReadDate,
x.PreviousReadRawValue,
x.PreviousReadQualityDesc,
x.PreviousReadTransactionCode,
x.DialDifference,
x.Quantity,
x.UOMDesc,
x.Multiplier,
x.DirectionDesc,
x.ValidationDesc,
x.EffectiveFromDateTime,
x.EffectiveToDateTime,
x.Kwh,
x.AverageDailyLoad,
x.ProfileName,
x.ProfileArea,
x.EffectiveFromDateTime,
x.UpdateTimestamp,
x.ChangedBy,
x.ChangeType,
x.ChangeComment
)
));
return File(Encoding.ASCII.GetBytes(csv.ToString()), "text/csv", "BasicReadsExport.csv");
c# mvc csv asp.net
I have an IEnumerable
of a view model that I need to convert to CSV and send back as a file response. I have written it out quite manually and I'm just seeking code review and suggestions on a more elegant solution, or alternatively if this looks acceptable, confirmation of that:
public ActionResult ExportBasicReads(string nmi, DateTime fromDate, DateTime toDate)
var reads = _dataService.GetBasicReads(nmi, fromDate, toDate)
.Where(r => r.CurrentReadQuality != ReadQuality.Estimate)
.OrderBy(r => r.CurrentReadDate)
.ThenBy(r => r.DeviceKey)
.ThenBy(r => r.ValidationCode);
StringBuilder csv = new StringBuilder();
csv.AppendLine("Read Date,Device : Suffix,Read,Quality,Tran Code,Service Order,Previous Read Date,Previous Read,Previous Quality," +
"Previous Tran Code,Dial Diff,Quantity,UOM,Dial Factor,Direction,Validation,From Date,To Date,Kwh,Avg Daily Load,Profile Name," +
"Profle Area,Reading Timestamp,Update Date,ChangedBy,ChangeType,ChangeComment");
reads.ForEach(x => csv.AppendLine(
string.Format("0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22," +
"23,24,25,26,27",
x.CurrentReadDate,
x.DeviceKey,
x.Suffix,
x.CurrentReadRawValue,
x.CurrentReadQualityDesc,
x.CurrentReadTransactionCode,
x.CurrentServiceOrder,
x.PreviousReadDate,
x.PreviousReadRawValue,
x.PreviousReadQualityDesc,
x.PreviousReadTransactionCode,
x.DialDifference,
x.Quantity,
x.UOMDesc,
x.Multiplier,
x.DirectionDesc,
x.ValidationDesc,
x.EffectiveFromDateTime,
x.EffectiveToDateTime,
x.Kwh,
x.AverageDailyLoad,
x.ProfileName,
x.ProfileArea,
x.EffectiveFromDateTime,
x.UpdateTimestamp,
x.ChangedBy,
x.ChangeType,
x.ChangeComment
)
));
return File(Encoding.ASCII.GetBytes(csv.ToString()), "text/csv", "BasicReadsExport.csv");
c# mvc csv asp.net
edited Jun 22 at 14:22
Jesse C. Slicer
10.9k2738
10.9k2738
asked Jun 22 at 4:02
TDSnet
283
283
2
You can use string interpolation instead ofstring.Format()
?
â vasily.sib
Jun 22 at 5:37
2
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
1
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called.ToCsv()
: docs.servicestack.net/csv-format
â Jesse C. Slicer
Jun 22 at 14:35
1
thestring.Format
is awfully hard to follow given the large number of parameters. I would suggest something like$"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.
â Zer0
Jun 23 at 4:09
add a comment |Â
2
You can use string interpolation instead ofstring.Format()
?
â vasily.sib
Jun 22 at 5:37
2
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
1
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called.ToCsv()
: docs.servicestack.net/csv-format
â Jesse C. Slicer
Jun 22 at 14:35
1
thestring.Format
is awfully hard to follow given the large number of parameters. I would suggest something like$"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.
â Zer0
Jun 23 at 4:09
2
2
You can use string interpolation instead of
string.Format()
?â vasily.sib
Jun 22 at 5:37
You can use string interpolation instead of
string.Format()
?â vasily.sib
Jun 22 at 5:37
2
2
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
1
1
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called
.ToCsv()
: docs.servicestack.net/csv-formatâ Jesse C. Slicer
Jun 22 at 14:35
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called
.ToCsv()
: docs.servicestack.net/csv-formatâ Jesse C. Slicer
Jun 22 at 14:35
1
1
the
string.Format
is awfully hard to follow given the large number of parameters. I would suggest something like $"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.â Zer0
Jun 23 at 4:09
the
string.Format
is awfully hard to follow given the large number of parameters. I would suggest something like $"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.â Zer0
Jun 23 at 4:09
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
I modified the formatting part for better readability and maintainability, at the cost of lower performance:
var columns = new Dictionary<string, Func<Reads, object>>
["Read Date"] = x => x.CurrentReadDate,
["Device"] = x => x.DeviceKey,
["Suffix"] = x => x.Suffix,
["Read"] = x => x.CurrentReadRawValue,
// add the rest of headers/property selectors below
;
//var format = "0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27";
var format = "01 : " + string.Join(",", columns.Select((_, i) => $"i").Skip(2));
var csv = new StringBuilder()
.AppendFormat(format, columns.Keys.ToArray())
.AppendLine();
foreach (var read in reads)
var values = columns.Values.Select(selector => selector(read));
csv
.AppendFormat(format, values.ToArray())
.AppendLine();
The advantage of this approach is that you can add/move/remove the columns without having to worry about updating the header and the format, and if they are kept in sync or not.
Note:
- You can also revert to the constant format if it becomes more complex.
- The property selector can be chained if you need special format on individual property, like:
x => x.CurrentReadDate.ToString("yyyyMMddThhmm")
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
I modified the formatting part for better readability and maintainability, at the cost of lower performance:
var columns = new Dictionary<string, Func<Reads, object>>
["Read Date"] = x => x.CurrentReadDate,
["Device"] = x => x.DeviceKey,
["Suffix"] = x => x.Suffix,
["Read"] = x => x.CurrentReadRawValue,
// add the rest of headers/property selectors below
;
//var format = "0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27";
var format = "01 : " + string.Join(",", columns.Select((_, i) => $"i").Skip(2));
var csv = new StringBuilder()
.AppendFormat(format, columns.Keys.ToArray())
.AppendLine();
foreach (var read in reads)
var values = columns.Values.Select(selector => selector(read));
csv
.AppendFormat(format, values.ToArray())
.AppendLine();
The advantage of this approach is that you can add/move/remove the columns without having to worry about updating the header and the format, and if they are kept in sync or not.
Note:
- You can also revert to the constant format if it becomes more complex.
- The property selector can be chained if you need special format on individual property, like:
x => x.CurrentReadDate.ToString("yyyyMMddThhmm")
add a comment |Â
up vote
4
down vote
accepted
I modified the formatting part for better readability and maintainability, at the cost of lower performance:
var columns = new Dictionary<string, Func<Reads, object>>
["Read Date"] = x => x.CurrentReadDate,
["Device"] = x => x.DeviceKey,
["Suffix"] = x => x.Suffix,
["Read"] = x => x.CurrentReadRawValue,
// add the rest of headers/property selectors below
;
//var format = "0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27";
var format = "01 : " + string.Join(",", columns.Select((_, i) => $"i").Skip(2));
var csv = new StringBuilder()
.AppendFormat(format, columns.Keys.ToArray())
.AppendLine();
foreach (var read in reads)
var values = columns.Values.Select(selector => selector(read));
csv
.AppendFormat(format, values.ToArray())
.AppendLine();
The advantage of this approach is that you can add/move/remove the columns without having to worry about updating the header and the format, and if they are kept in sync or not.
Note:
- You can also revert to the constant format if it becomes more complex.
- The property selector can be chained if you need special format on individual property, like:
x => x.CurrentReadDate.ToString("yyyyMMddThhmm")
add a comment |Â
up vote
4
down vote
accepted
up vote
4
down vote
accepted
I modified the formatting part for better readability and maintainability, at the cost of lower performance:
var columns = new Dictionary<string, Func<Reads, object>>
["Read Date"] = x => x.CurrentReadDate,
["Device"] = x => x.DeviceKey,
["Suffix"] = x => x.Suffix,
["Read"] = x => x.CurrentReadRawValue,
// add the rest of headers/property selectors below
;
//var format = "0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27";
var format = "01 : " + string.Join(",", columns.Select((_, i) => $"i").Skip(2));
var csv = new StringBuilder()
.AppendFormat(format, columns.Keys.ToArray())
.AppendLine();
foreach (var read in reads)
var values = columns.Values.Select(selector => selector(read));
csv
.AppendFormat(format, values.ToArray())
.AppendLine();
The advantage of this approach is that you can add/move/remove the columns without having to worry about updating the header and the format, and if they are kept in sync or not.
Note:
- You can also revert to the constant format if it becomes more complex.
- The property selector can be chained if you need special format on individual property, like:
x => x.CurrentReadDate.ToString("yyyyMMddThhmm")
I modified the formatting part for better readability and maintainability, at the cost of lower performance:
var columns = new Dictionary<string, Func<Reads, object>>
["Read Date"] = x => x.CurrentReadDate,
["Device"] = x => x.DeviceKey,
["Suffix"] = x => x.Suffix,
["Read"] = x => x.CurrentReadRawValue,
// add the rest of headers/property selectors below
;
//var format = "0,1 : 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27";
var format = "01 : " + string.Join(",", columns.Select((_, i) => $"i").Skip(2));
var csv = new StringBuilder()
.AppendFormat(format, columns.Keys.ToArray())
.AppendLine();
foreach (var read in reads)
var values = columns.Values.Select(selector => selector(read));
csv
.AppendFormat(format, values.ToArray())
.AppendLine();
The advantage of this approach is that you can add/move/remove the columns without having to worry about updating the header and the format, and if they are kept in sync or not.
Note:
- You can also revert to the constant format if it becomes more complex.
- The property selector can be chained if you need special format on individual property, like:
x => x.CurrentReadDate.ToString("yyyyMMddThhmm")
answered Jun 22 at 18:07
Xiaoy312
2,767915
2,767915
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197025%2fconvert-ienumerablereads-to-csv%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
You can use string interpolation instead of
string.Format()
?â vasily.sib
Jun 22 at 5:37
2
Looks pretty clean to me.
â paparazzo
Jun 22 at 12:21
1
No need to reinvent - the popular ServiceStack.Text NuGet package has an extension method called
.ToCsv()
: docs.servicestack.net/csv-formatâ Jesse C. Slicer
Jun 22 at 14:35
1
the
string.Format
is awfully hard to follow given the large number of parameters. I would suggest something like$"x.CurrentReadDate,x.DeviceKey" ...
. This would also help avoid errors due to matching up parameter indexes if this code was later modified.â Zer0
Jun 23 at 4:09