0

I am having trouble using the GetObject function from the Forge .NET SDK to download a file from a BIM 360 Docs hub.

Here is my jQuery ajax call (client side) :

function downloadFile(storageUrl, displayName) {
jQuery.ajax({
    url: '/api/forge/datamanagement/download?' + $.param({ storageUrl: storageUrl }),
    success: function (res) {
        // create a blob url representing the data
        var blob = new Blob([res]);
        var url = window.URL.createObjectURL(blob);
        // attach blob url to anchor element with download attribute
        var anchor = document.createElement('a');
        anchor.setAttribute('href', url);
        anchor.setAttribute('download', displayName);
        anchor.click();
        window.URL.revokeObjectURL(url);
    }
});

And here is my .NET C# corresponding controller function (server side) :

    [HttpGet]
    [Route("api/forge/datamanagement/download")]
    public async Task<dynamic> GetObject(string storageUrl)
    {
        Credentials = await Credentials.FromSessionAsync(base.Request.Cookies, Response.Cookies);
        if (Credentials == null) { return null; }

        ObjectsApi objectsApi = new ObjectsApi();
        objectsApi.Configuration.AccessToken = Credentials.TokenInternal;

        string[] idParams = storageUrl.Split('/');
        string bucketKey = idParams[6];
        string objectName = idParams[8];
        if (objectName.Contains("?"))
            objectName = objectName.Split("?")[0];

        dynamic obj = await objectsApi.GetObjectAsync(bucketKey, objectName);

        if (obj is FileStream)
            return File(obj, "application/octet-stream");

        if (obj is MemoryStream ms)
        {
            FileStream fs = new FileStream(Path.Combine(Path.GetTempPath(), objectName), FileMode.Create, FileAccess.ReadWrite);
            ms.CopyTo(fs);
            ms.Position = 0;
            fs.Position = 0;
            return File(fs, "application/octet-stream");
        }

        return null;
    }

The trouble is after getting the result from GetObjectAsync call :

  • If it returns a FileStream (like for .txt files), there is no problem, downloaded files are correct.
  • If it returns a MemoryStream (like for .json and .rvt files), I write it in a FileStream then returns it. But it works only for .json files. For .rvt files, the downloaded files are corrupt and cannot be opened by Revit.

What is strange is that :

  • the corrupt files are approximately 2 times bigger than the "real"/"correct" ones.
  • when copying the MemoryStream into a FileStream the temporary created Revit files in my server temp folder are correct.

What am I missing here ?

Thanks for your help.

Maxime

M.V.
  • 177
  • 9
  • I can reproduce this issue. If checking the response, its length looks correct. The length started to be wrong after converting the stream to blob. It looks not a problem with Download File of Forge, as you and me test, the stream can be saved to the correct file on server side. I will dig into how to make it work. – Xiaodong Liang Jan 20 '20 at 15:52

1 Answers1

0

There is probably an encoding issue here, as you mentioned the file is 2x bigger.

Anyway, I would suggest you use a "proxy" approach instead. Let me explain: the GetObjectAsync will download the entire file to your server, which can be big and allocate a lot of memory. Even if you save it locally before sending to the client, still allocating disk resources...

A proxy approach would just get chunks of data from Forge and stream each chunk to the client. There are different ways of implementing it, probably this other answer is a start.

Augusto Goncalves
  • 8,493
  • 2
  • 17
  • 44