使用Big DataSet将Razor视图导出到Excel

时间:2016-05-10 07:10:54

标签: c# asp.net-mvc excel asp.net-mvc-4 razor

我有高达150000的对象列表,我想在运行时绑定到razor视图,因为它导出为EXCEL但在绑定时我遇到了内存异常,是否有任何解决方法可以克服此限制?

导出方法:

  public void ExportToExcel()
    {
        string viewPath = "~/Modules/Reports/Views/" + TempData["reportName"] + ".cshtml";


        string viewPathCopy = "~/Modules/Reports/Views/" + TempData["reportName"] + "2.cshtml";

        string serverViewPath = Server.MapPath(viewPath);
        string serverViewPathCopy = Server.MapPath(viewPathCopy);

        if (System.IO.File.Exists(serverViewPathCopy))
        {
            System.IO.File.Delete(serverViewPathCopy);
        }

        System.IO.File.Copy(serverViewPath, serverViewPathCopy);

        string viewContents = System.IO.File.ReadAllText(serverViewPathCopy).Replace("thead", "tr");

        viewContents += "<style>body{font-size:8px !important;}table {padding:0 !important,margin:0 !important}</style>";
        System.IO.File.WriteAllText(serverViewPathCopy, viewContents);

        System.IO.File.WriteAllText(viewPathCopy, TemplateFromFile(viewPathCopy, TempData["reportData"]));

        FileInfo file = new FileInfo(viewPathCopy);
        if (file.Exists)
        {
            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name + ".xls");
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(file.FullName);
            Response.End();
        }
        else
        {
            Response.Write("This file does not exist.");
        }
    }

要查看的绑定模型:

  public  string TemplateFromFile(string file, dynamic model)
    {
        string template = "";
        TextReader textReader = new StreamReader(HelperMethods.GetFullFilePath(file));
        try
        {
            template = textReader.ReadToEnd();
        }
        finally
        {
            textReader.Close();
        }
        return Razor.Parse(template, model);
    }

1 个答案:

答案 0 :(得分:0)

如果要导出大量数据,我的goto工具为DoddleReport,这样可以创建有效的xlsx导出。使用doddle,您甚至可以创建多选项卡Excel工作表(请参阅Github上的示例)。

一些代码

IEnumerable的扩展程序

public static ExportBuilder<TModel> Export<TModel>(this IEnumerable<TModel> models) where TModel : class
    {
        return ExportBuilder<TModel>.Create(models);
    }

导出构建器

public class ExportBuilder<TModel> where TModel : class
{
    private readonly IEnumerable<TModel> _models;
    private readonly ICollection<IExportColumn<TModel>> _columns;

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Object"/> class.
    /// </summary>
    private ExportBuilder(IEnumerable<TModel> models)
    {
        _models = models;
        _columns = new List<IExportColumn<TModel>>();
    }

    public static ExportBuilder<TModel> Create(IEnumerable<TModel> models)
    {
        return new ExportBuilder<TModel>(models);
    }

    public ExportBuilder<TModel> Column<TProperty>(Expression<Func<TModel, TProperty>> display)
    {
        if (!(display.Body is MemberExpression))
            throw new ArgumentException(display + " is not a property!");

        var memberInfo = ((MemberExpression)display.Body).Member;
        if (!memberInfo.HasAttribute<DisplayNameAttribute>())
            throw new ArgumentException(display + " does not have a [Display] attribute");
        var displayAttribute = ExtensionsForMemberInfo.GetAttribute<DisplayNameAttribute>(memberInfo);

        _columns.Add(new ExportColumn<TModel, TProperty>(displayAttribute.DisplayName, display));
        return this;
    }

    public ExportBuilder<TModel> Column<TProperty>(string header, Expression<Func<TModel, TProperty>> property)
    {
        _columns.Add(new ExportColumn<TModel, TProperty>(header, property));
        return this;
    }

    public IReportSource ToReportSource()
    {
        if (_models.Any())
        {
            return DoddleExporter.ToReportSource(_models.Select(model => _columns.ToDictionary(c => c.Header, c => c.Display(model))));
        }
        var result = _columns
                .ToDictionary(a => a.Header, a => string.Empty);
        return DoddleExporter.ToReportSource(new[] { result });
    }

    public Report ToReport([CanBeNull] IEnumerable<KeyValuePair<string, string>> headers, [CanBeNull] IReportWriter writer = null)
    {
        headers = headers ?? Enumerable.Empty<KeyValuePair<string, string>>();
        var report = new Report(ToReportSource(), writer);
        //report.TextFields.Footer = string.Format(@"Aangemaakt op: {0}", DateTime.Now.ToString(DataFormatStrings.Date));
        var headersArray = headers as KeyValuePair<string, string>[] ?? headers.ToArray();
        if (headersArray.Any())
        {
            report.TextFields.Header = headersArray.Aggregate(string.Empty,
                                         (currentHeaders, header) => string.Format("{0}{3}{1} : {2}", currentHeaders, header.Key, header.Value, Environment.NewLine));
        }

        return report;
    }

