Skip to content

GridLab TUS Resumable Upload Protocol - Skills Guide

Skill Type: File Upload & Transfer
Technology Stack: .NET, ASP.NET Core, TUS Protocol, HTTP
Complexity Level: Intermediate
Last Updated: 2024


📋 Overview

The GridLab TUS module implements the TUS (Transloadit Upload Server) protocol, an open standard for resumable file uploads built on HTTP, enabling reliable large file transfers with automatic resume capability.

Key Capabilities

  • ✅ Resumable file uploads
  • ✅ Large file support
  • ✅ Network interruption recovery
  • ✅ Progress tracking
  • ✅ Configurable upload limits
  • ✅ File expiration management
  • ✅ CORS support

TUS Protocol Benefits

  • Reliability: Automatic resume on connection failure
  • Efficiency: Upload only missing chunks
  • Scalability: Handle large files without memory issues
  • Standardization: Open protocol with client library support

Prerequisites

  • .NET 9.0 or higher
  • ASP.NET Core application
  • NuGet package manager
  • Disk space for file storage

🚀 Quick Start

Step 1: Install NuGet Package

Install the GridLab.Abp.TUS package from NuGet:

Install-Package GridLab.Abp.TUS

Package Information:

Step 2: Add Module Dependency

Add the AbpGridLabTusModule to your ABP module's dependency list:

[DependsOn(
    //...other dependencies
    typeof(AbpGridLabTusModule)
)]
public class YourModule : AbpModule
{
}

Step 3: Configure Middleware

Configure TUS in your API host module. Important: Place UseTus after UseCors and before UseRouting and UseAuthorization:

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();

    // ... other middleware

    app.UseCors();

    // Configure TUS
    ITusConfiguration configuration = context.ServiceProvider.GetRequiredService<ITusConfiguration>();
    app.UseTus(httpContext => Task.FromResult(configuration.CreateTusConfiguration()));

    app.UseRouting();
    app.UseAuthentication();

    if (MultiTenancyConsts.IsEnabled)
    {
        app.UseMultiTenancy();
    }

    app.UseAbpRequestLocalization();
    app.UseAuthorization();

    // ... other middleware
}

Step 4: Enable TUS in Configuration

Configure TUS options in your module:

public override void ConfigureServices(ServiceConfigurationContext context)
{
    Configure<AbpTusConfigurationOptions>(options =>
    {
        options.IsEnabled = true; // TUS is disabled by default
        options.UrlPath = "/file-management/upload"; // Custom upload endpoint
        options.MaxAllowedUploadSizeInBytesLong = 5L * 1024 * 1024 * 1024; // 5 GB
    });
}

⚙️ Configuration Reference

TUS Configuration Options

Property Description Default Value Type
IsEnabled Enable/disable TUS service false bool
AbsolutePath File storage directory path {AppDirectory}/files string
UrlPath Upload endpoint URL path /file-management/upload string
Expiration Incomplete file expiration time 5 minutes TimeSpan
MetadataParsingStrategy Metadata parsing approach AllowEmptyValues enum
AllowedExtensions Allowed TUS extensions TusExtensions.All flags
MaxAllowedUploadSizeInBytes Max upload size (int) null (unlimited) int?
MaxAllowedUploadSizeInBytesLong Max upload size (long) null (unlimited) long?

Complete Configuration Example

Configure<AbpTusConfigurationOptions>(options =>
{
    // Enable TUS
    options.IsEnabled = true;

    // Custom storage path
    options.AbsolutePath = Path.Combine(
        Directory.GetCurrentDirectory(), 
        "uploads", 
        "tus"
    );

    // Custom endpoint
    options.UrlPath = "/api/uploads/resumable";

    // File expiration (incomplete uploads)
    options.Expiration = AbsoluteExpiration.Create(TimeSpan.FromHours(24));

    // Metadata parsing
    options.MetadataParsingStrategy = MetadataParsingStrategy.AllowEmptyValues;

    // Limit extensions
    options.AllowedExtensions = TusExtensions.Creation | 
                                TusExtensions.Termination | 
                                TusExtensions.Expiration;

    // Max file size: 10 GB
    options.MaxAllowedUploadSizeInBytesLong = 10L * 1024 * 1024 * 1024;
});

