WCF REST 工作总结(二)
上一篇 我们搭建了WCF REST 的服务 平且通过 三种方式发送get请求 实现了获取json 没看过的朋友可以先去看下----REST 工作总结一
今天主要写下 POST等其他方式 发送请求 以及 流方式 文件的上传与下载
一.Post 提交数据
先来想下 POST和Get 的不同 Get 方式 我们直接通过 url 来传递参数 先来看下我们的 创建方法吧
[WebInvoke(UriTemplate = "Tasks/Add", Method = "POST", RequestFormat = WebMessageFormat.Json)]
void Create(PocoTask pocoTask);
我们需要接受一个实体类 格式为json格式 这就再次出现上文的问题 我们的客户端没有实体类 没法把实体类序列化为json 难道要自己拼接json么? 当然不用。那简直太痛苦了。
这里给大家推荐 Json.Net 这里有两个类 可以帮我们完成 单个实体的转换 以及集合实体的转换 分别是 JObject 和 JArray
我们只需声明这两个类后 .toString 就可得到他的json格式了 很方便吧~ 看代码
这里完全可以不用dynamic的 像注释那样的写法就行 这样即使服务器不支持.net4.0 也可以使用的
知道了如何构建POST 提交的数据 就开始实现POST提交吧~ 上代码 依然是三种方式 放一起 对比
这三个方式 个人很推荐 第三种 也是目前最新的 .net4.5里集成的 访问REST 非常的方便 因为他支持 直接点出来 PUT 以及 DELETE请求
简直是为rest 量身定制的~~ 看下 PUT请求
这里需要注意下 因为我们发送的是json 不论是哪种发送请求的方式 都要记得 设置ContentType=application/json
否则会抛出 HTTP 400的错误 400-错误的请求 很多都是客户端请求不正确造成的 所以一般出来400错误 可以重点检查下 客户端请求的问题
因为 PUT 与 DELETE 和 POST 基本类似 我就不上代码了
二.REST 的文件上传 与下载
流文件的上传和下载
先来看服务端的接口与实现
我们要实现三个功能
1. 展示一张图片
2.下载一个文件
3.上传一个文件
一个一个说 先说展示图片 实现代码
这个是在浏览器中直接打开 比较简单 这里记得设置输出的 ContentType 有时我们想打开的是别的格式 这里有个小方法 根据文件扩展名获得输出的ContentType
也就是上面用到的GetContentType方法 在园子的知识库里发现的 GetContentType
客户端 非常简单 直接引用连接即可
2.下载
上面的是直接把文件显示在浏览器中 如果我们希望下载资源呢 方法也很简单和以前的方法是一样的 直接上代码
public void GetExecl(string execlName)
{
string folder = System.Web.Hosting.HostingEnvironment.MapPath("~/Files");
var FullFileName = Path.Combine(folder, execlName);
if (File.Exists(FullFileName))
{
FileInfo DownloadFile = new FileInfo(FullFileName);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(DownloadFile.FullName, System.Text.Encoding.ASCII));
HttpContext.Current.Response.AppendHeader("Content-Length", DownloadFile.Length.ToString());
HttpContext.Current.Response.WriteFile(DownloadFile.FullName);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
}
3.上传
这个文件上传 才是重点要说的 折腾了好久~
首先要说的是 一定要记得配置文件 如果用REST 模版 配置方法如下
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints >
<webHttpEndpoint >
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" maxReceivedMessageSize="3000000" defaultOutgoingResponseFormat="Json" helpEnabled="true" automaticFormatSelectionEnabled="true">
<readerQuotas maxArrayLength="300000"/>
</standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
这样就可以上传大文件了
客户端实现上传很简单 借助 HttpClient
本来写到这 以为上传很简单的就能完成了 结果却弄了好久
先说下以前的写法
以前这样 都能成功 谁知道这次移到 REST WCF 中 竟然报错 发现不能读取Stream.Length 在这里问下各位高手 ~为什么读取Stream.Length 会报错?
CSDN 的 fangxinggood 给了解释 非常感谢
因为它被封装成了MessageBodyStream,就像WCF Streamed的数据一样,Length是不支持的。WCF里是客户端一边传服务端一边收。到达服务端开始写IO时,流并没有全部传输完,所以 MessageBodyStream不支持Length。但REST时是Http协议,所以其实Stream已经全部到达服务端了。如果你想取长度,可以 用: var len = WebOperationContext.Current.IncomingRequest.ContentLength;来获得。
如图
最后就会抛出Http 400的错误
百思不得其解 只好换了另一种方法这种方法不需要 长度length
可是却发现在 转化成byte 这次是报错 输入的不是有效的 Base-64 字符串,因为它包含非 Base-64 字符、两个以上的填充字符,或者填充字符间包含非空白字符。
再次请问原因? 希望遇到过的朋友告知
解决办法
后来 通过谷歌 发现另外一种 获得长度的方法 在WCF REST里 这样就能用第一种方法了
把最早方法里的
long ByteLength=stream.Length;
换成
long ByteLength = WebOperationContext.Current.IncomingRequest.ContentLength;
这样就可以得到长度了 上传问题也就解决了~~
这里说下 如果上传的是图片 有个很简单的方法 核心代码 简单两行即可~
三.Session与Cookie
在WCF 里 是可以使用session的 但是在REST 的WCF 里 貌似却不能使用session 查了些资料 没有发现使用session的办法
可能是因为使用session会让服务器和客户端耦合。 后来找到了 REST 常见误区 http://www.prescod.net/rest/mistakes/
里面提到了一条 session 是无关紧要的。
cookie 还是可以正常使用的 这里说下 客户端读取cookie的方法 webclient 貌似不能读到 要使用更加灵活的 HttpWebRequest
主要是这两句
CookieContainer Cookie = new CookieContainer();
request.CookieContainer = Cookie;
四.总结
在做这方面的工作 把经验分享给大家 也希望会的人 能解答下我问中的问题~~
REST WCF 体现了ROA 面向资源编程 感觉更好了解耦了客户端与服务端 而且调用 REST 服务 也简单了很多 没有了代理等 效率也提高了 喜欢这种风格的方式
参考:
http://blog.csdn.net/fangxinggood/article/details/6235662
原文:
http://www.cnblogs.com/wlflovenet/archive/2011/10/28/WCFREST2.html