LondonFhirService.Providers.FHIR.STU3.Abstractions 0.6.0

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

🔥 LondonFhirService — FHIR - STU3 Abstractions

Build Nuget Nuget

A small, focused abstraction layer that lets you write your own concrete FHIR provider by implementing a couple of simple interfaces and base classes. It also ships with a Capabilities discovery feature so your provider can describe exactly which resources and operations it supports.


Why this library?

  • Pluggable providers. Implement FhirProviderBase and IFhirProvider to bring your own FHIR backend.
  • Resource‑first design. Each FHIR resource (e.g., Patient) has its own operations via ResourceOperationBase<TResource> and a matching interface.
  • Discoverable capabilities. Providers and resources automatically declare what they support — including custom operations — so callers can make safe, data‑driven decisions at runtime.

Core concepts

1) Providers

A provider is your concrete integration with a FHIR‑compatible system. Implement it by inheriting from FhirProviderBase and implementing IFhirProvider.

using Hl7.Fhir.Model;
using LondonFhirService.Providers.FHIR.STU3.Abstractions;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Extensions;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Resources;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Capabilities;

public sealed class MyFhirProvider : FhirProviderBase, IFhirProvider
{
    public IPatientResource Patients { get; }

    public MyFhirProvider()
    {
        // Wire up your supported concrete resource operations here
        // No need to implement anything else that is not supported
        Patients = new PatientResource();
    }
}

2) Resource operations

Every FHIR resource gets its own operations class that derives from ResourceOperationBase<TResource> and implements the matching interface (e.g., IPatientResource).

using System;
using System.Threading;
using System.Threading.Tasks;
using Hl7.Fhir.Model;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Resources;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Capabilities;

public sealed class PatientResource : ResourceOperationBase<Patient>, IPatientResource
{
    // Standard operations (Read, VRead, Search, History*, etc.)
    // are inherited. Override only the ones you actually support.

    // Example: custom operation (see next section for [FhirOperation])
    public ValueTask<Bundle> Match(Parameters parameters, CancellationToken cancellationToken = default)
        => throw new NotImplementedException();
}

Note: The pattern is the same for any resource (AllergyIntolerance, Encounter, Observation, etc.).


Custom operations (beyond IResourceOperation<TResource>)

Operations are not limited to the standard surface of IResourceOperation<TResource>. You can add custom operations — like $everything on Patient — by simply adding a public method on your resource class and marking it with the [FhirOperation] attribute. The Capabilities scanner will then detect and include it as a supported operation.

using System;
using System.Threading;
using System.Threading.Tasks;
using Hl7.Fhir.Model;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Resources;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Resources;
using LondonFhirService.Providers.FHIR.STU3.Abstractions.Models.Capabilities;

public sealed class PatientResource : ResourceOperationBase<Patient>, IPatientResource
{
    /// <summary>
    /// Patient plus related resources ($everything). Returns a searchset Bundle.
    /// Optional args align with common server conventions.
    /// </summary>
    /// <param name="id">Logical id of the patient resource.</param>
    /// <param name="start">Optional start date/time for records to include.</param>
    /// <param name="end">Optional end date/time for records to include.</param>
    /// <param name="typeFilter">Optional FHIR resource type filter (_type).</param>
    /// <param name="since">Optional timestamp for changes since (_since).</param>
    /// <param name="count">Optional page size limit (_count).</param>
    /// <param name="cancellationToken">Optional cancellation token.</param>
    [FhirOperation]
    public ValueTask<Bundle> Everything(
        string id,
        DateTimeOffset? start = null,
        DateTimeOffset? end = null,
        string typeFilter = null,
        DateTimeOffset? since = null,
        int? count = null,
        CancellationToken cancellationToken = default)
    {
        // Implement your callout to the underlying system here.
        return new ValueTask<Bundle>(new Bundle { Type = Bundle.BundleType.Searchset });
    }

    public ValueTask<Bundle> Match(Parameters parameters, CancellationToken cancellationToken = default)
        => throw new NotImplementedException();
}

Capabilities

Capabilities are computed metadata that describe what your provider and resources support. They power feature detection, documentation, and guard checks at runtime.

  • Provider capabilities include provider name and a list of supported resources.
  • Resource capabilities list supported operations. Methods decorated with [FhirOperation] are automatically added, alongside the standard operations you override on ResourceOperationBase<TResource>.

Example: printing capabilities

IFhirProvider provider = new MyFhirProvider();
var capabilities = provider.Capabilities;
Console.WriteLine($"Provider: {capabilities.ProviderName}");

foreach (var resource in capabilities.SupportedResources)
{
    Console.WriteLine($"  Resource: {resource.ResourceName}");

    foreach (var operation in resource.SupportedOperations)
    {
        Console.WriteLine($"    Operation: {operation}");
    }
}

What gets picked up?

  • Any overridden standard operation on ResourceOperationBase<TResource>.
  • Any public method on your resource class marked with [FhirOperation].

FhirProviderGuards extensions

The guards are convenience extension methods for answering questions like:

  • “Does this provider support the Patient resource?”
  • “Does it support the Everything operation on Patient?”
  • “Which of these providers support Everything for Patient?”

Single provider

IFhirProvider provider = new MyFhirProvider();
bool supportPatientResource = provider.SupportsResource("Patient");
bool supportEverythingOperationOnPatientResource = provider.SupportsResource("Patient", "Everything");

Multiple providers

IEnumerable<IFhirProvider> providers = new[] { new AProvider(), new BProvider() };

// Filter down to providers that support a resource + operation
IEnumerable<IFhirProvider> supportingProviders = providers.SupportsResource("Patient", "Everything");

// Just the resource (any operation)
IEnumerable<IFhirProvider> patientProviders = providers.SupportsResource("Patient");

