OpenSourceInitiative.LicenseApi
3.0.0
dotnet add package OpenSourceInitiative.LicenseApi --version 3.0.0
NuGet\Install-Package OpenSourceInitiative.LicenseApi -Version 3.0.0
<PackageReference Include="OpenSourceInitiative.LicenseApi" Version="3.0.0" />
<PackageVersion Include="OpenSourceInitiative.LicenseApi" Version="3.0.0" />
<PackageReference Include="OpenSourceInitiative.LicenseApi" />
paket add OpenSourceInitiative.LicenseApi --version 3.0.0
#r "nuget: OpenSourceInitiative.LicenseApi, 3.0.0"
#:package OpenSourceInitiative.LicenseApi@3.0.0
#addin nuget:?package=OpenSourceInitiative.LicenseApi&version=3.0.0
#tool nuget:?package=OpenSourceInitiative.LicenseApi&version=3.0.0
OpenSourceInitiative.LicenseApi
A lightweight, multi-targeted (.NET 10 / netstandard2.0) client library for the Open Source Initiative License API. Fetches the OSI license catalog, supports filtering by SPDX ID, name, keyword, and steward, and extracts human-readable license text from the OSI HTML pages. No caching layer — every call goes to the network; callers that want caching add their own decorator.
Quick start
DI registration (recommended)
services.AddOsiLicensesClient();
// With options
services.AddOsiLicensesClient(options =>
{
options.BaseAddress = new Uri("https://..."); // default: OSI API
});
Resolve IOsiClient from the container:
var client = sp.GetRequiredService<IOsiClient>();
// Stream all licenses
await foreach (var license in client.GetAllLicensesAsyncEnumerable())
Console.WriteLine(license?.Name);
// Filter
var gplFamily = await client.GetBySpdxIdAsync("GPL*");
var popular = await client.GetByKeywordAsync(OsiLicenseKeyword.PopularStrongCommunity);
Standalone (no DI)
await using var client = new OsiClient();
var mit = await client.GetByOsiIdAsync("mit");
Console.WriteLine(mit?.LicenseText);
Public API surface
IOsiClient
The primary interface for all license queries. Lives at OpenSourceInitiative.LicenseApi.Interfaces.
| Method | Description |
|---|---|
GetAllLicensesAsyncEnumerable(token) |
Streams the full catalog as IAsyncEnumerable<OsiLicense?>. |
GetByOsiIdAsync(id, token) |
Fetches a single license by its OSI ID (e.g. "mit"). |
GetBySpdxIdAsync(id, token) |
Filters by SPDX ID; supports * wildcards ("GPL*", "*-2.0"). |
GetByNameAsync(name, token) |
Filters by human-readable name. |
GetByKeywordAsync(keyword, token) |
Filters by OsiLicenseKeyword enum value. |
GetByStewardAsync(steward, token) |
Filters by steward organization slug. |
Implements IDisposable and IAsyncDisposable.
Input handling:
id/name/steward/keywordarguments are always treated as opaque values and escaped before being combined with the configuredBaseAddress— a caller passing a full URL, a//hostreference, or..segments through one of these methods cannot redirect the request to a different host. Don't rely on this as input validation, though: garbage in still means "license not found" or aJsonException, not a meaningful error.
OsiClient
public sealed class — the concrete HTTP implementation of IOsiClient. Registered as a typed IHttpClientFactory client named "OsiClient" when using DI.
Constructor: OsiClient(ILogger<OsiClient>? logger, OsiClientOptions? options, HttpClient? httpClient) — all parameters optional. When httpClient is null, the client owns and disposes the inner HttpClient; when provided externally it is not disposed.
License text is fetched automatically per license via a two-step strategy:
- OSI HTML page — extracts the node with CSS class
license-content. - Steward HTML URL — last resort, only used if the steward URL doesn't already point at a
.txtfile.
If both steps fail (network error, unreachable page, markup without a license-content node), LicenseText is left as an empty string rather than throwing — a scraping failure on a single license does not fail the whole call.
OsiClientOptions
public sealed class — configures the DI registration. Lives at OpenSourceInitiative.LicenseApi.Options.
| Property | Type | Default | Description |
|---|---|---|---|
BaseAddress |
Uri |
https://opensource.org/api/ |
OSI API base URL. |
PrimaryHandlerFactory |
Func<HttpMessageHandler>? |
null |
Injects a custom primary handler (useful for testing). |
UserAgent |
IList<ProductInfoHeaderValue> |
Assembly name + version | Added to every request. |
HttpClientHandler |
HttpClientHandler |
AllowAutoRedirect = true |
Used when no external HttpClient is supplied. |
OsiLicense
public sealed record — represents one OSI license entry. Lives at OpenSourceInitiative.LicenseApi.Models.
| Property | Type | Notes |
|---|---|---|
Id |
string |
OSI-internal identifier (e.g. "mit"). |
Name |
string |
Human-readable name. |
SpdxId |
string? |
SPDX identifier (e.g. "MIT"). |
Version |
string? |
Optional version string. |
SubmissionDate |
DateTime? |
Parsed from yyyyMMdd via CustomFormatDateTimeConverter. |
ApprovalDate |
DateTime? |
Parsed from yyyyMMdd. |
Approved |
bool |
OSI approval status. |
Keywords |
IReadOnlyCollection<OsiLicenseKeyword> |
Deserialized via OsiLicenseKeywordsConverter; unknown tokens are ignored. |
Stewards |
IReadOnlyCollection<string> |
Steward organization slugs. |
Links |
OsiLicenseLinks |
HAL-style _links object. |
LicenseText |
string? |
Extracted plain text — not part of the API payload, populated by the client after fetching. Empty string if scraping failed. Mutable, so you can set it yourself when constructing an OsiLicense by hand (e.g. in tests). |
OsiLicenseExtensions adds license.GetLicenseText(httpClient, token) and license.GetAndSetLicenseText(httpClient, token) for re-fetching or backfilling the text on an existing instance.
OsiLicenseKeyword
public enum — OSI classification keywords. Lives at OpenSourceInitiative.LicenseApi.Enums.
Values: PopularStrongCommunity, International, SpecialPurpose, NonReusable, Superseded, VoluntarilyRetired, RedundantWithMorePopular, OtherMiscellaneous, Uncategorized.
Serializes to/from the OSI API string tokens (e.g. popular-strong-community) via OsiLicenseKeywordsConverter.
ServiceCollectionExtensions
public static class — the single registration entry point. Lives at OpenSourceInitiative.LicenseApi.Extensions.
AddOsiLicensesClient(this IServiceCollection, Action<OsiClientOptions>?) — registers a named IHttpClientFactory client ("OsiClient") and IOsiClient → OsiClient as transient.
OsiException / OsiInitializationException
public abstract/sealed class — base and derived exception types. Live at OpenSourceInitiative.LicenseApi.Exceptions.
OsiInitializationException is thrown by the obsolete OsiLicensesClient.InitializeAsync when the catalog fetch fails.
CustomFormatDateTimeConverter
public class JsonConverter<DateTime?> — handles the yyyyMMdd date format used by the OSI API for submission and approval dates. Registered via [JsonConverter] attributes on OsiLicense. Null and empty strings deserialize to null; an unrecognized format throws JsonException.
IOsiLicensesClient / OsiLicensesClient (deprecated)
[Obsolete] — wraps IOsiClient with an eager-loading, snapshot-based API kept for backward compatibility. Use IOsiClient directly for new code. Unlike IOsiClient, its SearchAsync/Search assume every entry returned by the API has a non-null Id/Name; a malformed catalog entry missing either field will throw a NullReferenceException here rather than being filtered out.
Target frameworks
| TFM | Notes |
|---|---|
net10.0 |
Full feature set. Uses ValueTask.CompletedTask, MediaTypeNames, ReadAsStreamAsync(token), C# 14 extension blocks. |
netstandard2.0 |
Compatible subset. #if !NETSTANDARD2_0 guards cover API surface differences. System.Text.Json pulled as a NuGet dependency. |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 is compatible. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- HtmlAgilityPack (>= 1.12.4)
- JetBrains.Annotations (>= 2026.2.0)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Http (>= 10.0.9)
- Microsoft.Extensions.Logging (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- System.Text.Json (>= 10.0.9)
-
net10.0
- HtmlAgilityPack (>= 1.12.4)
- JetBrains.Annotations (>= 2026.2.0)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Http (>= 10.0.9)
- Microsoft.Extensions.Logging (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on OpenSourceInitiative.LicenseApi:
| Package | Downloads |
|---|---|
|
OpenSourceInitiative.LicenseApi.DependencyInjection
Dependency Injection extensions for OpenSourceInitiative.LicenseApi. Provides IServiceCollection extensions to register a typed IOsiLicensesClient with IHttpClientFactory and optional request logging via ILogger. Multi-targets net10.0 and netstandard2.0. |
GitHub repositories
This package is not used by any popular GitHub repositories.