2013-11-25 25 views
1

我有以下处理文件上传的ASP.net WebAPI代码。使用简单的HTML文件上传表单很好用。Objective C到ASP.net Web API文件上传给出错误MIME多部分流MIME多部分消息的意外结束未完成

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; 
      } 
    } 

但给出“MIME多流MIME多部分消息的意外的端部未完成”,如果从目标C代码调用,这个予通过对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表单上传集成正常工作,所以,probabaly有什么问题我是从目标调用的方式C(我新的目标C)

回答

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代码。

// EDITED 我.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方法即可使用。

+0

感谢您的帮手建议,但即使与此集成后,也会出现相同的错误。 – Pravin

+0

如果(info.Exists){//日志为了调试只能看到文件},你可以添加到你的代码吗? – Greg

+0

感谢格雷格,我添加了日志,它不会进入此块... var fileInfo = streamProvider.FileData.Select(i => { – Pravin

0

我们在iOS上特别讨论了这个问题。没有想到 - 为什么手工制作Http multipart请求会在.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); 
     }]; 
相关问题