我有以下ASP.net WebAPI代码处理文件上传。使用简单的HTML文件上传表单可以很好地工作。
public Task<IEnumerable<string>> UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
string fullPath = HttpContext.Current.Server.MapPath("~/uploads");
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider(fullPath);
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
var fileInfo = streamProvider.FileData.Select(i =>
{
var info = new FileInfo(i.LocalFileName);
return "File uploaded as " + info.FullName + " (" + info.Length + ")";
});
return fileInfo;
});
return task;
}
else
{
HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
return null;
}
}
但是如果从Objective C代码调用,则“MIME多部分流MIME多部分消息的意外结束”是完整的,我通过API侧的跟踪得出结论。以下是Objective C方法......
- (void) uploadFile
{
NSString *fileUploadSrvURL = @"http://server1/service/api/controller/uploadfile";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:fileUploadSrvURL]];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request setValue:contentType forHTTPHeaderField:@"content-type"];
NSURL *fullFileURL = [self getFilePath:CurrentVisitId];
NSData *fileData = [NSData dataWithContentsOfURL:fullFileURL];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"FileName\"; filename=\"%@\"\r\n",@"810474.rtf"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:@"Content-Type: application/rtf\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:fileData];
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSHTTPURLResponse* response =[[NSHTTPURLResponse alloc] init];
NSError* error = [[NSError alloc] init] ;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
}
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(@"%@", responseString);
}
由于ASP.net Web API端代码与HTML表单上传集成时工作正常,因此,我从Objective C调用它的方式可能有问题(我是Objective C的新手)
答案 0 :(得分:1)
我有类似的问题,我设法通过创建一个帮助类来对其进行排序(我在网上找到它但我不记得在哪里):
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path)
: base(path)
{ }
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : "NoName";
return name.Replace("\"", string.Empty); //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped
}
}
您还需要在代码中更改几行:
if (Request.Content.IsMimeMultipartContent())
{
string fullPath = HttpContext.Current.Server.MapPath("~/uploads");
var streamProvider = new CustomMultipartFormDataStreamProvider(fullPath);
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IEnumerable<string>>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
///.........
/// rest of your code
}
区别在于我通过AFNetworking调用web api,如果它不适合你,我也可以共享我的AFNetworking代码。
//已编辑 我的.h文件
#import "AFHTTPClient.h"
typedef void (^DataResponseSuccessBlock)(id JSON);
typedef void (^DataResponseFailureBlock)(NSError *error);
@interface MyHTTPClient : AFHTTPClient
+ (MyHTTPClient *)sharedMyHTTPClient;
- (id)initWithBaseURL:(NSURL *)url;
- (void)saveTemplateData:(TemplateData*)data success:(DataResponseSuccessBlock)successBlock failure:(DataResponseFailureBlock)failureBlock;
@end
我的.m文件
@implementation GLHTTPClient
+ (MyHTTPClient *)sharedMyHTTPClient
{
static dispatch_once_t pred;
static MyHTTPClient *_sharedMyHTTPClient = nil;
dispatch_once(&pred, ^{ _sharedMyHTTPClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:kJSON_URL]]; });
return _sharedMyHTTPClient;
}
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if (!self)
{
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:@"Accept" value:@"application/json"];
[self setParameterEncoding:AFJSONParameterEncoding];
return self;
}
- (void)saveTemplateData:(TemplateData*)data success:(DataResponseSuccessBlock)successBlock failure:(DataResponseFailureBlock)failureBlock
{
NSData *imageData = UIImagePNGRepresentation(data.image);
NSMutableURLRequest *request = [self multipartFormRequestWithMethod:@"POST" path:@"SaveData" //My web api class for uploading image
parameters:nil
constructingBodyWithBlock:^(id <AFMultipartFormData>formData)
{
[formData appendPartWithFileData:imageData
name:@"image"
fileName:@"image.png"
mimeType:@"image/png"];
}];
AFHTTPRequestOperation *op = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
if(successBlock)
successBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if(failureBlock)
failureBlock(error);
}];
[self enqueueHTTPRequestOperation:op];
}
@end
我已经更改了这段代码,所以如果有什么东西不起作用,请给我一个喊叫,我可以再看看它。 你需要调用saveTemplateData:success:failure方法,它应该可以工作。
答案 1 :(得分:0)
我们特意在iOS上弄乱了这个问题。没想到 - 为什么手工制作的Http多部分请求在.Net Server上出现了这个错误,但是使用了简单的AFNetworking(3)用法。
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
[manager.requestSerializer setValue:[[App instance].login token] forHTTPHeaderField:@"Authorization"];
[manager POST:url parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
for (UIImage *img in [params allValues]) {
[formData appendPartWithFileData:UIImageJPEGRepresentation(img, 1) name:[NSString stringWithFormat:@"photo_%d",count] fileName:[NSString stringWithFormat:@"photo_%d.jpg",count] mimeType:@"image/jpeg"];
}
}
progress:nil
success:^(NSURLSessionDataTask *task, id response) {
NSLog(@"Success");
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"Error: %@", error);
}];