Qutora.SDK
1.0.3
dotnet add package Qutora.SDK --version 1.0.3
NuGet\Install-Package Qutora.SDK -Version 1.0.3
<PackageReference Include="Qutora.SDK" Version="1.0.3" />
<PackageVersion Include="Qutora.SDK" Version="1.0.3" />
<PackageReference Include="Qutora.SDK" />
paket add Qutora.SDK --version 1.0.3
#r "nuget: Qutora.SDK, 1.0.3"
#:package Qutora.SDK@1.0.3
#addin nuget:?package=Qutora.SDK&version=1.0.3
#tool nuget:?package=Qutora.SDK&version=1.0.3
Qutora .NET SDK
Official .NET SDK for Qutora Document Management System
This SDK provides access to core document management functionality for external application integration. For complete administrative capabilities, see Qutora Admin SDK.
🌟 About Qutora
Qutora is a document management system that provides enterprise-grade document storage, metadata management, and API-first architecture. This SDK is freely available on GitHub under the MIT license for easy integration with any .NET application.
⚠️ Important Notice
This SDK provides access to the Qutora API endpoints designed for external application integration. It covers the core document management functionality that third-party applications typically need to integrate with any Qutora instance.
For administrative operations (user management, system configuration, advanced settings), please use the Qutora Admin SDK which provides comprehensive access to all administrative endpoints.
🎯 Purpose
This SDK is specifically designed for external application integration and covers the essential document management operations that third-party applications typically require:
- Document upload, download, and management
- Category browsing and organization
- Metadata operations and search
- Storage provider access
This is not a complete API wrapper - it intentionally focuses on integration scenarios rather than administrative functions.
🚀 Quick Start
Installation
Install the SDK via NuGet Package Manager:
dotnet add package Qutora.SDK
Or via Package Manager Console:
Install-Package Qutora.SDK
🚀 Performance Features
- Automatic Caching: Categories, Metadata Schemas, and Storage Providers are cached by default (15 minutes)
- Significant Performance Improvement:
- Categories: ~75x faster (cached)
- Metadata Schemas: ~67x faster (cached)
- Storage Providers: ~100x faster (cached)
- Zero Configuration: Caching works out-of-the-box with sensible defaults
- Flexible Cache Providers: Memory, Distributed (Redis/SQL Server), or disabled
- Smart Cache Invalidation: Automatic cache clearing on Create/Update/Delete operations
- Documents Not Cached: Documents are too large/dynamic for caching
Basic Usage
using Qutora.SDK;
using Qutora.SDK.Models;
using Qutora.SDK.Extensions; // For DI registration
// Initialize the client
var client = new QutoraClient(
baseUrl: "https://your-qutora-instance.com/api",
apiKey: "your-api-key",
apiSecret: "your-api-secret"
);
// Test connection
var isConnected = await client.TestConnectionAsync();
if (!isConnected)
{
throw new Exception("Failed to connect to Qutora API");
}
// Get documents (Categories, Metadata, Storage are automatically cached)
var documents = await client.Documents.GetDocumentsAsync(page: 1, size: 10);
Console.WriteLine($"Found {documents.TotalCount} documents");
// Upload a document
var fileBytes = File.ReadAllBytes("document.pdf");
var createRequest = new CreateDocumentRequest
{
Name = "My Important Document",
CategoryId = "category-guid",
BucketId = "bucket-guid"
};
var newDocument = await client.Documents.CreateDocumentAsync(
fileName: "document.pdf",
fileContent: fileBytes,
request: createRequest
);
// Download a document
var documentContent = await client.Documents.DownloadDocumentAsync(newDocument.Id);
File.WriteAllBytes("downloaded-document.pdf", documentContent);
// Work with metadata
var metadata = await client.Metadata.CreateDocumentMetadataAsync(
newDocument.Id,
new CreateMetadataRequest
{
Values = new Dictionary<string, object>
{
["title"] = "Important Document",
["department"] = "Finance",
["created_date"] = DateTime.UtcNow
},
Tags = new List<string> { "important", "finance", "2024" }
}
);
📚 API Reference
Document Operations
// Get paginated documents
var documents = await client.Documents.GetDocumentsAsync(page: 1, size: 20);
// Get specific document with metadata
var document = await client.Documents.GetByIdAsync("document-id", includeMetadata: true);
// Upload document with full options
var createRequest = new CreateDocumentRequest
{
Name = "Contract Document",
CategoryId = "legal-category-id",
BucketId = "secure-bucket-id",
MetadataJson = JsonSerializer.Serialize(new { department = "Legal" }),
CreateShare = true,
ExpiresAfterDays = 30,
AllowDownload = true,
AllowPrint = false
};
var document = await client.Documents.CreateDocumentAsync(
"contract.pdf",
fileBytes,
createRequest
);
// Update document
var updateRequest = new UpdateDocumentRequest
{
Name = "Updated Document Name",
CategoryId = "new-category-id",
BucketId = "new-bucket-id"
};
var updated = await client.Documents.UpdateDocumentAsync("document-id", updateRequest);
// Download document
var content = await client.Documents.DownloadDocumentAsync("document-id");
// or as stream
var stream = await client.Documents.DownloadDocumentStreamAsync("document-id");
// Get documents by category
var categoryDocs = await client.Documents.GetDocumentsByCategoryAsync("category-id");
// Manage document versions
var versions = await client.Documents.GetDocumentVersionsAsync("document-id");
var newVersion = await client.Documents.CreateVersionAsync(
"document-id",
newFileBytes,
"contract_v2.pdf",
"Updated terms and conditions"
);
Category Operations
// Get all categories (simple list) - Cached automatically
var categories = await client.Categories.GetAllCategoriesAsync();
// Get categories with pagination and search - Cached automatically
var pagedCategories = await client.Categories.GetCategoriesPagedAsync(
page: 1,
pageSize: 20,
searchTerm: "legal"
);
// Get root categories (no parent)
var rootCategories = await client.Categories.GetRootCategoriesAsync();
// Get subcategories
var subcategories = await client.Categories.GetSubcategoriesAsync("parent-category-id");
// Get specific category
var category = await client.Categories.GetCategoryByIdAsync("category-id");
// Create new category
var newCategory = await client.Categories.CreateCategoryAsync(
"Legal Documents",
"Category for legal and compliance documents"
);
Metadata Operations
// Get document metadata
var metadata = await client.Metadata.GetDocumentMetadataAsync("document-id");
// Create metadata with schema validation
var createRequest = new CreateMetadataRequest
{
SchemaName = "document-schema",
Values = new Dictionary<string, object>
{
["title"] = "Project Proposal",
["author"] = "John Doe",
["created_date"] = DateTime.UtcNow,
["priority"] = "high"
},
Tags = new List<string> { "proposal", "project", "2024" }
};
var metadata = await client.Metadata.CreateDocumentMetadataAsync("document-id", createRequest);
// Update metadata
var updateRequest = new UpdateMetadataRequest
{
Values = new Dictionary<string, object> { ["status"] = "approved" },
Tags = new List<string> { "approved", "final" }
};
var updated = await client.Metadata.UpdateDocumentMetadataAsync("document-id", updateRequest);
// Search metadata with pagination
var searchResults = await client.Metadata.SearchMetadataPagedAsync(
query: "department:legal AND status:active",
page: 1,
pageSize: 10
);
// Get all available tags
var tags = await client.Metadata.GetTagsAsync();
// Get metadata schemas - Cached automatically
var schemas = await client.Metadata.GetSchemasAsync(page: 1, pageSize: 50);
var specificSchema = await client.Metadata.GetSchemaByIdAsync("schema-id");
// Validate metadata against schema
var validateRequest = new ValidateMetadataRequest
{
SchemaName = "document-schema",
Values = new Dictionary<string, object> { ["title"] = "Test Document" }
};
var validation = await client.Metadata.ValidateMetadataAsync(validateRequest);
Storage Operations
// Get accessible buckets with pagination - Cached automatically
var buckets = await client.Storage.GetAccessibleBucketsAsync(page: 1, pageSize: 20);
// Get accessible storage providers - Cached automatically
var providers = await client.Storage.GetAccessibleProvidersAsync();
⚙️ Configuration
Using Configuration Options
var options = new QutoraClientOptions
{
BaseUrl = "https://your-qutora-instance.com/api",
ApiKey = "your-api-key",
ApiSecret = "your-api-secret",
TimeoutSeconds = 60,
MaxRetryAttempts = 3,
UserAgent = "MyApp/1.0.0",
DefaultHeaders = new Dictionary<string, string>
{
["X-Custom-Header"] = "CustomValue"
},
Cache = new QutoraCacheConfiguration
{
Enabled = true,
ProviderType = CacheProviderType.Memory,
DefaultDuration = TimeSpan.FromMinutes(15)
}
};
var client = new QutoraClient(options);
Using Dependency Injection (Recommended)
// In Program.cs - Simple setup with automatic caching
services.AddQutoraSDK(
baseUrl: configuration["Qutora:BaseUrl"]!,
apiKey: configuration["Qutora:ApiKey"]!,
apiSecret: configuration["Qutora:ApiSecret"]!
);
// Custom cache configuration
services.AddQutoraSDK(
baseUrl: configuration["Qutora:BaseUrl"]!,
apiKey: configuration["Qutora:ApiKey"]!,
apiSecret: configuration["Qutora:ApiSecret"]!,
enableCache: true,
cacheMinutes: 30
);
// Distributed cache (Redis/SQL Server/etc.)
services.AddStackExchangeRedisCache(options =>
options.Configuration = configuration.GetConnectionString("Redis"));
services.AddQutoraSDK(
baseUrl: configuration["Qutora:BaseUrl"]!,
apiKey: configuration["Qutora:ApiKey"]!,
apiSecret: configuration["Qutora:ApiSecret"]!,
useDistributedCache: true,
cacheMinutes: 60
);
// Manual registration (advanced)
services.AddHttpClient<QutoraClient>();
services.AddSingleton(provider => new QutoraClientOptions
{
BaseUrl = configuration["Qutora:BaseUrl"],
ApiKey = configuration["Qutora:ApiKey"],
ApiSecret = configuration["Qutora:ApiSecret"]
});
services.AddScoped<QutoraClient>();
Configuration from appsettings.json
{
"Qutora": {
"BaseUrl": "https://your-qutora-instance.com/api",
"ApiKey": "your-api-key",
"ApiSecret": "your-api-secret",
"TimeoutSeconds": 30,
"MaxRetryAttempts": 3
},
"ConnectionStrings": {
"Redis": "localhost:6379"
}
}
🔐 Authentication
The SDK uses API Key authentication with two headers:
X-QUTORA-Key
: Your API keyX-QUTORA-Secret
: Your API secret
Generate API credentials through the Qutora API or admin interface. Ensure your API key has appropriate permissions for the operations you need to perform.
🚨 Error Handling
try
{
var document = await client.Documents.GetByIdAsync("invalid-id");
}
catch (HttpRequestException ex) when (ex.Message.Contains("404"))
{
Console.WriteLine("Document not found");
}
catch (HttpRequestException ex) when (ex.Message.Contains("401"))
{
Console.WriteLine("Authentication failed - check your API credentials");
}
catch (HttpRequestException ex) when (ex.Message.Contains("403"))
{
Console.WriteLine("Access forbidden - insufficient permissions");
}
catch (HttpRequestException ex) when (ex.Message.Contains("500"))
{
Console.WriteLine("Server error - please try again later");
}
catch (TaskCanceledException ex)
{
Console.WriteLine("Request timeout - check your network connection");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}
📝 Logging
The SDK supports Microsoft.Extensions.Logging:
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder =>
builder.AddConsole().SetMinimumLevel(LogLevel.Debug)
);
var logger = loggerFactory.CreateLogger<QutoraClient>();
var client = new QutoraClient(options, httpClient: null, logger: logger);
🔧 Advanced Usage
Custom HttpClient Configuration
var handler = new HttpClientHandler()
{
UseCookies = false
};
var httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Add("X-Custom-Header", "Value");
var client = new QutoraClient(options, httpClient);
Connection Testing
var isConnected = await client.TestConnectionAsync();
if (!isConnected)
{
Console.WriteLine("Failed to connect to Qutora API - check your configuration");
}
Retry Logic and Resilience
The SDK includes built-in retry logic for transient failures:
var options = new QutoraClientOptions
{
BaseUrl = "https://your-qutora-instance.com/api",
ApiKey = "your-api-key",
ApiSecret = "your-api-secret",
MaxRetryAttempts = 5, // Retry up to 5 times
TimeoutSeconds = 120 // 2 minute timeout
};
📋 Supported API Endpoints
This SDK covers the following Qutora API endpoints:
Documents (8 endpoints)
GET /api/documents
- List documents with filtering and paginationPOST /api/documents
- Upload new document with full optionsGET /api/documents/{id}
- Get document detailsPUT /api/documents/{id}
- Update document metadataGET /api/documents/{id}/download
- Download document contentGET /api/documents/category/{categoryId}
- Get documents by categoryPOST /api/documents/{id}/versions
- Create new document versionGET /api/documents/{id}/versions
- Get document version history
Categories (4 endpoints)
GET /api/categories
- List categories with paginationGET /api/categories/all
- Get all categories (simple list)POST /api/categories
- Create new categoryGET /api/categories/{id}
- Get category details
Metadata (8 endpoints)
GET /api/metadata/document/{documentId}
- Get document metadataPOST /api/metadata/document/{documentId}
- Create document metadataPUT /api/metadata/document/{documentId}
- Update document metadataGET /api/metadata/search
- Search documents by metadataGET /api/metadata/tags
- Get all available tagsPOST /api/metadata/validate
- Validate metadata against schemaGET /api/metadata/schemas
- Get metadata schemasGET /api/metadata/schemas/{id}
- Get specific metadata schema
Storage (2 endpoints)
GET /api/storage/buckets/my-accessible-buckets
- Get accessible storage bucketsGET /api/storage/providers/user-accessible
- Get accessible storage providers
Total: 22 API endpoints supported
🏗️ Architecture
The SDK follows clean architecture principles:
Qutora.SDK/
├── Interfaces/ # Service contracts
├── Services/ # API service implementations
├── Models/ # Data transfer objects
├── Constants/ # API endpoint definitions
├── QutoraClient.cs # Main client facade
└── QutoraClientOptions.cs # Configuration options
🤝 Contributing
This SDK is open-source and we welcome contributions!
Development Setup
- Clone the SDK repository:
git clone https://github.com/qutora/qutora-sdk-dotnet.git
cd qutora-sdk-dotnet
- Build the project:
dotnet build
- Run tests:
dotnet test
Contributing Guidelines
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
📄 License
This SDK is licensed under the MIT License - see the LICENSE file for details.
🆘 Support & Community
- Documentation: SDK Documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
🚀 Getting Started with Qutora
To use this SDK, you'll need a running Qutora API instance. The Qutora backend provides the API endpoints that this SDK connects to.
Qutora API Setup
For information about setting up the Qutora API backend, please refer to the Qutora API documentation.
🔄 Version History
- 1.0.0 - Initial release
- Complete API endpoint coverage (22 endpoints)
- Document upload/download/management
- Category operations with hierarchy support
- Metadata management with schema validation
- Storage bucket and provider access
- Built-in retry logic and error handling
- Comprehensive logging support
- Automatic caching system with 2-5x performance improvement
- Dependency injection support with simple setup
- Distributed cache support (Redis, SQL Server, etc.)
🌟 Related Projects
- Qutora API - The main document management system backend
- Qutora Admin SDK - Complete administrative SDK with all API endpoints for system management
Made with ❤️ for the .NET community. Star ⭐ the project on GitHub if you find it useful!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Caching.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Caching.Memory (>= 8.0.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
- System.Text.Json (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.0.3 | 117 | 6/28/2025 |
1.0.1-preview | 74 | 6/27/2025 |
v1.0.1-preview: Fixed metadata schema deserialization, improved error handling for expected behaviors (404 responses), enhanced JSON parsing with $values format support. 100% test success rate (43/43 tests). Complete support for 22 API endpoints including document management, categories, metadata operations, and storage access.