Overview
MetadataBinder is the central class in the UI Metadata Framework that holds mappings between server-side types and client-side UI components. It provides APIs to simplify the creation of metadata and manages collections of input and output field bindings.
Namespace
UiMetadataFramework.Core.Binding
Properties
Service provider instance used for dependency injection when instantiating components and factories.
Collection of input field bindings. Use this to access and register input components.
Collection of output field bindings. Use this to access and register output components.
Constructors
Default Constructor
Initializes a new instance using DependencyInjectionContainer.Default as the service provider.
Constructor with Service Provider
public MetadataBinder(
IServiceProvider container,
MetadataBinderConfiguration? config = null)
Initializes a new instance with a custom service provider and optional configuration.
Service provider for dependency injection.
config
MetadataBinderConfiguration?
Optional configuration. If null, default configuration will be used.
Methods
RegisterAssembly
public void RegisterAssembly(Assembly assembly)
Scans an assembly for implementations of ComponentBinding and registers them. This method automatically discovers and registers all component bindings defined in the assembly.
Assembly to scan for component bindings.
public static string GetFormId(Type formType)
Retrives the unique identifier for a form. If the FormAttribute.Id property is specified, it will be used; otherwise, the fully qualified type name is returned.
Type representing the form.
Returns: Unique identifier for the form.
Throws: BindingException if the type does not have a FormAttribute.
GetFieldCollection
public FieldCollection GetFieldCollection(string category)
Retrieves the field collection for a specific category.
Field category (see ComponentCategories).
Returns: FieldCollection for the specified category.
Throws: BindingException if no field collection exists for the category.
GetBaseComponent<TAttribute>
public static Type? GetBaseComponent<TAttribute>(Type component)
where TAttribute : ComponentAttribute
Looks into the inheritance chain of a component and finds the class which has the specified attribute applied directly to it. This is useful for working with derived components.
Component class or a class deriving from a component class.
Returns: Class that has the attribute applied directly to it, or null if not found.
Throws: BindingException if multi-level derived components are detected.
ComponentCategories
Static class containing standard component category constants:
public static class ComponentCategories
{
public const string Input = "input";
public const string Output = "output";
}
Usage Examples
Basic Initialization
using UiMetadataFramework.Core.Binding;
// Create a metadata binder with default settings
var binder = new MetadataBinder();
// Register assemblies containing component bindings
binder.RegisterAssembly(typeof(BasicComponents).Assembly);
Registering Custom Components
// Define a custom component binding
public class CustomTextInputBinding : ComponentBinding
{
public CustomTextInputBinding()
: base(
category: MetadataBinder.ComponentCategories.Input,
serverType: typeof(string),
componentType: "custom-text",
metadataFactory: null)
{
}
}
// Register the assembly containing the binding
var binder = new MetadataBinder();
binder.RegisterAssembly(typeof(CustomTextInputBinding).Assembly);
[Form(Id = "user-profile", Label = "User Profile")]
public class UserProfileForm
{
[InputField(Required = true)]
public string FirstName { get; set; }
[InputField(Required = true)]
public string LastName { get; set; }
[InputField(Required = true)]
public string Email { get; set; }
}
public class UserProfileResponse
{
[OutputField(Label = "Profile Updated")]
public string Message { get; set; }
}
// Generate metadata for the form
var binder = new MetadataBinder();
binder.RegisterAssembly(typeof(UserProfileForm).Assembly);
var formMetadata = binder.BuildForm<UserProfileForm, UserProfileResponse, object>();
// Get form ID
var formId = MetadataBinder.GetFormId(typeof(UserProfileForm));
Console.WriteLine(formId); // Output: "user-profile"
[Form(Id = "contact")]
public class ContactForm
{
[InputField(Label = "Name", Required = true, OrderIndex = 1)]
public string Name { get; set; }
[InputField(Label = "Email", Required = true, OrderIndex = 2)]
public string Email { get; set; }
[InputField(Label = "Message", Required = true, OrderIndex = 3)]
public string Message { get; set; }
}
var binder = new MetadataBinder();
binder.RegisterAssembly(typeof(ContactForm).Assembly);
// Get input fields for the form
var inputFields = binder.Inputs.GetFields(typeof(ContactForm));
foreach (var field in inputFields)
{
Console.WriteLine($"Field: {field.Id}, Type: {field.Type}");
}
Using Custom Service Provider
using Microsoft.Extensions.DependencyInjection;
// Set up dependency injection
var services = new ServiceCollection();
services.AddSingleton<IMyCustomService, MyCustomService>();
var serviceProvider = services.BuildServiceProvider();
// Create binder with custom service provider
var binder = new MetadataBinder(serviceProvider);
binder.RegisterAssembly(typeof(MyForms).Assembly);
Working with Field Collections
var binder = new MetadataBinder();
binder.RegisterAssembly(typeof(MyComponents).Assembly);
// Get input field collection
var inputCollection = binder.GetFieldCollection(MetadataBinder.ComponentCategories.Input);
// Get output field collection
var outputCollection = binder.GetFieldCollection(MetadataBinder.ComponentCategories.Output);
// Or access directly
var inputs = binder.Inputs;
var outputs = binder.Outputs;
Finding Base Components
[Component("base-dropdown")]
public class BaseDropdown<T>
{
public T Value { get; set; }
public IEnumerable<T> Options { get; set; }
}
public class CountryDropdown : BaseDropdown<string>
{
// Additional properties specific to country selection
}
// Find the base component
var baseComponent = MetadataBinder.GetBaseComponent<ComponentAttribute>(typeof(CountryDropdown));
Console.WriteLine(baseComponent.Name); // Output: "BaseDropdown`1"
using UiMetadataFramework.Core.Binding;
using System.Reflection;
public class FormMetadataService
{
private readonly MetadataBinder binder;
public FormMetadataService(IServiceProvider serviceProvider)
{
binder = new MetadataBinder(serviceProvider);
// Register all assemblies with form definitions
binder.RegisterAssembly(Assembly.GetExecutingAssembly());
}
public FormMetadata GetFormMetadata<TRequest, TResponse>()
{
return binder.BuildForm<TRequest, TResponse, object>();
}
public string GetFormId<TRequest>()
{
return MetadataBinder.GetFormId(typeof(TRequest));
}
public IEnumerable<FieldMetadata> GetInputFields<TRequest>()
{
return binder.Inputs.GetFields(typeof(TRequest));
}
public IEnumerable<FieldMetadata> GetOutputFields<TResponse>()
{
return binder.Outputs.GetFields(typeof(TResponse));
}
}
// Usage
var service = new FormMetadataService(serviceProvider);
var metadata = service.GetFormMetadata<LoginForm, LoginResponse>();
var formId = service.GetFormId<LoginForm>();
Registering Multiple Assemblies
var binder = new MetadataBinder();
// Register multiple assemblies
binder.RegisterAssembly(typeof(CoreComponents).Assembly);
binder.RegisterAssembly(typeof(CustomComponents).Assembly);
binder.RegisterAssembly(typeof(ThirdPartyComponents).Assembly);
// Registering the same assembly multiple times is safe - it will be ignored
binder.RegisterAssembly(typeof(CoreComponents).Assembly); // No effect
Notes
- The
MetadataBinder is thread-safe for registration operations.
- Assemblies are only registered once, even if
RegisterAssembly() is called multiple times with the same assembly.
- Component bindings are automatically discovered from assemblies - you don’t need to manually register each binding.
- The binder supports dependency injection through the
Container property.
- Form IDs must be unique across your application.
See Also