-
C#创建临时文件
by{ guangboo }, published {2009-12-08}, Tag { CSharp / .net / asp.net / }在使用C1.C1Excel控件将DataTable导出到Excel表格的时候,遇到一个问题。原来的代码是:
C1XLBook book = ExcelDocument.Instance.ExpertExcel(dt); string fileName = Path.GetFileNameWithoutExtension(TMP_PATH + "\\" + dt.TableName) + ".xls"; book.Save(fileName); book.Dispose(); FileStream fs = null; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] buffer = new byte[(int)fs.Length]; fs.Read(buffer, 0, buffer.Length); Response.ContentEncoding = Encoding.GetEncoding("GB2312"); Response.HeaderEncoding = Encoding.GetEncoding("GB2312"); Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(Path.GetFileNameWithoutExtension(fileName)) + ".xls"); Response.AppendHeader("Content-Length", buffer.Length.ToString()); Response.ContentType = "application/octet-stream"; Response.OutputStream.Write(buffer, 0, buffer.Length); }finally{ fs.Close(); try{ File.Delete(fileName); }catch{} }上面的代码中fileName的值为Path.GetFileNameWithoutExtension(TMP_PATH + "\\" + dt.TableName) + ".xls",其中TMP_PATH是Web.config里面配置的,使用ConfigurationManager.AppSettings[""]获取的,fileName="E:\TMP\****.xls"。
我其实也没有在E盘下创建TMP文件夹,跟没有给该文件夹添加任何的权限,但是我在使用VS自带的服务器运行网站的时候,完全没有问题,奇怪的是,我在将数据导出到Excel的过程中,一直观察E盘,就是没有发现TMP文件,也没有错误信息,也许是我刷新的不够快吧。
但到我不网站部署到测试服务器的时候,运行导出程序就出现问题了“System.IO.IOExcetpion:Failed to create storage file.”,问题就出在book.Save(fileName)上,立即想到的是没有给这个TMP_PATH文件夹足够的权限,但是设了半天,问题还是一样。
然后使用reflector工具,查看C1.C1Excel的源码,根据异常堆栈提供的错误信息,找到C1XLBook的Save(fileName)方法:
public void Save(string fileName) { string str; bool flag = false; if (((str = Path.GetExtension(fileName).ToLower()) != null) && ((str == ".xlsx") || (str == ".zip"))) { flag = true; } this.o(fileName, flag); }该方法执行到this.o(fileName, flag)的时候出现异常,然后我又跟踪到o方法:
internal void o(string A_0, bool A_1) { if (this.Sheets.Count == 0) { n("Cannot save empty book (need at least one sheet).", true); } bool flag = false; foreach (XLSheet sheet in (IEnumerable) this.Sheets) { if (sheet.Visible) { flag = true; break; } } if (!flag) { n("Cannot save book without any visible sheets.", true); } this.f(); using (au au = au.a(A_0)) { using (cg cg = au.c("Workbook")) { this.q(cg); } } this.e(); }继续向上跟踪,到在using (au au = au.a(A_0))语句的时候出现了异常,然后定位到au类的a方法:
internal static au a(string A_0) { int num = 0x1012; bg bg = null; if ((StgCreateDocfile(A_0, num, 0, out bg) != 0) || (bg == null)) { throw new IOException(l.e("Failed to create storage file.")); } return new au(bg); }很显然IOException(l.e("Failed to create storage file."))异常被抛出了,然后我又定位到StgCreateDocfile方法:
[DllImport("OLE32.DLL")] private static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string A_0, int A_1, int A_2, out bg A_3);该方法是来说OLE32.DLL文件,此时我马上想到也行测试服务器上没有ole32.dll文件,后来我在windows/system32/下面找到ole32.dll文件,虽然文件大小和版本和我的win7上的不一样,但是问题应该不在这里,而且无也不敢随便将这个文件替换,怕影响了sql和其他程序的运行。
然后我就开始在google上搜寻答案,其中有一个答案最有可能:
>>>>>>>>>>>>> IIS requires file/directory permissions to be set so that the anonymous users have write access to the directory. IUSR_, IWAM_ By file permissions, I mean the permissions you would set using Windows Explorer file/directory Properties - Security tab. You can also set these using cacls.exe from Run or a command line. Setting them from code is nasty, with all kinds of objects involved. It's so nasty, that even MS installations tend to use calcs.exe from a system or spawn call (that's the little Dos box you see pop up and go away during some installations). It is also necessary to allow write permission on the Virtual directory - Virtual Directory tab of IIS Website directory properties. Note, that in a live situation, both Write and Execute (scripts or executables) should NOT be granted together. You don't want people writing things that execute. >>>>>>>>>>>>> I did write a sample to check this. Here's what my code looks like: private void Button1_Click(object sender, System.EventArgs e) { this.c1XLBook1.Clear(); C1.C1Excel.XLSheet sheet = this.c1XLBook1.Sheets[0]; sheet[0,0].Value = "Hello from ASP.NET"; string xlsFile = @"temp\hello.xls"; this.c1XLBook1.Save(Page.MapPath(xlsFile)); // << map to absolute path this.Response.Redirect(xlsFile); } When I ran this, I got the error you described. That was to be expected, since I didn't create or set permissions on the "temp2" folder. Then I did this: 1) Open the IIS management console, look for the application's virtual directory, right-click, select "New | Virtual Directory". 2) Type in the alias ("temp") and select the path for the new virtual directory. (Navigate to the app folder, click the "Make New Folder" button, and type "temp" to create the new temp folder). 3) In the "Access Permissions" step, select "Read" and "Write" (make sure "Run" and "Execute" are not checked). This takes care of the IIS side of the story. If you run the app now, you will get the same error though. That's because the folder permissions are not set yet. To set the folder permissions, right-click the new folder in the Windows Explorer, select "Sharing and Security...", then pick the "Security" tab. This is where things get complicated, because you must grant permissions based on how your accounts are set up, and this depends on which OS/IIS/.NET combination you have. The simplest thing to do (on your development machine) is delete all groups except two: "Administrators" and "Everyone". Members of the "Administrators" group should be allowed to do everything. Members of the "Everyone" group should be allowed to "Read" and "Write" (but not execute, list folder contents, etc). To delete the groups, you will probably have to click the "Advanced" button and uncheck the "Inherit" checkbox. Attached is a screenshot of the Security Properties dialog after this is all setup. After making these changes, my sample web app works fine. The xls files are created under the temp folder and I can redirect the browser to them. I hope this information helps. Please note that this is an easy way to set up the securities on your development environment. On production systems, the sysadmin would probably be more restrictive and grant permissions to specific users instead of "Everyone". But since we're not granting execute permissions anyway, this seems OK at least for debugging environments. If anyone has additional information on this topic, please feel free to share it.这段EN文,大概的意思就是在目录文件IIS运行用户的权限,我觉得很麻烦,然后就试着不要自己手动添加临时文件夹,而采用系统自己的临时文件夹,使用System.IO.Path.GetTempFileName()可以创建一个临时文件,如:C:\Users\Jeff\AppData\Local\Temp\tmpEAFD.tmp,这是我的Win7下的临时文件,也行你的XP是:C:\Documents and Settings\UserName\Local Settings\Temp\tmpEAFD.tmp。而且你也可以使用File.Delete来删除该临时文件。
修改后的代码为:C1XLBook book = ExcelDocument.Instance.ExpertExcel(dt); string fileName = Path.GetTempFileName(); book.Save(fileName); book.Dispose(); FileStream fs = null; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] buffer = new byte[(int)fs.Length]; fs.Read(buffer, 0, buffer.Length); Response.ContentEncoding = Encoding.GetEncoding("GB2312"); Response.HeaderEncoding = Encoding.GetEncoding("GB2312"); Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(Path.GetFileNameWithoutExtension(fileName)) + ".xls"); Response.AppendHeader("Content-Length", buffer.Length.ToString()); Response.ContentType = "application/octet-stream"; Response.OutputStream.Write(buffer, 0, buffer.Length); } catch(Exception ex) { lblResult.Text = "生成Excel文件过程中,出现异常:" + ex.Source; lblResult.Visible = true; } finally { fs.Close(); try { File.Delete(fileName); } catch { } } -
无法序列化会话状态,在“Stateserver”或“Sqlserver”模式下
by{ guangboo }, published {2009-08-18}, Tag { CSharp / .net / web应用 / asp.net / }发布ASP.NET2.0应用时候出现错误:
无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP_NET 将序列化会话状态对象,因此不允许使用无法序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“Custom”模式下执行了类似的序列化,则适用同样的限制。

