【问题标题】:Upload file (> 4MB) to OneDrive using Graph API使用 Graph API 将文件 (> 4MB) 上传到 OneDrive
【发布时间】:2020-08-11 14:36:30
【问题描述】:

我正在尝试使用 Graph API 将文件上传到 OneDrive。当我上传小于 4MB 的文件时,以下代码可以正常工作,但当我尝试上传大于 4MB 的文件时,它会显示错误。我经历了this documentation,但我仍然不确定如何才能完成这项工作。

以下是小于 4MB 文件的工作代码。

using (var client = new HttpClient())
{
    var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content";
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());

    byte[] sContents = System.IO.File.ReadAllBytes(filePath);
    var content = new ByteArrayContent(sContents);

    var response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}

请帮忙

【问题讨论】:

    标签: c# microsoft-graph-api onedrive


    【解决方案1】:

    我们需要按长度(即 4MB)分割字节数组并将它们传递给 OneDrive API。工作版本如下:

    using (var client = new HttpClient())
    {
        var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/createUploadSession";
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
    
        var sessionResponse = client.PostAsync(apiUrl, null).Result.Content.ReadAsStringAsync().Result;
    
        byte[] sContents = System.IO.File.ReadAllBytes(filePath);
        var uploadSession = JsonConvert.DeserializeObject<UploadSessionResponse>(sessionResponse);
        string response = UploadFileBySession(uploadSession.uploadUrl, sContents);
    }
    

    UploadFileBySession 如下:

    private string UploadFileBySession(string url, byte[] file)
    {
        int fragSize = 1024 * 1024 * 4;
        var arrayBatches = ByteArrayIntoBatches(file, fragSize);
        int start = 0;
        string response = "";
    
        foreach (var byteArray in arrayBatches)
        {
            int byteArrayLength = byteArray.Length;
            var contentRange = " bytes " + start + "-" + (start + (byteArrayLength - 1)) + "/" + file.Length;
    
            using (var client = new HttpClient())
            {
                var content = new ByteArrayContent(byteArray);
                content.Headers.Add("Content-Length", byteArrayLength.ToProperString());
                content.Headers.Add("Content-Range", contentRange);
    
                response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
            }
    
            start = start + byteArrayLength;
        }
        return response;
    }
    
    internal IEnumerable<byte[]> ByteArrayIntoBatches(byte[] bArray, int intBufforLengt)
    {
        int bArrayLenght = bArray.Length;
        byte[] bReturn = null;
    
        int i = 0;
        for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
        {
            bReturn = new byte[intBufforLengt];
            Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
            yield return bReturn;
        }
    
        int intBufforLeft = bArrayLenght - i * intBufforLengt;
        if (intBufforLeft > 0)
        {
            bReturn = new byte[intBufforLeft];
            Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
            yield return bReturn;
        }
    }
    

    UploadSessionResponse 类文件,用于在创建上传会话时反序列化 JSON 响应

    public class UploadSessionResponse
    {
        public string odatacontext { get; set; }
        public DateTime expirationDateTime { get; set; }
        public string[] nextExpectedRanges { get; set; }
        public string uploadUrl { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      对于大于 4MB 的文件,您需要将 create an uploadSession 发布到此 URL:

      https://graph.microsoft.com/v1.0/me/drive/root:/{item-path}:/createUploadSession
      

      传递一个项目数组,

      {
        "item": {
          "@odata.type": "microsoft.graph.driveItemUploadableProperties",
          "@microsoft.graph.conflictBehavior": "rename",
          "name": "largefile.dat"
        }
      }
      

      我使用"@microsoft.graph.conflictBehavior": "overwrite",而不是rename

      响应会提供上传url,用于批量上传文件

      {
        "uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
        "expirationDateTime": "2015-01-29T09:21:55.523Z"
      }
      

      我没有 c# 示例,但这里有一个 PHP 示例:

      $url = $result['uploadUrl'];
      $fragSize = 1024*1024*4;
      $file = file_get_contents($source);
      $fileSize = strlen($file);
      $numFragments = ceil($fileSize / $fragSize);
      $bytesRemaining = $fileSize;
      $i = 0;
      $response = null;
      
      while ($i < $numFragments) {
          $chunkSize = $numBytes = $fragSize;
          $start = $i * $fragSize;
          $end = $i * $fragSize + $chunkSize - 1;
          $offset = $i * $fragSize;
      
          if ($bytesRemaining < $chunkSize) {
              $chunkSize = $numBytes = $bytesRemaining;
              $end = $fileSize - 1;
          }
      
          if ($stream = fopen($source, 'r')) {
              // get contents using offset
              $data = stream_get_contents($stream, $chunkSize, $offset);
              fclose($stream);
          }
      
          $contentRange = " bytes " . $start . "-" . $end . "/" . $fileSize;
          $headers = array(
              "Content-Length: $numBytes",
              "Content-Range: $contentRange"
          );
      
          $ch = curl_init($url);
          curl_setopt($ch, CURLOPT_URL, $url);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
          curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
          curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
          curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
          $server_output = curl_exec($ch);
          $info = curl_getinfo($ch);
          curl_close($ch);
      
          $bytesRemaining = $bytesRemaining - $chunkSize;
          $i++;
      }
      

      【讨论】:

      • 非常感谢。我现在可以成功上传大小超过 4MB 的文件。我现在将添加 C# 版本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多