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;
/**
  * 服务器端<a href="http://www.cxyclub.cn/Tag/jiekou.html" target="_blank">接口</a>
  * @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;
      }
}

 

五:运行效果:

 

 

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。  因为,我的写作热情也离不开您的肯定支持。

分类:  Android, ASP.NET, WCF

本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/p/3795576.html ,如需转载请自行联系原作者
相关文章
|
6月前
|
移动开发 前端开发 数据安全/隐私保护
iOS发布证书.p12文件无密码解决办法及导出带密码的新.p12文件方法
iOS发布证书.p12文件无密码解决办法及导出带密码的新.p12文件方法
198 0
|
6月前
|
安全 编译器 开发工具
​iOS安全加固方法及实现
​iOS安全加固方法及实现
71 0
​iOS安全加固方法及实现
|
6月前
|
存储 监控 iOS开发
iOS应用崩溃了,如何通过崩溃手机连接电脑查找日志方法
在iOS应用开发过程中,调试日志和奔溃日志是开发者必不可少的工具。当iOS手机崩溃时,我们可以连接电脑并使用Xcode Console等工具来查看日志。然而,这种方式可能不够方便,并且处理奔溃日志也相当繁琐。克魔助手的出现为开发者带来了极大的便利,本文将详细介绍其功能和使用方法。 克魔助手会提供两种日志,一种是实时的,一种的是崩溃的。(由于崩溃日志的环境很麻烦,目前只展示实时日志操作步骤)
|
6月前
|
存储 iOS开发 开发者
使用克魔助手进行iOS数据抓包和HTTP抓包的方法详解
使用克魔助手进行iOS数据抓包和HTTP抓包的方法详解
101 0
|
3月前
|
语音技术 开发工具 图形学
Unity与IOS⭐一、百度语音IOS版Demo调试方法
Unity与IOS⭐一、百度语音IOS版Demo调试方法
|
6月前
|
iOS开发 UED
实现一个自定义的iOS动画效果
【4月更文挑战第9天】本文将详细介绍如何在iOS平台上实现一个自定义的动画效果。我们将通过使用Core Animation框架来实现这个动画效果,并展示如何在不同的场景中使用它。文章的目标是帮助读者理解如何使用Core Animation框架来创建自定义动画,并提供一个简单的示例代码。
52 1
|
17天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
32 1
|
26天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
47 5
|
1月前
|
Swift iOS开发 UED
实现一个自定义的iOS动画效果
本文介绍如何使用Swift和UIKit在iOS应用中实现一个自定义按钮动画,当按钮被点击时,其颜色从蓝色渐变为绿色,形状从圆形变为椭圆形,释放后恢复原状。通过UIView动画方法实现这一效果,代码示例展示了动画的平滑过渡和状态切换,有助于提升应用的视觉体验和用户交互。
50 1
|
2月前
|
Swift iOS开发 UED
揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【9月更文挑战第5天】本文通过具体案例介绍如何在iOS应用中使用Swift与UIKit实现自定义按钮动画,当用户点击按钮时,按钮将从圆形变为椭圆形并从蓝色渐变到绿色,释放后恢复原状。文中详细展示了代码实现过程及动画平滑过渡的技巧,帮助读者提升应用的视觉体验与特色。
61 11