IOSAndWCF上传文件

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

IOS And WCF Story研究IOS上传到WCF图片的小功能,WCF实现服务端的文件上传的例子很多,单独实现IOS发送图片的例子也很多,但是两个结合起来的就很少了。

可以通过base64来上传图片,这个方式比较简单,但是我想要的是通过网络流来传送,这样以后IOS发送任何的文件,服务器不需要修改就能直接来用。想法很简单,但是历程很辛苦。。。

IOS发送首先研究一下IOS端的图片传输,我用的网络框架是AFNetWorking,附上代码

NSString *filename=@"test.jpg";

AFHTTPRequestOperationManager *AFManager=[[AFHTTPRequestOperationManager alloc]initWithBaseURL:[NSURL URLWithString:@FileTranUrl]];

AFHTTPRequestOperation *operation=[AFManager POST:path parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formdata){[formdata appendPartWithFileData:imagedata name:name fileName:filename mimeType:@"image/jpeg"];} success:^(AFHTTPRequestOperation *operation, id responSEObject) {

if (success) {

success(operation,responseObject);

}

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

if (failure) {

failure(operation,error);

}

}];

imagedata是image转换为NSdata后的值。

这里的代码看起来很多,其实很简单,关键只有一处就是

[formdata appendPartWithFileData:imagedata name:name fileName:filename mimeType:@"image/jpeg"];

AFMultipartFormData做了什么呢?

查看它的appendPartWithFileData:name:filename:mimeType:源代码,我们可以看到

- (void)appendPartWithFileData:(NSData *)data

name:(NSString *)name

fileName:(NSString *)fileName

mimeType:(NSString *)mimeType

{

NSParameterAssert(name);

NSParameterAssert(fileName);

NSParameterAssert(mimeType);

NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];

[mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];

[mutableHeaders setValue:mimeType forKey:@"Content-Type"];

[self appendPartWithHeaders:mutableHeaders body:data];

}

multableHeaders包含了name,filename,mimeType再次查看最后一个方法的定义

- (void)appendPartWithHeaders:(NSDictionary *)headers

body:(NSData *)body

{

NSParameterAssert(body);

AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];

bodyPart.stringEncoding = self.stringEncoding;

bodyPart.headers = headers;

bodyPart.boundary = self.boundary;

bodyPart.bodyContentLength = [body length];

bodyPart.body = body;

[self.bodyStream appendHTTPBodyPart:bodyPart];

}

[self.bodyStream appendHTTPBodyPart:bodyPart];看到这里的时候我们已经明白了,以上所有包含的数据全部放到网络流里了。为什么要查看这些呢?因为WCF需要契约定义,我们不知道AFNetwork发送的时候我们应该用什么契约来接受这个方法。

WCF接受通过上面的分析,我们已经大概知道契约的定义了

void(Stream requestStream)

WCF在接受数据之前还需要进行配置,在

<system.serviceModel>

<bindings>

<webHttpBinding>

<binding name="WebConfiguration"

maxBufferSize="65536"

maxReceivedMessageSize="2000000000"

transferMode="Streamed">

</binding>

</webHttpBinding>

</bindings>

<services>

<!--文件服务-->

<service name="WcfServiceForIOS.ServiceForIOSFile" behaviorConfiguration="ServiceBehavior">

<endpoint address="" binding="webHttpBinding" behaviorConfiguration="web" bindingConfiguration="WebConfiguration" contract="WcfServiceForIOS.IServiceForIOSFile" />

</service>

</services>

<behaviors>

<endpointBehaviors>

<behavior name="web">

<webHttp />

</behavior>

</endpointBehaviors>

<serviceBehaviors>

<behavior name="ServiceBehavior">

<serviceMetadata httpGetEnabled="true" />

<serviceDebug includeExceptionDetailInFaults="false" />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

尝试实现契约的主要代码

using (targetStream = new FileStream(filePathAndName, FileMode.Create, Fileaccess.Write, FileShare.None))

{

const int bufferLen = 4096;

Byte[] buffer = new Byte[bufferLen];

int count = 0;

while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)

{

targetStream.Write(buffer, 0, count);

filesize += count;

}

targetStream.Close();

sourceStream.Close();

}

等IOS上传图片后,可以在相应的文件夹中找到生成的图片,但是不幸的是我们无法打开,提示图片损坏太大。用NotePad++打开这个文件流,可以看到以下代码

--Boundary+4AA85CFEE4A1D140

Content-Disposition: form-data; name="file"; filename="test.jpg"

Content-Type: image/jpeg

(乱码,目测是图片的数据流)

--Boundary+4AA85CFEE4A1D140--

是不是和发送时候的很眼熟,这样和前面的分析就对上了,传输过来的文件流是包含图片的信息和图片的数据。需要分开处理。

处理方法和web发送的form-data是一样的,先编码为string,通过正则表达取出各个属性值

private void Parse(Stream stream, Encoding encoding)

{

this.Success = false;

// Read the stream into a byte array

byte[] data = ToByteArray(stream);

requestData = data;

// Copy to a string for header parsing

string content = encoding.GetString(data);

// The first line should contain the delimiter

int delimiterEndIndex = content.IndexOf("\r\n");

if (delimiterEndIndex > -1)

{

string delimiter = content.Substring(0, content.IndexOf("\r\n"));

// Look for Content-Type

Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");

Match contentTypeMatch = re.Match(content);

// Look for filename

re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");

Match filenameMatch = re.Match(content);

// Did we find the required values?

if (contentTypeMatch.Success && filenameMatch.Success)

{

// Set properties

this.ContentType = contentTypeMatch.Value.Trim();

this.Filename = filenameMatch.Value.Trim();

// Get the start & end indexes of the file contents

int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;

byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);

int endIndex = IndexOf(data, delimiterBytes, startIndex);

int contentLength = endIndex - startIndex;

// Extract the file contents from the byte array

byte[] fileData = new byte[contentLength];

Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);

this.FileContents = fileData;

this.Success = true;

}

}

}

取出各个段后就能用来存文件了

参考连接stackOverFlow_1

stackOverFlow_2

逆时针の风Cnblog

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航