WebSvc.DbProvisioner 1.0.2

dotnet add package WebSvc.DbProvisioner --version 1.0.2
                    
NuGet\Install-Package WebSvc.DbProvisioner -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WebSvc.DbProvisioner" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WebSvc.DbProvisioner" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="WebSvc.DbProvisioner" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add WebSvc.DbProvisioner --version 1.0.2
                    
#r "nuget: WebSvc.DbProvisioner, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package WebSvc.DbProvisioner@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=WebSvc.DbProvisioner&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=WebSvc.DbProvisioner&version=1.0.2
                    
Install as a Cake Tool

WebSvc.DbProvisioner

Given a database name, create a real, ready-to-use MySQL or PostgreSQL database — plus a scoped user and a working connection string — on Plesk, cPanel, or a bare/standalone server, behind one interface. The counterpart to WebSvc.SqlConnector: that talks to a database that exists; this makes one exist in the first place.

What it does — and deliberately doesn't

  • Provisions a database "inside an existing thing" — a Plesk subscription, a cPanel account, or a server an admin credential already reaches. It does not create the subscription/account itself (Plesk's webspace-id or the cPanel account must already exist).
  • Creates a scoped user with full read/write on that one database only — never a "universal" user with access to every database in the subscription/account.
  • Deprovisions the reverse — removes the database (and, where the host's own API supports it, the user) given the reference ProvisionAsync returned.
  • Does not create tables. ProvisionAsync hands back an empty database and working credentials; what schema goes inside it is entirely your own application's concern (an EF Core migration, a config-driven schema generator, plain CREATE TABLE statements — connect with the returned credentials using any normal MySQL/PostgreSQL client, or WebSvc.SqlConnector, and do exactly what you'd do for a database that already existed). One narrow escape hatch exists for this: ProvisionDatabaseRequest.InitializationScript, raw SQL run once immediately after creation, if you supply it — currently implemented for the Standalone provider only (see below).
  • Does not store anything. ProvisionAsync/DeprovisionAsync never write credentials or references anywhere on their own — where you persist the result (a database row, a secrets vault, nothing at all) is entirely your own application's decision.

Setup

builder.Services.AddDbProvisioner(builder.Configuration);
{
  "DbProvisioner": {
    "Plesk": {
      "HostOrIp": "203.0.113.10",
      "Port": 8443,
      "SecretKey": "778a476a-cf1c-7434-ea47-9f229d70e934",
      "DefaultWebspaceId": 142,
      "DefaultConnectionHostOverride": "172.17.0.1"
    },
    "CPanel": {
      "HostOrIp": "198.51.100.20",
      "Username": "acmehost",
      "ApiToken": "…"
    },
    "Standalone": {
      "MySql": { "Host": "10.0.0.5", "Port": 3306, "AdminUsername": "root", "AdminPassword": "…" }
    }
  }
}

Using it

public class DatabaseController(IDatabaseProvisioningProviderRegistry providers)
{
    public async Task<IActionResult> Provision(string tenant)
    {
        var provider = providers.Get("plesk")!;
        var result = await provider.ProvisionAsync(new ProvisionDatabaseRequest
        {
            DatabaseName = $"{tenant}_app",
            Engine = DatabaseEngine.MySql,
        });

        if (!result.Success) return Problem(result.Error);

        // result.Database.ConnectionString / .Host / .Port / .Username / .Password
        // are all real, immediately usable — persist result.Database.Reference
        // yourself if you might ever need to call DeprovisionAsync later.
        return Ok(result.Database);
    }
}

Why the returned host might not be what the panel itself reports

Plesk and cPanel both report their own idea of the database server's address — commonly localhost, since the panel and the database server usually live on the same box. From inside a Docker container (default bridge networking), localhost resolves to the container itself, not the host — that address is simply wrong for a containerized consumer, every time.

Every provider resolves the connection host in this order:

  1. ProvisionDatabaseRequest.ConnectionHostOverride, if set — always wins.
  2. The provider's own DefaultConnectionHostOverride option, if set.
  3. Otherwise, the host the panel's own API reported — unless that's a loopback address (localhost/127.0.0.1/::1), in which case host.docker.internal is used instead of silently trusting a value that's almost never reachable from a container. On Linux, this requires the consuming container to be run with --add-host=host.docker.internal:host-gateway; it works out of the box on Docker Desktop.

Provider notes

Plesk — tries the REST API (POST /api/v2/databases) first only if RestApiKey is configured; this path is best-effort, since the exact request/response shape wasn't confirmed against a live server as of this release (Plesk's REST database coverage varies by version — check your own server's live spec at https://<host>:8443/api/v2/openapi.yml, or in-panel under Tools & Settings → Remote API (REST) → API Reference and Playground, and let us know if it differs from what's implemented here). Falls back to the XML-RPC API (add-db/add-db-user/del-db/ del-db-user) otherwise or on any REST failure — fully implemented, verified against docs.plesk.com, and works on every Plesk version checked.

cPanel — UAPI only, deliberately (WHM creates whole hosting accounts; UAPI acts inside one that already exists — provisioning a new account is out of scope here). MySQL only in this release — Postgres support in cPanel is far less commonly available and UAPI's Postgres module differs enough to warrant its own pass. cPanel silently prefixes both the database and user name with your account username ({account}_{name}) — ProvisionedDatabase.DatabaseName/.Username already reflect the real, qualified names you connect with. Mysql::delete_user isn't independently confirmed in cPanel's own UAPI docs (only create_user and delete_database are) — deprovisioning removes the database and attempts the user removal best-effort, surfacing a warning rather than failing outright if that specific call isn't supported on a given server.

Standalone — no external API, no control panel: connects directly with an admin MySQL/Postgres login you already hold and runs the DDL itself. For PostgreSQL specifically, the new user is made the owner of the new database (rather than only granted database-level privileges) — Postgres' privilege model doesn't give a plain GRANT full control over objects created inside a database the way MySQL's does, so ownership is the correct way to give "maximum permission on this one database" here. The only provider InitializationScript currently runs against.

Not built yet, deliberately

  • Aiven — assessed, a good fit for this same interface (POST .../service/{name}/db), with one real caveat: Aiven's users are scoped to the whole service, not to one database, so a strict single-database restriction would need this package to additionally REVOKE CONNECT on every other database in the service.
  • Supabase — assessed, not a clean fit for this interface. Supabase's API provisions a whole new project (one Postgres per project — async, billable, region/plan-selected), not "a database inside an existing thing." Better as its own ProvisionProjectAsync-shaped concept later.

Adding either — or any future host that fits the "add to an existing thing" shape — is one new class against IDatabaseProvisioningProvider, never a redesign.

What this package hasn't been tested against yet

Every provider here is built against verified, sourced API documentation (Plesk's XML-RPC API, cPanel's UAPI) and unit-tested for connection-string building, host resolution, and response parsing — but none of the three has been exercised against a real, live Plesk server, cPanel account, or MySQL/PostgreSQL instance yet (none was available in the environment this was built in). Verify against your own real infrastructure before depending on this in production, and please report back anything that doesn't match — especially Plesk's REST behavior, which is the one area explicitly built as best-effort rather than confirmed.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.2 86 9/17/2026
1.0.1 80 9/17/2026
1.0.0 77 9/16/2026