docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Use case: Finalize thumbnail upload for an annotation

    Before you start

    Before you finalize a thumbnail upload, ensure you have completed the following prerequisites:

    1. Thumbnail Uploaded: You must have already uploaded a thumbnail file to the pre-signed URL obtained from ReadThumbnailUploadUrlAsync.
    2. Project Access: Ensure you have the necessary permissions to modify annotations in the target project.
    3. Upload Verification: Verify that your upload to the pre-signed URL completed successfully (HTTP 200/204 response).
    4. Set Up SDK Environment: Confirm that your Unity environment is correctly configured with the Collaboration SDK.

    How do I...?

    Finalize a thumbnail upload

    To complete the thumbnail upload process and make the thumbnail visible, follow these steps:

    1. Complete Upload: Ensure you have successfully uploaded the thumbnail image to the pre-signed URL.
    2. Prepare Identifiers: Have your project and annotation identifiers ready.
    3. Call Finalize: Use the SDK to finalize the upload, which registers the thumbnail with the annotation.
    4. Verify: Confirm that the annotation now shows HasThumbnail = true.

    Example:

    var projectId = new ProjectId("87cf845f-8ca7-4b2f-9cc1-c3d731335810");
    var annotationId = new AnnotationId("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
    
    var annotationReference = new annotationReference(projectId, annotationId);
    
    // After successfully uploading to the pre-signed URL, finalize the upload
    await annotationManagement.FinalizeThumbnailUploadAsync(
        annotationReference,
        cancellationToken);
    
    Debug.Log("Thumbnail upload finalized successfully");
    
    // The annotation now has a thumbnail available
    

    Complete thumbnail upload workflow with error handling

    Here's the full workflow from upload to finalization with comprehensive error handling:

    public async Task<bool> UploadAndFinalizeThumbnail(
        ProjectId projectId,
        AnnotationId annotationId,
        byte[] imageData)
    {
        string uploadUrl = null;
    
        var annotationReference = new annotationReference(projectId, annotationId);
    
        try
        {
            // Step 1: Get upload URL
            ReadThumbnailUploadUrlResult urlResult = await annotationManagement.ReadThumbnailUploadUrlAsync(
                annotationReference,
                cancellationToken);
    
            uploadUrl = urlResult.Url;
            Debug.Log("Upload URL obtained");
    
            // Step 2: Upload the image
            using (var httpClient = new HttpClient())
            {
                var content = new ByteArrayContent(imageData);
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
    
                HttpResponseMessage uploadResponse = await httpClient.PutAsync(uploadUrl, content);
    
                if (!uploadResponse.IsSuccessStatusCode)
                {
                    Debug.LogError($"Upload to pre-signed URL failed: {uploadResponse.StatusCode}");
                    return false;
                }
    
                Debug.Log("Image uploaded successfully");
            }
    
            // Step 3: Finalize the upload
            await annotationManagement.FinalizeThumbnailUploadAsync(
                annotationReference,
                cancellationToken);
    
            Debug.Log("Thumbnail finalized successfully");
            return true;
        }
        catch (Exception ex)
        {
            Debug.LogError($"Failed to upload and finalize thumbnail: {ex.Message}");
            return false;
        }
    }
    

    Verify thumbnail after finalization

    To confirm that the thumbnail is now available on the annotation:

    var annotationReference = new annotationReference(projectId, annotationId);
    
    // Upload and finalize the thumbnail
    await UploadAndFinalizeThumbnail(annotationReference, imageData);
    
    // Read the annotation to verify the thumbnail is present
    var annotationResult = await annotationManagement.ReadAnnotationAsync(
        annotationReference,
        cancellationToken);
    
    if (annotationResult.Annotation.HasThumbnail)
    {
        Debug.Log("Thumbnail is now available on the annotation");
    
        // You can now get the download URL to display the thumbnail
        var downloadResult = await annotationManagement.ReadThumbnailDownloadUrlAsync(
            annotationReference,
            cancellationToken);
    
        Debug.Log($"Thumbnail download URL: {downloadResult.Url}");
    }
    else
    {
        Debug.LogWarning("Thumbnail finalization may not have completed yet");
    }
    

    Handle finalization failures

    To handle cases where finalization might fail:

    public async Task FinalizeThumbnailWithRetry(
        ProjectId projectId,
        AnnotationId annotationId,
        int maxRetries = 3)
    {
        int retryCount = 0;
    
        var annotationReference = new annotationReference(projectId, annotationId);
        
        while (retryCount < maxRetries)
        {
            try
            {
                await annotationManagement.FinalizeThumbnailUploadAsync(
                    annotationReference,
                    cancellationToken);
    
                Debug.Log("Thumbnail finalized successfully");
                return;
            }
            catch (Exception ex)
            {
                retryCount++;
    
                if (retryCount >= maxRetries)
                {
                    Debug.LogError($"Failed to finalize after {maxRetries} attempts: {ex.Message}");
                    throw;
                }
    
                Debug.LogWarning($"Finalization attempt {retryCount} failed, retrying...");
                await Task.Delay(1000 * retryCount); // Exponential backoff
            }
        }
    }
    

    Update thumbnail (replace existing)

    To replace an existing thumbnail with a new one:

    public async Task ReplaceThumbnail(
        ProjectId projectId,
        AnnotationId annotationId,
        byte[] newImageData)
    {
        Debug.Log("Replacing existing thumbnail...");
    
        // The process is the same: get new upload URL, upload, finalize
        // The new thumbnail will replace the old one
    
        var annotationReference = new annotationReference(projectId, annotationId);
    
        // Step 1: Get new upload URL
        ReadThumbnailUploadUrlResult urlResult = await annotationManagement.ReadThumbnailUploadUrlAsync(
            annotationReference,
            cancellationToken);
    
        // Step 2: Upload new image
        using (var httpClient = new HttpClient())
        {
            var content = new ByteArrayContent(newImageData);
            content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
    
            await httpClient.PutAsync(urlResult.Url, content);
        }
    
        // Step 3: Finalize - this replaces the old thumbnail
        await annotationManagement.FinalizeThumbnailUploadAsync(
            annotationReference,
            cancellationToken);
    
        Debug.Log("Thumbnail replaced successfully");
    }
    

    Understanding finalization

    The finalization step is crucial in the thumbnail upload workflow:

    • Registration: Finalization registers the uploaded file with the annotation system
    • Visibility: The thumbnail becomes visible only after finalization
    • Validation: The server validates that a file was uploaded to the expected location
    • Metadata Update: The annotation's HasThumbnail property is set to true
    • Atomic Operation: Finalization ensures the thumbnail is fully available or not at all

    Why finalization is required

    1. Two-Phase Upload: Separating upload and finalization allows for validation and prevents incomplete uploads
    2. Direct Storage Upload: Since uploads go directly to cloud storage (not through Unity servers), finalization notifies Unity that the upload completed
    3. Consistency: Ensures thumbnails are only shown when they're fully available
    4. Error Recovery: If upload fails, no finalization occurs, keeping the annotation state consistent

    Important notes

    1. Must Follow Upload: Always call finalize immediately after successful upload
    2. Idempotent: Calling finalize multiple times for the same upload is safe
    3. No Partial State: Without finalization, the uploaded file won't be associated with the annotation
    4. Timeout Considerations: Finalize promptly after upload; delayed finalization may fail if upload URLs expire
    5. Error Handling: Always handle finalization errors and provide user feedback

    For related operations, see documentation on getting upload URLs and downloading thumbnails.

    See the API documentation for more details on the FinalizeThumbnailUploadAsync method.

    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)