winform 通过webservice向服务器提交图片需要注意的地方

最近一个winform项目中需要通过拍照或者上传本地文件或者截图的方式把产品图片上传到服务器,最后选择了服务器部署webservice的方式来进行。其中遇到了一些问题记录下来。

不多说,直接上服务端代码

[WebMethod(Description = "上传文件")]
 
   public bool UploadFiles(string filename, byte[] content)
   {
       try
       {
           int index = filename.LastIndexOf(".");
           if (index == 0)
           {
               return false;
           }
           else
           {
               string extended = string.Empty;
               if (index + 1 == filename.Length)
               {
                   return false;
               }
               else
               {
                   extended = filename.Substring(index + 1);
                   if (extended == "jpeg" || extended == "gif" || extended == "jpg" || extended == "png")
                   {
                       try
                       {
                           string Path = System.Web.HttpContext.Current.Server.MapPath("~/ProductImages/");
                           if (!Directory.Exists(Path))
                           {
                                Directory.CreateDirectory(Path);
                           }
                         
                           MemoryStream mymemorystream = new MemoryStream(content, 0, content.Length);
                      
                           File.WriteAllBytes((Path + filename), content);
                           return true;
                       }
                       catch (Exception ex)
                       {
                           return false;
                       }
                   }
                   else
                   {
                       return false;
                   }
               }
           }
       }
       catch
       {
           return false;
       }
   }

  这其实是一种比较通用的方式,不仅可以用来接收图片文件,也可以是其他文件。当然你也可以做一些文件大小的限制,自己添加一个判断就行。没啥好说的,问题也没有出现。

接下来说说winform这边,下图是图片上传部分

至于如何通过拍照和加载图片或者截图上传到picturebox上大家自己去找吧,网上一大堆。

接下来就是把picture的图片上传到服务器了,首先是添加服务引用,这也很简单就不说了,注意如果一个解决方案中有很多项目,而这个图片上传所在的项目不是主项目,那么需要在主项目的app.config文件中添加一个节点,否则会报找不到什么节点的错误。

<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WebServiceSoap" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/WebService.asmx" binding="basicHttpBinding"
bindingConfiguration="WebServiceSoap" contract="WebService.WebServiceSoap"
name="WebServiceSoap" />
</client>
</system.serviceModel>

  接下来就是上传部分了

if (image != null&isnewimage)
          {
              MemoryStream ms = new MemoryStream();
              image.Save(ms, ImageFormat.Png);
              byte[] bytes = new byte[ms.Length];
              bytes = ms.GetBuffer();       
              WebService.WebServiceSoapClient webservice = new WebService.WebServiceSoapClient();
              string filename = cInvCode + ".png";
              if (webservice.UploadFiles(filename, bytes))
              {
                  
              }
              else
              {
                  issaveok = false;
                  failreason = "图片上传失败!";
                   
                  return;
              }            
          }

  这里首先获取图片资源放到一个image对象中,然后转换为字节数组通过webservice上传,这里我让图片全部以png格式上传,当然你可以以其他格式上传。

刚开始在向字节数组赋值的时候我用的不是bytes = ms.GetBuffer();而是用的ms.Write(bytes, 0, (int)ms.Length);结果文件是可以上传到服务器,但是服务器端的图片文件始终打不开,说可能文件已经损坏,查了半天查不出来原因,最后发现其实还有bytes = ms.GetBuffer();这种方法,一试,问题果然解决,服务器端的图片成为可以预览查看的正常图片了。

好了,这是第一次写博客,写的不好,还请吐槽啊。

Stream.Write 与 StreamWriter.Write 的区别

Posted on 2011-11-02 09:10 ☆磊☆ 阅读(2377) 评论(8) 编辑 收藏

Stream.Write 与 StreamWriter.Write 是我们在向流中写数据时,最常用的方法。下面就详细讲解这两个方法。

一、测试方法是否结果相同

首先看下面两段代码左侧是StreamWriter.Write 右侧是Stream.Write:

1
2
3
4
5
6
Stream ms = new MemoryStream();
string str = "这是测试字符串";
 
