autodesk-forgeopen-sourceautodeskautodesk-designautomation

How to Upload a Zip File and Create an AppBundle in Autodesk Forge Design Automation SDK?


I am trying to upload a zip file to Autodesk Forge's Object Storage Service (OSS) and then use it to create an AppBundle for Design Automation. While I successfully upload the file and create the AppBundle, the package URL linked to the AppBundle always gives a NoSuchKey error when accessed.

Here’s the relevant part of my code:

var auth = new TwoLeggedApi();

dynamic tokenResponse = await auth.AuthenticateAsync(
    ClientId,
    ClientSecret,
    oAuthConstants.CLIENT_CREDENTIALS,
    [Scope.DataRead, Scope.DataWrite]
);

var objectsApi = new ObjectsApi { Configuration = { AccessToken = tokenResponse.access_token; } };

using var fileStream = new FileStream(zipFilePath, FileMode.Open, FileAccess.Read);

dynamic response = await objectsApi.UploadObjectAsync(
    bucketKey,
    objectKey,
    (int)fileStream.Length,
    fileStream,
    "application/zip"
);

string ossObjectUrl = $"https://developer.api.autodesk.com/oss/v2/buckets/{bucketKey}/objects/{objectKey}";

string fullyQualifiedId = $"{_account}.{bundleId}";
var newVersion = new AppBundle
{
    Id = fullyQualifiedId,
    Engine = $"Autodesk.Revit+{yearVersion}",
    Package = ossObjectUrl,
    Description = $"App bundle for Revit {yearVersion}",
};

AppBundle bundle = await _daClient.CreateAppBundleAsync(newVersion);
// package URL is valid
// after creating an alias and fetching the AppBundle again, the package url is invalid

The AppBundle is created successfully, but when I set an alias and try to access the package URL, I get an error:

<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
</Error>

Solution

  • You cannot pass an OSS URL to the Package property in the AppBundle class. This property requires the path to the package zip file located on your local disk.

    var newVersion = new AppBundle
    {
        Id = fullyQualifiedId,
        Engine = $"Autodesk.Revit+{yearVersion}",
        Package = @"D:\Temp\package.zip", // Must be a local disk path
        Description = $"App bundle for Revit {yearVersion}",
    };
    

    Steps to Manage AppBundles:​

    1. Register the AppBundle:
      Use the Design Automation API (https://developer.api.autodesk.com/da/us-east/v3/appbundles) to create a new AppBundle and obtain upload details. ​
    2. Upload the AppBundle:
      Upload the AppBundle zip file to the provided signed AWS URL. Ensure all required form data is included. ​
    3. Create an Alias:
      Assign an alias (e.g., test) to the AppBundle for easier version management.

    Example Code

    private async Task<string> SetupAppBundleAsync()
    {
        // Log the start of the AppBundle setup process
        Console.WriteLine("Setting up AppBundle...");
    
        // Construct the fully qualified AppBundle name
        var myApp = $"{_config.Owner}.{_config.BundleName}+{_config.Label}";
    
        // Check if the AppBundle already exists
        var appResponse = await _designAutomationClient.AppBundlesApi.GetAppBundleAsync(myApp, throwOnError: false);
    
        // Define the new AppBundle details
        var app = new AppBundle
        {
            Engine = _config.TargetEngine,
            Id = _config.BundleName
        };
    
        // Validate that the package path is not null
        var package = _config.BundlePath ?? throw new NullReferenceException("BundlePath cannot be null.");
    
        if (appResponse.HttpResponse.StatusCode == HttpStatusCode.NotFound)
        {
            // If the AppBundle doesn't exist, create it
            Console.WriteLine($"\tCreating AppBundle {myApp}...");
            await _designAutomationClient.CreateAppBundleAsync(app, _config.Label, package);
            return myApp;
        }
    
        // Ensure the response is successful if the AppBundle exists
        await appResponse.HttpResponse.EnsureSuccessStatusCodeAsync();
        Console.WriteLine("\tFound existing AppBundle...");
    
        // Check if the existing package matches the new one
        if (!await EqualsAsync(package, appResponse.Content.Package))
        {
            // If the packages differ, update the AppBundle
            Console.WriteLine($"\tUpdating AppBundle {myApp}...");
            await _designAutomationClient.UpdateAppBundleAsync(app, _config.Label, package);
        }
    
        // Return the name of the AppBundle
        return myApp;
    }
    

    Reference

    Follow this step-by-step guide for detailed instructions: Publishing an AppBundle