💡 Client Integration

JavaScript/TypeScript Client

import * as tus from 'tus-js-client';

function uploadFile(file) {
    const upload = new tus.Upload(file, {
        endpoint: 'https://your-api.com/file-management/upload',
        retryDelays: [0, 3000, 5000, 10000, 20000],
        metadata: {
            filename: file.name,
            filetype: file.type
        },
        onError: function(error) {
            console.error('Upload failed:', error);
        },
        onProgress: function(bytesUploaded, bytesTotal) {
            const percentage = (bytesUploaded / bytesTotal * 100).toFixed(2);
            console.log(`Progress: ${percentage}%`);
        },
        onSuccess: function() {
            console.log('Upload completed successfully!');
        }
    });

    upload.start();
}

C# Client

public class TusClientService
{
    private readonly HttpClient _httpClient;

    public TusClientService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> UploadFileAsync(Stream fileStream, string fileName)
    {
        var tusClient = new TusClient();
        var fileUrl = await tusClient.CreateAsync(
            "https://your-api.com/file-management/upload",
            fileStream,
            metadata: new Dictionary<string, string>
            {
                { "filename", fileName }
            }
        );

        await tusClient.UploadAsync(fileUrl, fileStream);

        return fileUrl;
    }
}

🔧 Advanced Scenarios

Post-Upload Processing

public class TusUploadHandler : ITransientDependency
{
    private readonly ILogger<TusUploadHandler> _logger;

    public TusUploadHandler(ILogger<TusUploadHandler> logger)
    {
        _logger = logger;
    }

    public async Task OnUploadCompleteAsync(string fileId, string filePath)
    {
        _logger.LogInformation(
            "Upload complete for file {FileId} at {FilePath}", 
            fileId, 
            filePath
        );

        // Move file to permanent storage
        var permanentPath = GetPermanentStoragePath(fileId);
        File.Move(filePath, permanentPath);

        // Process file (virus scan, thumbnail generation, etc.)
        await ProcessFileAsync(permanentPath);
    }
}

Custom File Validation

Configure<AbpTusConfigurationOptions>(options =>
{
    options.IsEnabled = true;

    // Add custom validation
    options.OnAuthorizeAsync = async context =>
    {
        // Check user permissions
        var authService = context.HttpContext.RequestServices
            .GetRequiredService<IAuthorizationService>();

        var result = await authService.AuthorizeAsync(
            context.HttpContext.User,
            "FileUpload.Create"
        );

        return result.Succeeded;
    };
});

📚 Best Practices

✅ Do's

  • Enable TUS for files larger than 100 MB
  • Set appropriate file size limits
  • Implement file expiration for incomplete uploads
  • Use virus scanning on completed uploads
  • Monitor disk space usage
  • Implement proper error handling
  • Use HTTPS for security

❌ Don'ts

  • Don't use TUS for small files (< 10 MB)
  • Don't store sensitive files without encryption
  • Don't ignore file expiration settings
  • Don't allow unlimited file sizes
  • Don't skip authentication/authorization
  • Don't forget to clean up incomplete uploads

🔍 Troubleshooting

Common Issues

Issue: Upload fails immediately

  • Solution: Verify IsEnabled = true in configuration
  • Solution: Check CORS settings allow TUS headers
  • Solution: Ensure storage directory exists and is writable

Issue: Upload doesn't resume after interruption

  • Solution: Verify client supports TUS protocol
  • Solution: Check that file ID is being preserved
  • Solution: Ensure file hasn't expired

Issue: 413 Payload Too Large error

  • Solution: Increase MaxAllowedUploadSizeInBytesLong
  • Solution: Check web server (IIS/Kestrel) upload limits
  • Solution: Verify reverse proxy settings

📖 Additional Resources