Dloizides.Credits 1.0.1

dotnet add package Dloizides.Credits --version 1.0.1
                    
NuGet\Install-Package Dloizides.Credits -Version 1.0.1
                    
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="Dloizides.Credits" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dloizides.Credits" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Dloizides.Credits" />
                    
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 Dloizides.Credits --version 1.0.1
                    
#r "nuget: Dloizides.Credits, 1.0.1"
                    
#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 Dloizides.Credits@1.0.1
                    
#: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=Dloizides.Credits&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Dloizides.Credits&version=1.0.1
                    
Install as a Cake Tool

Dloizides.Credits

Storage-agnostic per-tenant metering for multi-tenant SaaS. Four independent, composable caps over a tenant's billable units, extracted verbatim from PROOViD AMLService's screening-quota mechanics:

  • Pre-paid credits — a CreditBalance decremented by a CreditCostPerScreen per unit. Cost 0 = not enforced (free); > 0 = pay-per-use, blocked once the balance can't cover the next unit.
  • Monthly quota — fair-use / billing cap over the current calendar month (UTC).
  • Rate limit — throughput / burst cap over a rolling 60-second window.
  • Per-IP demo cap — a rolling 1-hour cap partitioned by client-IP hash, for a shared demo tenant.

All decision logic (allowed/blocked, window math, month-start calc, credit affordability) lives in the package. The package owns no database — each product implements a small ICreditQuotaStore over its own storage (EF Core, Dapper, anything). A second product gets metering in a handful of lines.

Install

dotnet add package Dloizides.Credits

Wire-up

// Program.cs
builder.Services.AddCreditsMetering();                       // registers CreditQuotaService (scoped)
builder.Services.AddScoped<ICreditQuotaStore, MyEfStore>();  // your persistence, over your DbContext

Use

public MyController(CreditQuotaService metering) => _metering = metering;

// On the metered path:
var rate = await _metering.CheckRateAsync(tenantId, ct);
if (!rate.Allowed) return TooManyRequests(rate.RetryAfterSeconds);

var quota = await _metering.CheckQuotaAsync(tenantId, ct);
if (!quota.Allowed) return QuotaExceeded(quota.Used, quota.Limit);

var credit = await _metering.CheckCreditsAsync(tenantId, ct);
if (!credit.Allowed) return PaymentRequired(credit.Balance, credit.CostPerScreen);

// ... do the metered work ...
await _metering.ChargeCreditsAsync(tenantId, ct);            // atomic; no-op when cost == 0

var usage = await _metering.GetUsageAsync(tenantId, ct);     // GET /usage body

Public surface

CreditQuotaService

Method Returns Meaning
CheckQuotaAsync QuotaCheck Monthly quota. Null limit = unlimited.
CheckRateAsync RateLimitCheck Per-minute burst cap (60s window).
CheckIpRateAsync DemoIpRateCheck Per-IP demo cap (1h window); no-op unless set.
CheckCreditsAsync CreditCheck Affordability; free when cost 0.
ChargeCreditsAsync Task Atomic decrement; no-op when cost 0.
GetUsageAsync MeteringUsage Full usage + credit position.
SetCreditsAsync bool Top-up balance/cost (clamped ≥ 0).
SetQuotaAsync / SetRateLimitAsync / SetDemoIpRateLimitAsync / SetMaxBatchRowsAsync bool Master config setters.

ICreditQuotaStore (you implement)

Reads: GetMonthlyQuotaAsync, GetRateLimitPerMinuteAsync, GetDemoIpRateLimitPerHourAsync, GetCreditSnapshotAsync, GetLimitsAsync, CountBillableUnitsSinceAsync, CountBillableUnitsByIpSinceAsync. Writes: ChargeCreditsAsync (atomic), plus the five setters.

The store is responsible for counting only billable/externally-initiated units (e.g. excluding internal system events via a source filter) and for making ChargeCreditsAsync a storage-side atomic decrement guarded by cost > 0.

Result records

CreditCheck(Balance, CostPerScreen, Allowed), QuotaCheck(Limit, Used, Allowed), RateLimitCheck(Limit, Recent, Allowed, RetryAfterSeconds), DemoIpRateCheck(Limit, Recent, Allowed, RetryAfterSeconds), MeteringUsage(...), CreditSnapshot(Balance, CostPerScreen), TenantMeteringLimits(...).

License

MIT

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.1 587 7/7/2026