【问题标题】:Objective C to ASP.net Web API file upload giving error Unexpected end of MIME multipart stream MIME multipart message is not completeObjective C 到 ASP.net Web API 文件上传给出错误 MIME 多部分流的意外结束 MIME 多部分消息不完整
【发布时间】:2013-12-10 08:34:06
【问题描述】:

我有以下处理文件上传的 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);

}

如果与 HTML 表单上传集成,ASP.net Web API 端代码工作正常,因此,我从 Objective C 调用它的方式可能有问题(我是 Objective C 的新手)

【问题讨论】:

    标签: objective-c file-upload asp.net-web-api


    【解决方案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 方法就可以了。

    【讨论】:

    • 感谢这个帮助建议,但即使在与此集成后也会出现相同的错误。
    • 如果 (info.Exists){// LOG TO SEE HAVE YOU GOT THE FILE } 只是为了调试,您可以添加到您的代码中吗?
    • 谢谢 Greg,我添加了那个日志,但它没有进入这个块... var fileInfo = streamProvider.FileData.Select(i => {
    • 您可以尝试将 [HttpPost] 属性添加到您的 UploadFile 方法。如果它不起作用,请尝试使用 AFNetworking 或 NSURLSession 将图像上传到 web api。
    • 感谢您的所有帮助 Greg,我将尝试与 AFNetworking 集成,您可以分享您使用 AFNetworking 上传文件的代码吗?
    【解决方案2】:

    我们专门在 iOS 上解决了这个问题。没弄清楚 - 为什么手工制作的 Http 多部分请求会在 .Net 服务器上出现该错误,但使用了简单的 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);
          }];
    

    【讨论】:

      猜你喜欢
      • 2021-05-18
      • 2022-07-12
      • 2016-12-31
      • 1970-01-01
      • 2017-05-12
      • 2012-11-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      相关资源
      最近更新 更多