微软的坑,你有踩过吗?
2015-09-17 14:07
337 查看
最近在做一个很简单的小工具,需求大概是这样的,做一个定时任务系统,定期从服务器上统计相关的业务数据,生成相关报表,然后以Excel方式发送给相关人员。任务很简单,定时任务没问题,生成报表没问题,导出Excel没问题,导出的Excel放在C盘temp目录下,然后设好发送时间,一切都感觉妥妥的,结果也很美好,过了10秒钟(本也测试,时间设得很短),邮件也妥妥的收到,附件中的excel表格也妥妥的能打开,报表也没问题。Oh,yeah,so,easy..,即然结果这么美好,那就打包发布吧。
此处省略100字,就部署完了。
嘀哒。。嘀哒。。,10秒,20秒,30秒,。。。没搞错,为了先跑一个起来,我在正式环境也是设置了10秒运行一次呀?这10秒也太漫长了吧?1分钟了,好吧,应该是出问题了,心里仍在想着是不是哪部署出了问题呀,也不应该呀,就这么简单的一个小工具是吧?
此处省略200字,检查部署没有任何问题。好吧,查日志。
果不其然,报错了,错得还很趾高气扬:
System.FormatException: An invalid character was found in the mail header: '周'.
at System.Net.Mime.MailBnfHelper.GetTokenOrQuotedString(String data, StringBuilder builder)
at System.Net.Mime.ContentDisposition.ToString()
at System.Net.Mime.ContentDisposition.PersistIfNeeded(HeaderCollection headers, Boolean forcePersist)
at System.Net.Mime.MimePart.Send(BaseWriter writer)
at System.Net.Mime.MimeMultiPart.Send(BaseWriter writer)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
没搞错,An invalid character was found in the mail header“周”? 这应该是乱码时,才会这样提示的吧?页面我邮件发送直接是使用SmtpClient,根本就没有设置header呀?
此处省略1000字,各种度娘,各种google,各种恶补邮件头,MIME的知识,各种设置附件ContentType。结果都一样,唯一不一样的就是乱码的字,从“周“变成不是”周“。。
此处省略2000字,突然听同事说有可能和CurrentCulture有关系,顿时眼前一亮,赶紧google一下,果然,有答案了。
.net 4.0中有一个Bug:Culture Bug in ContentDisposition,即只要设置了ContentDisposition的时间,任何时间,如CreationDate,或是ModificationDate,.net内部,会将这些时间通过调用DateTime的toString方法传递给SmtpDateTime,问题就出现在,这些时间格式是和本地语言环境相关的,toString很可能出问题。(官方说法是在vs2013中修复了这个问题)好了,找到问题就好办了,即然和Culture有关,我又不想升级.net Framework,那就让它和CurrentCulture暂时没关系吧。
果然,那个另人讨厌的”周“不见了,10秒后邮件到了,哈哈,,终于可以收工了。等等。。,为什么我一个好好的Excel附件,发出来后,即没文件名(实际应该有,只是乱码了,没显示出来),里面的内容也是乱码的?天呀,你在和我开玩笑嘛?我本地开发环境都是好好的呀!!
此处省略3000字,各种尝试,各种用网友的办法,各种失去理智的尝试,各种。。无果而终。
就快要放弃的时间,突然想起,有问题找stackoverflow.com呀,度啥娘呀。好吧,我是乱了方寸了。谁让我本应该2小时前就下班的,到现在问题还没头绪呢。果然,这个问题早在n年前就有人发现了,仍然是我们可爱的微软埋下的坑:
View Code
过程是坎坷的,结局是美好的!
只能怪我爱得太深了,竟不曾怀疑过你。用它来结语,再好不过了吧!
此处省略100字,就部署完了。
嘀哒。。嘀哒。。,10秒,20秒,30秒,。。。没搞错,为了先跑一个起来,我在正式环境也是设置了10秒运行一次呀?这10秒也太漫长了吧?1分钟了,好吧,应该是出问题了,心里仍在想着是不是哪部署出了问题呀,也不应该呀,就这么简单的一个小工具是吧?
此处省略200字,检查部署没有任何问题。好吧,查日志。
果不其然,报错了,错得还很趾高气扬:
System.FormatException: An invalid character was found in the mail header: '周'.
at System.Net.Mime.MailBnfHelper.GetTokenOrQuotedString(String data, StringBuilder builder)
at System.Net.Mime.ContentDisposition.ToString()
at System.Net.Mime.ContentDisposition.PersistIfNeeded(HeaderCollection headers, Boolean forcePersist)
at System.Net.Mime.MimePart.Send(BaseWriter writer)
at System.Net.Mime.MimeMultiPart.Send(BaseWriter writer)
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Mail.SmtpClient.Send(MailMessage message)
没搞错,An invalid character was found in the mail header“周”? 这应该是乱码时,才会这样提示的吧?页面我邮件发送直接是使用SmtpClient,根本就没有设置header呀?
此处省略1000字,各种度娘,各种google,各种恶补邮件头,MIME的知识,各种设置附件ContentType。结果都一样,唯一不一样的就是乱码的字,从“周“变成不是”周“。。
此处省略2000字,突然听同事说有可能和CurrentCulture有关系,顿时眼前一亮,赶紧google一下,果然,有答案了。
.net 4.0中有一个Bug:Culture Bug in ContentDisposition,即只要设置了ContentDisposition的时间,任何时间,如CreationDate,或是ModificationDate,.net内部,会将这些时间通过调用DateTime的toString方法传递给SmtpDateTime,问题就出现在,这些时间格式是和本地语言环境相关的,toString很可能出问题。(官方说法是在vs2013中修复了这个问题)好了,找到问题就好办了,即然和Culture有关,我又不想升级.net Framework,那就让它和CurrentCulture暂时没关系吧。
var currentCulture = Thread.CurrentThread.CurrentCulture; var attachment = new Attachment(attachmentFile, displayName); try { ... Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; attachment.ContentDisposition.CreationDate = File.GetCreationTime(attachmentFilePath); attachment.ContentDisposition.ModificationDate = File.GetLastWriteTime(attachmentFilePath); attachment.ContentDisposition.ReadDate = File.GetLastAccessTime(attachmentFilePath); ... } finally { Thread.CurrentThread.CurrentCulture = currentCulture; }
果然,那个另人讨厌的”周“不见了,10秒后邮件到了,哈哈,,终于可以收工了。等等。。,为什么我一个好好的Excel附件,发出来后,即没文件名(实际应该有,只是乱码了,没显示出来),里面的内容也是乱码的?天呀,你在和我开玩笑嘛?我本地开发环境都是好好的呀!!
此处省略3000字,各种尝试,各种用网友的办法,各种失去理智的尝试,各种。。无果而终。
就快要放弃的时间,突然想起,有问题找stackoverflow.com呀,度啥娘呀。好吧,我是乱了方寸了。谁让我本应该2小时前就下班的,到现在问题还没头绪呢。果然,这个问题早在n年前就有人发现了,仍然是我们可爱的微软埋下的坑:
... Attachment attachment = null; //添加附件 if (!String.IsNullOrEmpty(attachmentFilePath) && File.Exists(attachmentFilePath)) { attachment = CreateAttachment(WriteFileToMemory(attachmentFilePath), attachmentFileName,contentType,attachmentFilePath); message.Attachments.Add(attachment); } ... public static Attachment CreateAttachment(Stream attachmentFile, string displayName, string contentType, string attachmentFilePath) { var currentCulture = Thread.CurrentThread.CurrentCulture;//.net4.0 bug, var attachment = new Attachment(attachmentFile, displayName); try { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; attachment.ContentType = new ContentType(contentType); attachment.ContentDisposition.CreationDate = File.GetCreationTime(attachmentFilePath); attachment.ContentDisposition.ModificationDate = File.GetLastWriteTime(attachmentFilePath); attachment.ContentDisposition.ReadDate = File.GetLastAccessTime(attachmentFilePath); attachment.TransferEncoding = TransferEncoding.Base64; attachment.NameEncoding = Encoding.UTF8; string encodedAttachmentName = Convert.ToBase64String(Encoding.UTF8.GetBytes(displayName)); encodedAttachmentName = SplitEncodedAttachmentName(encodedAttachmentName); attachment.Name = encodedAttachmentName; } finally { Thread.CurrentThread.CurrentCulture = currentCulture; } return attachment; } private static Stream WriteFileToMemory(string filePath) { var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); return fileStream; } private static string SplitEncodedAttachmentName(string encoded) { const string encodingtoken = "=?UTF-8?B?"; const string softbreak = "?="; const int maxChunkLength = 30; int splitLength = maxChunkLength - encodingtoken.Length - (softbreak.Length * 2); IEnumerable<string> parts = SplitByLength(encoded, splitLength); string encodedAttachmentName = encodingtoken; foreach (var part in parts) { encodedAttachmentName += part + softbreak + encodingtoken; } encodedAttachmentName = encodedAttachmentName.Remove(encodedAttachmentName.Length - encodingtoken.Length, encodingtoken.Length); return encodedAttachmentName; } private static IEnumerable<string> SplitByLength(string stringToSplit, int length) { while (stringToSplit.Length > length) { yield return stringToSplit.Substring(0, length); stringToSplit = stringToSplit.Substring(length); } if (stringToSplit.Length > 0) { yield return stringToSplit; } }
View Code
过程是坎坷的,结局是美好的!
只能怪我爱得太深了,竟不曾怀疑过你。用它来结语,再好不过了吧!
相关文章推荐
- Linq左关联 右关联 内关联
- CentOS7 yum 源的配置与使用
- JQuery实现级联下拉框效果实例讲解
- Linux如何在线修改hostname
- Java在Jar包中初始化log4j的方法
- ADT开发中的一些优化设置:代码自动补全等
- This Android SDK requires Android Developer Toolkit version 22.6.2 or above.
- awk 的使用方法
- FFMPEG使用参数详解
- 【分享】零基础学习iOS开发的学习方法总结
- 项目中遇到创建oracle定时任务
- 理解 Node.js 里的 process.nextTick()
- Effective C++——尽可能使用const
- Linux系统中特殊文件权限
- 软件工程的实践项目的自我目标
- Js获取下拉框选定项的值和文本
- Linux中常用的操作命令和vi操作命令以及gdb调试命令
- 从51信用卡到OAuth2协议
- 事务xmin,xmax
- linux 代码段,数据段,堆,栈的存放的数据