1

I am trying to upload a PDF using Angular 8. I am successfully getting the file the user selects on the front end. I am passing something off to the back-end but when I am attempt to read the file from the memory stream, during my test in converting it to a string I get "[object FileList]" instead of the contents of the file.

Is this something with swagger I am not familiar with? I think I might be stuck more than I was before.

Below is my HTML for the selection of the file.

    <div>
        <form [formGroup] = "uploadForm" (ngSubmit)="onSubmit()">      
      <div>
        <!-- TODO: rename profile -->
        <input type="file" name="profile" (change)="onFileSelect($event)" 
    accept=".pdf"/>
      </div>
      <div>
        <button type="submit">Upload</button>
      </div>
    </form>
  </div>

Below is my TypeScript:

    import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule} from '@angular/forms';

@Component({
  selector: 'app-pdf',
  templateUrl: './pdf.component.html',
  styleUrls: ['./pdf.component.css']
})
export class PDFComponent implements OnInit {

  SERVER_URL = "http://localhost:64528/api/uploadPDF";
  uploadForm: FormGroup; 
  file;

  constructor(private formBuilder: FormBuilder, private httpClient: HttpClient) { }

  ngOnInit() {
    this.uploadForm = this.formBuilder.group({
      profile:['']
    });
  }

  onFileSelect(event){
    var file = event.target.files;
    if(file.length > 0){
       this.file = event.target.files[0];
      this.uploadForm.get('profile').setValue(file);

      var confirm = this.uploadForm.get('profile').value;
    }
  }

  onSubmit(){
    const formData = new FormData();
    formData.append('file', this.uploadForm.get('profile').value);

    this.httpClient.post<any>(this.SERVER_URL, formData).subscribe(
      (res) => console.log(res),
      (err) => console.log(err)
    );
  }

}

and Below is my C#

using HeadcountTrackingAPI.Repositories;
using HeadcountTrackingAPI.Utilities;
using Swashbuckle.Swagger.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace HeadcountTrackingAPI.Controllers
{
    public class PDFController : ApiController
    {
        // GET api/<controller>
        [SwaggerOperation("uploadPDF")]
        [HttpPost]
        [Route("api/uploadPDF")]
        public async Task<IHttpActionResult> UploadFile()
        {
            try
            {
                if (!Request.Content.IsMimeMultipartContent("form-data"))
                    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

                // Initialize the memorty stream provider
                MultipartMemoryStreamProvider memoryStream = new MultipartMemoryStreamProvider();

                // Assign it's contents
                memoryStream = await Request.Content.ReadAsMultipartAsync();

                // Read the contents asynchronosly 
                using (System.IO.Stream pdfStream = await memoryStream.Contents.First().ReadAsStreamAsync())
                {

                    byte[] bytes = new byte[pdfStream.Length];

                    // streamBytes to the byte array starting a position 0 and ending at the end of the file
                    pdfStream.Read(bytes, 0, (int)pdfStream.Length);

                    var byteString = BitConverter.ToString(bytes);
                    string utfString = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                }

                    return Ok(new { Posted = true });
            }
            catch (Exception ex)
            {
                ex.LogException();
                return InternalServerError(ex);
            }
        }
    }
}

Below is the Resources I have accessed https://learn.microsoft.com/en-us/previous-versions/aspnet/dn202095(v%3Dvs.118)

'multipart/form-data' is not supported for this resource

https://www.c-sharpcorner.com/UploadFile/2b481f/uploading-a-file-in-Asp-Net-web-api/

Send a file via HTTP POST with C#

How To Accept a File POST

any and all help is appreciated, thank you.

Adam Schneider
  • 275
  • 1
  • 5
  • 18
  • 1
    If you're talking about the first comment on the *question*, they're talking about the code in the *question*, not the code in the *answer*, which is where you should be looking for, you know, answers :). – Heretic Monkey Aug 23 '19 at 20:00
  • yeah sorry I am dumb, I am testing now. The line ` string file1 = provider.BodyPartFileNames.First().Value;` is giving me red squgglies and no way to fix. – Adam Schneider Aug 23 '19 at 20:03
  • @AdamSchneider if you hover over the line, does intellisense offer any suggestions? – Dortimer Aug 23 '19 at 20:16
  • string file1 = provider.FileData.First().LocalFileName; This is supposedly the way to do it, but 1. I see it accessing my file system and making a path, but I don't see it ingesting the file, no where do I see the file actually making it to the server, when I check the response message I dont see the message File Uploaded. 2. When I look through the code, unless I am missing something I dont actually see where it is saving the code. – Adam Schneider Aug 23 '19 at 20:37
  • @AdamSchneider you'd have to test it out, but I think in the controller you could use something like `var file = Request.Files[0];` (or `Request.Files.FirstOrDefault()` the difference being that `FirstOrDefault()` won't throw a null reference exception if there isn't a file in the request). And work from there. `HttpPostedFileBase` as a parameter to the controller could also probably work. – Dortimer Aug 23 '19 at 21:01

1 Answers1

0

Try this:

[HttpPost]
[Route("api/uploadPDF")]
public async Task<IHttpActionResult> UploadFile()
{
    try
    {
        if (!Request.Content.IsMimeMultipartContent("form-data"))
        {
            return StatusCode(HttpStatusCode.UnsupportedMediaType);
        }

        var fileProvider = await Request.Content.ReadAsMultipartAsync();

        var pdfStream = await fileProvider.Contents.First().ReadAsStreamAsync();

        //do something with the pdf stream

        return Ok(new { Posted = true });                
    }
    catch (Exception ex)
    {
        ex.LogException();
        return InternalServerError(ex);
    }
}
Luis Lavieri
  • 4,064
  • 6
  • 39
  • 69
  • 2
    It might be worth noting that `var pdfStream` could potentially include a `using` statement to ensure it gets disposed (iirc, memory streams/file streams, etc aren't fantastic about cleaning themselves up). – Dortimer Aug 23 '19 at 20:15
  • I keep getting ExceptionMessage: "Invalid 'HttpContent' instance provided. It does not have a 'multipart' content-type header with a 'boundary' parameter. ↵Parameter name: content". I changed my content type on the angular side and tried commenting out your if statement to see if that would let me get past it. I am unaware of why this is happening, when this happened before it was because my old function needed content type "application/x-www-form-urlencoded", but changing it back to Multipart/form-data doesnt seem to be fixing it. – Adam Schneider Aug 23 '19 at 20:49
  • 500 internal service error. IDK I feel like your solution might be correct, but I aint getting anywhere – Adam Schneider Aug 23 '19 at 21:03
  • Well that hurt, it was because I defined the content type and not a boundary, if I just don't define the content type Swagger does it correctly automagically. geez. – Adam Schneider Aug 23 '19 at 21:25