Files
adas-core/adas-core.module.ProxyDevices/README.md
T
2026-06-26 10:29:23 +02:00

11 KiB

adas-core.module.ProxyDevices — Proxy Devices Module

A functional module of the ADAS Core platform.
Encapsulates all logic for proxying communication with external hardware devices over HTTP. This module acts as a configurable gateway layer that the Host registers at startup, translating internal requests into authenticated HTTP calls to remote endpoints.


Table of Contents

  1. Overview
  2. Responsibilities
  3. Project Structure
  4. Dependencies
  5. Device Proxy Architecture
  6. ProxyDeviceService Flow
  7. Design Rules

Overview

adas-core.module.ProxyDevices is a modular satellite project that provides a proxy gateway for interacting with external hardware devices over HTTP. It abstracts the complexity of device authentication, connection management, and response handling behind a uniform IProxyDevice contract.

Key characteristics:

  • Modular Monolith Pattern — Self-contained module with its own device drivers, service orchestration, and configuration model. No other module depends on it directly.
  • Plugin Architecture — New device types are added by creating a class that implements IProxyDevice and naming it {Type}Device. The service discovers and instantiates them at runtime via reflection.
  • Digest Authentication Support — The built-in HttpDevice supports HTTP Digest authentication via NetworkCredential.
  • Instance CachingProxyDeviceService maintains an in-memory cache of initialized device instances to avoid repeated construction and initialization overhead.
  • Dual Operation Modes — Each device supports both Process() (full response) and Stream() (response-headers-read) operations.
  • Configuration-Driven — All devices, their types, and parameters are defined in ProxyDeviceSettings bound from appsettings.json.

Responsibilities

Concern What this project does
Device Proxying Acts as an intermediary between the Host and external HTTP-based devices, shielding the rest of the system from protocol specifics.
Device Lifecycle Manages device initialization, caching, and disposal through the IProxyDevice contract.
HTTP Communication HttpDevice performs authenticated and unauthenticated HTTP GET requests with timeout handling.
Digest Authentication Supports HTTP Digest auth via username, password, and optional domain parameters.
Reflection-Based Factory ProxyDeviceService dynamically instantiates device classes by type name at runtime ({Type}Device).
Instance Caching Caches initialized IProxyDevice instances per deviceId to minimize repeated setup costs.
Streaming vs Processing Offers Process() for complete responses and Stream() for streaming (headers-first) scenarios.
Error Translation Converts HttpRequestException, TaskCanceledException, and missing-device errors into standardized HttpResponseMessage responses.
Configuration Model Defines ProxyDeviceSettings and ProxyDevice as strongly-typed configuration objects bound from the Host's configuration system.
Audit Logging Emits audit events for device access and proxy operations via AuditLogs.

Project Structure

adas-core.module.ProxyDevices/
├── ProxyDeviceSettings.cs          # Strongly-typed settings model (list of configured proxy devices)
│
├── Devices/
│   ├── IProxyDevice.cs             # Core contract: Initialize, Process, Stream
│   └── HttpDevice.cs               # Concrete HTTP proxy with digest-auth support
│
└── Services/
    ├── IProxyDeviceService.cs      # Service contract: Process(deviceId), Stream(deviceId)
    └── ProxyDeviceService.cs       # Orchestrator: reflection factory, caching, error handling
File Role
ProxyDeviceSettings.cs Configuration root. A List<ProxyDevice> bound from appsettings.json. Each entry defines Id, Type, Enabled, and Parameters.
IProxyDevice.cs Interface contract. All proxy devices implement Initialize(Dictionary), Process(), and Stream().
HttpDevice.cs Concrete proxy for HTTP endpoints. Validates url, optional digest auth, performs GET requests, handles timeouts.
IProxyDeviceService.cs Application-facing contract. Host controllers depend on this interface, not on module internals.
ProxyDeviceService.cs Implementation. Reads settings, looks up devices by Id, lazily instantiates and caches drivers, delegates to Process() or Stream().

Dependencies

Downstream References

This project has no direct project references to other ADAS Core projects. It is a completely decoupled satellite module.

Package Version Purpose
Microsoft.Extensions.DependencyInjection 10.0.8 DI registration helpers used during Host startup.
Microsoft.Extensions.Hosting 10.0.8 Hosting abstractions for optional background proxy services.

Upstream References (projects that depend on this)

Project Reason
adas-core (Host) Registers IProxyDeviceService and ProxyDeviceSettings at startup. Host controllers invoke Process() and Stream() through the service interface.

NuGet Packages

