The Community is undergoing a major upgrade. Find out more, ask us questions or share your thoughts here.

Forum Discussion

NetSecCSU3's avatar
NetSecCSU3
New member | Level 2
6 years ago

Dropbox Asynchronous API Calls Throwing "ArgumentOutOfRangeException"

I am building a Unity game that needs to utilize file storage of some sort. Because of its examples, documentation, and support, I decided to go with Dropbox API 2.0.

I am using the code from Dropbox API-2.0 Examples-SimpleTest to implement an asynchronous file uploader. The file simply uploads a pseudo-randomly named *.json file to an app folder /nullJSON. The uploaded files are simply *.json files that contain a json string.

Below is my code. Since Unity uses .NetCore, I cannot use WebRequestHandler when setting up the http Client:

API Calls:

//For Game
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Xml;
using UnityEngine.Networking;
using System.IO;
using UnityEngine.EventSystems;
using System.Net;
using UnityEngine.Networking.NetworkSystem;
using System;
using System.Net.Sockets;
//For Dropbox API
using System.Threading;
using System.Runtime.InteropServices;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;
using Newtonsoft.Json;
using Dropbox.Api;
using Dropbox.Api.Common;
using Dropbox.Api.Files;
using Dropbox.Api.Team;


Client Initializer (responsible for setting up the HTTP/Dropbox Client):

public void dBoxSetup()
    {
        //Only run if the dropbox client doesn't exist.
        if (dBoxClient == null)
        {
            //Connect to Dropbox
            DropboxCertHelper.InitializeCertPinning();
            httpClient = new HttpClient()
            {
                Timeout = TimeSpan.FromMinutes(20)
            };
            try
            {
                var config = new DropboxClientConfig("nullificationApp")
                {
                    HttpClient = httpClient
                };
                dBoxClient = new DropboxClient(accessToken, config);
            }
            catch (HttpException e)
            {
                StartCoroutine(ShowMessage("Application Error: Exception reported from RPC layer", 5));
                Debug.Log("Exception reported from RPC layer");
                Debug.Log("    Status code: " + e.StatusCode);
                Debug.Log("    Message    : " + e.Message);
                if (e.RequestUri != null)
                {
                    Debug.Log("    Request uri: " + e.RequestUri);
                }
            }
        }
    }

This code seems to work as the API analytics show that it is successfully connecting, and I am not getting any exception errors on its setup.

 

Create A New JSON File:

public async void dBoxCreate()
    {
        //This fucntion creates a new JSON file.
        if (!IPaddr.text.Equals(""))
        {
            //Naming convention should have already been checked.
            string defenderInfo = pathJSON();
            //Create Page to Upload
            await ChunkUpload(dBoxClient, jsonPath, fileName + ".json", defenderInfo);
            Debug.Log("Creating file " + fileName);
            StartCoroutine(ShowMessage("Creating file" + fileName, 5));
        }
        else
        {
            Debug.Log("Please provide an Opponent IP Address");
            StartCoroutine(ShowMessage("Please provide an Opponent IP Address", 5));
        }
    }

This code also work fine with no errors.

 

