Export files to YouTube in .Net C# using open source libraries

Exporting videos to YouTube programmatically is essential for automating video content management. Although YouTube offers an official .NET client library, leveraging direct REST API integration using open source libraries can give you greater control and flexibility. In this guide, we demonstrate how to export files to YouTube in .NET C# using the Google APIs client library, updated asynchronous authentication, and robust error handling practices.
Prerequisites
- .NET 6.0 or later
- Google Cloud Project with YouTube Data API enabled
- OAuth 2.0 credentials from Google Cloud Console (download your client_secrets.json file)
- Google.Apis.YouTube.v3 NuGet package
Setting up the YouTube API client
First, install the required NuGet package:
dotnet add package Google.Apis.YouTube.v3
Use the following asynchronous factory method to create a YouTube service instance. This approach leverages the official GoogleCredential class for OAuth 2.0 authentication:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.YouTube.v3;
using System.Threading;
using System.Threading.Tasks;
public class YouTubeUploader
{
private readonly YouTubeService _youtubeService;
private YouTubeUploader(YouTubeService youtubeService)
{
_youtubeService = youtubeService;
}
public static async Task<YouTubeUploader> CreateAsync(string credentialsPath)
{
var credential = await GoogleCredential.FromFileAsync(credentialsPath, CancellationToken.None)
.ConfigureAwait(false);
credential = credential.CreateScoped(YouTubeService.Scope.YoutubeUpload);
var youtubeService = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "YOUR_APP_NAME"
});
return new YouTubeUploader(youtubeService);
}
}
Uploading videos
The method below handles video uploads with progress tracking and comprehensive error handling:
using System;
using System.IO;
using System.Threading.Tasks;
using Google.Apis.Upload;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
public async Task<string> UploadVideoAsync(
string filePath,
string title,
string description,
string[] tags,
IProgress<IUploadProgress> progress = null)
{
var video = new Video
{
Snippet = new VideoSnippet
{
Title = title,
Description = description,
Tags = tags,
CategoryId = "22" // People & Blogs category
},
Status = new VideoStatus
{
PrivacyStatus = "private" // or "public", "unlisted"
}
};
using var fileStream = new FileStream(filePath, FileMode.Open);
var videosInsertRequest = _youtubeService.Videos.Insert(
video,
"snippet,status",
fileStream,
"video/*");
videosInsertRequest.ChunkSize = ResumableUpload.MinimumChunkSize;
if (progress != null)
{
videosInsertRequest.ProgressChanged += progress.Report;
}
try
{
var uploadResponse = await videosInsertRequest.UploadAsync();
if (uploadResponse.Status == UploadStatus.Completed)
{
return videosInsertRequest.ResponseBody.Id;
}
else
{
throw new Exception($"Upload failed with status: {uploadResponse.Status}");
}
}
catch (Google.GoogleApiException ex) when (ex.Error != null &&
(ex.Error.Code == 403 || ex.Error.Code == 429 || ex.Error.Code == 503))
{
throw new Exception("Quota exceeded, rate limit reached, or authentication error. Please check your API credentials and quota usage.", ex);
}
catch (Exception ex)
{
throw new Exception("Upload failed: " + ex.Message, ex);
}
}
Handling quotas and rate limits
YouTube Data API enforces quota limits to ensure fair usage. For example, a free account typically has a daily limit of 10,000 units, and each video upload costs approximately 1,600 units. In production, be sure to implement quota tracking and rate limiting to avoid exceeding your daily quota. If necessary, you can request a quota increase from Google Cloud.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class QuotaManager
{
private readonly SemaphoreSlim _uploadSemaphore;
private readonly Dictionary<DateTime, int> _quotaUsage;
public QuotaManager(int maxConcurrentUploads = 3)
{
_uploadSemaphore = new SemaphoreSlim(maxConcurrentUploads);
_quotaUsage = new Dictionary<DateTime, int>();
}
public async Task<T> ExecuteWithQuotaAsync<T>(
Func<Task<T>> operation,
int quotaCost)
{
await _uploadSemaphore.WaitAsync();
try
{
var today = DateTime.UtcNow.Date;
if (!_quotaUsage.ContainsKey(today))
{
_quotaUsage.Clear();
_quotaUsage[today] = 0;
}
if (_quotaUsage[today] + quotaCost > 10000)
{
throw new QuotaExceededException("Daily quota would be exceeded");
}
var result = await operation();
_quotaUsage[today] += quotaCost;
return result;
}
finally
{
_uploadSemaphore.Release();
}
}
}
Best practices for production use
- Implement retry logic with exponential backoff to handle transient errors such as network issues or temporary rate limits.
- Store your credentials securely to protect your OAuth 2.0 secrets.
- Monitor upload progress to give feedback and troubleshoot issues in real time.
- Ensure robust error handling to cover quota exceedance, authentication failures, and file size or network constraints.
Implement retry logic
using System;
using System.Net.Http;
using System.Threading.Tasks;
public async Task<T> RetryWithExponentialBackoff<T>(
Func<Task<T>> operation,
int maxAttempts = 3)
{
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
return await operation();
}
catch (Exception ex) when (IsTransientException(ex))
{
if (attempt == maxAttempts) throw;
var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt));
await Task.Delay(delay);
}
}
throw new Exception("Retry attempts exhausted");
}
private bool IsTransientException(Exception ex)
{
return ex is HttpRequestException ||
(ex is GoogleApiException gex && (gex.Error?.Code == 429 || gex.Error?.Code == 503));
}
Store credentials securely
using System;
public class SecureCredentialManager
{
private readonly IConfiguration _configuration;
public SecureCredentialManager(IConfiguration configuration)
{
_configuration = configuration;
}
public string GetCredentialsPath()
{
var path = _configuration.GetValue<string>("YouTube:CredentialsPath");
if (string.IsNullOrEmpty(path))
{
throw new InvalidOperationException("YouTube credentials path not configured");
}
return path;
}
}
Monitor upload progress
using Google.Apis.Upload;
public class UploadProgressHandler : IProgress<IUploadProgress>
{
private readonly ILogger _logger;
public UploadProgressHandler(ILogger logger)
{
_logger = logger;
}
public void Report(IUploadProgress progress)
{
var status = progress.Status switch
{
UploadStatus.Uploading => $"Uploading: {progress.BytesSent}/{progress.TotalBytes} bytes",
UploadStatus.Failed => $"Upload failed: {progress.Exception?.Message}",
UploadStatus.Completed => "Upload completed",
_ => $"Status: {progress.Status}"
};
_logger.LogInformation(status);
}
}
Conclusion
Exporting files to YouTube in .NET C# requires up-to-date authentication practices, careful quota management, and robust error handling. By integrating the Google APIs client library with asynchronous credential loading and following best practices for production deployments, you can build a resilient video upload solution. For a more streamlined approach to handling file exports and video processing at scale, consider using Transloadit's file exporting service.