由于系统需要在网页上导 出Excel文件,最近花了一段时间去学习NPOI插件。通过NPOI插件在服务端来生成Excel文件流并下载到本地。NPOI实际上和Excel一毛 钱关系都没有,它只是完全破译了Excel文件的存储格式,并用C#来生成同样的格式从而被识别为Excel文件。 NPOI和Excel VBA相比优点很多,首先是Excel VBA中的对象太多,而且是基于Visual Basic语言来书写,而且是在Excel中进行编程开发,IDE十分原始,没有任何的智能感知和代码着色功能。(最近可以在VS进行VBA开发了) 抛开这些不说,微软官方是不建议在服务器端来操作Excel的。原话好像是不建议用asp,asp.net等无人的方式来使用Excel。而且最要命的是 VBA方式来操作Excel后,其进程很难释放干净。在桌面端生成一两个文件倒无所谓,后台多跑两个Excel也不是啥大事。但在服务器端多用户操作,很 有可能会出现死锁等问题。 NPOI是从JAVA的POI移植而来,使用方式非常自然。 但是我发现在NPOI中实现宽度和高度自适应很难,宽度和高度自适应,说简单点就是如何让宽度和高度刚刚好。不让内容被遮挡,使用者在下载表格后不需要手工调整。 NPOI有一个宽度自适应属性,可惜只对英文和数字有效,对汉字无效。后来在一个台湾博客上发现了一段解决代码,我稍加改造后如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
for (int columnNum = 0; columnNum <= 26; columnNum++) { int columnWidth = ffSheet.GetColumnWidth(columnNum) / 256;//获取当前列宽度 for (int rowNum = 1; rowNum <= ffSheet.LastRowNum; rowNum++)//在这一列上循环行 { IRow currentRow = ffSheet.GetRow(rowNum); ICell currentCell = currentRow.GetCell(columnNum); int length = Encoding.UTF8.GetBytes(currentCell.ToString()).Length;//获取当前单元格的内容宽度 if (columnWidth < length + 1) { columnWidth = length + 1; }//若当前单元格内容宽度大于列宽,则调整列宽为当前单元格宽度,后面的+1是我人为的将宽度增加一个字符 } ffSheet.SetColumnWidth(columnNum, columnWidth * 256); } |
columnNum是列号,从0开始循环到表格最后一列,循环的范围可以自己指定,原理很简单,就是在先循环列,在列上循环行,比对行内容宽度与列宽度,若行内容宽度大于列宽则增大列宽,循环以后,每列宽度等于该列中最宽的那一行的宽度。 值得注意的是使用UTF8编码来计算的,在UTF8编码中数字和英文字母宽度为2,汉字宽度为3。而且字号越小,其效果就越好。在实际使用中内容为10磅的时候,其效果就相当不错。 仅仅有宽度自适应是不够的,宽度自适应只是针对较短的内容而言的,如果单元格内容很长采用这个方法会将表格拉的非常宽。下面来谈一谈高度自适应解决方法, 高度自适应是指内容换行后行高能够自动增加以完整的显示内容,高度自适应是我自己想出来的,和宽度自适应很类似:
1 2 3 4 5 6 7 |
for (int rowNum = 2; rowNum <= ffSheet.LastRowNum; rowNum++) { IRow currentRow = ffSheet.GetRow(rowNum); ICell currentCell = currentRow.GetCell(27); int length = Encoding.UTF8.GetBytes(currentCell.ToString()).Length; currentRow.HeightInPoints = 20 * (length / 60 + 1); } |
首先要设置该列能够自动换行,然后将行高设置为20,获得列内容宽度后整除一个列宽常数,将其倍数乘以行高,从而增加行高。值得注意的是这个常数需要自己 测试,因为实际内容都是英文、数字和汉字混杂的,很难判断一行能容纳多少个字符,只能取一个中间值,如果取的太大可能会造成行高小于内容,取的过小会造成 行高过大而内容较少。而且在字磅数较小时精度较好。 转载于:https://www.cnblogs.com/nearpengju123/p/4112935.html from:https://blog.csdn.net/weixin_30846599/article/details/99535103?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-99535103-blog-51893264.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-99535103-blog-51893264.pc_relevant_default&utm_relevant_index=2
View Details1、添加对NPOI的引用 2、创建excel文件对象 HSSFWorkbook wb = new HSSFWorkbook(); 3、创建 工作表,也就是Excel中的sheet,给工作表赋一个名称 title HSSFSheet sheet = (HSSFSheet)wb.CreateSheet(title); 4、设置某一列宽度 sheet.SetColumnWidth(0, 10 * 256); 列号从0开始 5、合并单元格 例: 第1行到第2行 第3列到第4列围成的矩形区域 sheet.AddMergedRegion(new CellRangeAddress(0, 1, 2, 3)); 合并单元格后,只需对第一个位置赋值即可 6、在工作表中创建一行 /// <summary> /// 创建行 /// </summary> /// <param name="wb"></param> /// <param name="sheet"></param> /// <param name="rowNum">创建 一行 的行号 从0开始</param> /// <param name="rowHeigh">行高</param> public HSSFRow CreateRow(HSSFSheet sheet, int rowNum, float rowHeight) { HSSFRow row = (HSSFRow)sheet.CreateRow(rowNum); //创建行 row.HeightInPoints = rowHeight; //设置列头行高 return row; } 7、设置单元格样式 /// <summary> /// 设置样式 /// </summary> /// <param name="wb"></param> /// <param name="hAlignment">水平布局方式</param> /// <param name="vAlignment">垂直布局方式</param> […]
View Details
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//准备序化列对象 XmlSerializer xs = new XmlSerializer(obj.GetType()); MemoryStream ms = new MemoryStream(); //设置序序化XML格式 XmlWriterSettings xws = new XmlWriterSettings(); xws.Indent = true; xws.OmitXmlDeclaration = true; xws.Encoding = Encoding.UTF8; XmlWriter xtw = XmlTextWriter.Create(ms, xws); //去掉要结点的 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 属性 XmlSerializerNamespaces _namespaces = new XmlSerializerNamespaces( new XmlQualifiedName[] { new XmlQualifiedName(string.Empty, "aa") }); xs.Serialize(xtw, obj,_namespaces); ms.Position = 0; xmlDoc = new XmlDocument(); xmlDoc.Load(ms); //给文档添加<?xml version="1.0" encoding="utf-8"?> XmlDeclaration xmlDecl = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null); xmlDoc.InsertBefore(xmlDecl, xmlDoc.DocumentElement); |
from:https://blog.csdn.net/a5251199/article/details/106546967
View Details
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; namespace object2xml { public static class XmlExtension { public static string Serialize<T>(this T value) { if (value == null) return string.Empty; var xmlserializer = new XmlSerializer(typeof(T)); using (StringWriter stringWriter = new StringWriter()) { using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true })) { xmlserializer.Serialize(writer, value); return stringWriter.ToString(); } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace object2xml { public class Persion { public string Name { get; set; public int Age { get; set; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; namespace object2xml { class Program { static void Main(string[] args) { Persion p = new Persion(); p.Name = "张三"; p.Age = 18; var xml = p.Serialize<Persion>(); Console.WriteLine(xml); } } } |
from:https://blog.csdn.net/justgono/article/details/45887619
View Details去除命名空间:
1 2 3 4 5 6 7 8 |
//Create our own namespaces for the output XmlSerializerNamespaces ns = new XmlSerializerNamespaces (); //Add an empty namespace and empty value ns.Add ("", ""); //Create the serializer XmlSerializer slz = new XmlSerializer (someType); //Serialize the object with our own namespaces (notice the overload) slz.Serialize (myXmlTextWriter, someObject, ns); |
此外,在评论中还提到了去除开头的<?xml version="1.0" encoding="utf-8"?>的方法:
1 2 3 4 |
XmlWriterSettings settings = new XmlWriterSettings (); // Remove the <?xml version="1.0" encoding="utf-8"?> settings.OmitXmlDeclaration = true; XmlWriter writer = XmlWriter.Create ("output_file_name.xml", settings); |
另外,如果出现开头没有encoding="utf-8"时,应该使用:
1 2 3 |
XmlWriterSettings settings = new XmlWriterSettings (); settings.Encoding = Encoding.UTF8; XmlWriter writer = XmlWriter.Create ("output_file_name.xml", settings); |
参考文献: 1.在XML序列化时去除默认命名空间xmlns:xsd和xmlns:xsi from:https://www.swack.cn/wiki/001559619644599d7563755fc544a19aebbb4eaf0dcb274000/0015889968933656748bbc3214e4f04a714c163b9227520000
View Details背景 工作中遇到一个需求,客户要求按照他们指定的入参和出参开发一套WebService接口。 出入参不能有丝毫的出入,以方便他们的业务系统调用。 目标已明确,我们看看入参和出参(为了保护客户的商业机密,出入参都是虚构的): 入参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<BusinessQuery> <pageIndex value="1"/> <pageSize value="20"/> <paramList> <slot> <name value="$businessId"/> <valueList> <value value="x3c3738a4946472da595c45eb781e46c"/> <value value="adff738a4946472da595c45eb781e46c"/> </valueList> </slot> <slot> <name value="$biState"/> <valueList> <value value="1"/> <value value="2"/> </valueList> </slot> </paramList> </BusinessQuery> |
出参(正常)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<BusinessQueryResponse> <business> <id>x3c3738a4946472da595c45eb781e46c</id> <name>智能策略1</name> <category> <code value="1"/> <name value="BI"/> </category> <extension> <name value="ext1"/> <value value="01"/> </extension> <extension> <name value="ext2"/> <value value="2022-04-15"/> </extension> <department> <code value="001"/> <name value="商务运营部1"/> </department> <addDate value="2022-04-15 18:10:10"/> </business> <business> <id>adff738a4946472da595c45eb781e46c</id> <name>智能策略2</name> <category> <code value="1"/> <name value="BI"/> </category> <extension> <name value="ext1"/> <value value="01"/> </extension> <extension> <name value="ext2"/> <value value="2022-04-15"/> </extension> <department> <code value="001"/> <name value="商务运营部2"/> </department> <addDate value="2022-04-15 18:10:10"/> </business> </BusinessQueryResponse> |
出参(错误)
1 2 3 4 5 |
<returnData> <funCode>500</funCode> <errorCode/> <detail>查询记录为空</detail> </returnData> |
出入参看上去都挺简单的,开工吧~ 项目创建 添加Web服务 项目框架 SoapUI获取的请求模板如图 去掉上一步的前缀 入参XML节点配置 出参根节点配置 出参列表节点名称配置 出参XML节点名称完整配置 最终效果:与客户要求入参出参完全一致 异常出参需要用HttpModule自定义输出 定义HttpModule 异常输出方法 异常测试,效果哪下图 忘了说,HttpModule要在web.config里注册一下 完整代码下载>>
View Details在特殊的情况下查询过滤视图 会出现重复的数据结果集(返回的多条数据结果一致)。 原因是啥:主键 在数据库设计的理念中:每个表都应该的唯一的主键。但视图不同,EF中会自动按视图的最前几个非空型字段设置为主键。 如果在某些特殊的查询情况下。前几列数据一致时,EF就会返回重复数据。 解决方案: 1. 在使用的视图后 加入 AsNoTracking 阻止EF缓存数据集。(EF会依据主键建立数据缓存,实现后续的级联操作)。 2. 修改视图列顺序,将能区分内容的列放入最前列中,并保证为非空类型。 建议使用第二方案。 from:https://www.cnblogs.com/shikyoh/p/8794541.html
View Details在NetCore时代开发WebService和FrameWork时代差别有一点儿大,毕竟NetCore是跨平台的一个框架,不过使用起来也得很简单,下面我就使用Visual Studio2019开发一个示例服务程序。你依然要注意我这个我写的这个demo是soap1.2。在开发前你必须清楚这一点,因为有很多时候SOAP1.1和SOAP1.2 并不通用。至于soap1.1我暂时不用netcore写示例了。 下面是开发详细过程: (1)创建新项目,选择ASP.NET Core Web应用程序 ,如下图 (2)配置新项目,为自己的项目起个名字,然后点击下一步,如下图 (3)进入模板选择页面,选择空,如下图 (4)项目建立好后需要我们通过NuGet引用开发依赖包 SoapCore,如下图一样添加引用。 (5)这时我们新一个类用于示例的返回和接受参数,类名StudentModel 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[DataContract] public class StudentModel { /// <summary> /// 学号 /// </summary> [DataMember] public string Sno { get; set; } /// <summary> /// 姓名 /// </summary> [DataMember] public string Name { get; set; } /// <summary> /// 班级 /// </summary> [DataMember] public string Grade { get; set; } /// <summary> /// 生日 /// </summary> [DataMember] public DateTime Birthday { get; set; } } |
(6)添加接口约束IContract,我们和framework下保持一致,实现两个方法,Get和Add代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[ServiceContract] public interface IContract { /// <summary> /// 查询学生信息 /// </summary> /// <param name="sno">学号</param> /// <returns>学生信息</returns> [OperationContract] StudentModel Get(string sno); /// <summary> /// 添加学生信息 /// </summary> /// <param name="student">学生信息</param> /// <returns>result</returns> [OperationContract] int Add(StudentModel student); } |
(7)添加服务实现类StudentService,来实现我们的约定服务接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class StudentService : IContract { public StudentModel Get(string sno) { return new StudentModel() { Sno = sno, Name = "小红", Grade = "202002", Birthday = new DateTime(2012, 8, 15) }; } /// <summary> /// 添加学生信息 /// </summary> /// <param name="student"></param> /// <returns></returns> public int Add(StudentModel student) { return 1; } } |
(8)在netcore中添加注入,这个想必不会陌生吧,现在netcore的注入已经很普遍了,修改 Startup.cs类中的ConfigureServices方法,添加代码如下:
1 |
services.TryAddSingleton<IContract, StudentService>(); |
(9)添加服务发布接口地址,修改Startup.cs类中的Configure方法,在最后修改UseEndpoints这一部分代码如下:
1 2 3 4 5 6 7 8 9 10 11 |
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseSoapEndpoint<IContract>("/StudentService.asmx", new BasicHttpBinding(), SoapSerializer.XmlSerializer); } |
(10)点击Visual Studio2019上的运行按钮,此时便可以在浏览器里预览了。直接运行看到的页面是错误的地址,需要手动改一下地址如下:https://localhost:44376/StudentService.asmx,添加后半部分StudentService.asmx。我们便可以看到正常的返回了,如下图: 至此我们已经完成了一个简单的WebService,这个服务实现两个接口,一个Get 一个Add方法。 可以下载我示例源码百度网盘链接:https://pan.baidu.com/s/1wCXaGyThXTuS04aupJFsbg 查看提取码请先点击下方的捐赠按钮。 原创作品 相关文章:C# net framework 开发WebService(Soap) from:https://lebang2020.cn/details/210110njneqn2f.html
View Details关于C# webservices 返回的soap节点标签会包含方法名+result的修改 有时候做项目的时候需要用到webservices与其他系统进行交互,但是当使用asp.net开发webservice的时候,webservices返回数据的xml节点标签会默认带 方法名+result 如下图: 这样的返回方式不利于客户端进行解析 我们可以在方法头添加属性: 这样返回的数据就会变化 from:https://blog.csdn.net/qq_40099189/article/details/107120068
View Details