1

I am working with Angular 9 to upload a file to OneDrive using MS Graph.

I got so far as to upload an empty file and upload a file with some bogus content (the datatype). I suppose I am not adding the right stream,

I read “Upload or replace the contents of a DriveItem” and another bunch of documents. it says: The contents of the request body should be the binary stream of the file to be uploaded.

In the same document, in the Example (updating an existing file) section it says:

const stream = The contents of the file goes here.; 
let res = await client.api('/me/drive/items/{item-id}/content') .put(stream);

which is useless.

I am getting the files from an object, I use

onChangeFilePicker() {
    this.upload(this.filePicker.nativeElement.files)
}

which gives me an array of File objects.

Then I tried many different ways, the last one

    private async uploadFile(graphClient: Client, folderItemId: string, file: File) {
      file.arrayBuffer().then((buffer: ArrayBuffer) => {
        let u8Buffer = new Uint8Array(buffer)
        graphClient
          .api(`/me/drive/items/${folderItemId}:/${file.name}:/content`)
          .post(u8Buffer.values())
            .then(response => {
                console.log('ok')
            })
            .catch(error => {
                console.error(error.stack)
            })        
      })
  }

which creates a file with two bytes.

Do you have any idea on how to solve it?

  • I tried this in past and it worked: string path = "D:\\LessThan4MB.txt"; byte[] data = System.IO.File.ReadAllBytes(path); using (Stream stream = new MemoryStream(data)) { var item = await _client.Me.Drive.Items[FolderID] .ItemWithPath("LessThan4MB.txt") .Content .Request() .PutAsync(stream); } You can try this approach with memory stream and PutAsync request to see if it fits your scenario. – Dev Dec 16 '20 at 19:14
  • I will update it in the answer. so that you can read the code snippet properly. – Dev Dec 17 '20 at 05:25
  • I read your response, thank you. It is C# so I used the equivalent ideas in TypeScript. But It does not work. I keep on getting a file with corrupted content. – DigitalOnion Dec 17 '20 at 14:34
  • @DigitalOnion Hi. I am trying to upload the files to one drive and I am not able to get the access token. Can you help me out with how you have done this?. I have also set a bounty on a question if you could answer that. – Lenzman Apr 13 '21 at 09:46

1 Answers1

0

I found the solution, it was about encoding and the Graph Client.

I skipped the Graph Client and went for pure Graph API requests. This requires to pass the Authentication Token, and requires to put together the Body of the request. Though I had similar results, those got fixed when I encoded the ArrayBuffer as a UInt8Array, like this:

To get the Authentication Token:

  let graphScopes = new MSALAuthenticationProviderOptions(["Files.ReadWrite.All"]);    
  let userAgentApplication = new UserAgentApplication( { auth: this.authConfiguration} )
  let authProvider = new ImplicitMSALAuthenticationProvider(userAgentApplication, graphScopes );
  
  await authProvider.getAccessToken().
  .then(
    token => {
        let headers = new HttpHeaders({
          'Content-Type':'application/json; charset=utf-8',
          'Authorization': `Bearer ${token}`
        })

Then to transform the Array Buffer (as suggested at: Angular 5 HttpClient post raw binary data)

      file.arrayBuffer().then( buffer => {            
          let body = new Uint8Array(buffer)
          let uIntBody = body.buffer;
          

and finally making the HttpClient PUT Request:

async experimentHTTPPostFile(parentId: string, file: File) {    
  let graphScopes = new MSALAuthenticationProviderOptions(["Files.ReadWrite.All"]);    
  let userAgentApplication = new UserAgentApplication( { auth: this.authConfiguration} )
  let authProvider = new ImplicitMSALAuthenticationProvider(userAgentApplication, graphScopes );
  
  await authProvider.getAccessToken()
  .then(
    token => {
        let headers = new HttpHeaders({
          'Content-Type':'application/json; charset=utf-8',
          'Authorization': `Bearer ${token}`
        })

        file.arrayBuffer().then( buffer => {            
          let body = new Uint8Array(buffer)
          let uIntBody = body.buffer;
        
          let url = `${this.MS_GRAPH_BASE_URL}/me/drive/items/${parentId}:/${file.name}:/content`
          this.http.put(url, uIntBody, { headers: headers }).toPromise()
          .then(response => {
            console.log(response)
          })
          .catch(error => {
            console.error(error)
          });                
        })            
      }
  ).catch(error => {
      console.error(error)
  })
}

It worked perfectly, I tested with PDF, JPEG and other binary files.

I tried doing the same UInt8 transformation of the buffer with the Graph Client graphClient.api(...).put(...), and it does not fix the problem.

  • Glad to hear the above solution helped you moving forward. – Dev Dec 19 '20 at 18:07
  • Yes, it helped thank you. Seems like the subject does not have good or finished documentation and articles are rolling out slowly. Thanks again. – DigitalOnion Dec 21 '20 at 03:11