The actual Uploader (Where the Error Actually Occurs):

    /// <summary>
    /// Uploads a big file in chunk. The is very helpful for uploading large file in slow network condition
    /// and also enable capability to track upload progerss.
    /// </summary>
    /// <param name="client">The Dropbox client.</param>
    /// <param name="folder">The folder to upload the file.</param>
    /// <param name="fileName">The name of the file.</param>
    /// <param name="contentBody">The content of the file.</param>
    /// <returns></returns>
    private async Task ChunkUpload(DropboxClient myclient, string folder, string fileName, string contentBody)
    {
        Console.WriteLine("Chunk upload file...");
        // Chunk size is 128KB.
        const int chunkSize = 128 * 1024;

        // Create a random file of 1MB in size.
        //var fileContent = new byte[1024 * 1024];
        //new System.Random().NextBytes(fileContent);
        var fileContent = System.Text.UTF8Encoding.UTF8.GetBytes(contentBody);

        using (var stream = new MemoryStream(fileContent))
        {
            int numChunks = (int)Math.Ceiling((double)stream.Length / chunkSize);

            byte[] buffer = new byte[chunkSize];
            string sessionId = null;

            for (var idx = 0; idx < numChunks; idx++)
            {
                Console.WriteLine("Start uploading chunk {0}", idx);
                var byteRead = stream.Read(buffer, 0, chunkSize);

                using (MemoryStream memStream = new MemoryStream(buffer, 0, byteRead))
                {
                    if (idx == 0)
                    {
                        var result = await myclient.Files.UploadSessionStartAsync(body: memStream);
                        sessionId = result.SessionId;
                    }

                    else
                    {
                        UploadSessionCursor cursor = new UploadSessionCursor(sessionId, (ulong)(chunkSize * idx));

                        if (idx == numChunks - 1)
                        {
                            await myclient.Files.UploadSessionFinishAsync(cursor, new CommitInfo(folder + "/" + fileName), memStream);
                        }

                        else
                        {
                            await myclient.Files.UploadSessionAppendV2Async(cursor, body: memStream);
                        }
                    }
                }
            }
        }
    }

To be specific, the error occurs on the line I call the await myclient.Files.UploadSessionStartAsync() [or any myclient.Files async method for that matter]. 

This is the exception that the game throws, which also indicates that the error occurs with the function I mentioned above:

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.

Parameter name: index
Mono.Unity.UnityTlsContext.ProcessHandshake () (at <0079a30f96a047348857e1cecc6c638a>:0)
Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status) (at <0079a30f96a047348857e1cecc6c638a>:0)
(wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus)
Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) (at <0079a30f96a047348857e1cecc6c638a>:0)
Mono.Net.Security.AsyncProtocolRequest+<ProcessOperation>d__24.MoveNext () (at <0079a30f96a047348857e1cecc6c638a>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
Mono.Net.Security.AsyncProtocolRequest+<StartOperation>d__23.MoveNext () (at <0079a30f96a047348857e1cecc6c638a>:0)
Rethrow as AuthenticationException: A call to SSPI failed, see inner exception.
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
Mono.Net.Security.MobileAuthenticatedStream+<ProcessAuthentication>d__47.MoveNext () (at <0079a30f96a047348857e1cecc6c638a>:0)
Rethrow as AggregateException: One or more errors occurred.
System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Threading.Tasks.Task.Wait () (at <7d97106330684add86d080ecf65bfe69>:0)
Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) (at <0079a30f96a047348857e1cecc6c638a>:0)
Mono.Net.Security.MonoTlsStream.CreateStream (System.Byte[] buffer) (at <0079a30f96a047348857e1cecc6c638a>:0)
System.Net.WebConnection.CreateStream (System.Net.HttpWebRequest request) (at <0079a30f96a047348857e1cecc6c638a>:0)
Rethrow as WebException: Error: TrustFailure (One or more errors occurred.)
System.Net.HttpWebRequest.EndGetRequestStream (System.IAsyncResult asyncResult) (at <0079a30f96a047348857e1cecc6c638a>:0)
System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func`2[T,TResult] endFunction, System.Action`1[T] endAction, System.Threading.Tasks.Task`1[TResult] promise, System.Boolean requiresSynchronization) (at <7d97106330684add86d080ecf65bfe69>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Net.Http.HttpClientHandler+<SendAsync>d__64.MoveNext () (at <09b222309a944a9a9cd1b50a05dde50d>:0)
Rethrow as HttpRequestException: An error occurred while sending the request
System.Net.Http.HttpClientHandler+<SendAsync>d__64.MoveNext () (at <09b222309a944a9a9cd1b50a05dde50d>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Net.Http.HttpClient+<SendAsyncWorker>d__47.MoveNext () (at <09b222309a944a9a9cd1b50a05dde50d>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
Dropbox.Api.DropboxRequestHandler+<RequestJsonString>d__17.MoveNext () (at <4b4ce9e876cb41c699e393c69aa2a3f1>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
Dropbox.Api.DropboxRequestHandler+<RequestJsonStringWithRetry>d__15.MoveNext () (at <4b4ce9e876cb41c699e393c69aa2a3f1>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
Dropbox.Api.DropboxRequestHandler+<Dropbox-Api-Stone-ITransport-SendUploadRequestAsync>d__13`3[TRequest,TResponse,TError].MoveNext () (at <4b4ce9e876cb41c699e393c69aa2a3f1>:0)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
GameScript+<ChunkUpload>d__106.MoveNext () (at Assets/GameScript.cs:1184)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.TaskAwaiter.GetResult () (at <7d97106330684add86d080ecf65bfe69>:0)
GameScript+<dBoxCreate>d__90.MoveNext () (at Assets/GameScript.cs:898)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <7d97106330684add86d080ecf65bfe69>:0)
System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) (at <7d97106330684add86d080ecf65bfe69>:0)
UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at C:/buildslave/unity/build/Runtime/Export/Scripting/UnitySynchronizationContext.cs:115)
UnityEngine.UnitySynchronizationContext:ExecuteTasks()

