IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,
最近做一个项目后端使用WCF接收Android手机拍照并带其它参数保存到服务器里;刚好把最近学习的WCF利用上,本以为是个比较简单的功能应该很好实现,没想到其中碰到不少问题,在网上搜索很久一直没有想到的解决方案,最后实现对数据流的分段写入然后后端再来解析流实现的此功能;后端运用WCF中的REST来接收数据;REST还是比较简单的知识,若是不懂可以简单网上了解一下;下面我们先了解一些本次运用到的理论知识:
一:理论知识
由于低层协议特性限制,WCF的流模式只支持如下四种:1:BasicHttpBinding 2:NetTcpBinding 3:NetNamedPipeBinding 4:WebHttpBinding
1.设置TransferMode。它支持四种模式(Buffered、Streamed、StreamedRequest、StreamedResponse),请根据具体情况设置成三种Stream模式之一。
2.修改MaxReceivedMessageSize。该值默认大小为64k,因此,当传输数据大于64k时,则抛出CommunicationException异常。
3.修改receiveTimeout 和sendTimeout。大数据传送时间较长,需要修改这两个值,以免传输超时。
二:解决问题
WCF如果使用Stream做为参数时只能唯一一个,不能有其它另外的参数,这个也是本次碰到要重点解决的一个问题;可是我们Android手机除的图片还要有其它的参数,最后决定采用手机端把参数跟图片都一起写入Stream里面,后端WCF再来解析这个参数的流;
下面就是定义好Stream的格式,传过来的Stream分成三部分: 参数信息长度 参数信息 图片
1 参数信息长度(1字节):用于存放参数信息的长度(以字节为单位);
2 参数信息: 除图片以外的参数,以JSON的形式存放如{"type":"jpg","EmployeeID":"12","TaskID":"13"}
3 图片:图片的字节
三:WCF编码内容
1:我们首先定义一个WCF契约,由于我们运用REST(在命名空间ServiceModel.Web下面)契约IAndroidInfo内容如下,采用POST方式进行接收:
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ServiceModel.Web;
using System.IO; namespace Coreius.CEIMS.AndroidInterface
{
[ServiceContract]
public interface IAndroidInfo
{
[WebInvoke(UriTemplate = "GpsUpFile", Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
bool GpsUpFile(Stream ImageContext);
}
}
2:根据契约我们定义服务的内容,接收一个流的参数内容,首先把这个Stream转化成字节,然后根据我们先前约定好的内容获得第一个字节的值,再根据此值定义我们另外三个参数的字节长度,再通过JSON转换格式把它里面的三个参数值取出来,最后其它字节是存放一张手机拍的照片,把它存放在于们服务器D盘文件夹下
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.IO;
using Newtonsoft.Json; namespace Coreius.CEIMS.AndroidService
{
public class AndroidInfoService:IAndroidInfo
{ public bool GpsUpFile(Stream ImageContext)
{
byte[] m_Bytes = ReadToEnd(ImageContext);
int len = (int)m_Bytes[0]; byte[] data = m_Bytes.Skip(1).Take(len).ToArray();
string Jsonstr = System.Text.Encoding.Default.GetString(data); JsonModel item = JsonConvert.DeserializeObject<JsonModel>(Jsonstr);
string ImageType=item.type;
string EmployeeID=item.EmployeeID;
string TaskID=item.TaskID; byte[] Imagedata = m_Bytes.Skip(1 + len).ToArray(); string DiskName = "d:";
string FileAddress = "\\UpLoad\\";
string LocationAddress = DiskName + FileAddress;
if (!DirFileHelper.IsExistDirectory(LocationAddress))
{
DirFileHelper.CreateDirectory(LocationAddress);
} string ImageName = DateTime.Now.ToString("yyyyMMddhhmmss.") + ImageType;
string ImagePath = LocationAddress + ImageName;
if (!File.Exists(ImagePath))
{
try
{
System.IO.File.WriteAllBytes(ImagePath, Imagedata);
ImageContext.Close();
return true;
}
catch
{
return false;
}
}
else
{
return false;
}
}
}
}
上面的代码用到几个方法,比如把流转化成字节、把JSON转化成实现等,代码如下:
public byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0; if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
} try
{
byte[] readBuffer = new byte[4096]; int totalBytesRead = 0;
int bytesRead; while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead; if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
} byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if (stream.CanSeek)
{
stream.Position = originalPosition;
}
}
} public class JsonModel
{
public string type { get; set; }
public string EmployeeID { get; set; }
public string TaskID { get; set; }
}
3:新建一个文本,然后修改其后缀名为.svc,作为我们发布服务(宿主为IIS)让Android手机调用, 然后把下面的代码写入
<%@ ServiceHost Language="C#" Debug="true" Service="Coreius.CEIMS.AndroidService.AndroidInfoService" %>
修改Web.config里面的内容:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="ConnectionString" value="server=127.0.0.1;database=Coreius;uid=sa;pwd=admin"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MapConfigBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors> <bindings>
<webHttpBinding>
<binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/>
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="Coreius.CEIMS.AndroidService.AndroidInfoService" behaviorConfiguration="MapConfigBehavior">
<endpoint binding="webHttpBinding" contract="Coreius.CEIMS.AndroidInterface.IAndroidInfo" bindingConfiguration="webHttpBindConfig" behaviorConfiguration="webHttp"/>
</service>
</services>
</system.serviceModel>
</configuration>
此处有些要注意的地方:
(1):此处采用的是webHttpBinding 所以一定要设置behaviorConfiguration才会有效果,其中helpEnabled="true"则是为实现可以在发布可以查看帮助信息
<behavior name="webHttp">
<webHttp helpEnabled="true"/>
</behavior>
(2):为了实现上传大文件所以我们要如下设置最大值,其中security是设置访问服务的认证,此处是把它设置成为不认证,transferMode就是设置运用流的模式
<webHttpBinding>
<binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/>
<security mode="None"></security>
</binding>
</webHttpBinding>
4:编写完上面的代码后就可以服务器IIS上部署这个WCF服务:
四:Android编码
由于Android手机端的代码是另外一个朋友编写,所以就把大体的代码贴出来,大体的原理就是把参数跟图片写入流,然后调用部署好的WCF服务
代码一:因为服务器不是公用的,所以下面的IP我就随便修改的一个;
private void toUploadFile(File file) throws FileNotFoundException {
String result = null;
requestTime= 0;
int res = 0;
long requestTime = System.currentTimeMillis();
long responseTime = 0; //封装参数信息
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("EmployeeID", MainActivity.guid);
jsonObject.put("TaskID", "e52df9b4-ee3b-46c5-8387-329b76356641");
String[] type = file.getName().split("\\.");
jsonObject.put("type", type[type.length-1]);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} /**上传文件*/
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 1000*30);
HttpConnectionParams.setSoTimeout(httpParameters, 1000*30);
HttpConnectionParams.setTcpNoDelay(httpParameters, true); String path = PictureUtil.zipNewImage(file); //压缩文件后返回的文件路径
byte[] bytes = null;
InputStream is;
File myfile = new File(path);
try {
is = new FileInputStream(path);
bytes = new byte[(int) myfile.length()];
int len = 0;
int curLen = 0;
while ((len = is.read(bytes)) != -1) {
curLen += len;
is.read(bytes);
}
is.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] updata = GpsImagePackage.getPacket(jsonObject.toString(), bytes); //参数与文件封装成单个数据包
HttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpPost httpPost = new HttpPost(MyUrl.upload_file);
HttpResponse httpResponse;
//单个文件流上传
InputStream input = new ByteArrayInputStream( updata );
InputStreamEntity reqEntity;
reqEntity = new InputStreamEntity(input, -1);
reqEntity.setContentType("binary/octet-stream");
reqEntity.setChunked(true);
httpPost.setEntity(reqEntity);
try {
httpResponse = httpClient.execute(httpPost);
responseTime = System.currentTimeMillis();
this.requestTime = (int) ((responseTime-requestTime)/1000);
res = httpResponse.getStatusLine().getStatusCode();
if (httpResponse.getStatusLine().getStatusCode() ==200) {
Log.e(TAG, "request success");
Log.e(TAG, "result : " + result);
return;
} else {
Log.e(TAG, "request error");
sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:code=" + res);
return;
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} package com.anthony.util;
/**
* 服务器端接口
* @author YWJ
*
*/
public class MyUrl {
public static String upload_GPS = "http://122.199.19.23:8088/AndroidInfoService.svc/SetGpsInfo";
}
代码二:
package com.anthony.util; public class GpsImagePackage {
public GpsImagePackage() {
// TODO Auto-generated constructor stub
} //封装字节数组与参数
public static byte[] getPacket(String json,byte[] image){ byte[] jsonb = json.getBytes();
int length = image.length + jsonb.length;
System.out.println(image.length +" "+ jsonb.length);
byte[] bytes = new byte[length+1];
byte[] lengthb = InttoByteArray(jsonb.length, 1);
System.arraycopy(lengthb, 0, bytes, 0, 1);
System.arraycopy(jsonb, 0, bytes, 1, jsonb.length);
System.arraycopy(image, 0, bytes, 1+jsonb.length, image.length);
return bytes; } //将int转换为字节数组
public static byte[] InttoByteArray(int iSource, int iArrayLen) { byte[] bLocalArr = new byte[iArrayLen];
for ( int i = 0; (i < 4) && (i < iArrayLen); i++) {
bLocalArr[i] = (byte)( iSource>>8*i & 0xFF );
}
return bLocalArr;
} // 将byte数组bRefArr转为一个整数,字节数组的低位是整型的低字节位
public static int BytestoInt(byte[] bRefArr) { int iOutcome = 0;
byte bLoop;
for ( int i =0; i<bRefArr.length ; i++) {
bLoop = bRefArr[i];
iOutcome+= (bLoop & 0xFF) << (8 * i);
}
return iOutcome;
}
}
五:运行效果:
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。 因为,我的写作热情也离不开您的肯定支持。
IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,的更多相关文章
- C++析构函数的自动调用(析构函数必须是虚拟的,这样删除父类指针指向的子类对象,才能同时调用两者的析构函数,否则就没有机会调用子类析构函数)
class A {public: A() { printf("A \n"); } ~A() { printf(" ~A \n"); } // 这里不管写不写vi ...
- WCF服务编程 读书笔记——第1章 WCF基础(2)
续:第1章 WCF基础(1) 元数据交换 服务有两种方案可以发布自己的元数据.一种是基于HTTP-GET协议提供元数据, 另一种则是后面将要讨论的使用专门的终结点的方式.WCF能够为服务自动提供基于H ...
- python基础----函数的定义和调用、return语句、变量作用域、传参、函数嵌套、函数对象、闭包、递归函数
1.函数的定义: 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可 ...
- 学习调用WCF服务的各种方法
1.开发工具调用WCF 这中方法很方便也很简单,很多工作VS就帮我们完成了.相信大家也不会对这种方法陌生.这里简单提一下.打开VS,在项目中添加服务引用: 在config中自动声明了有关服务的节点信息 ...
- [转]学习 WCF (6)--学习调用WCF服务的各种方法
转自:http://www.cnblogs.com/gaoweipeng/archive/2009/07/26/1528263.html 作者这篇博文写得很全面. 根据不同的情况,我们可以用不同的方法 ...
- 真实世界:使用WCF扩展记录服务调用时间
WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...
- 使用WCF扩展记录服务调用时间
随笔- 64 文章- 0 评论- 549 真实世界:使用WCF扩展记录服务调用时间 WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Lay ...
- WCF扩展记录服务调用时间
WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服务模型层(Serv ...
- WebService学习总结(四)——调用第三方提供的webService服务
http://www.cnblogs.com/xdp-gacl/p/4260627.html 互联网上面有很多的免费webService服务,我们可以调用这些免费的WebService服务,将一些其他 ...
随机推荐
- 软工实践 - 第十九次作业 Alpha 冲刺 (10/10)
队名:起床一起肝活队 组长博客:https://www.cnblogs.com/dawnduck/p/10046955.htmlz 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 ...
- 团队Alpha版本(五)冲刺
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- J2EE的十三个技术——JSP
简介 JSP,Java Server Page,Java服务器页面.它是在传统的网页HTML文件中插入Java程序段(Scriptlet)和JSP标记,从而形成JSP文件,后缀名为(*.jsp). ...
- PHP面向对象练习2
思路:构造函数完成数据库连接,增删改一个方法,查询一条记录一个方法,查询多条一个方法,sql执行失败则返回提示,并交出sql语句方便查错 代码: <?class dbcontroll{ priv ...
- ES6 Destructuring Assignment All In One
ES6 Destructuring Assignment All In One ES6 & Destructuring Assignment Axios, vue https://develo ...
- css实现0.5像素
.border{ position: relative; } .border:before{ content: ''; position: absolute; width: 200%; height: ...
- SQL UNPIVOT和PIVOT
/* table_source PIVOT( 聚合函数(value_column) FOR pivot_column IN(<column_list>) ) 完整语法: table_sou ...
- 在Linux内核中添加系统调用,并编译内核
1 环境准备 运行系统:vmware下安装的ubuntu10.10 32bit桌面版. 编译内核版本: linux-2.6.32.63 内核目录: /home/wanchouchou/linuxKer ...
- WCF回调操作
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.s ...
- HDU1083_Courses_课程_C++
给你们人工翻译一下题目哈,刚好练一下英语 对于一个组中有 N 个学生和 P 种课程.每个学生能够参加0种,1种或者更多的课程.你的任务是找到一种可能的方案使恰好P个学生同时满足下列条件: ‧ 方案中的 ...