Skip to main content

Introduction

UI Metadata Framework is a metadata-driven approach to building user interfaces. Instead of manually creating UI components, you define C# classes with attributes, and the framework automatically generates metadata that client applications use to render the interface.

Core Architecture

The framework follows a client-server protocol with metadata as the contract between them:
C# Classes → Reflection → Metadata → JSON → Client → UI Rendering

The Flow

  1. Server-Side Definition: You define forms using C# classes decorated with attributes
  2. Metadata Generation: The MetadataBinder uses reflection to scan your classes and generate metadata
  3. JSON Serialization: Metadata is serialized to JSON and sent to the client
  4. Client Rendering: The client reads the metadata and dynamically renders the appropriate UI components
The framework is client-agnostic. Any client that can parse JSON and render components based on metadata can work with the framework.

Three Core Concepts

The framework is built around three fundamental concepts:

1. Forms

Forms are the top-level containers that define complete user interactions. Each form has:
  • Input fields (what the user provides)
  • Output fields (what the server returns)
  • Metadata properties (label, behavior, etc.)
[Form(Label = "User Registration", PostOnLoad = false)]
public class RegisterUser : Form<RegisterUser.Request, RegisterUser.Response>
{
    public class Request : IRequest<Response>
    {
        [InputField(Label = "Email", Required = true)]
        public string Email { get; set; }
    }

    public class Response : FormResponse
    {
        [OutputField(Label = "User ID")]
        public int UserId { get; set; }
    }
}
Learn more in Forms.

2. Input Fields

Input fields represent data that users provide. They are decorated with InputFieldAttribute and support validation, ordering, and visibility control.
[InputField(Label = "Date of Birth", Required = true, OrderIndex = 2)]
public DateTime DateOfBirth { get; set; }

[InputField(Hidden = true)]
public int InternalId { get; set; }
Learn more in Input Fields.

3. Output Fields

Output fields represent data returned from the server. They are decorated with OutputFieldAttribute and control how responses are displayed.
[OutputField(Label = "Full Name", OrderIndex = 1)]
public string FullName { get; set; }

[OutputField(Hidden = true)]
public decimal InternalScore { get; set; }
Learn more in Output Fields.

Component Binding System

The framework maps C# types to UI components using the ComponentBinding system:
public class StringInputComponentBinding : ComponentBinding
{
    public StringInputComponentBinding() : base(
        MetadataBinder.ComponentCategories.Input,
        serverType: typeof(string),
        componentType: "text",
        metadataFactory: null)
    {
    }
}
This binding tells the framework:
  • string properties → render as "text" input components
  • The component belongs to the Input category
  • No custom metadata factory is needed
You can create custom bindings to map any C# type to any client-side component. This makes the framework highly extensible.

Metadata Binder

The MetadataBinder is the heart of the framework. It:
  1. Registers assemblies containing forms and components
  2. Scans for attributes using reflection
  3. Builds metadata from the attributes and type information
  4. Manages bindings between server types and client components
var binder = new MetadataBinder();

// Register assemblies containing components
binder.RegisterAssembly(typeof(StringInputComponentBinding).Assembly);

// The binder now has:
// - Input field collection (binder.Inputs)
// - Output field collection (binder.Outputs)
// - Component bindings for all registered types
Learn more in Metadata Binding.

Metadata Categories

The framework organizes components into categories:
public static class ComponentCategories
{
    public const string Output = "output";
    public const string Input = "input";
}
Each category has its own:
  • FieldCollection: Manages component bindings for that category
  • Attribute types: InputFieldAttribute vs OutputFieldAttribute
  • Metadata factories: Generate category-specific metadata

Key Benefits

Type Safety

Define your UI contract in strongly-typed C# with compile-time validation

Client Agnostic

Support multiple client implementations (web, mobile, desktop) from a single backend

Reduced Boilerplate

Attributes replace repetitive UI code - the framework handles the rest

Extensible

Create custom attributes, components, and metadata factories for any use case

Form Lifecycle

Understanding the lifecycle helps you leverage the framework effectively:
  1. Registration: Forms are registered with FormRegister
  2. Metadata Request: Client requests form metadata by form ID
  3. Metadata Response: Server returns JSON metadata describing the form
  4. User Interaction: Client renders UI and user fills in input fields
  5. Form Submission: Client sends input data to server
  6. Processing: Server executes form handler logic
  7. Response: Server returns output data with response metadata
  8. Rendering: Client renders the response based on metadata
Use PostOnLoad = true on the FormAttribute to auto-submit forms when they load. This is perfect for displaying reports or read-only data.

Next Steps

Forms

Deep dive into form creation and configuration

Input Fields

Learn about input field attributes and validation

Output Fields

Understand output field configuration and rendering

Metadata Binding

Explore how reflection and binding work

Build docs developers (and LLMs) love