This guide covers everything you need to install and configure WitDatabase in your .NET projects.
Prerequisites
System Requirements
Supported .NET Versions:
| Version | Support | Notes |
|---|---|---|
| .NET 10.0 | ✅ Full | Recommended |
| .NET 9.0 | ✅ Full | Fully supported |
| .NET 8.0 | ⚠️ Not tested | May work, not officially supported |
| .NET Framework | ❌ Not supported | Use .NET 9+ |
Supported Platforms:
| Platform | Support | Notes |
|---|---|---|
| Windows (x64, x86, ARM64) | ✅ Full | All features |
| Linux (x64, ARM64) | ✅ Full | All features |
| macOS (x64, Apple Silicon) | ✅ Full | All features |
| Blazor WebAssembly | ✅ Full | Requires IndexedDb package |
| iOS / Android (MAUI) | ✅ Full | File storage |
Development Tools:
- Visual Studio 2022 (17.8+) — recommended
- Visual Studio Code with C# Dev Kit
- JetBrains Rider 2024.1+
- .NET CLI
Choosing the Right Package
WitDatabase is distributed as several NuGet packages. Choose based on your needs:
| Package | Use Case | Includes |
|---|---|---|
OutWit.Database.EntityFramework |
EF Core with LINQ, migrations, DbContext | AdoNet, Core |
OutWit.Database.AdoNet |
SQL queries with ADO.NET patterns | Core |
OutWit.Database.Core |
Direct key-value API, maximum control | — |
OutWit.Database.Core.IndexedDb |
Blazor WebAssembly browser storage | Core |
OutWit.Database.Core.BouncyCastle |
ChaCha20-Poly1305 encryption | Core |
Decision Guide:
Installation Methods
.NET CLI
The simplest way to add WitDatabase to your project:
# For Entity Framework Core (most common)
dotnet add package OutWit.Database.EntityFramework
# For ADO.NET only
dotnet add package OutWit.Database.AdoNet
# For Core API only
dotnet add package OutWit.Database.CoreAdditional packages:
# Blazor WebAssembly support
dotnet add package OutWit.Database.Core.IndexedDb
# ChaCha20 encryption (for WASM or ARM without AES-NI)
dotnet add package OutWit.Database.Core.BouncyCastleNuGet Package Manager (Visual Studio)
- Right-click your project in Solution Explorer
- Select Manage NuGet Packages...
- Search for
OutWit.Database.EntityFramework - Click Install
Or use the Package Manager Console:
Install-Package OutWit.Database.EntityFrameworkPackageReference (Manual)
Add directly to your .csproj file:
<ItemGroup>
<PackageReference Include="OutWit.Database.EntityFramework" Version="1.0.0" />
</ItemGroup>For multiple packages:
<ItemGroup>
<!-- EF Core support -->
<PackageReference Include="OutWit.Database.EntityFramework" Version="1.0.0" />
<!-- Blazor WASM support -->
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="1.0.0" />
<!-- ChaCha20 encryption -->
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="1.0.0" />
</ItemGroup>Package Dependencies
Packages automatically include their dependencies:
OutWit.Database.EntityFramework
└── OutWit.Database.AdoNet
└── OutWit.Database.Core
OutWit.Database.Core.IndexedDb
└── OutWit.Database.Core
OutWit.Database.Core.BouncyCastle
└── OutWit.Database.CoreTip: Install only the highest-level package you need. Dependencies are included automatically.
Platform-Specific Setup
Console Application
1. Create a new project:
dotnet new console -n MyApp
cd MyApp
dotnet add package OutWit.Database.AdoNet2. Minimal example (Program.cs):
using OutWit.Database.AdoNet;
// Create and open connection
using var connection = new WitDbConnection("Data Source=myapp.witdb");
connection.Open();
// Create a table
using var cmd = connection.CreateCommand();
cmd.CommandText = """
CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(100) NOT NULL,
Email VARCHAR(255) UNIQUE
)
""";
cmd.ExecuteNonQuery();
// Insert data
cmd.CommandText = "INSERT INTO Users (Name, Email) VALUES (@name, @email)";
cmd.Parameters.Add(new WitDbParameter("@name", "John Doe"));
cmd.Parameters.Add(new WitDbParameter("@email", "john@example.com"));
cmd.ExecuteNonQuery();
Console.WriteLine("Database created and data inserted!");
// Query data
cmd.Parameters.Clear();
cmd.CommandText = "SELECT * FROM Users";
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine($"User: {reader["Id"]} - {reader["Name"]} ({reader["Email"]})");
}3. Run:
dotnet runASP.NET Core Web API
1. Create a new project:
dotnet new webapi -n MyWebApi
cd MyWebApi
dotnet add package OutWit.Database.EntityFramework2. Create a DbContext (Data/AppDbContext.cs):
using Microsoft.EntityFrameworkCore;
namespace MyWebApi.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
public DbSet<User> Users => Set<User>();
public DbSet<Product> Products => Set<Product>();
}
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}3. Configure in Program.cs:
using Microsoft.EntityFrameworkCore;
using MyWebApi.Data;
using OutWit.Database.EntityFramework;
var builder = WebApplication.CreateBuilder(args);
// Add WitDatabase with EF Core
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseWitDb("Data Source=mywebapi.witdb"));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Ensure database is created
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Database.EnsureCreated();
}
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();4. Create a controller (Controllers/UsersController.cs):
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyWebApi.Data;
namespace MyWebApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly AppDbContext _context;
public UsersController(AppDbContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
[HttpPost]
public async Task<ActionResult<User>> CreateUser(User user)
{
_context.Users.Add(user);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetUsers), new { id = user.Id }, user);
}
}WPF / WinForms / MAUI Desktop
1. Add package:
dotnet add package OutWit.Database.EntityFramework2. Choose database location:
// Option 1: Application data folder (recommended for user data)
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var dbPath = Path.Combine(appDataPath, "MyApp", "data.witdb");
Directory.CreateDirectory(Path.GetDirectoryName(dbPath)!);
// Option 2: Application directory (for portable apps)
var dbPath = Path.Combine(AppContext.BaseDirectory, "data.witdb");
// Option 3: User's documents
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var dbPath = Path.Combine(documentsPath, "MyApp", "data.witdb");3. Configure DbContext:
public class AppDbContext : DbContext
{
private readonly string _dbPath;
public AppDbContext(string dbPath)
{
_dbPath = dbPath;
}
public DbSet<Document> Documents => Set<Document>();
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseWitDb($"Data Source={_dbPath}");
}
}4. With encryption (for sensitive user data):
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseWitDb($"Data Source={_dbPath};Encryption=aes-gcm;Password={_userPassword}");
}Blazor WebAssembly
1. Add packages:
dotnet add package OutWit.Database.Core.IndexedDb
dotnet add package OutWit.Database.Core.BouncyCastle # Optional: for encryption2. Add JavaScript files to wwwroot/index.html:
<!DOCTYPE html>
<html>
<head>
<!-- ... existing head content ... -->
</head>
<body>
<div id="app">Loading...</div>
<!-- Add before the blazor script -->
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb.js"></script>
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb-index.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>3. Create a database service:
using Microsoft.JSInterop;
using OutWit.Database.Core.Builder;
using OutWit.Database.Core.IndexedDb;
public class DatabaseService : IAsyncDisposable
{
private readonly IJSRuntime _jsRuntime;
private WitDatabase? _database;
public DatabaseService(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public async Task InitializeAsync()
{
_database = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyBlazorApp", _jsRuntime)
.WithBTree()
.WithTransactions()
.Build();
// Initialize IndexedDB storage
if (_database.Store is StorageIndexedDb indexedDbStorage)
{
await indexedDbStorage.InitializeAsync();
}
}
public WitDatabase Database => _database
?? throw new InvalidOperationException("Database not initialized. Call InitializeAsync first.");
public async ValueTask DisposeAsync()
{
if (_database != null)
{
await _database.DisposeAsync();
}
}
}4. Register in Program.cs:
builder.Services.AddScoped<DatabaseService>();5. Use in a component:
@page "/data"
@inject DatabaseService DbService
@implements IAsyncDisposable
<h3>Data Manager</h3>
@if (_initialized)
{
<button @onclick="SaveData">Save</button>
<button @onclick="LoadData">Load</button>
<p>@_message</p>
}
else
{
<p>Initializing database...</p>
}
@code {
private bool _initialized;
private string _message = "";
protected override async Task OnInitializedAsync()
{
await DbService.InitializeAsync();
_initialized = true;
}
private async Task SaveData()
{
var key = System.Text.Encoding.UTF8.GetBytes("test-key");
var value = System.Text.Encoding.UTF8.GetBytes($"Saved at {DateTime.Now}");
await DbService.Database.PutAsync(key, value);
_message = "Data saved!";
}
private async Task LoadData()
{
var key = System.Text.Encoding.UTF8.GetBytes("test-key");
var value = await DbService.Database.GetAsync(key);
_message = value != null
? System.Text.Encoding.UTF8.GetString(value)
: "No data found";
}
public async ValueTask DisposeAsync()
{
await DbService.DisposeAsync();
}
}With encryption in browser:
// Use ChaCha20 for better WASM performance (no AES-NI in browser)
_database = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyBlazorApp", _jsRuntime)
.WithBTree()
.WithBouncyCastleEncryption("user-password") // ChaCha20-Poly1305
.WithTransactions()
.Build();Configuration
Connection String Format
WitDatabase uses a connection string format similar to other ADO.NET providers:
Data Source=path/to/database.witdb;Encryption=aes-gcm;Password=secret;Store=btreeFull Parameter Reference:
| Parameter | Type | Default | Description |
|---|---|---|---|
| Core | |||
Data Source |
string | — | Path to database file, or :memory: for in-memory |
Mode |
enum | ReadWriteCreate | ReadOnly, ReadWrite, ReadWriteCreate |
| Storage Engine | |||
Store |
enum | BTree | BTree, LSM |
| Encryption | |||
Encryption |
enum | None | None, AesGcm, ChaCha20 |
Password |
string | — | Encryption password |
User |
string | — | Username for salt derivation |
Fast Encryption |
bool | false | Use faster PBKDF2 iterations (for WASM) |
| Transactions | |||
Transactions |
bool | true | Enable ACID transactions |
MVCC |
bool | true | Enable Multi-Version Concurrency Control |
Isolation Level |
enum | ReadCommitted | Default isolation level |
| Concurrency | |||
Parallel Mode |
enum | None | None, Auto, Latched, Buffered |
Max Writers |
int | CPU count | Max parallel writers (for Buffered mode) |
| Performance | |||
Cache Size |
int | 1000 | Number of pages in cache |
Page Size |
int | 4096 | Page size in bytes |
| Connection Pool | |||
Pooling |
bool | true | Enable connection pooling |
Min Pool Size |
int | 0 | Minimum connections in pool |
Max Pool Size |
int | 100 | Maximum connections in pool |
Example connection strings:
// Simple file database
"Data Source=app.witdb"
// In-memory database
"Data Source=:memory:"
// With encryption
"Data Source=secure.witdb;Encryption=aes-gcm;Password=MySecretPassword123!"
// With all options
"Data Source=app.witdb;Store=btree;Encryption=aes-gcm;Password=secret;MVCC=true;Isolation Level=Snapshot;Cache Size=2000"
// For multi-threaded access
"Data Source=app.witdb;Parallel Mode=Auto"
// Read-only mode
"Data Source=app.witdb;Mode=ReadOnly"Using WitDbConnectionStringBuilder
For programmatic connection string construction:
using OutWit.Database.AdoNet;
var builder = new WitDbConnectionStringBuilder
{
DataSource = "myapp.witdb",
Encryption = WitDbEncryptionType.AesGcm,
Password = "MySecretPassword",
Mvcc = true,
IsolationLevel = WitDbIsolationLevel.Snapshot,
CacheSize = 2000
};
using var connection = new WitDbConnection(builder.ConnectionString);Builder Pattern (Core API)
For direct Core API usage, the builder pattern provides full control:
using OutWit.Database.Core.Builder;
var db = new WitDatabaseBuilder()
// Storage location
.WithFilePath("data.witdb") // File storage
// .WithMemoryStorage() // In-memory (testing)
// Storage engine
.WithBTree() // Read-optimized (default)
// .WithLsmTree() // Write-optimized
// Encryption
.WithEncryption("password") // AES-256-GCM
// .WithBouncyCastleEncryption("pw") // ChaCha20-Poly1305
// Transactions
.WithTransactions() // Enable ACID
.WithMvcc() // Enable MVCC
.WithDefaultIsolationLevel(IsolationLevel.Snapshot)
// Concurrency
.WithFileLocking() // File-level locking
.WithParallelMode(ParallelMode.Auto) // Thread-safe mode
// Performance
.WithCacheSize(2000) // Pages in cache
.WithPageSize(4096) // Bytes per page
.Build();Builder Methods Reference:
| Category | Method | Description |
|---|---|---|
| Storage | WithFilePath(path) |
Use file storage |
WithMemoryStorage() |
Use in-memory storage | |
WithIndexedDbStorage(name, js) |
Use browser IndexedDB | |
| Engine | WithBTree() |
B+Tree engine (read-optimized) |
WithLsmTree() |
LSM-Tree engine (write-optimized) | |
WithLsmTree(dir, opts) |
LSM-Tree with options | |
| Encryption | WithEncryption(password) |
AES-256-GCM |
WithEncryption(user, password) |
AES-GCM with user salt | |
WithEncryptionFast(password) |
AES-GCM optimized for WASM | |
WithBouncyCastleEncryption(pw) |
ChaCha20-Poly1305 | |
WithAesEncryption(key) |
AES-GCM with raw 256-bit key | |
| Transactions | WithTransactions() |
Enable transactions |
WithoutTransactions() |
Disable (for performance) | |
WithMvcc() |
Enable MVCC | |
WithDefaultIsolationLevel(level) |
Set default isolation | |
| Concurrency | WithFileLocking() |
Enable file locking |
WithoutFileLocking() |
Disable file locking | |
WithParallelMode(mode) |
Set parallel access mode | |
WithLockTimeout(timeout) |
Set lock timeout | |
| Performance | WithCacheSize(pages) |
Set cache size |
WithPageSize(bytes) |
Set page size |
Entity Framework Core Configuration
Basic configuration:
services.AddDbContext<AppDbContext>(options =>
options.UseWitDb("Data Source=app.witdb"));With connection string from configuration:
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=app.witdb;Encryption=aes-gcm;Password=secret"
}
}
// Program.cs
services.AddDbContext<AppDbContext>(options =>
options.UseWitDb(Configuration.GetConnectionString("DefaultConnection")));With additional options:
services.AddDbContext<AppDbContext>(options =>
options.UseWitDb("Data Source=app.witdb", witOptions =>
{
witOptions.UseParallelWrites(WitDbParallelMode.Auto);
witOptions.MaxWriters(8);
}));Factory pattern for multiple databases:
services.AddDbContextFactory<AppDbContext>(options =>
options.UseWitDb("Data Source=app.witdb"));
// Usage
public class MyService
{
private readonly IDbContextFactory<AppDbContext> _factory;
public MyService(IDbContextFactory<AppDbContext> factory)
{
_factory = factory;
}
public async Task DoWorkAsync()
{
await using var context = await _factory.CreateDbContextAsync();
// Use context...
}
}Verifying Installation
Quick Test (ADO.NET)
Create a simple test to verify everything works:
using OutWit.Database.AdoNet;
try
{
// Test in-memory database
using var connection = new WitDbConnection("Data Source=:memory:");
connection.Open();
Console.WriteLine($"✓ Connection opened successfully");
Console.WriteLine($" Server Version: {connection.ServerVersion}");
Console.WriteLine($" State: {connection.State}");
// Test query execution
using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT 1 + 1 AS Result";
var result = cmd.ExecuteScalar();
Console.WriteLine($"✓ Query executed: 1 + 1 = {result}");
Console.WriteLine();
Console.WriteLine("WitDatabase is installed and working correctly!");
}
catch (Exception ex)
{
Console.WriteLine($"✗ Error: {ex.Message}");
}Quick Test (Entity Framework Core)
using Microsoft.EntityFrameworkCore;
using OutWit.Database.EntityFramework;
// Simple test context
public class TestDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseWitDb("Data Source=:memory:");
public DbSet<TestEntity> TestEntities => Set<TestEntity>();
}
public class TestEntity
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
// Test
try
{
using var context = new TestDbContext();
context.Database.EnsureCreated();
Console.WriteLine("✓ Database created successfully");
// Test insert
context.TestEntities.Add(new TestEntity { Name = "Test" });
context.SaveChanges();
Console.WriteLine("✓ Entity inserted successfully");
// Test query
var entity = context.TestEntities.First();
Console.WriteLine($"✓ Entity retrieved: Id={entity.Id}, Name={entity.Name}");
Console.WriteLine();
Console.WriteLine("Entity Framework Core provider is working correctly!");
}
catch (Exception ex)
{
Console.WriteLine($"✗ Error: {ex.Message}");
}Common Installation Issues
1. Package not found
error NU1101: Unable to find package OutWit.Database.EntityFrameworkSolution: Ensure you have the correct NuGet source configured:
dotnet nuget list source
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org2. Version conflicts
error NU1107: Version conflict detected for OutWit.Database.CoreSolution: Ensure all WitDatabase packages are the same version:
<ItemGroup>
<PackageReference Include="OutWit.Database.EntityFramework" Version="1.0.0" />
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="1.0.0" />
</ItemGroup>3. Blazor WASM: JavaScript files not found
Error: Could not find 'witdb-indexeddb.js'Solution: Verify the script tags in index.html:
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb.js"></script>
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb-index.js"></script>4. File access denied
System.UnauthorizedAccessException: Access to the path 'data.witdb' is denied.Solution: Check file permissions or use a different location:
// Use AppData folder instead
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"MyApp",
"data.witdb");
Directory.CreateDirectory(Path.GetDirectoryName(path)!);5. Database locked
WitDbException: Database file is locked by another processSolution: Ensure only one process accesses the database, or use parallel mode:
// For multi-process scenarios
"Data Source=app.witdb;Parallel Mode=Auto"Upgrading
From Previous Versions
When upgrading WitDatabase packages:
1. Update all packages together:
dotnet add package OutWit.Database.EntityFramework --version 1.1.0
dotnet add package OutWit.Database.Core.IndexedDb --version 1.1.02. Check for breaking changes in the release notes.
3. Test your application thoroughly before deploying.
Database File Compatibility
WitDatabase maintains backward compatibility for database files:
- Files created with v1.0 can be opened with v1.x
- Major version upgrades may require migration (documented in release notes)
Uninstalling
Removing Packages
dotnet remove package OutWit.Database.EntityFramework
dotnet remove package OutWit.Database.AdoNet
dotnet remove package OutWit.Database.Core
dotnet remove package OutWit.Database.Core.IndexedDb
dotnet remove package OutWit.Database.Core.BouncyCastleCleaning Up
1. Remove database files:
// Find and delete database files
File.Delete("app.witdb");
File.Delete("app.witdb-journal"); // If using rollback journal
Directory.Delete("app.witdb-wal", true); // If using WAL2. Remove Blazor WASM scripts from index.html if applicable.
3. Remove any configuration from appsettings.json.