I am trying to create a utility class where I could pass a list of Anonymous Type (AT) and it would produce a CSV file with the AT's properties as its columns and property values as its respective data.
I have a working code but I feel it could be improved (a lot!). I inherited a class from FileResult
and decorate it with my custom implementations. Here's what I have so far:
public class ExportCSVAnonymous : FileResult {
public dynamic List {
set;
get;
}
public char Separator {
set;
get;
}
public ExportCSVAnonymous(dynamic list, string fileDownloadName, char separator = ',') : base("text/csv") {
List = list;
Separator = separator;
FileDownloadName = fileDownloadName;
}
public ExportCSVAnonymous(dynamic list, string fileDownloadName, char separator = ',') : base("text/csv") {
List = list;
Separator = separator;
FileDownloadName = fileDownloadName;
}
protected override void WriteFile(HttpResponseBase response) {
var outputStream = response.OutputStream;
using (var memoryStream = new MemoryStream()) {
WriteList(memoryStream);
outputStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
}
private void WriteList(Stream stream) {
var streamWriter = new StreamWriter(stream, Encoding.Default);
WriteHeaderLine(streamWriter);
streamWriter.WriteLine();
WriteDataLines(streamWriter);
streamWriter.Flush();
}
//I wish this part could be improved
private void WriteHeaderLine(StreamWriter streamWriter) {
foreach (var line in List) {
foreach (MemberInfo member in line.GetType().GetProperties()) {
WriteValue(streamWriter, member.Name);
}
break;
}
}
private void WriteValue(StreamWriter writer, String value) {
writer.Write("\"");
writer.Write(value.Replace("\"", "\"\""));
writer.Write("\"" + Separator);
}
private void WriteDataLines(StreamWriter streamWriter) {
foreach (var line in List) {
foreach (MemberInfo member in line.GetType().GetProperties()) {
WriteValue(streamWriter, GetPropertyValue(line, member.Name));
}
streamWriter.WriteLine();
}
}
private static string GetPropertyValue(object src, string propName) {
object obj = src.GetType().GetProperty(propName).GetValue(src, null);
return (obj != null) ? obj.ToString() : "";
}
}
I used dynamic
as a way to pass my AT inside the class. Is there better way to do this? Lastly, I want to improve the WriteHeaderLine
method. Since I am using dynamic
type, I cannot cast it successfully to inspect the properties of the AT. What's the best way to do this?