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:
[[Svg Src="./witdatabase-package-decision-tree.svg" Alt=".NET Embedded Databases"]]
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.Core
Additional 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.BouncyCastle
NuGet 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.EntityFramework
PackageReference (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.Core
Tip: 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.AdoNet
2. 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(
Loading...
quot;User: {reader["Id"]} - {reader["Name"]} ({reader["Email"]})");
}
3. Run:
dotnet run
ASP.NET Core Web API
1. Create a new project:
dotnet new webapi -n MyWebApi
cd MyWebApi
dotnet add package OutWit.Database.EntityFramework
2. 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.EntityFramework
2. 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(
Loading...
quot;Data Source={_dbPath}");
}
}
4. With encryption (for sensitive user data):
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseWitDb(
Loading...
quot;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 encryption
2. 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(
Loading...
quot;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=btree
Full 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(
Loading...
quot;✓ Connection opened successfully");
Console.WriteLine(
Loading...
quot; Server Version: {connection.ServerVersion}");
Console.WriteLine(
Loading...
quot; State: {connection.State}");
// Test query execution
using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT 1 + 1 AS Result";
var result = cmd.ExecuteScalar();
Console.WriteLine(
Loading...
quot;✓ Query executed: 1 + 1 = {result}");
Console.WriteLine();
Console.WriteLine("WitDatabase is installed and working correctly!");
}
catch (Exception ex)
{
Console.WriteLine(
Loading...
quot;✗ 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(
Loading...
quot;✓ Entity retrieved: Id={entity.Id}, Name={entity.Name}");
Console.WriteLine();
Console.WriteLine("Entity Framework Core provider is working correctly!");
}
catch (Exception ex)
{
Console.WriteLine(
Loading...
quot;✗ Error: {ex.Message}");
}
Common Installation Issues
1. Package not found
error NU1101: Unable to find package OutWit.Database.EntityFramework
Solution: 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.org
2. Version conflicts
error NU1107: Version conflict detected for OutWit.Database.Core
Solution: 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 process
Solution: 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.0
2. 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.BouncyCastle
Cleaning 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 WAL
2. Remove Blazor WASM scripts from index.html if applicable.
3. Remove any configuration from appsettings.json.