1

I have an Angular application, written in Typescript, with an ASP.Net Web Api backend. I am trying to use the ng-file-upload (see this link for details) directive to upload an image file.

I receive an exception in my Web API Post method:

"Unexpected end of MIME multipart stream. MIME multipart message is not complete."

I've done my research and found similar issues here - I have tried to implement Landuber Kassa's answer but without success.

Also this although my project is not MVC and in any case it did not work.

I am fresh out of ideas and would appreciate the community's thoughts. I am happy to consider any other alternatives if I can be pointed in the right direction.

Ash

My .Net Post method (implementing Landuber Kassa's idea):

[RoutePrefix("BeaufortAppStore/api/Image")]
public class ImageController : ApiController
{

    #region Methods

    #region Posts

    [Route("UploadImage")]
    [HttpPost]
    public async Task<IHttpActionResult> UploadImage()
    {
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        var provider = new MultipartMemoryStreamProvider();

        Stream reqStream = Request.Content.ReadAsStreamAsync().Result;
        MemoryStream tempStream = new MemoryStream();
        reqStream.CopyTo(tempStream);

        tempStream.Seek(0, SeekOrigin.End);
        StreamWriter writer = new StreamWriter(tempStream);
        writer.WriteLine();
        writer.Flush();
        tempStream.Position = 0;

        StreamContent streamContent = new StreamContent(tempStream);
        foreach (var header in Request.Content.Headers)
        {
            streamContent.Headers.Add(header.Key, header.Value);
        }

        // Read the form data and return an async task.
        await streamContent.ReadAsMultipartAsync(provider); // FAILS AT THIS POINT
        foreach (var file in provider.Contents)
        {
            var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
            var buffer = await file.ReadAsByteArrayAsync();
            //Do whatever you want with filename and its binary data.
        }
        return Ok();
    }

    #endregion

    #endregion

My angular controller method:

public upload(): void {
        //Create config used in ng-file-upload
        var config: IFileUploadConfigFile = {
            data: this.file, url: "BeaufortAppStore/api/Image/UploadImage/", method: "POST" };
        this._dataService.uploadImage(config).then((result: any) => {
            this.thumbnail = result.data;
        });
    }

My angular view (partial view for a directive):

<div class="form-group">
<label for="file" class="control-label col-xs-2">Choose a file</label>
<input id="file" type="file" name="file" class="form-control" ngf-select ngf-pattern="'image/*'"
       ng-model="vm.file" />
<img style="width:100px;" ngf-thumbnail="thumbnail || '/thumb.jpg'" />
<button type="submit" ng-click="vm.upload()">Upload</button>

Community
  • 1
  • 1
The Dumb Radish
  • 886
  • 7
  • 18
  • Any update on this issue? I am getting the same while uploading files. It would be helpful to share if u found any solution on this. – Finder Aug 07 '19 at 11:27

1 Answers1

0

Try this in C#:

    [HttpPost]
    [Route("Profile/Image")]
    public Task<HttpResponseMessage> UploadImgProfile()
            {
                try
                {
                    if (!ModelState.IsValid) return null;

                    var currentUser = _userUtils.GetCurrentUser(User);
                    if (currentUser == null) return null;

                    HttpRequestMessage request = this.Request;
                    if (!request.Content.IsMimeMultipartContent())
                        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));

                    string root = HttpContext.Current.Server.MapPath("~" + Constant.Application.User_Image_Directory);

                    bool exists = Directory.Exists(root);
                    if (!exists)
                        Directory.CreateDirectory(root);

                    var provider = new   MultipartFormDataStreamProvider(root);





     var task = request.Content.ReadAsMultipartAsync(provider).
                    ContinueWith<HttpResponseMessage>(o =>
                    {
                        var finfo = new     FileInfo(provider.FileData.First().LocalFileName);

          string guid = Guid.NewGuid().ToString();

          var fileName = guid + "_" + currentUser.IdOwin + ".jpg"; 

                        File.Move(finfo.FullName, Path.Combine(root, fileName));

                        return new HttpResponseMessage()
                        {
                            Content = new StringContent(Path.Combine(Constant.Application.User_Image_Directory, fileName))
                        };
                        }
                        );
                    return task;
                }
                catch (Exception ex)
                {
                    _logger.LogException(ex);
                    return null;
                }
            }