Package Version Purpose
Microsoft.Extensions.DependencyInjection 10.0.8 Service-collection registration helpers.
Microsoft.Extensions.Hosting 10.0.8 Hosting abstractions for background services.
Serilog 4.3.1 Structured logging for timeout and HTTP error events.
AuditLogs 1.0.59 Audit trail emission for device access and proxy operations.
SharpCompress 0.49.0 Available for potential compression pipelines in future device types.
Snappier 1.3.1 Fast compression library for future streaming optimization.

Device Proxy Architecture

IProxyDevice Contract

public interface IProxyDevice
{
    void Initialize(Dictionary<string, object?> deviceParameters);
    Task<HttpResponseMessage> Process();
    Task<HttpResponseMessage> Stream();
}
Member Purpose
Initialize(parameters) One-time setup. Validates required keys (url), extracts optional keys (name, username, password, domain), and marks the device as ready.
Process() Performs a full HTTP GET request and returns the complete HttpResponseMessage.
Stream() Performs an HTTP GET with HttpCompletionOption.ResponseHeadersRead, enabling callers to stream the body without buffering.

HttpDevice — Built-in HTTP Proxy

  • URI Validation — Requires a non-empty, absolute url in parameters. Throws ArgumentNullException if missing or invalid.
  • Single Initialization Guard — Throws InvalidOperationException if Initialize() is called twice.
  • Optional Digest Auth — When username is provided, sets HttpClientHandler.Credentials with NetworkCredential(username, password, domain).
  • Timeout Translation — Catches TaskCanceledException (timeout) and re-throws as TimeoutException with a descriptive message.
  • Diagnostics — Overrides ToString() to emit [HttpDevice] (name uri username password domain) for logging.

Adding a New Device Type

  1. Create a class in Devices/ that implements IProxyDevice.
  2. Name it {Type}Device (e.g., TcpDevice, UdpDevice).
  3. Register the type string in appsettings.json under ProxyDeviceSettings.
  4. ProxyDeviceService will resolve it automatically via reflection at first use.

ProxyDeviceService Flow

Device Resolution & Caching

[Host Controller] --> [ProxyDeviceService.Process(deviceId)]
                              |
                              v
                    [Look up ProxyDevice by Id in settings]
                              |
                    +---------+---------+
                    |                   |
                    v                   v
              [Enabled=true]      [Enabled=false / Not Found]
                    |                   |
                    v                   v
          [Check _cache]          [Return 404 Not Found]
              |     |
              |     +--> [Miss] --> [Reflect {Type}Device]
              |                       [Call Initialize(params)]
              |                       [Add to _cache]
              v                       |
          [Call device.Process()] <--+
              |
              v
          [Return HttpResponseMessage]

Key Behaviors

  • Thread-Safe Cache — The _cache dictionary is guarded by a lock during read/write to prevent race conditions.
  • Lazy Instantiation — Devices are created only on first access, not at startup.
  • Graceful Degradation — If a device is not found, disabled, or throws HttpRequestException, the service returns an HttpResponseMessage with an appropriate status code rather than crashing.
  • No Dispose Lifecycle — Cached instances are reused for the lifetime of the service. The Host manages the service scope (typically Singleton).

Design Rules

  1. True Module Independence — This project must not reference any other ADAS Core project. It communicates with the Host exclusively through its own public interfaces and the .NET configuration/options system.
  2. Configuration-Driven Discovery — Device types, endpoints, and credentials must come exclusively from ProxyDeviceSettings bound to appsettings.json. No hardcoded URLs or auth secrets.
  3. Reflection Factory — New device types are added by convention ({Type}Device implementing IProxyDevice). No central switch statement needs modification (Open/Closed).
  4. Cache Safety — The device instance cache is protected by a lock during writes. Reads inside the lock are safe because initialization is atomic.
  5. Fail Securely — Missing or disabled devices return 404 Not Found. HTTP failures are translated into HttpResponseMessage with the original status code. Timeouts become TimeoutException.
  6. No Business Logic — This module handles transport only. Any transformation, validation, or business-rule enforcement belongs in Application or the Host.
  7. Lazy Initialization — Devices are instantiated on first request, not at Host startup. This prevents delaying startup when a remote device is unreachable.
  8. Digest Auth OnlyHttpDevice supports HTTP Digest authentication. Basic auth, bearer tokens, or mTLS must be implemented in a separate IProxyDevice implementation if needed.
  9. Audit Every Access — Every Process() and Stream() call emits an audit event via AuditLogs tagging the device ID and outcome.
  10. Singleton ServiceProxyDeviceService is registered as a Singleton because it holds cached device instances and settings that are immutable after startup.

Back to adas-core Root README