而在开发模式下是没有问题的。
查看异常描述可以发现“StateServer”和“SQLServer”模式等字眼,在web.config文件中可以发现,<sessionState mode="StateServer"/>,将该句去掉或将"StateServer"或"SQLServer"改成”InProc“可以解决该问题。
-
Httpwebrequest如何去Https的网址抓取数据
by{ guangboo }, published {2009-08-04}, Tag { CSharp / }针对昨天做的使用HttpWebRequest请求https网址数据时出现的问题做一下更正:
其实要解决的问题很简单,就是通过浏览器直接访问https://220.178.30.189:8080/winner_new/images/quote/600000_mk_520_299.png时,IE,Chorme都会给出警告:


只是浏览器的警告,IE可以浏览,而Chrome是在浏览前给出警告,点击仍然继续就可以正常浏览内容了,浏览器给出警告是因为证书不是办法给trade.hazq.com的而不是https://220.178.30.189:8080的,这可能存在风险,证书是不可信任的。
using System.Net; using System.IO; protected void Page_Load(object sender, EventArgs e) { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(IsTrust); string url = @"https://220.178.30.189:8080/winner_new/images/quote/600000_mk_520_299.png"; WebClient client = new WebClient(); byte[] buffer = client.DownloadData(url); Response.ContentType = "image/png"; Response.OutputStream.Write(buffer, 0, buffer.Length); Response.End(); } public bool IsTrust(object obj, X509Certificate cer, X509Chain chain, System.Net.Security.SslPolicyErrors error) { return true; }其中ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(IsTrust); 表示证书验证的回发,IsTrust是验证证书是否受信任的方法,这里总是返回true,表示忽略证书的验证,都为可信任的证书。
-
用Httpwebrequest加载证书建立Ssl通道
by{ guangboo }, published {2009-08-03}, Tag { CSharp / }
使用C# 2.0 来实现请求HTTPS(SSL)页面数据的实现:
using System.Security.Cryptography.X509Certificates; using System.Security; using System.Net; using System.IO; public partial class RequestSSL : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { X509Certificate cer = X509Certificate.CreateFromCertFile(@"d:\My Documents\My Pictures\hazq.cer"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"https://220.178.30.189:8080/winner_new/images/quote/600000_mk_520_299.png"); //请求浦发银行的股票走势曲线 System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(IsTrust); request.ClientCertificates.Add(cer); request.Method = "GET"; request.ContentType = "image/png"; request.KeepAlive = true; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); int length = int.Parse(response.Headers["Content-Length"]); Stream stream = response.GetResponseStream(); byte[] buffer = new byte[length]; stream.Read(buffer, 0, length); Response.Clear(); Response.ContentType = "image/png"; Response.OutputStream.Write(buffer, 0, length); Response.End(); } public bool IsTrust(object obj, X509Certificate cer, X509Chain chain, System.Net.Security.SslPolicyErrors error) { return true; } }该方法在chrome浏览器中的表现是:

chrome运行效果截图而在IE 7中什么都没有了,就是图片没有加载过来。

ie 7运行效果截图而且chrome请求到的图片,我另存到磁盘,使用FW编辑的时候,提示说“无法打开文件,未知文件类型”。
-
数据库 数据类型Float到C#类型Decimal, Float数据类型转化无效
by{ guangboo }, published {2009-07-06}, Tag { CSharp / 数据库 / }今天运行系统突然出错,数据类型转化无效,错误在system.data.sqlclient.get_decimal()方法,初步估计是数据库的float类型转换为c#的decimal类型时出错了,实体类使用的是decimal?类型,心想就算数据库里的数值是空,也不能出现转换错误啊。
网上百般搜索,很多人遇到类似情况,多数是直接去float类型时候出错,如(float)dr[0],后来看到有说应该是先转化成double,然后在转化成float就可以了
尝试了一下把实体类的decimal?类型的字段改成double?类型,OK.
-
给存储过程不能将0作为参数?
by{ guangboo }, published {2008-08-06}, Tag { CSharp / ado.net / .net / 数据库 / }遇到一个有趣的问题:
cmd.CommandText = "getClasses";
cmd.Parameters.Add(new SqlParameter("@PageIndex", 0));结果报错:过程 'getClasses' 需要参数 '@PageIndex',但未提供该参数。
我晕明明这样定义的啊:
。。。PROCEDURE [dbo].[getClasses]
@PageIndex int,
@PageSize int,
@Total int out....
找了很久的原因,结果在使用cmd.Parameters.Add(new SqlParameter("@PageIndex","0"));
成功了!
难道真的不能将0做为存储过程的参数吗?
baidu一艘,发现:
int a=0;
cmd.Parameters.Add(new SqlParameter("@PageIndex",a));
成功!
奇怪的MS。