Angular Controller:

 //Upload Func
            $scope.upload = function (files) {
                if (files && files.length) {
                    for (var i = 0; i < files.length; i++) {
                        var file = files[i];
                        $scope.uploading = true;
                        //   $scope.imageName = file.name;
                        $upload.upload({
                            url: enviroment.apiUrl + '/api/CurrentUser/Profile/Image',
                            //fields: { 'username': $scope.username },
                            file: file
                        }).progress(function (evt) {
                            $scope.uploading = true;
                            var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                            console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
                            $scope.progress = progressPercentage;
                        }).success(function (data, status, headers, config) {
                            console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
                            $scope.imageName = data;
                            $scope.uploading = false;
                            $scope.loadSuccess = true;
                            vm.uploadImage = false;
                            //AR
                            var reader = new FileReader();
                            reader.onload = function (evt) {
                                $scope.$apply(function ($scope) {
                                    $scope.myImage = evt.currentTarget.result;
                                });
                            };
                            reader.readAsDataURL(files[0]);
                            //END AR
                        });
                    }
                }
            };


    // Stay on Listen upload file
    $scope.$watch('files', function (evt) {
        $scope.upload($scope.files);
    });

HTML:

 <div class="row">
                                <!--UPLOAD-->
                                <div class="up-buttons">

                                    <div class="clearfix visible-xs-block"></div>
                                    <div class="col-md-12 col-lg-12 col-sm-12 col-xs-12 text-center box-upload-image" data-ng-show="profileCtrl.uploadImage">
                                        <br />
                                        <div id="imgDragDrop" ng-file-drop ng-model="files"
                                             drag-over-class="dragover"
                                             accept="image/*">

                                            <div class="cropArea-bkg">
                                                <h4>
                                                    <span class="mdi mdi-account mdi-48px"></span>
                                                    <br /><br />
                                                    Carica immagine profilo
                                                </h4>

                                                <p>Trascina qui la tua immagine, oppure</p>

                                                <div ng-file-select="" ng-model="files" class="btn btn-secondary" ng-accept="'*.pdf,*.jpg,*.png'" tabindex="0">
                                                    Sfoglia sul tuo computer
                                                </div><br>
                                            </div>
                                        </div>
                                        <div ng-no-file-drop class="well bg-danger">File Drag/Drop non è supportato da questo browser</div>
                                        <br />
                                        <div class="text-center">
                                            <div class="progress" ng-show="uploading">
                                                <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ ::progress }}" aria-valuemin="0" aria-valuemax="100" style="width: {{::progress}}% ">
                                                    <span class="sr-only">{{ ::progress }}% Complete</span>
                                                </div>
                                            </div>
                                        </div>

                                    </div>

                                    <!--END UPLOAD-->

                                </div>
                            </div>
federico scamuzzi
  • 3,708
  • 1
  • 17
  • 24
  • Thanks for the quick answer. Before I try it can you explain a little about what is different about this approach. – The Dumb Radish Dec 28 '16 at 11:07
  • Basically it's a battle tested way to retrive a mutipart upload content from a angular upload... it take the correct format from the this.Request and with an async task it generate a name (with a random guid to don't overwrite or go in exception if someone upload the same image with same name of other) – federico scamuzzi Dec 28 '16 at 11:10
  • I'll show to you also the controller (Angular) and the html if you need it..and be sure of your post method (check it on chrome console..if format is right..if it's not try to overwrite the header of the request) – federico scamuzzi Dec 28 '16 at 11:10
  • Yes please give me the controller and html and I will try and put it all together – The Dumb Radish Dec 28 '16 at 11:12
  • ok iedit the answer..it's not typescript..i hope you can re arrange it – federico scamuzzi Dec 28 '16 at 11:12