These guards respect null/empty input and will return an empty sequence or false without throwing.


Putting it together: minimal provider

public sealed class MinimalProvider : FhirProviderBase, IFhirProvider
{
    public IPatientResource Patients { get; } = new MinimalPatientResource();
}

public sealed class MinimalPatientResource : ResourceOperationBase<Patient>, IPatientResource
{
    [FhirOperation]
    public ValueTask<Bundle> Everything(
        string id,
        DateTimeOffset? start = null,
        DateTimeOffset? end = null,
        string typeFilter = null,
        DateTimeOffset? since = null,
        int? count = null,
        CancellationToken cancellationToken = default)
        => new(new Bundle { Type = Bundle.BundleType.Searchset });

    public ValueTask<Bundle> Match(Parameters parameters, CancellationToken cancellationToken = default)
        => throw new NotImplementedException();
}

Usage

var provider = new MinimalProvider();

if (provider.SupportsResource("Patient", "Everything"))
{
    var bundle = await provider.Patients.Everything("12345");
}

Testing suggestions (and production usage)

  • Assert that your provider Capabilities include the resources and operations you expect.
  • Use the guards to keep tests expressive:
IFhirProvider provider = new MinimalProvider();
provider.SupportsResource("Patient").Should().BeTrue();
provider.SupportsResource("Patient", "Everything").Should().BeTrue();

Production example: safely call $everything across many providers

If you have a collection of providers and want to call a custom operation such as $everything, first use the FhirProviderGuards extension to filter to only those providers that advertise support. This avoids runtime errors and lets you fan‑out work confidently.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Hl7.Fhir.Model;

public static class PatientEverythingFanout
{
    public static async Task<IReadOnlyList<Bundle>> GetEverythingAsync(
        IEnumerable<IFhirProvider> providers,
        string patientId,
        CancellationToken cancellationToken = default)
    {
        if (providers is null)
        {
            return Array.Empty<Bundle>();
        }

        // Filter to only providers that support Patient + Everything
        IEnumerable<IFhirProvider> supportingProviders =
            providers.SupportsResource("Patient", "Everything");

        // Fan-out concurrently across providers
        List<Task<Bundle>> tasks = supportingProviders
            .Select(provider => provider.Patients.Everything(
                patientId,
                start: null,
                end: null,
                typeFilter: null,
                since: null,
                count: null,
                cancellationToken: cancellationToken).AsTask())
            .ToList();

        Bundle[] bundles = await Task.WhenAll(tasks).ConfigureAwait(false);

        return bundles;
    }
}

FAQ

Q: Do I have to override every method? No. Only override what you support; unimplemented methods can throw by default.

Q: How do I add non‑standard operations? Add a public method and decorate it with [FhirOperation]. The Capabilities scanner will include it.

Q: Can I detect support at runtime? Yes. You can inspect the provider’s Capabilities object (or a resource’s capabilities) to see which operations are available. Alternatively, use the FhirProviderGuards extension methods such as SupportsResource for a simpler runtime check.


Contributing

We welcome all forms of contribution — whether it’s a small bug fix, a new feature, or simply improving the documentation.

  • Pull Requests (PRs): Please fork the repository and submit a PR with clear commit messages.
    Where possible, include tests that validate your changes. We follow TDD — anything that can be tested must be tested before a PR will be accepted.
  • Issues: Suggestions, feature requests, and bug reports can be logged through the Issues tab. Please provide enough context and steps to reproduce (if reporting a bug).
  • Discussions: If you’re unsure about an idea, feel free to open a discussion before investing time in code. Early feedback is encouraged.
  • Coding Standards: We follow "The-Standard" architecture conventions (Broker/Service/Orchestration layers, async suffixes, 120 char line limit, etc.). Please align with these patterns where possible.
  • Testing: New functionality should include unit tests and/or integration tests.
    We use xUnit with FluentAssertions. Tests should be clear, deterministic, and align with the Given–When–Then pattern.

Note: All contributions are welcome! Even if it’s just a typo fix, don’t hesitate to submit a PR.


Appendix: key types (at a glance)

  • IFhirProvider — Provider surface (resources as properties).
  • FhirProviderBase — base class that computes and exposes provider-level capabilities by scanning its resource operations.
  • IResourceOperation<TResource> — Standard REST‑like surface for a resource.
  • ResourceOperationBase<TResource> — Base class with capability discovery.
  • [FhirOperation] — Attribute to mark custom methods for capability discovery.
  • FhirProviderGuards — Extensions to query support for resources/operations.

Appendix: Key Types (at a Glance)

Public API

  • IFhirProvider — Canonical provider surface (resources exposed as properties).
  • IResourceOperation<TResource> — Standard REST-like surface for a resource.
  • [FhirOperation] — Attribute used to mark custom methods for capability discovery.
  • FhirProviderGuards — Extension methods to query support for resources/operations.

Internal Helpers

  • FhirProviderBase — Optional base class that computes and exposes provider-level capabilities by scanning its resource operations.
  • ResourceOperationBase<TResource> — Base class that computes and exposes resource-level capabilities by scanning its methods.

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

NuGet packages (1)

Showing the top 1 NuGet packages that depend on LondonFhirService.Providers.FHIR.STU3.Abstractions:

Package Downloads
LondonFhirService.Providers.FHIR.STU3.DiscoveryDataService

LondonFhirService.Providers.FHIR.STU3.DiscoveryDataService provider for FHIR resources.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0 703 2/23/2026
0.5.0 621 11/19/2025
0.4.0 462 11/18/2025
0.3.0 373 11/12/2025
0.2.1 237 11/6/2025
0.2.0 269 11/4/2025
0.1.0 220 11/3/2025

Initial release of LondonFhirService.Providers.FHIR.STU3.Abstractions.