public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext) { // Create a worksheet var package = new ExcelPackage(); package.Workbook.Worksheets.Add("Data"); var worksheet = package.Workbook.Worksheets[1]; int rowCount = 0; var valueType = value.GetType(); // Apply cell styles. CellStyle?.Invoke(worksheet.Cells.Style); // Get the item type. var itemType = (util.IsSimpleType(valueType)) ? null : util.GetEnumerableItemType(valueType); // If a single object was passed, treat it like a list with one value. if (itemType == null) { itemType = valueType; value = new[] { value }; } // Enumerations of primitive types are also handled separately, since they have // no properties to serialise (and thus, no headers or attributes to consider). if (util.IsSimpleType(itemType)) { // Can't convert IEnumerable<primitive> to IEnumerable<object> var values = (IEnumerable)value; foreach (var val in values) { AppendRow(new[] { val }, worksheet, ref rowCount); } // Autofit cells if specified. if (AutoFit) { worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns(); } // Save and done. return(Task.Factory.StartNew(() => package.SaveAs(writeStream))); } // What remains is an enumeration of object types. var serialisableMembers = util.GetMemberNames(itemType); var properties = (from p in itemType.GetProperties() where p.CanRead & p.GetGetMethod().IsPublic & p.GetGetMethod().GetParameters().Length == 0 select p).ToList(); var fields = new List <string>(); var fieldInfo = new ExcelFieldInfoCollection(); // Instantiate field names and fieldInfo lists with serialisable members. foreach (var field in serialisableMembers) { var propName = field; var prop = properties.FirstOrDefault(p => p.Name == propName); if (prop == null) { continue; } fields.Add(field); fieldInfo.Add(new ExcelFieldInfo(field, util.GetAttribute <ExcelColumnAttribute>(prop))); } var props = itemType.GetProperties().ToList(); foreach (var prop in props) { var attributes = prop.GetCustomAttributes(true); foreach (var attribute in attributes) { var propertyName = prop.Name; if (!fieldInfo.Contains(propertyName)) { continue; } string displayFormatString = null; var displayFormatAttribute = (DisplayFormatAttribute)prop.GetCustomAttributes(typeof(DisplayFormatAttribute), true).FirstOrDefault(); if (displayFormatAttribute != null) { displayFormatString = displayFormatAttribute.DataFormatString; } string displayName = null; var displayNameAttribute = (DisplayNameAttribute)prop.GetCustomAttributes(typeof(DisplayNameAttribute), true).FirstOrDefault(); if (displayNameAttribute != null) { displayName = displayNameAttribute.DisplayName; } var field = fieldInfo[propertyName]; if (!field.IsExcelHeaderDefined) { field.Header = propertyName; } if (!field.IsExcelHeaderDefined) { field.Header = displayName ?? propertyName; } var excelAttribute = attribute as ExcelColumnAttribute; if (excelAttribute != null && excelAttribute.UseDisplayFormatString) { field.FormatString = displayFormatString; } } } if (fields.Count == 0) { return(Task.Factory.StartNew(() => package.SaveAs(writeStream))); } // Add header row AppendRow((from f in fieldInfo select f.Header).ToList(), worksheet, ref rowCount); var data = value as IEnumerable <object>; // Output each row of data if (data?.FirstOrDefault() != null) { foreach (var dataObject in data) { var row = new List <object>(); for (int i = 0; i <= fields.Count - 1; i++) { var cellValue = GetFieldOrPropertyValue(dataObject, fields[i]); var info = fieldInfo[i]; // Boolean transformations. if (info.ExcelAttribute != null && info.ExcelAttribute.TrueValue != null && cellValue.Equals("True")) { row.Add(info.ExcelAttribute.TrueValue); } else if (info.ExcelAttribute != null && info.ExcelAttribute.FalseValue != null && cellValue.Equals("False")) { row.Add(info.ExcelAttribute.FalseValue); } else if (!string.IsNullOrWhiteSpace(info.FormatString) & string.IsNullOrEmpty(info.ExcelNumberFormat)) { row.Add(string.Format(info.FormatString, cellValue)); } else { row.Add(cellValue); } } AppendRow(row.ToArray(), worksheet, ref rowCount); } } // Enforce any attributes on columns. for (int i = 1; i <= fields.Count; i++) { if (!string.IsNullOrEmpty(fieldInfo[i - 1].ExcelNumberFormat)) { worksheet.Cells[2, i, rowCount, i].Style.Numberformat.Format = fieldInfo[i - 1].ExcelNumberFormat; } } // Header cell styles HeaderStyle?.Invoke(worksheet.Row(1).Style); if (FreezeHeader) { worksheet.View.FreezePanes(2, 1); } var cells = worksheet.Cells[worksheet.Dimension.Address]; // Add autofilter and fit to max column width (if requested). if (AutoFilter) { cells.AutoFilter = AutoFilter; } if (AutoFit) { cells.AutoFitColumns(); } // Set header row where specified. if (HeaderHeight.HasValue) { worksheet.Row(1).Height = HeaderHeight.Value; worksheet.Row(1).CustomHeight = true; } return(Task.Factory.StartNew(() => package.SaveAs(writeStream))); }
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) { var response = context.HttpContext.Response; // Create a worksheet var package = new ExcelPackage(); package.Workbook.Worksheets.Add("Data"); var worksheet = package.Workbook.Worksheets[0]; var rowCount = 0; var valueType = context.ObjectType; var value = context.Object; // Apply cell styles. CellStyle?.Invoke(worksheet.Cells.Style); // Get the item type. var itemType = util.IsSimpleType(valueType) ? null : util.GetEnumerableItemType(valueType); // If a single object was passed, treat it like a list with one value. if (itemType == null) { itemType = valueType; value = new[] { context.Object }; } // Enumerations of primitive types are also handled separately, since they have // no properties to serialise (and thus, no headers or attributes to consider). if (util.IsSimpleType(itemType)) { // Can't convert IEnumerable<primitive> to IEnumerable<object> var values = (IEnumerable)value; foreach (var val in values) { AppendRow(new[] { val }, worksheet, ref rowCount); } // Autofit cells if specified. if (AutoFit) { worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns(); } // Save and done. var bytes = package.GetAsByteArray(); await response.Body.WriteAsync(bytes, 0, bytes.Length); await package.Stream.FlushAsync(); return; } var data = value as IEnumerable <object>; // What remains is an enumeration of object types. var serialisableMembers = util.GetMemberNames(itemType); var metadataProvider = (IModelMetadataProvider)context.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider)); var metadata = metadataProvider.GetMetadataForType(itemType); var properties = (from p in itemType.GetProperties() where p.CanRead & p.GetGetMethod().IsPublic & p.GetGetMethod().GetParameters().Length == 0 select p).ToList(); var fields = new List <string>(); var fieldInfo = new ExcelFieldInfoCollection(); // Instantiate field names and fieldInfo lists with serialisable members. foreach (var field in serialisableMembers) { var propName = field; var prop = properties.FirstOrDefault(p => p.Name == propName); if (prop == null) { continue; } fields.Add(field); fieldInfo.Add(new ExcelFieldInfo(field, util.GetAttribute <ExcelColumnAttribute>(prop))); } if (metadata.Properties != null) { foreach (var modelProp in metadata.Properties) { var propertyName = modelProp.PropertyName; if (!fieldInfo.Contains(propertyName)) { continue; } var field = fieldInfo[propertyName]; var attribute = field.ExcelAttribute; if (!field.IsExcelHeaderDefined) { field.Header = modelProp.DisplayName ?? propertyName; } if (attribute != null && attribute.UseDisplayFormatString) { Console.WriteLine(modelProp.DisplayFormatString); field.FormatString = modelProp.DisplayFormatString; } } } if (fields.Count == 0) { var bytes = package.GetAsByteArray(); await response.Body.WriteAsync(bytes, 0, bytes.Length); await package.Stream.FlushAsync(); return; } // Add header row AppendRow((from f in fieldInfo select f.Header).ToList(), worksheet, ref rowCount); // Output each row of data if (data?.FirstOrDefault() != null) { foreach (var dataObject in data) { var row = new List <object>(); for (int i = 0; i <= fields.Count - 1; i++) { var cellValue = GetFieldOrPropertyValue(dataObject, fields[i]); var info = fieldInfo[i]; // Boolean transformations. if (info.ExcelAttribute != null && info.ExcelAttribute.TrueValue != null && cellValue.Equals("True")) { row.Add(info.ExcelAttribute.TrueValue); } else if (info.ExcelAttribute != null && info.ExcelAttribute.FalseValue != null && cellValue.Equals("False")) { row.Add(info.ExcelAttribute.FalseValue); } else if (!string.IsNullOrWhiteSpace(info.FormatString) & string.IsNullOrEmpty(info.ExcelNumberFormat)) { row.Add(string.Format(info.FormatString, cellValue)); } else { row.Add(cellValue); } } AppendRow(row.ToArray(), worksheet, ref rowCount); } } // Enforce any attributes on columns. for (int i = 1; i <= fields.Count; i++) { if (!string.IsNullOrEmpty(fieldInfo[i - 1].ExcelNumberFormat)) { worksheet.Cells[2, i, rowCount, i].Style.Numberformat.Format = fieldInfo[i - 1].ExcelNumberFormat; } } // Header cell styles HeaderStyle?.Invoke(worksheet.Row(1).Style); if (FreezeHeader) { worksheet.View.FreezePanes(2, 1); } var cells = worksheet.Cells[worksheet.Dimension.Address]; // Add autofilter and fit to max column width (if requested). if (AutoFilter) { cells.AutoFilter = AutoFilter; } if (AutoFit) { cells.AutoFitColumns(); } // Set header row where specified. if (HeaderHeight.HasValue) { worksheet.Row(1).Height = HeaderHeight.Value; worksheet.Row(1).CustomHeight = true; } var packageBytes = package.GetAsByteArray(); await response.Body.WriteAsync(packageBytes, 0, packageBytes.Length); await package.Stream.FlushAsync(); }