Skip to main content

Application Services

The Alert.CA.Frontend.Application project implements business logic using the CQRS pattern with MediatR. Controllers dispatch commands and queries through the mediator pipeline, which routes them to dedicated handlers that coordinate with repositories and services.

CQRS Pattern with MediatR

Commands modify state (e.g., PanTiltCameraCommand, CreateSubscriptionCommand). Queries read state (e.g., GetStaticMetadataByCameraIdsQuery, GetTimelapseForCameraQuery). MediatR handlers are registered automatically via assembly scanning in ConfigureServices.cs:

services.AddMediatR(cfg => {
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
});

Services

CameraControlService

The core service for all camera movement and control operations. Orchestrates PTZ movements, focus, brightness, guard tour toggling, and camera leasing.

Key Operations:

MethodDescription
PanTiltZoomCamera()Validates camera access for the user, checks the device is an active RealCam, then sends a MoveCameraTrigger to the Image Acquisition API via HTTP POST
SetCameraFocus()Sends a FocusCameraTrigger with manual focus value and auto-focus toggle
SetCameraBrightness()Sends a CameraBrightnessTrigger. Reset to default sets brightness to 5000
MoveCameraHome()Sends a home position trigger. Returns lease data from callback
GuardTourToggle()Validates device supports autopan (IsAutopanEnabled), then sends a ToggleGuardTourTrigger to the Image Acquisition API
CloseLease()Sets the lease end time and calculates actual duration
LeaseCameraAfterMove()Called by the callback endpoint. Validates the camera response, patches PTZ/focus/brightness state in Cosmos DB, creates a lease + movement record in SQL Server

Validation Rules:

  • Camera Access: The user's Entra ID is checked against the UserCameras SQL table. Users must either have AllCameras access or have the specific camera in their allowed list (excluding any excluded cameras).
  • Device Type: Only devices with CameraType == "RealCam" and IsAlertCaActive == true can be controlled.
  • Guard Tour: Additionally requires IsAutopanEnabled == true on the device.

Integration with Image Acquisition API:

  • All movement triggers are sent as HTTP POST requests to the Image Acquisition API
  • Requests include an x-api-key header from FunctionApiKeyOptions
  • The Image Acquisition API processes the movement and calls back to /functionendpoints/leaseCameraAfterMove

Lease & Movement Defaults:

  • Default lease duration: 60 seconds
  • Default movement expiration: 60 minutes from the movement time
  • If the current expiration is already further in the future, it is not shortened

ESRI Sync: After each movement, the camera's position is synced to ESRI Feature Layers by upserting a CameraLocationEntity with updated pan, tilt, zoom, movement expiration time, and the latest image timestamp.


ClipGenerationService

Generates animated GIFs from sequences of camera images stored in Azure Blob Storage.

Process:

  1. Receives a list of image metadata (single or panorama)
  2. Extracts blob URLs and downloads images from Azure Blob Storage
  3. Uses ImageMagick (Magick.NET) to create an animated GIF with 100ms frame delay per frame
  4. Uploads the generated GIF back to blob storage at {cameraId}/clips/{date}/{timestamp}.gif
  5. Returns the GIF bytes to the client

Supports both SingleImageMetadata and PanoImageMetadata inputs.


ValidatorService

Provides environment-based camera visibility validation by wrapping camera repository queries. Enforces rules about which cameras are visible in a given deployment environment.


AlertService

Handles alert message creation including map image upload. Registered from the Alert.CA.Infrastructure package and coordinated with ESRI-based and point-based subscription services.

For the full list of commands and queries, see the Command & Query Catalog.


Data Access

Repositories are provided by the AlertCAInfrastructure NuGet package and registered during startup:

Repository TypeStorageKey Repositories
Cosmos DBCamera state, leases, users, acquisition devicesICameraStaticRepository, ICameraOperationalRepository, IAcquisitionDeviceRepository, ICameraLeaseRepository
SQL ServerActivity logs, leases, camera accessICameraSqlRepository
Table StorageImage metadataISingleImageMetadataRepository
Blob StorageCamera imagesISingleImageStorageRepository
Microsoft GraphUser and group dataGraph service from infrastructure package

Custom Exceptions

ExceptionWhen Thrown
CameraConfigNotFoundExceptionCamera configuration not found in any data store
CameraMovementInvalidResponseExceptionImage Acquisition API returns errors or null position for a home move
InvalidCameraExceptionCamera ID doesn't exist or isn't valid
InvalidClaimsExceptionRequired Entra ID claim (oid, name, preferred_username) is missing from the JWT
InvalidMovementExtensionExceptionMovement expiration extension request is invalid
InvalidTimeRangeExceptionStart time is after end time
MissingCameraIdExceptionCamera ID was not provided in the request
TimelapseExceedsRangeExceptionTimelapse request exceeds the 6-hour maximum range

Validators

TimelapseValidator

Validates timelapse and panorama requests:

  • Camera ID must not be empty
  • startTime must be before endTime
  • Time range must not exceed 6 hours

CameraValidator

Validates camera-specific business rules for operations.


Utilities

UtilityPurpose
CoordinateExtensionsPan/tilt/zoom coordinate math and conversions
RequestUtilityGenerates overlay text for camera movement triggers
ImageUtilityMethodsMaps table storage entities to image metadata DTOs
CameraUtilityMethodsComposes camera metadata from multiple data sources (Cosmos, SQL, Table Storage)
CodeGeneratorGenerates unique identifiers for shared views and other entities
CommonExtensionsGeneral-purpose extension methods
ExpressionExtensionsExpression tree utilities for dynamic queries