Search code examples
c#node.jsdotnet-httpclientautodesk-forgemulter

Uploading a Revit file to Autodesk Forge OSS by Multer on a Node JS server with C# .NET HTTPClient


I have a node.js server using autodesk forge by Forge Node.js SDK. For uploading an object I have used uploadObject() method and multer middleware like what has been said here. The code is like this:

router.post(
    '/objects',
    multer({ dest: 'uploads/' }).single('fileToUpload'),
    XAuth,
    async (req, res, next) => {
        fs.readFile(req.file.path, async (err, data) => {
            if (err) {
                next(err);
            }
            try {
                req.setTimeout(0);

                await new ObjectsApi().uploadObject(
                    req.body.bucketKey,
                    req.file.originalname,
                    data.length,
                    data,
                    {},
                    req.oauth_client,
                    req.oauth_token
                );
                res.status(200).end();
            } catch (err) {
                next(err);
            }
        });
    }
);

And like what it has been said in here I can call this api by Ajax like this (I have used an input html element to get the file):

var file = input.files[0];
var formData = new FormData();
formData.append('fileToUpload', file);
formData.append('bucketKey', bucketKey.toLowerCase());

$.ajax({
    url: '/api/forge/oss/objects',
    headers: {
       'x-auth': token,
    },
    type: 'POST',
    data: formData,
    processData: false,
    contentType: false,
    success: function (data) {
        console.log('success: Object has been uploaded');
    },
    error: function (err) {
        console.log(err);
    },
});

I what to do the same process by creating a C# Revit plugin for uploading a Revit model. I mean how I can have an object similar to FormData() in C#. I have tried below code by HttpClient and MultipartFormDataContent:

using (MultipartFormDataContent httpContent = new MultipartFormDataContent())
{
    Stream file = new FileStream(App.Path, FileMode.Open);
    httpContent.Add(new StringContent(bucketKey.ToLower()), "bucketKey");
    httpContent.Add(new StreamContent(file), "fileToUpload");

    using (var httpClient = new HttpClient { BaseAddress = App.Uri })
    {
        httpClient.DefaultRequestHeaders.Add("x-auth", App.Token);

        using (var httpResponse = await httpClient.PostAsync("/api/forge/oss/objects", httpContent))
        {
            if (httpResponse.IsSuccessStatusCode)
            {
                TaskDialog.Show("Upload", "success: Object has been uploaded"); 
            }
        }
    }
}

But I got a MulterError: Field value too long error in my server and a 500: 'Internal Server Error response to my Revit plugin.


Solution

  • Thanks to Xiaodong Liang, I edited my code like below and it worked for me.

    using (MultipartFormDataContent httpContent = new MultipartFormDataContent())
    {
        byte[] byteArray = File.ReadAllBytes(App.Path);
        Stream stream = new MemoryStream(byteArray);
    
        StreamContent streamContent = new StreamContent(stream);
        streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    
        httpContent.Add(streamContent, "fileToUpload");
        httpContent.Add(new StringContent(bucketKey.ToLower()), "bucketKey");
    
        using (var httpClient = new HttpClient { BaseAddress = App.Uri })
        {
            httpClient.DefaultRequestHeaders.Add("x-auth", App.Token);
    
            using (var httpResponse = await httpClient.PostAsync("/api/forge/oss/objects", httpContent))
            {
                if (httpResponse.IsSuccessStatusCode)
                {
                    TaskDialog.Show("Upload", "success: Object has been uploaded"); 
                }
            }
        }
    }