Skip to content

Instantly share code, notes, and snippets.

@jeffwindsor
Created December 22, 2011 03:21
Show Gist options
  • Save jeffwindsor/1508773 to your computer and use it in GitHub Desktop.
Save jeffwindsor/1508773 to your computer and use it in GitHub Desktop.
Reflection based MVC Csv File Result for use with lists of models or dtos
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace System.Web.Mvc
{
/// <summary>
/// Reflection Based CSV File Result
/// </summary>
/// <typeparam name="TSource">source type that will be reflected into rows</typeparam>
public class CsvFileResult<TSource> : FileResult
{
private const string seperator = ",";
private readonly IEnumerable<TSource> _sources;
private readonly IEnumerable<string> _limitToPropertyNames;
/// <param name="source">source objects for value rows</param>
/// <param name="limitToPropertyNames">limit output to these property names</param>
public CsvFileResult(IEnumerable<TSource> sources, IEnumerable<string> limitToPropertyNames = null)
: base("text/csv")
{
_sources = sources;
_limitToPropertyNames = limitToPropertyNames;
}
protected override void WriteFile(System.Web.HttpResponseBase response)
{
//Get Reflected objects as a csv table and write it to the response stream
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream, Encoding.Default))
{
writer.Write(ReflectPropertiesToCsvTable(_sources, _limitToPropertyNames));
writer.Flush();
response.OutputStream.Write(stream.GetBuffer(), 0, (int)stream.Length);
}
}
}
private static string ReflectPropertiesToCsvTable(IEnumerable<TSource> sources, IEnumerable<string> limitToPropertyNames = null)
{
var propertyNames = GetPropertyNames(limitToPropertyNames);
var headerValues = ConvertToCsvString(propertyNames);
var rowValues = from source in sources select ConvertToCsvString(GetPropertyValues(source, propertyNames));
var sb = new StringBuilder();
sb.AppendLine(headerValues);
foreach (var row in rowValues)
{
sb.AppendLine(row);
}
return sb.ToString();
}
private static string ConvertToCsvString(IEnumerable<string> source)
{
return string.Join(seperator, source);
}
private static IEnumerable<string> GetPropertyNames(IEnumerable<string> limitToPropertyNames = null)
{
return limitToPropertyNames ??
from pi in typeof (TSource).GetProperties()
select pi.Name;
}
public static IEnumerable<string> GetPropertyValues(TSource source, IEnumerable<string> limitToPropertyNames = null)
{
//Extract Reflection Info
var columns = from pi in source.GetType().GetProperties()
orderby pi.Name
select new
{
pi.Name,
Value = GetPropertyValue(pi, source)
};
//Filter by Property Names if supplied
if (limitToPropertyNames != null)
{
columns = from item in columns
from allowedName in limitToPropertyNames
where item.Name == allowedName
select item;
}
return from item in columns select item.Value;
}
private static string GetPropertyValue(PropertyInfo pi, object source)
{
try
{
var result = pi.GetValue(source, null);
return (result==null) ? "Null": result.ToString();
}
catch (Exception)
{
return "Reflection Failed to Obtain Value";
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment