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应该怎么传参呢?请问有了解的么,

时间: 2024-10-17 03:14:08

IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,的相关文章

.NET Framework 4.6 and 4.5 &gt; 开发指南 &gt; 使用 WCF 的面向服务的应用程序 &gt; Windows Communication Foundation (WCF)

.NET Framework 4.6 and 4.5 > 开发指南 >  使用 WCF 的面向服务的应用程序 > Windows Communication Foundation (WCF) :https://msdn.microsoft.com/zh-cn/library/dd456779(v=vs.110).aspx 文档指南: https://msdn.microsoft.com/zh-cn/library/ms730846(v=vs.110).aspx 入门教程: https:/

WCF服务编程 读书笔记——第1章 WCF基础(2)

续:第1章 WCF基础(1) 元数据交换 服务有两种方案可以发布自己的元数据.一种是基于HTTP-GET协议提供元数据, 另一种则是后面将要讨论的使用专门的终结点的方式.WCF能够为服务自动提供基于HTTPGET的元数据,但需要显式地添加服务行为( Behavior)以支持这一功能.本书后面的章节会介绍行为的相关知识.现在,我们只需要知道行为属于服务的本地特性,例如是否需要基于HTTP-GET交换元数据, 就是一种服务行为.我们可以通过编程方式或管理方式添加行为.在例 1 - 10 演示的宿主应

JAVA入门学习: 方法参数的传递(函数传参问题)

引言:我们知道C++中拥有两种参数传递方式, 值调用和引用调用. 有些程序员认为JAVA程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的. 由于这种误解存在普遍性,所以下面将阐述一下这个问题. 所以用一段简单的代码来阐述一下这个问题: 1 //如果方法参数是的输入时引用,那么我们将交换两个指针(即引用) 2 public static void swap(Employee x, Employee y) 3 { 4 Employee temp = x; 5 x =y; 6 y = te

学习调用WCF服务的各种方法

1.开发工具调用WCF 这中方法很方便也很简单,很多工作VS就帮我们完成了.相信大家也不会对这种方法陌生.这里简单提一下.打开VS,在项目中添加服务引用: 在config中自动声明了有关服务的节点信息,这样VS就创建了调用服务的代理: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->ServiceReference1.Service1Client

绑定服务调用本地服务中的方法

如果想调用服务中的方法, 通过startService()是做不到的, 这时需要用bindService来解决. 下面的demo是在Activity中调用Service中的自定义方法---methodInService 这个demo可以解决在项目开发中调用service里的数据. 这里在service中使用到了代理模式.这是为了,给service组件和activity组件中间添加一个中间人. 通过代理来传递数据.也就是binder对象.这个代理就是接口IService Service中的代码如下

WebService学习总结(四)——调用第三方提供的webService服务

WebService学习总结(四)——调用第三方提供的webService服务 互联网上面有很多的免费webService服务,我们可以调用这些免费的WebService服务,将一些其他网站的内容信息集成到我们的Web应用中显示,下面就以获取天气预报数据和查询国内手机号码归属地为例进行说明. 气象中心的管理系统将收集的天气信息并将数据暴露出来(通过WebService Server), 而各大站点的应用就去调用它们得到天气信息并以不同的样式去展示(WebService Client).一. 调用

远程调用服务里的方法service,进程间通信adil的学习

1当一个进程需要调用另外一个进程的方法时候,进程可以通过aidl文件以接口的方式将方法抛出.比如android没有对外提供挂电话的方法,若用户想要调用这个方法就必须与电话管理这个应用程序通信,调用挂电话的方法. 2.下面我就举例一个demo调用远程服务里的方法.为了验证service能否单独启动,这个demo启动了2个远程服务,一个有activity的一个只有service的.并且他们抛出的接口名字相同,正好学习一下同名的引用,发现一个java文件里只能import  1个同同名的类,若想调用另

.netcore 3.1高性能微服务架构:封装调用外部服务的接口方法--HttpClient客户端思路分析

众所周知,微服务架构是由一众微服务组成,项目中调用其他微服务接口更是常见的操作.为了便于调用外部接口,我们的常用思路一般都是封装一个外部接口的客户端,使用时候直接调用相应的方法.webservice或WCF的做法就是引用服务,自动生成客户端.在webapi2.0里,我们都会手动封装一个静态类.那么在.netcore3.1的微服务时代,我们该如何处理这个问题呢? ----思路都是一样的,封装一个外部服务,并且使用依赖注入和 HttpFactory工厂等.netcore特有的方式提升性能.接下来我们

通过接口方式调用服务里面的方法

  接口可以隐藏代码内部的细节 让程序员暴露自己只想暴露的方法   (6)定义一个接口 把想暴露的方法都定义在接口里面 (7)我们定义的中间人对象 实现我们定义的接口 (8)在获取我们定义的中间人对象方式变了 public interface Iservice { //把领导想暴露的方法 都定义在接口里面 public void callBanZheng(int money); public void callPlayMaJiang(); } public class MainActivity