mvc Dapper_Report_Down_ExcelFile
一、基于Aspose.Cells、Dapper导出Excel
Dapper的Query返回要不是对象的IEnumerable,要不是Dynamic的IEnumerable,都不适合不用反射就能够动态获取各个属性值得情况,而反射浪费性能是大伙儿共同认知的,Down下来Dapper源码发现返回Dynamic的IEnumerable,是返回一个Dapper内部的对象DapperRow的Dynamic的IEnumerable,而DapperRow是可以通过属性索引的,当然需要做一下小的改变:
这就好办了,如下是基于Aspose.Cells
关于Aspose.Cells可以基于excel模板来生成Excel,这点解释如下:
- &=DataSource.Field,&=[DataSource].[Field]是对DataTable或集合类型的引用,将会从当前行开始竖直向下生成多行数据。
- &=$data:是对变量或数组的引用。数组存在skip,horizontal等属性
- &=&=动态公式计算;{r}当前行,{c}当前列,{-n},{n}当前行或列的偏移量前n或后n。
- &==是动态计算,如excel,if等语句。(if(logic_test,true_value,false_value))
public struct KeyValueDic
{
public KeyValueDic(string key,string value)
{
this.Key = key;
this.Value = value;
this.IsMutilText = false;
this.MatchText = null;
this.MatchTextDic = null;
} public KeyValueDic(string key, string value,bool isMutilText)
{
this.Key = key;
this.Value = value;
this.IsMutilText = isMutilText;
this.MatchText = null;
this.MatchTextDic = null;
} public KeyValueDic(string key, string value, string matchText)
{
Key = key;
Value = value;
IsMutilText = false;
MatchText = matchText;
MatchTextDic = null;
MatchTextDic = GetDic(matchText);
} public KeyValueDic(string key, string value, bool isMutilText, string matchText)
{
Key = key;
Value = value;
IsMutilText = isMutilText;
MatchText = matchText;
MatchTextDic = null;
MatchTextDic = GetDic(matchText);
}
public string Key { get; set; }//列名 public string Value { get; set; }//列中文名 public bool IsMutilText { get; set; }//是否是大字段 public string MatchText { get; set; }//需要匹配的文本,例sex=0;1,0;男,1;女,other;未知 public Dictionary<string, string> MatchTextDic { get; private set; } private Dictionary<string, string> GetDic(string text)
{
if (string.IsNullOrEmpty(text))
return null;
string[] _strs = text.Split(',');
if (_strs.Length == )
return null;
Dictionary<string, string> _dic = new Dictionary<string, string>();
foreach (string item in _strs)
{
string[] _strItems = item.Split(';');
if (_strItems.Length != ||string.IsNullOrEmpty(_strItems[]))
return null;
_dic.Add(_strItems[], _strItems[]);
}
return _dic;
} }
public class ExcelUtils
{
private static Style HeadStyle(Workbook workbook)//头部样式
{
//为单元格添加样式
Aspose.Cells.Style headStyle = workbook.Styles[workbook.Styles.Add()];
headStyle.HorizontalAlignment = Aspose.Cells.TextAlignmentType.Center;
headStyle.Pattern = BackgroundType.Solid;
headStyle.Font.IsBold = true;
headStyle.ForegroundColor = System.Drawing.Color.Blue;
headStyle.Font.Color = System.Drawing.Color.White;
headStyle.Font.IsSubscript = true;
headStyle.Font.Size = ;
headStyle.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
headStyle.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
headStyle.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
headStyle.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
return headStyle;
} private static Style BodyStyle(Workbook workbook)//文本样式
{
Aspose.Cells.Style bodyStyle = workbook.Styles[workbook.Styles.Add()];
bodyStyle.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
bodyStyle.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
bodyStyle.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
bodyStyle.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
bodyStyle.IsTextWrapped = true;
return bodyStyle;
} public static Stream SaveToStream(IEnumerable<DapperRow> list, List<KeyValueDic> listColumns, string sheetName)
{
if (list == null || list.Count() == || listColumns == null || listColumns.Count == || listColumns.Count > list.ElementAt().Count())
throw new Exception("Excel数据源不匹配导致无法保存!"); Workbook workbook = new Workbook();
Worksheet sheet = (Worksheet)workbook.Worksheets[];
sheet.Name = sheetName; for (int i = ; i < listColumns.Count; i++)
{
sheet.Cells[, i].PutValue(listColumns[i].Value);
if (listColumns[i].IsMutilText)
sheet.Cells.SetColumnWidth(i, );
}
sheet.Cells.CreateRange(, , , listColumns.Count).SetStyle(HeadStyle(workbook));
int row = ;
foreach (var item in list)
{
row++;
for (int i = ; i < listColumns.Count; i++)
{
object val = item[listColumns[i].Key];
if (val == null)
continue;
if (val.GetType() == typeof(DateTime))//时间格式
{
DateTime dtime = (DateTime)val;
if (dtime.Hour == || dtime.Minute == || dtime.Second == )
sheet.Cells[row, i].PutValue(dtime.ToString("yyyy-MM-dd"));
else
sheet.Cells[row, i].PutValue(dtime.ToString("yyyy-MM-dd HH:mm:ss"));
}
else if (listColumns[i].MatchText != null && listColumns[i].MatchTextDic != null)//是否有需要匹配的文本
{
string _val = val.ToString();
if (listColumns[i].MatchTextDic.ContainsKey(_val))
sheet.Cells[row, i].PutValue(listColumns[i].MatchTextDic[_val]);
else
sheet.Cells[row, i].PutValue(listColumns[i].MatchTextDic["other"]);
}
else
sheet.Cells[row, i].PutValue(val.ToString());
}
}
sheet.Cells.CreateRange(, , row, listColumns.Count).SetStyle(BodyStyle(workbook));
for (int i = ; i < listColumns.Count; i++)
{
if (!listColumns[i].IsMutilText)
sheet.AutoFitColumn(i);
}
sheet.AutoFitRows();
MemoryStream ms = new MemoryStream();
workbook.Save(ms, SaveFormat.Excel97To2003);
ms.Position = ;
return ms;
} }
logic:
public static class Utils
{
private static log4net.ILog log = log4net.LogManager.GetLogger("FMDS"); /// <summary>
/// 将指定的字符串信息写入日志。
/// </summary>
/// <param name="message">需要写入日志的字符串信息。</param>
public static void Log(string message)
{
log.Info(message);
}
/// <summary>
/// 将指定的异常实例详细信息写入日志
/// </summary>
public static void Log(Exception ex)
{
log.Error("Exception:", ex);
}
/// <summary>
/// 将指定的异常实例详细信息写入日志。
/// </summary>
public static void Log(object message, Exception e)
{
log.Error(message, e);
} public static string TrimOrNull(this string str)
{
return str == null ? null : str.Trim();
} }
public class DbConnection
{
public static SqlConnection OpenConnection()
{
if (string.IsNullOrEmpty(ConfigUtils.ConStr))
{
Utils.Log("数据库连接失败:没有读取到FMDS链接字符串。");
return null;
}
SqlConnection connection = new SqlConnection(ConfigUtils.ConStr);
try
{
connection.Open();
return connection;
}
catch (Exception ex)
{
Utils.Log("数据库FMDS连接失败:" + ex.Message);
return null;
}
}
}
public Stream Export()
{ string sql = @""; var param = new DynamicParameters();
param.Add("mydate", DateTime.Today, System.Data.DbType.DateTime); using (SqlConnection conn = DbConnection.OpenFMJConnection())
{
if (conn == null)
return null;
var list=conn.Query<SqlMapper.DapperRow>(sql, param);
List<KeyValueDic> listKeyValue = new List<KeyValueDic>()
{
new KeyValueDic("Column1","列1"),
new KeyValueDic("Column2","列2","0;男,1;女,other;未知"),
new KeyValueDic("Column3","列3",true)
};
System.IO.Stream stream = ExcelUtils.SaveToStream(list, listKeyValue, "excelSheetName");
return stream;
}
}
Action中使用: public FileResult Export()
{
Stream stream = logic.Export();
return File(stream, "application/vnd.ms-excel", DateTime.Now.ToString("yyyyMMddHHmmss") + "—excelName.xls");
}//"application/ms-excel",
View中使用: window.location.href = "@Url.Action("Export")";
二、基于System.Web.UI.WebControls.DataGrid、Ado.net导出Excel public void ExportExcel(DataTable dt, string filename)
{
StringWriter stringWriter = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
//使用System.Web.UI.WebControls的DataGrid导出excel
DataGrid excel = new DataGrid();
System.Web.UI.WebControls.TableItemStyle headerStyle = new TableItemStyle();//标题行样式
headerStyle.BackColor = System.Drawing.Color.LightGray;
headerStyle.Font.Bold = true;
headerStyle.HorizontalAlign = System.Web.UI.WebControls.HorizontalAlign.Center;
excel.HeaderStyle.MergeWith(headerStyle);
System.Web.UI.WebControls.TableItemStyle alternatingStyle = new TableItemStyle();//隔行样式
alternatingStyle.BackColor = System.Drawing.Color.LightGray;
excel.AlternatingItemStyle.MergeWith(alternatingStyle);
System.Web.UI.WebControls.TableItemStyle itemStyle = new TableItemStyle();//单元格样式
itemStyle.HorizontalAlign = System.Web.UI.WebControls.HorizontalAlign.Center;
excel.ItemStyle.MergeWith(itemStyle); excel.GridLines = GridLines.Both;
excel.HeaderStyle.Font.Bold = true;
excel.DataSource = dt.DefaultView;//输出DataTable的内容
excel.DataBind();
excel.RenderControl(htmlWriter);
MemoryStream stream = new MemoryStream();
System.IO.StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8);
sw.Write(stringWriter.ToString());
sw.Flush();
DownResult(stream, filename);
} public ActionResult DownResult(Stream stream,string fileName)
{
stream.Position = ;
const int ChunkSize = ;
byte[] buffer = new byte[ChunkSize];
long dataLengthToRead = stream.Length;
Response.Clear();
Response.Charset = "UTF-8";
Response.ContentType = "application/octet-stream";
Response.AppendHeader("content-disposition", string.Format("attachment;filename={0}.xls", fileName));
Response.AppendHeader("Content-Length", dataLengthToRead.ToString());
Response.Filter.Close();
while (dataLengthToRead > && Response.IsClientConnected)
{
int lengthRead = stream.Read(buffer, , ChunkSize);
Response.OutputStream.Write(buffer, , lengthRead);
Response.Flush();
dataLengthToRead = dataLengthToRead - lengthRead;
}
stream.Close();
stream.Dispose();
Response.Flush();
/*****
这里可以做一些自己的处理,比如把谁下载的文件信息存到库里,但是这个时候,就不能用Response.Close();了,否则报下载失败,网络错误。这里可以使用如下(需放在自己的处理程序之后):
参考:https://blogs.msdn.microsoft.com/aspnetue/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation/
http://stackoverflow.com/questions/5533068/httpcontext-throws-httpexception
http://stackoverflow.com/questions/1087777/is-response-end-considered-harmful
if (Response.IsClientConnected)
{
Response.SuppressContent = true;//Prevents any other content from being sent to the browser
HttpContext.ApplicationInstance.CompleteRequest();//Directs the thread to finish, bypassing additional processing
}
GC.Collect();
*****/
Response.Close();//不要直接用Response.End();
return new EmptyResult();
}
附:以上代码偶尔仍回抛如下异常“System.Web.HttpException (0x80070057): 远程主机关闭了连接。错误代码是 0x80070057。”
突然在异常错误日志中看到这个错误,虽然在测试中发现不影响流的传输,但是不代表没错误,解决方法如下:
Response.Flush(); Response.End();//结束文件下载,但是程序在运行时会报出“正在中止线程”的错误,可以确定的是引起错误的代码就是Response.End(),所以需要删除此方法。 在IIS .5下这样做问题就解决了,不过在IIS 7.0 下又会报出另外一个错误“与远程主机通信时发生错误。错误代码是 0x800704CD。” 在网上翻查了一翻资料后,终于找到了解决方法: 就是将Response.End();换成Response.Close(); 总结一下,帮助对Response.Close的解释是关闭到客户端的连接。对Response.End的解释是停止该页的执行,并引发Application_EndRequest。也就说用Response.End程序就直接停止后面的工作了转而触发Application_EndRequest,那么当程序在后面还有代码需要运行时,程序就会抛出ThreadAbortException的异常。还有需要了解的就是end方法在不抛出异常时还会调用flush的方法。接着来,close方法是关闭了连接,也就说程序顺利执行完了所有代码后关闭了连接。对于只运行flush后报出的“与远程主机通信时发生错误”,我的理解是当执行了flush后在底层马上开始向客户端发送数据,但是flush貌似只能指示 程序开始连接发送,却没有停止关闭的标识,导致程序报出异常。当然这是在IIS .0下会出错(可能在IIS 7.0 开始在调用flush后需要显示关闭socket连接)。所以以后再在用完flush后最好加上close。就像数据库连接一样,用完就关闭连接。
如下是Response.End()的source code:
public void End()
{
if (this._context.IsInCancellablePeriod)
{
InternalSecurityPermissions.ControlThread.Assert();
Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
}
else if (!this._flushing)
{
this.Flush();
this._ended = true;
if (this._context.ApplicationInstance != null)
{
this._context.ApplicationInstance.CompleteRequest();
}
}
}
也就是说使用Response.End()是包含了Response.Flush()的功能的。
附:Response.End()同样是报(偶尔情况下):
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at System.Web.HttpResponse.Flush()
修改为如下(待测试吧):
//Response.End();
HttpContext.ApplicationInstance.CompleteRequest();
mvc Dapper_Report_Down_ExcelFile的更多相关文章
- Asp.Net Mvc 使用WebUploader 多图片上传
来博客园有一个月了,哈哈.在这里学到了很多东西.今天也来试着分享一下学到的东西.希望能和大家做朋友共同进步. 最近由于项目需要上传多张图片,对于我这只菜鸟来说,以前上传图片都是直接拖得控件啊,而且还是 ...
- .Net Core MVC 网站开发(Ninesky) 2.4、添加栏目与异步方法
在2.3中完成依赖注入后,这次主要实现栏目的添加功能.按照前面思路栏目有三种类型,常规栏目即可以添加子栏目也可以选择是否添加内容,内容又可以分文章或其他类型,所以还要添加一个模块功能.这次主要实现栏目 ...
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库
在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...
- ASP.NET Core MVC/WebAPi 模型绑定探索
前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...
- ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入
原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...
- 开源:Taurus.MVC 框架
为什么要创造Taurus.MVC: 记得被上一家公司忽悠去负责公司电商平台的时候,情况是这样的: 项目原版是外包给第三方的,使用:WebForm+NHibernate,代码不堪入目,Bug无限,经常点 ...
- Taurus.MVC 2.2 开源发布:WebAPI 功能增强(请求跨域及Json转换)
背景: 1:有用户反馈了关于跨域请求的问题. 2:有用户反馈了参数获取的问题. 3:JsonHelper的增强. 在综合上面的条件下,有了2.2版本的更新,也因此写了此文. 开源地址: https:/ ...
- Taurus.MVC 2.0 开源发布:WebAPI开发教程
背景: 有用户反映,Tausus.MVC 能写WebAPI么? 能! 教程呢? 嗯,木有! 好吧,刚好2.0出来,就带上WEBAPI教程了! 开源地址: https://github.com/cyq1 ...
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...
随机推荐
- 自测之Lesson15:TCP&UDP网络编程
题目:编写一个TCP通信的程序. 实现代码: #include <stdio.h> #include <sys/socket.h> #include <unistd.h& ...
- Thunder团队第五周 - Scrum会议4
Scrum会议4 小组名称:Thunder 项目名称:i阅app Scrum Master:李传康 工作照片: 邹双黛同学在拍照,所以不在照片内. 参会成员: 王航:http://www.cnblog ...
- Java学习个人备忘录之接口
abstract class AbsDemo { abstract void show1(); abstract void show2(); } 当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类 ...
- python执行linux命令的两种方法
python执行linux命令有两种方法: 在此以Linux常用的ls命令为例: 方法一:使用os模块 1 2 3 shell# python >> import os >> ...
- 【IdentityServer4文档】- 支持协议
IdentityServer 实现了以下协议: OpenID Connect OpenID Connect Core 1.0 (spec) OpenID Connect Discovery 1.0 ( ...
- tomcat web页面管理应用配置
大部分时候,我们的tomcat服务器都不是部署在本机,那么怎么样不通过ftp/sftp方式来将war包部署到tomcat容器呢? tomcat有提供web页面管理应用的功能. 我们来看看怎么配置实现该 ...
- AutoResetEvent的基本用法
The following example uses an AutoResetEvent to synchronize the activities of two threads.The first ...
- java 基础--switch--003
1,break可以省略吗? default中的可以省略,其他的如果省略会执行下一个case,从下一个case的 break中中断.(case穿透) 2,default一定要在最后吗? 不是,可以在任意 ...
- C# Directory.GetFiles()获取文件时如果是根目录时有隐藏文件则报错的处理
如果Directory.GetFiles("d:\"),则由于回收站是隐藏文件而报错,怎么躲避这种错误呢, 我要了一种办法,只要遇到隐藏文件夹就跳过的方法: foreach (va ...
- Python高级数据类型模块collections
collections模块提供更加高级的容器数据类型,替代Python的内置dict,list, set,和tuple Counter对象 提供计数器,支持方便和快速的计数.返回的是一个以元素为键, ...