StreamWriter sw = new StreamWriter(ms, Encoding.UTF8);
sw.Write(str);
sw.Flush();
1
2
3
4
5
6
Stream ms = new MemoryStream();
string str = "这是测试字符串";
 
byte[] buffer = Encoding.UTF8.GetBytes(str);           
ms.Write(buffer, 0, buffer.Length);
ms.Flush();
 

上面我们可以看到StreamWriter.Write的可读性更好一些。

但是这两段代码执行后的ms是否是相同的结果呢?

首先我们来看下长度吧,在代码最后分别加上

1
2
Console.WriteLine("StreamWriter.Write:{0}", ms.Length);
Console.WriteLine("Stream.Write:{0}", ms.Length);

执行后结果如下:

各位看官,看到这里有何想法?

二、深究原因

下面继续深究一下这个多出来的3个字节

在方法后面都加上如下一段代码将MemoryStream的内容以十六进制的形式打印出来

1
2
3
4
5
6
7
8
ms.Position = 0;
byte[] bytes = new byte[ms.Length];
ms.Read(bytes, 0, bytes.Length);
foreach (var item in bytes)
{
    Console.Write(item.ToString("X2") + " ");
}
Console.WriteLine(String.Empty);

再次执行结果如下:

这里我们发现用StreamWriter.Write输出多出了EF BB BF这3个字节

Google一下:多出来的这个玩意是 字节顺序记号(英语:byte-order mark,BOM)

在维基百科中可以查到:

编码 表示 (十六进制) 表示 (十进制)
UTF-8 EF BB BF 239 187 191
UTF-16(大端序) FE FF 254 255
UTF-16(小端序) FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76和以下的一个字节:[ 38 | 39 | 2B | 2F ] 43 47 118和以下的一个字节:[ 56 | 57 | 43 | 47 ]
en:UTF-1 F7 64 4C 247 100 76
en:UTF-EBCDIC DD 73 66 73 221 115 102 115
en:Standard Compression Scheme for Unicode 0E FE FF 14 254 255
en:BOCU-1 FB EE 28 及可能跟随着FF 251 238 40 及可能跟随着255

ok,了解了这个东西后我们就就需要知道在StreamWriter.Write中能否用代码控制不输出这个BOM吗?

三、查找解决办法

开始反编译StreamWriter.Write这个方法:

大致猜测是红色方框的代码输出了BOM信息,ok再进去看:

果然在这里,看上图红框处,GetPreamble方法是获取编码的字节序列,和我们之前查到的信息完全一致。

好下面继续找这个haveWrittenPreamble有没设置的可能,在Init方法中找到了它的身影。

杯具了,CanSeed没有set方法,Write之前的Position肯定为0,至此结束。

四、结论

由上面的结论,我们可以确定:

1.如果双方协议无BOM时,可以使用Stream.Write方法来输出,或者使用StreamWriter.Write时加入new UTF8Encoding(false)参数。

2.有BOM时,我们可以通过GetPreamble和Stream.Write来完成StreamWriter.Write的功能。

参考文献:

维基百科  字节顺序记号

MSND     Encoding.GetPreamble 方法

谢谢FJ. Zhou提示

使用StreamWriter sw = new StreamWriter(ms, new UTF8Encoding(false));可以达到不输出BOM的需求。

谢谢dudu提示,已更正。

 
 

