UniversalBFF Architecture
Abstract
UniversalBFF is a modular ASP.NET Core backend-for-frontend for U-Shell applications. Its architecture centers on discovering modules, collecting their frontend and backend registrations, exposing U-Shell portfolio metadata, and hosting both static frontend assets and UJMW-based backend service endpoints.
The system follows a capability-first model: product code should compose reusable standards rather than rebuilding discovery, token handling, logging, remote communication, or portfolio modeling infrastructure locally.
High-Level Structure
The solution is organized into shared source projects and framework-specific wrapper projects.
| Area | Role |
|---|---|
UniversalBFF |
Core composition model, application singleton, module loading, module registrar, portfolio service implementation. |
UniversalBFF.ModuleContract |
Contracts exposed to modules, including frontend module providers, backend service providers, registrars, product definitions, and static hosting abstractions. |
UniversalBFF.AspNetCore |
ASP.NET Core integration layer, service registration, middleware/pipeline setup, UJMW controller wiring, UShell and static frontend hosting. |
UniversalBFF.AspHost |
Executable ASP.NET Core host projects for direct web hosting. |
UniversalBFF.WebViewHost |
WinForms/WebView2 host that runs the ASP.NET Core pipeline in-memory and bridges WebView requests into it. |
UniversalBFF.OobModules.* |
Out-of-box module projects. User Management is the most complete current module; other modules are currently skeleton or model-oriented areas. |
UniversalBFF.Tests |
MSTest-based test project, currently minimal. |
Core Runtime Flow
At startup, the ASP.NET Core integration creates the composition objects and loads modules:
- SmartStandards Logging is registered.
- Optional plugin assembly resolve paths can be added through configuration.
- Instance discovery ambience is connected to a shared
InstanceDiscoveryContext. - Optional providers such as
IPortfolioSecurityProviderare discovered. - A product definition provider is selected, with a file-based fallback when discovery does not provide one.
- An ASP.NET-specific
ModuleRegistraris created. ModuleLoader.Load()discovers module providers and invokes them.- The registrar is added to dependency injection as portfolio service and module registrar.
- U-Shell portfolio controllers, MVC controllers, UJMW controllers, authentication, authorization, Swagger support, and static frontend hosting are configured.
- The ASP.NET Core pipeline runs with static hosting, routing, CORS, authentication, authorization, and controller mapping.
ComponentDiscovery Role
BffApplication owns a central AssemblyIndexer and lazy TypeIndexer. These are exposed as discoverable instances and are used to find module provider types.
ModuleLoader queries the type indexer for:
IFrontendModuleProviderIBackendServiceProvider
Each discovered frontend provider receives an IFrontendModuleRegistrar. Each discovered backend provider receives an IBackendServiceRegistrar. Provider instances are currently created through Activator.CreateInstance, so discoverable providers are expected to be instantiable in that model unless this lifecycle is changed later.
Module Contract Layer
The module contract layer defines the extension points modules use to integrate with the BFF:
IFrontendModuleProviderregisters frontend/module metadata.IBackendServiceProviderregisters backend services.IFrontendModuleRegistraraccepts UShell module descriptions and frontend extension registrations.IBackendServiceRegistraraccepts backend endpoint registrations.IStaticHostingRegistrarabstracts static frontend mount registration.IProductDefinitionProvidersupplies product definitions that drive portfolio composition.
This contract layer is intentionally small. Modules should not need to know the internal ASP.NET Core hosting details to register their capabilities.
Module Registrar
ModuleRegistrar is the central composition object. It collects registrations and implements portfolio-facing behavior.
Its responsibilities include:
- keeping the configured application base URL,
- collecting
ModuleDescriptionregistrations, - collecting delayed static frontend registrations,
- registering embedded or externally hosted frontend extensions,
- exposing backend registration APIs implemented by host-specific subclasses,
- composing portfolio descriptions from product definitions and registered modules,
- integrating security, tenancy, and application-scope information where available.
AspModuleRegistrar provides the ASP.NET Core-specific implementation for UJMW endpoint registration. It maps a typed service contract to a dynamic UJMW controller route and registers a service factory in dependency injection.
UJMW Backend Endpoint Architecture
UniversalBFF uses UJMW dynamic controllers for typed HTTP/RPC-style service contracts.
The default route shape is:
{moduleScopingKey}/api/v{apiV}/{endpointAlias}
For example, the User Management module registers contracts under the oob-usrmgmt module scope. The route is built by AspModuleRegistrar.BuildEndpointRoute and by the dynamic controller options in AspModuleRegistrar.RegisterUjmwServiceEndpoint.
Authentication header evaluation is delegated to SmartStandards AuthTokenHandling through UjmwHostConfiguration.AuthHeaderEvaluator = AccessTokenValidator.TryValidateHttpAuthHeader.
U-Shell And Portfolio Hosting
UniversalBFF hosts the U-Shell frontend bundle and exposes portfolio/module metadata consumed by U-Shell.
The main U-Shell frontend is registered as a static file provider at the application root. Portfolio data is exposed through UShell portfolio hosting support. Product definitions control which modules are enabled and which workspace is used as the landing workspace.
When explicit product definitions are missing, UniversalBFF currently creates a fallback/default product so the application remains runnable and can still expose available module metadata.
Static Frontend Hosting
Static hosting is configured through SetupSpaMultiHosting and StaticFileConsolidatorIApp.
The static hosting flow is:
- Create a consolidator for the ASP.NET Core application builder.
- Register the root U-Shell bundle.
- Register module frontend extensions collected by the module registrar.
- Apply the consolidated registrations.
The consolidator registers default files, static files, and SPA fallback endpoints for configured mounts. It throws on duplicate mounts to keep static hosting deterministic.
Embedded frontend assets are exposed through an embedded bundle file provider. Module authors must use the correct embedded resource namespace; these namespaces are case-sensitive and can be hard to diagnose when incorrect.
Host Models
ASP.NET Core Host
UniversalBFF.AspHost is the direct ASP.NET Core executable host. It builds a WebApplication, applies branch-specific configuration, supports launch profile URL selection, delegates service setup to the shared ASP.NET Core layer, and runs the application.
WebView Host
UniversalBFF.WebViewHost is a WinForms/WebView2 host. It creates an in-memory ASP.NET Core host through TestServer and bridges WebView2 requests into that pipeline. This allows the same shared BFF and U-Shell hosting logic to run in a local desktop-style shell.
Out-Of-Box Modules
User Management
UniversalBFF.OobModules.UserManagement is currently the most complete OOB module. It registers:
- user management service contracts,
- local credential management service contracts,
- a FUSE-fx repository endpoint for local credential entities,
- a UShell module description with administration workspace/usecases,
- embedded frontend assets under the
oob-usrmgmtmodule scope.
Diagnostics, FileStore, ModuleManager
These projects currently contain skeleton or commented module-provider examples. They indicate planned module areas but should not be documented as finished runtime modules until implemented.
Edmx
The EDMX module project contains an Entity Data Model and generated/model files. It is model-oriented and does not currently follow the same active module-provider pattern as User Management.
Configuration
Common host configuration includes:
| Setting | Purpose |
|---|---|
BaseUrl |
Application base path, usually /. |
PluginDir |
Optional directory added as assembly resolve path for plugin/module discovery. |
ProdMode |
Controls whether developer exception pages are enabled. |
EnableSwaggerUi |
Enables Swagger UI support where configured by the host packages. |
OAuthClientIdForSwaggerUi |
OAuth client ID used by Swagger UI configuration. |
OAuthAuthorizeUrlForSwaggerUi_ |
Optional authorization URL setting pattern for Swagger UI. |
OAuthScopeExpressionForSwaggerUi |
Optional Swagger UI OAuth scope expression. |
SmartStandards Logging is configured through the normal Logging:SmartStandards configuration section.
Cross-Cutting Capabilities
| Capability | Architectural Use |
|---|---|
| ComponentDiscovery | Locates module and backend service provider types. |
| UJMW | Exposes typed backend contracts as dynamic HTTP endpoints and can create dynamic clients. |
| SmartStandards AuthTokenHandling | Owns token evaluation and OAuth-related integration. |
| SmartAmbience | Provides ambient context flow and MVC middleware integration. |
| SmartStandards Logging | Provides runtime diagnostics and ASP.NET Core logging integration. |
| UShell | Defines frontend shell, portfolio descriptions, module metadata, commands, workspaces, and usecases. |
| FUSE-fx | Provides repository abstractions used by data-oriented module services. |
Current Architectural Limitations
Some areas are intentionally documented as incomplete current state:
RegisterServerCommandsis declared but not implemented.RegisterBackendExtension<TServiceContract>exists but does not currently add meaningful behavior.- Some portfolio index/description code still returns default values and contains TODO markers.
- Some security integration paths are currently bypassed or incomplete.
- Several OOB module projects are skeletons.
- Test coverage is very limited.
Future changes should either complete these areas or keep them listed as ideas rather than treating them as active documented behavior.