Recently done a project backend using WCF to receive Android phone photos and save the other parameters to the server; Just the recent study of WCF utilization, this thought is a relatively simple function should be very good to achieve, did not expect to encounter many problems in the online search for a long time has not thought of the solution, Finally, the data stream is segmented and then the backend is used to parse the stream, and the backend uses rest in WCF to receive the data; Rest is relatively simple knowledge, if you do not understand can be a simple online understanding; Let's start with some of the theoretical know-how:
One: Theoretical knowledge
WCF's streaming mode supports only the following four types due to low-level protocol feature limitations: 1:basichttpbinding 2:nettcpbinding 3:netnamedpipebinding 4:webhttpbinding
1. Set the Transfermode. It supports four modes (Buffered, Streamed, Streamedrequest, Streamedresponse), and is set to one of three stream modes depending on the situation.
2. Modify the MaxReceivedMessageSize. The default size is 64k, so the communicationexception exception is thrown when the transfer data is greater than 64k.
3. Modify ReceiveTimeout and Sendtimeout. Big data transfer takes a long time, and these two values need to be modified to avoid transmission timeouts.
Second: Solve the problem
WCF if you use stream as a parameter can only be the only one, can not have other parameters, this is also a problem to focus on this time, but our Android phone in addition to the picture to have other parameters, and finally decided to use the mobile phone with the parameters and pictures are written into the stream inside, Back-end WCF again to parse the flow of this parameter;
The following is the definition of the stream format, passed the stream into three parts: parameter information length parameter information picture
1 parameter information Length (1 bytes): Length (in bytes) used to hold parameter information;
2 parameter information: Except for the picture parameters, in the form of JSON storage such as {"type": "JPG", "EmployeeID": "A", "TaskID": "13"}
3 Pic: byte of picture
Three: WCF-encoded content
1: We first define a WCF contract, because we use the rest (below the namespace Servicemodel.web) contract Iandroidinfo content as follows, using post to receive:
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 = WebMessage Format.json, Responseformat = Webmessageformat.json)] bool Gpsupfile (Stream imagecontext);} }
2: According to the contract we define the content of the service, receive a stream of parameter content, first convert the stream into bytes, and then according to our previously agreed content to get the first byte value, and then according to this value to define our other three parameters of the byte length, Then through the JSON conversion format to take out the three parameter values in it, the last other byte is to hold a picture of a mobile phone, put it in the Server D disk folder
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 B Ool 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 (I Magepath, Imagedata); Imagecontext.close (); return true; } catch {return false; }} else {return false; } } }}
The code above uses several methods, such as converting streams to bytes, converting JSON into implementations, and so on, with the following code:
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) {totalbyt Esread + = 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: Create a new text, and then modify the suffix named. svc, as we publish the service (host for IIS) to let the Android phone call, and then write the following code
<%@ ServiceHost language= "C #" debug= "true" service= "Coreius.CEIMS.AndroidService.AndroidInfoService"%>
Modify the contents of the 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&G T <endpointBehaviors> <behavior name= "webhttp" > <webhttp helpenabled= "true"/> </ behavior> </endpointBehaviors> <serviceBehaviors> <behavior name= "Mapconfigbehavior" ; <!--to avoid leaking metadata information, set the following values to false before deployment and delete the above metadata endpoint--<servicemetadata httpgetenabled= "true"/> <!--to receive the fault exception details for debugging, set the following value to True. Set to false before deployment to avoid leaking exception information--<servicedebug includeexceptiondetailinfaults= "true"/> <datacontr Actserializer maxitemsinobjectgraph= "2147483647"/> </behavior> </servicebehaviors> </behaviors> <bindings> <webHttpBinding> <binding name= "webhttpbindconf IG "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" Bindingconfigura tion= "Webhttpbindconfig" behaviorconfiguration= "webhttp"/> </service> </services> </system.ser Vicemodel></configuration>
Here are some things to keep in mind:
(1): WebHttpBinding is used here so be sure to set behaviorconfiguration to have an effect, where helpenabled= "true" is for the implementation to be able to view help information in the publication
<behavior name= "Webhttp" > <webhttp helpenabled= "true"/> </behavior>
(2): In order to achieve the upload of large files so we want to set the maximum value, where security is set to access the service authentication, here is to set it to not authentication, Transfermode is set to use the flow mode
<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: After writing the above code, you can deploy this WCF service on server IIS:
Quad: Android encoding
Because the Android phone code is written by another friend, so the general code is pasted out, the general principle is to write parameters and pictures to the stream, and then invoke the deployment of the WCF service
Code one: Because the server is not public, so the following IP I have casually modified one;
private void Touploadfile (file file) throws FileNotFoundException {String result = null;requesttime= 0;int res = 0;long RE Questtime = System.currenttimemillis (); Long responsetime = 0;//package parameter information 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 Blocke.printstacktrace ();} /** upload file */httpparams httpparameters = new Basichttpparams (); Httpconnectionparams.setconnectiontimeout (Httpparameters, 1000*30); Httpconnectionparams.setsotimeout (Httpparameters, 1000*30); Httpconnectionparams.settcpnodelay (Httpparameters, true); String Path = pictureutil.zipnewimage (file);//files returned after compressing the file path 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 C UrlEn = 0;while (len = is.read (bytes))! =-1) {Curlen + = Len;is.read (bytes);} Is.close ();} catch (FileNotFoundException E1) {//Todo auto-generated catch Blocke1.printstacktrace ();} catch (IOException e) {//TODO Auto-generated catch Blocke.printstacktrace ();} byte[] Updata = Gpsimagepackage.getpacket (jsonobject.tostring (), bytes);//parameters and files encapsulated into a single packet httpClient httpClient = new Defaulthttpclient (httpparameters); HttpPost HttpPost = new HttpPost (myurl.upload_file); HttpResponse httpresponse;//Single File stream upload 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, "Upload failed: code=" + res); return;} } catch (Clientprotocolexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} catch (IOException e) {//TOD O auto-generated catch Blocke.printstacktrace ();}} Package com.anthony.util;/** * Server-side interface * @author YWJ * */public class Myurl {public static String Upload_gps = "http://122. 199.19.23:8088/androidinfoservice.svc/setgpsinfo ";}
Code two:
Package Com.anthony.util;public class Gpsimagepackage {public Gpsimagepackage () {//TODO auto-generated constructor stub }//encapsulated byte array with parameter public static byte[] GetPacket (String json,byte[] image) {byte[] jsonb = Json.getbytes (); int length = Image.le Ngth + jsonb.length; System.out.println (Image.length + "" + jsonb.length); byte[] bytes = new byte[length+1];byte[] LENGTHB = Inttobytearray (j Sonb.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;} convert int to byte array public static byte[] Inttobytearray (int iSource, int iarraylen) {byte[] Blocalarr = new Byte[iarr Aylen]; for (int i = 0; (I < 4) && (I < iarraylen); i++) {Blocalarr[i] = (byte) (Isource>>8*i & 0xFF); } return Blocalarr; }//Converts a byte array Brefarr to an integer, the low byte array is the lower bit of the integer type 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; }}
Five: Operation effect:
If you think reading this blog gives you something to gain, just click on the "Recommend" button in the lower right corner. Because, my writing enthusiasm also inseparable from your affirmation support.