StreamWriter(ms, new UTF8Encoding(false))可以达到不输出BOM的需求。的更多相关文章

  1. Encoding.UTF8 与 new UTF8Encoding(false) 有什么区别?

    System.Text.Encoding.UTF8 是一个静态实例,它省略了 BOM,而 new UTF8Encoding(false) 创建的实例是含有 BOM 的. BOM,即 Byte Orde ...

  2. StreamWriter结合UTF-8编码使用不当,会造成BOM(Byte Order Mark )问题生成乱码(转载)

    问: I was using HttpWebRequest to try a rest api in ASP.NET Core MVC.Here is my HttpWebRequest client ...

  3. 无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(二)

    上一篇文章 "无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)"中,我们实现了监视每个页面的执行情况和调用WebService的简单信息. ...

  4. .NET Core/.NET之Stream简介

    之前写了一篇C#装饰模式的文章提到了.NET Core的Stream, 所以这里尽量把Stream介绍全点. (都是书上的内容) .NET Core/.NET的Streams 首先需要知道, Syst ...

  5. 9102年了,汇总下HttpClient问题,封印一个

    如果找的是core的HttpClientFactory 出门右转. 官方写法,高并发下,TCP连接不能快速释放,导致端口占完,无法连接 Dispose 不是马上关闭tcp连接 主动关闭的一方为什么不能 ...

  6. .NET Core/.NET之Stream简介 Rx.NET 简介

    .NET Core/.NET之Stream简介   之前写了一篇C#装饰模式的文章提到了.NET Core的Stream, 所以这里尽量把Stream介绍全点. (都是书上的内容) .NET Core ...

  7. 【C#公共帮助类】 Utils 10年代码,最全的系统帮助类

    为大家分享一下个人的一个Utils系统帮助类,可能有些现在有新的技术替代,自行修改哈~ 这个帮助类主要包含:对象转换处理 .分割字符串.截取字符串.删除最后结尾的一个逗号. 删除最后结尾的指定字符后的 ...

  8. 【C#公共帮助类】 Utils最全的系统帮助类

    最近闲的没事做,自己想着做一些东西,不知不觉居然在博客园找到了这么多公共类,感觉还是挺有用的,平时自己还是用到了好多,就是缺少整理,现在为大家分享一下一个Utils系统帮助类,可能有些现在有新的技术替 ...

  9. 完整的系统帮助类Utils

    //来源:http://www.cnblogs.com/yuangang/p/5477324.html using System; using System.Collections.Generic; ...

随机推荐

  1. 【源代码】StringBuilder和StringBuffer震源深度分析

    //------------------------------------------------------------------------ 写篇博客不easy.请尊重作者劳动成果. 转载请注 ...

  2. Jquery zTree实例

    zTree[简单介绍] zTree 是利用 JQuery 的核心代码,实现一套能完毕大部分经常使用功能的 Tree 插件 兼容 IE.FireFox.Chrome 等浏览器 在一个页面内可同一时候生成 ...

  3. [CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性

    原文:[CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性 1.6 Framework类库 1. .NET Framework中包含了Framework类库(Frame ...

  4. Swift编程语言学习12 ——实例方法(Instance Methods)和类型方法(Type Methods)

    方法是与某些特定类型相关联的函数.类.结构体.枚举都能够定义实例方法:实例方法为给定类型的实例封装了详细的任务与功能.类.结构体.枚举也能够定义类型方法:类型方法与类型本身相关联.类型方法与 Obje ...

  5. jQuery 文件碎片

    经JS操作DOM节点可以是节点的单位,让我们连接节点,能够createElement,createTextNode,然后,appendChild定在一起,然后再用appendChild或insertB ...

  6. Fckeditor用法

    试Fckeditor版本号:2.6.3 眼下Fckeditor仅仅能用于基于ie内核的浏览器,假设要使用于chrome等浏览器,请使用ckeditor. 详细用法: 1.将解压后的fckeditor整 ...

  7. 使用flex和bison实现的sql引擎解析

    因为老师要求,近期在做oceanbase存储过程的实现,在oceanbase 0.4曾经是不支持存储过程的.实现的主要步骤主要包含 1.语法解析 2.词法解析 3.详细运行语法树的步骤 如今先来说说语 ...

  8. AppiumDriver升级到2.0.0版本引发的问题--Cannot instantiate the type AppiumDriver

    1. 问题描述和起因 在使用Appium1.7.0及其以下版本的时候,我们可以直接使用如下代码来创建一个AppiumDriver实例进行对安卓设备的操作. driver = new AndroidDr ...

  9. Objective-C系列

    我的Objective-C系列文章和坚持写博客的感想   做iOS开发有一段时间了,也有自己上线的App产品,也在坚持着发表技术博客总结自己所学的东西.在写博客的时候虽然博文中不免有错别字,但每句话都 ...

  10. php 解析xml 的四种方法

    XML处理是开发过程中经常遇到的,PHP对其也有很丰富的支持,本文只是对其中某几种解析技术做简要说明,包括:Xml parser, SimpleXML, XMLReader, DOMDocument. ...