Any idea as to what is going on? My first guess had been that the json was just too large, but that clearly wasn't it. My next guess would be that it would be WebRequestHandler, as the SimpleTest app works just fine, but then the issue becomes that .NetCore supposedly doesn't support WebRequestHandler. Any recommendations/ideas?

A quicker response the better.

  • Greg-DB's avatar
    Greg-DB
    Icon for Dropbox Staff rankDropbox Staff

    [ Cross-linking for reference: https://stackoverflow.com/questions/58399992/unity-netcore-dropbox-api-2-0-throwing-argumentoutofrangeexception-on-async-d ]

    I'm afraid we probably can't offer much support on this particular issue, as we don't officially support Unity, and the error appears to be occurring deeper in the stack, outside of Dropbox code anyway.

    It looks like this exception is occurring during the TLS connection with content.dropboxapi.com, inside Mono.Unity.UnityTlsContext.ProcessHandshake.

    The reference to 'TrustFailure' would seem to indicate an issue with the certificate verification, but the Dropbox API content servers are being served with a valid certificate though. 

    The top exception seems to be a generic index exception anyway though, so it may just be a bug in ProcessHandshake.

    I'd try eliminating the use of `InitializeCertPinning`, as well as the use of the custom `HttpClient` (the SDK will use a default one if you don't supply one).

    • NetSecCSU3's avatar
      NetSecCSU3
      New member | Level 2

      Getting rid of the custom client and IntializeCertPinning does get rid of the Exception, however, no file is ever uploaded, which means the Certificate issue likely still applies. My next question then would be: is there any way to provide Unity with a static dropbox certificate beforehand like such?: Unity - Manual - Networking Issues 

      • Greg-DB's avatar
        Greg-DB
        Icon for Dropbox Staff rankDropbox Staff

        Thanks for trying that and letting me know. I'm glad to hear that cleared up that exception.

        There are other ways for uploads like this to fail, so it may not still be a certificate issue. The file would be committed by the `UploadSessionFinishAsync` method. What does that method return for you now? Or, does code execution even reach there? I recommend adding some logging and/or stepping through with a debugger to see what's happening, since you don't currently seem to be checking the return value for the upload session calls.

        Anyway, I'd also try adding back each of the `InitializeCertPinning` and the custom HTTP client individually to see which one is causing the issue (if it is just one of them). If it's just the custom client, you may still be able to use `InitializeCertPinning`. Otherwise, I can't offer much guidance on how to configuring Unity to pin the certificate. You can find the certificate information and code here though, in case it helps. In any case, the Dropbox API servers aren't self-signed, and the certificate pinning isn't strictly necessary. All Dropbox API calls require TLS, and the pinning would just be an additional security measure.