Centeva.AdamsInterface
2.0.0
Prefix Reserved
dotnet add package Centeva.AdamsInterface --version 2.0.0
NuGet\Install-Package Centeva.AdamsInterface -Version 2.0.0
<PackageReference Include="Centeva.AdamsInterface" Version="2.0.0" />
<PackageVersion Include="Centeva.AdamsInterface" Version="2.0.0" />
<PackageReference Include="Centeva.AdamsInterface" />
paket add Centeva.AdamsInterface --version 2.0.0
#r "nuget: Centeva.AdamsInterface, 2.0.0"
#:package Centeva.AdamsInterface@2.0.0
#addin nuget:?package=Centeva.AdamsInterface&version=2.0.0
#tool nuget:?package=Centeva.AdamsInterface&version=2.0.0
Centeva.AdamsInterface
ADAMS API client library for .NET. Wraps the 43 operations the NRC ADAMS document management system exposes, so a consuming application can push and pull content without re-implementing the contract.
Supports Windows Authentication with Kerberos delegation, bearer tokens for OIDC, and a no-auth mode for local development.
Built With
| Package | Version | Purpose |
|---|---|---|
| Ardalis.Result | 10.1.0 | Operation outcomes |
| FluentValidation | 12.1.1 | Request validation |
| Microsoft.Extensions.Http | 8.0.1 | IHttpClientFactory |
| Microsoft.AspNetCore.Http | 2.3.0 | IHttpContextAccessor for the auth strategies |
Targets net8.0, net9.0 and net10.0.
Installation
dotnet add package Centeva.AdamsInterface
Configuration
{
"Adams": {
"BaseUri": "https://your-adams-server/adams/api/",
"AuthMode": "Windows",
"ValidateRequests": true
}
}
| Key | Default | Notes |
|---|---|---|
BaseUri |
required | Trailing slash matters: operation paths are resolved relative to it. |
AuthMode |
Windows |
Windows, Bearer or None. An unrecognized value fails at startup. |
ValidateRequests |
true |
Validates requests before sending. Turn off only if ADAMS accepts something the rules reject. |
services.AddAdamsClient(configuration);
That reads Adams:AuthMode and wires the matching strategy, so moving an environment to
OIDC is a configuration change rather than a code change. To decide in code instead:
services.AddAdamsClientCore(configuration)
.AddBearerTokenAuthentication(); // or AddWindowsAuthentication / AddNoAuthentication
Usage
Inject IAdamsApiClient and call the operation you need. Everything returns
Result<T> from Ardalis.Result.
public class DocumentService(IAdamsApiClient adams)
{
public async Task<string> AddDraftAsync(string blobPath, CancellationToken ct)
{
var result = await adams.Document.AddNewDraft(new AddNewDraft.Request
{
DocumentPathAndFileName = blobPath,
DocumentTitle = "RAI Response",
SensitivityReviewCompleted = "Yes",
SunsiDocumentSensitivity = Adams.NonSensitive,
Availability = Adams.PubliclyAvailable
}, ct);
if (!result.IsSuccess)
{
// result.Status is Invalid for a request that broke its own rules, Error for
// anything ADAMS refused. result.Errors carries the ADAMS message.
throw new InvalidOperationException(string.Join("; ", result.Errors));
}
return result.Value.AccessionNumber;
}
}
How outcomes map
| Outcome | Result |
|---|---|
ADAMS accepted the call (responseCode 0) |
ResultStatus.Ok, payload in Value |
| The request broke its own validation rules | ResultStatus.Invalid, fields in ValidationErrors, nothing sent |
ADAMS answered with a non-zero responseCode |
ResultStatus.Error, ADAMS message in Errors |
| ADAMS answered with a non-success HTTP status | ResultStatus.Error |
| No network, DNS failure, timeout | throws |
That last row is deliberate. A transport failure is infrastructure breakage rather than
an answer from ADAMS; turning it into a Result would hide an outage and defeat any
retry policy, which acts on exceptions.
Operations
IAdamsApiClient exposes four groups covering all 43 ADAMS operations.
| Group | Count | Examples |
|---|---|---|
Document |
14 | AddNewDraft, AddNewOfficialRecord, RetrieveProperties, UpdateProperties, CheckInNewVersion, SubmitToDpcForNormalProcessing, SubmitToDpcForImmediatePublicRelease, ChangeClass, Declare, permissions, Delete |
Folder |
8 | AddNewFolder, FileIntoFolder, UpdateProperties, permissions, Delete |
Package |
12 | AddNewPackage, FileIntoPackage, RetrieveProperties, UpdateProperties, DPC submission, Declare, permissions, Delete |
ReferenceData |
9 | Availability, SUNSI sensitivity, document type, distribution list codes, author and addressee lookups, docket numbers |
Every relative path lives in AdamsRoutes, which is the single source of truth for the
route contract. A simulated ADAMS server should bind the same constants so the two
cannot drift.
Authentication
IAuthenticationStrategy has three implementations, selected by Adams:AuthMode.
Windows (default, and what ADAMS requires today). Resolves the caller's
WindowsIdentity from the HTTP context and wraps the call in
WindowsIdentity.RunImpersonatedAsync so the Kerberos hop to ADAMS is made as them.
Windows-only. Requires IIS with ASP.NET Impersonation and Kerberos delegation to reach a
remote ADAMS.
Bearer, for OIDC and OAuth. The package sends tokens; it does not acquire them.
Resolution order is a caller-supplied provider, then the inbound Authorization header,
then an access_token claim:
services.AddAdamsClientCore(configuration)
.AddBearerTokenAuthentication(async () => await myTokenService.GetAccessTokenAsync());
None, for local development against a simulated ADAMS.
Background jobs
Header pass-through cannot work outside an HTTP request, so code calling ADAMS from a background job under OIDC must supply a token provider, typically a client-credentials flow. There is no ambient identity to fall back on the way Windows authentication has.
Note the matching Windows behavior: with no HTTP context, the Windows strategy falls back to the process identity, so ADAMS calls from a background job act as the app pool account rather than a user.
Validation
Each request entity ships a FluentValidation Validator describing the ADAMS field
contract. AddAdamsClientCore registers them and the client runs them before sending, so
a malformed accession number is rejected locally rather than costing a round trip and
coming back as an opaque response code.
Set Adams:ValidateRequests to false to bypass, which exists because these rules were
written against observed ADAMS behavior rather than a published specification. If ADAMS
accepts something they reject, a consumer should not have to wait for a package release.
Local development
The simulated ADAMS server that 1.x bundled into this package has been removed, so the client no longer drags ASP.NET Core MVC into your application or registers routes in it.
It is being rebuilt as Centeva.RpsSimulatedAdams, a standalone container. That is not published yet. Until it is, point development at whatever ADAMS stand-in you already run and turn authentication off against it:
{ "Adams": { "BaseUri": "http://localhost:9070/api/", "AuthMode": "None" } }
Document content
ADAMS reads document content itself; this client never sends bytes. AddNewDraft and
AddNewOfficialRecord take DocumentPathAndFileName, which is a container-relative
logical path inside the configured Azure Blob Storage container - for example
/NRR/RAI App/EPID-12345/response.pdf. There is no scheme, host, container name or SAS
token in it; ADAMS knows the account and container out of band and resolves the rest.
Write the file to storage before calling ADAMS.
Upload workflow
The order matters, because ADAMS resolves the content and the folder tree as it goes.
// 1. Put the file in storage where ADAMS can reach it.
await objectStorage.WriteAsync(StoragePath.Combine(destinationFolder, fileName), stream, ct);
// 2. Create the folder path, one segment at a time.
var folder = await adams.Folder.AddNewFolder(new AddNewFolder.Request
{
ParentFolderPath = "/NRR/RAI App",
NewFolderName = epid
}, ct);
// 3. Create a package, if the documents are to be released together.
var package = await adams.Package.AddNewPackage(new AddNewPackage.Request
{
PackageTitle = title,
Availability = Adams.PubliclyAvailable
}, ct);
// 4. Add the document, referencing the path written in step 1.
var document = await adams.Document.AddNewDraft(new AddNewDraft.Request
{
DocumentPathAndFileName = $"{destinationFolder}/{fileName}",
DocumentTitle = title,
SensitivityReviewCompleted = "Yes",
SunsiDocumentSensitivity = Adams.NonSensitive,
Availability = Adams.PubliclyAvailable
}, ct);
// 5. File it into the package or the folder.
await adams.Package.FileIntoPackage(new FileIntoPackage.Request
{
DocumentAccessionNumber = document.Value.AccessionNumber,
PackageAccessionNumber = package.Value.AccessionNumber
}, ct);
// 6. Submit to DPC, if it should be released.
await adams.Package.SubmitToDpcForNormalProcessing(new SubmitToDpcForNormalProcessing.Request
{
AccessionNumber = package.Value.AccessionNumber
}, ct);
Check IsSuccess on each step. The sequence is not transactional: a failure partway
through leaves the folder, package and documents already created in ADAMS.
Running tests
dotnet test Centeva.AdamsInterface.slnx
Contributing
Branch from master, open a pull request. CI builds and tests against all three target
frameworks. Releases are cut by publishing a GitHub Release tagged vX.Y.Z from
master; the tag is the only source of the package version.
License
MIT. See LICENSE.
Platform compatibility
net8.0, net9.0 and net10.0. WindowsAuthenticationStrategy is Windows-only, as
Kerberos impersonation has no cross-platform equivalent; the bearer and none strategies
run anywhere.
| Product | Versions 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 is compatible. 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. |
-
net10.0
- Ardalis.Result (>= 10.1.0)
- FluentValidation (>= 12.1.1)
- FluentValidation.DependencyInjectionExtensions (>= 12.1.1)
- Microsoft.AspNetCore.Http (>= 2.3.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.3.0)
- Microsoft.Extensions.Http (>= 8.0.1)
- VeracodeAttributes (>= 1.2.1)
-
net8.0
- Ardalis.Result (>= 10.1.0)
- FluentValidation (>= 12.1.1)
- FluentValidation.DependencyInjectionExtensions (>= 12.1.1)
- Microsoft.AspNetCore.Http (>= 2.3.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.3.0)
- Microsoft.Extensions.Http (>= 8.0.1)
- VeracodeAttributes (>= 1.2.1)
-
net9.0
- Ardalis.Result (>= 10.1.0)
- FluentValidation (>= 12.1.1)
- FluentValidation.DependencyInjectionExtensions (>= 12.1.1)
- Microsoft.AspNetCore.Http (>= 2.3.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.3.0)
- Microsoft.Extensions.Http (>= 8.0.1)
- VeracodeAttributes (>= 1.2.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.