winfrom运用webservice上传文件到服务器

winfrom做文件上传的功能显然没有BS的简单,本实例是运用了webservice获取二进制流转换的字符串。然后,解析字符串,把流文件再转成pdf.

webservice 里面的代码为下:

  [WebMethod]
        public bool Create(string Base64String, string name)
        {
            try
            {
                Stream stream = FromBase64String(Base64String);
                using (FileStream fs = new FileStream("D:\word\" + name, FileMode.Create))
                {
                    byte[] bytes = new byte[stream.Length];
                    int numBytesRead = 0;
                    int numBytesToRead = (int)stream.Length;
                    stream.Position = 0;
                    while (numBytesToRead > 0)
                    {
                        int n = stream.Read(bytes, numBytesRead, Math.Min(numBytesToRead, int.MaxValue));
                        if (n <= 0)
                        {
                            break;
                        }
                        fs.Write(bytes, numBytesRead, n);
                        numBytesRead += n;
                        numBytesToRead -= n;
                    }
                    fs.Close();
                    
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 返回一个只读流
        /// </summary>
        /// <param name="content">文件的二进制形式</param>
        /// <returns></returns>
        public static Stream FromBase64String(string content)
        {
            //临时文件
            string file = Path.Combine("d://"+Guid.NewGuid().ToString()) + ".tmp";

            try
            {
                using (Stream sw = new System.IO.FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    //缓存
                    byte[] buff = new byte[1024*8];

                    StringBuilder sb = new StringBuilder(content);

                    int bufLenght = Convert.ToBase64String(buff).Length;
                    int startindex = 0;

                    //大于缓存数组大小的时候
                    while (sb.Length - startindex >= bufLenght)
                    {
                        buff = Convert.FromBase64String(sb.ToString(startindex, bufLenght));
                        //写入流
                        sw.Write(buff, 0, buff.Length);
                        startindex += bufLenght;
                    }

                    //小于缓存数组的时候
                    if (sb.Length - startindex > 0)
                    {
                        buff = Convert.FromBase64String(sb.ToString(startindex, sb.Length - startindex));
                        sw.Write(buff, 0, buff.Length);
                    }

                    sw.Close();
                }

                return new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Delete);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }

可能会疑问,为啥不直接传一个sream对象过来,反而要传个编码字符串过来,再解析,是不是做了无用功?其实我觉得也是。但是直接传递stream会报错的~

stream的类型无法转换(具体的错误可以自己试一试。此处不截图了。)也许有更好的方法,只是我没找到。

客户端调用webservice代码如下:

      private void button2_Click(object sender, EventArgs e)
        {
        
            WebReference.WebServiceasmx web = new WebReference.WebServiceasmx();
            string str = FileToStream("d:\word\2014标准馆数据监控系统用户手册.pdf");
            bool r = web.Create(str,"987.pdf");
            MessageBox.Show(r.ToString());
        }
        /// <summary> 
        /// 从文件读取 Stream 
        /// </summary> 
        public string FileToStream(string fileName)
        {
            // 打开文件 
            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            // 读取文件的 byte[] 
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();
            // 把 byte[] 转换成 Stream 
            Stream stream = new MemoryStream(bytes);

            return ToBase64String(stream);
        }



        /// <summary>
        /// 将流转换成字符串
        /// </summary>
        /// <param name="s">文件留</param>
        /// <returns>流的字符形式</returns>
        public static string ToBase64String(Stream s)
        {

            byte[] buff = null;
            StringBuilder rtnvalue = new StringBuilder();

            using (System.IO.BinaryReader br = new System.IO.BinaryReader(s))
            {
                do
                {
                    buff = br.ReadBytes(BufferSize);
                    rtnvalue.Append(Convert.ToBase64String(buff));

                } while (buff.Length != 0);

                br.Close();
            }
            return rtnvalue.ToString(); ;
        }

 当传递的文件大小超过4M的时候,会报错:

常日志信息:
运行配置文件中指定的扩展时出现异常。 ---> 超过了最大请求长度。
System.Web.Services.Protocols.SoapException: 运行配置文件中指定的扩展时出现异常。 ---> 超过了最大请求长度。
在 System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
在 System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
那么问题来了:为什么报错?怎么修改?
问题原因:
Asp.Net默认上传文件大小是4M,防止Ddos攻击。试想一下,如果不现在上传大小。。。。你的服务器会咋样。


解决方法1:
针对单个项目,只需修改Web.config就可以了,如下: 
< configuration>
< system.web>
< httpRuntime maxRequestLength = "40960"  executionTimeout="3600" />
< /system.web>
< /configuration>
限制最大长度是40M,超时时间1小时。




解决方法2
找到:C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/CONFIG/machine.config文件(版本及系统不同,目录稍有差异),找到“maxRequestLength="4096"”这行,将其中的4096换成较大的数值,单位是KB。


后记
httpRuntime 是配置asp.net http运行时设置,以确定如何处理对asp.net应用程序的请求。 
executionTimeout:表示允许执行请求的最大时间限制,单位为秒 
maxRequestLength:指示 ASP.NET 支持的最大文件上载大小。该限制可用于防止因用户将大量文件传递到该服务器而导致的拒绝服务攻击。指定的大小以 KB 为单位。默认值为 4096 KB (4 MB),最大值:2097151。 
useFullyQualifiedRedirectUrl:表示指示客户端重定向是否是完全限定的(采用 "http://server/path" 格式,这是某些移动控件所必需的),或者指示是否代之以将相对重定向发送到客户端。如果为 True,则所有不是完全限定的重定向都将自动转换为完全限定的格式。false 是默认选项。 
minFreeThreads:表示指定允许执行新请求的自由线程的最小数目。ASP.NET 为要求附加线程来完成其处理的请求而使指定数目的线程保持自由状态。默认值为 8。 
minLocalRequestFreeThreads:表示ASP.NET 保持的允许执行新本地请求的自由线程的最小数目。该线程数目是为从本地主机传入的请求而保留的,以防某些请求在其处理期间发出对本地主机的子请求。这避免了可能的因递归重新进入 Web 服务器而导致的死锁。 
appRequestQueueLimit:表示ASP.NET 将为应用程序排队的请求的最大数目。当没有足够的自由线程来处理请求时,将对请求进行排队。当队列超出了该设置中指定的限制时,将通过“503 - 服务器太忙”错误信息拒绝传入的请求。 
enableVersionHeader:表示指定 ASP.NET 是否应输出版本标头。Microsoft Visual Studio 2005 使用该属性来确定当前使用的 ASP.NET 版本。对于生产环境,该属性不是必需的,可以禁用.

原文地址:https://www.cnblogs.com/liuruitao/p/4036887.html