    public ReportResult ToExcelReportResult([CanBeNull] IEnumerable<KeyValuePair<string, string>> headers)
    {
        return new ReportResult(ToReport(headers), new ExcelReportWriter(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    }
}

出口商

public static class DoddleExporter
{
    /// <summary>
    ///     Converts an enumerable of dictionaries to a report source
    /// </summary>
    /// <typeparam name="TValue">
    ///     The type of values in the dictionaries
    /// </typeparam>
    /// <param name="elements">
    ///     An enumerable of elements
    /// </param>
    /// <returns>The report source that was created from the elements</returns>
    public static IReportSource ToReportSource<TValue>(IEnumerable<IDictionary<string, TValue>> elements)
    {
        var elementsArray = elements.ToArray();
        if (!elementsArray.Any())
            throw new ArgumentException("Can't export empty list of elements");
        return ToReportSource(elementsArray, elementsArray.First().Keys.ToArray(),
            (element, key) => element.ContainsKey(key) ? element[key] : default(TValue));
    }

    /// <summary>
    /// Converts an enumerable of XElement to a report source
    /// </summary>
    /// <param name="rootElements">
    ///     The xml root elements that contain the values
    /// </param>
    /// <param name="keys">
    ///     They keys that can be used to fetch values from each root element
    /// </param>
    /// <returns>The report source that was created from the elements</returns>
    public static IReportSource ToReportSource(IEnumerable<XElement> rootElements, string[] keys)
    {
        return ToReportSource(rootElements, keys, delegate(XElement element, string key)
        {
            var value = element.Element(XmlConvert.EncodeLocalName(key));
            return value != null ? value.Value : null;
        });
    }

    /// <summary>
    ///     Converts a list of elements to a report source
    /// </summary>
    /// <param name="elements">
    ///     An enumerable of elements
    /// </param>
    /// <param name="keys">
    ///     They keys with which the values can be fetched from one element
    /// </param>
    /// <param name="valueSelector">
    ///     The function with which one value can be fetched given one key and one element
    /// </param>
    /// <returns>The report source that was created from the elements</returns>
    public static IReportSource ToReportSource<T>(IEnumerable<T> elements, string[] keys,
        Func<T, string, object> valueSelector)
    {
        var expandos = new List<ExpandoObject>();
        foreach (var element in elements)
        {
            var expando = new ExpandoObject();
            var expandoDictionary = (IDictionary<string, object>) expando;
            foreach (var key in keys)
            {
                var value = valueSelector(element, key);
                expandoDictionary[key] = value;
            }
            expandos.Add(expando);
        }
        return expandos.ToReportSource();
    }
}

帮助程序类

public interface IExportColumn<TModel> where TModel : class
{
    string Header { get; }
    Func<TModel, Object> Display { get; }
}
public class ExportColumn<TModel, TProperty> : IExportColumn<TModel> where TModel : class
{
    private readonly string _header;
    private readonly Expression<Func<TModel, TProperty>> _display;

    public string Header { get { return _header; } }
    public Func<TModel, Object> Display { get { return model => _display.Compile().Invoke(model); } }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Object"/> class.
    /// </summary>
    public ExportColumn(string header, Expression<Func<TModel, TProperty>> display)
    {
        _header = header;
        _display = display; ;
    }

    /// <summary>
    /// Returns a string that represents the current object.
    /// </summary>
    /// <returns>
    /// A string that represents the current object.
    /// </returns>
    public override string ToString()
    {
        return string.Format("Header: {0}, Display: {1}", _header, _display);
    }
}

<强>用法

var report = probing.Measurements.Export()
            .Column(MeasurementResource.Depth, m => m.Depth)
            .Column(MeasurementResource.DepthBelowWater, m => m.DepthBelowWater)
            .Column(MeasurementResource.ResistancePoint, m => m.ResistancePoint)
            .Column(MeasurementResource.FrictionLateral, m => m.FrictionLateral)
            .Column(MeasurementResource.FrictionLocal, m => m.FrictionLocal)
            .Column(MeasurementResource.FrictionTotal, m => m.FrictionTotal)
            .Column(MeasurementResource.Inclination, m => m.Inclination)
            .Column(MeasurementResource.PoreWaterPressure, m => m.PoreWaterPressure)
            .Column(MeasurementResource.Speed, m => m.Speed)
            .Column(MeasurementResource.CalcAlpha, m => m.CalcAlpha)
            .Column(MeasurementResource.CalcGammaDry, m => m.CalcGammaDry)
            .Column(MeasurementResource.CalcGammaWet, m => m.CalcGammaWet)
            .Column(MeasurementResource.GrainTension, m => m.GrainTension)
            .Column(MeasurementResource.CompressionCoefficient, m => m.CompressionCoefficient)
            .ToReport(null, new ExcelReportWriter());

        var stream = new MemoryStream();

        writer.WriteReport(report, stream);

        stream.Seek(0, SeekOrigin.Begin);

        return File(stream, "application/vnd.ms-excel", string.Format(@"{0}-{1}.xlsx", probing.Project.ProjectNumber, probing.ProbingNumber));