如何通过REST上传文件

1.定义接口:

[ServiceContract]
publicinterface IUploadService
{
[OperationContract]
[WebInvoke(Method
="POST", UriTemplate ="/Create")]
string Create(Stream stream);
}

  

2.实现服务:

publicclass UploadService: IUploadService
{
publicstring Create(Stream stream)
{
//TODO: manipulate the stream whatever you want
}
}

3.Host Service:

  新建一个WCF Service Application项目,在Web.Config进行如下配置:

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>

<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="UploadService.svc" service="Service.UploadService"/>
</serviceActivations>
</serviceHostingEnvironment>

<services>
<service name="Service.UploadService">
<endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" contract="Contract.IUploadService"/>
</service>
</services>
</system.serviceModel>

  

4.扔到IIS里,结束

5.测试上传(用WebClient有点问题没有来得及找出原因——原因是WebClient在内部生成的Request中添加了一些信息,导致生成的MessageBodyStream是这些信息跟所上传文件的并集,造成无法直接变成文件的MemoryStream;要的话需要去除这些信息,所以直接使用WebRequest):

using (var fileStream =new FileStream("F:\\abcdefg.zip", FileMode.Open))
{
var request
= (HttpWebRequest)WebRequest.Create("http://localhost:8800/UploadService.svc/Create");
request.Method
="POST";
request.ContentType
="application/x-zip-compressed";
request.ContentLength
= fileStream.Length;

var requestStream
= request.GetRequestStream();
// The buffer size is set to 2kb
constint buffLength =2048;
var buff
=newbyte[buffLength];
fileStream.Position
=0;
var contentLength
= fileStream.Read(buff, 0, buffLength);
while (contentLength !=0)
{
requestStream.Write(buff,
0, contentLength);
contentLength
= fileStream.Read(buff, 0, buffLength);
}
requestStream.Close();

var response
= (HttpWebResponse)request.GetResponse();
var reader
=new StreamReader(response.GetResponseStream());
var temp
= reader.ReadToEnd();
Console.WriteLine(temp);
reader.Close();
}

============================ 分割线 ============================

以上代码未经测试,是由当前实现中抽出,可能隐含bug。

其实以上都不是我在这篇文章要说的东西,因为这类代码相信到处都是。今天花了大半下午解决的一个问题(对WCF不熟)才是我想说的。

之前针对Service写了个测试代码(采用XUnit框架):

[Fact]
publicvoid Create_Should_Success()
{
using (var zip =new FileStream("F:\\abcdefg.zip", FileMode.Open))
{
var msg
= _service.Create(zip);

Assert.Equal(
"Success!", msg);
}
}

用这个方法悲剧的地方就是避开了上传文件这一步骤,让我认为在IIS环境里UploadService.Create()读取到的Stream就是FileStream或者是MemoryStream。结果下午部署到IIS(之前在本机上用IIS Express)一看,问题来了:stream.Length无法读取。仔细看看stream的类型,成了MessageBodyStream。呵,这下傻眼了,原本对IO这块不甚了解,现在还蹦出个让人挠头的东西。

花了好多时间,终于找到原因了:通过REST上传的文件,一定是MessageBodyStream类型的,它本身可以直接用,但如果有一些特殊的应用场景——譬如读取Length——则必须将它转换成别的类型(MemoryStream..)。

写完回家。

posted @ 2011-08-02 17:58  _龙猫  阅读(2305)  评论(0编辑  收藏  举报