Examples - Runtime Surfaces
Practical examples for UnitOfWork, DataView, Caching, Proxy, Rules, Services, and Migration
Table of Contents
UnitOfWork Examples
Basic CRUD
using var uow = new UnitofWork<Customer>(editor, "MyDB", "Customers", "Id");
// Create
uow.New();
uow.CurrentItem.Name = "John Doe";
uow.CurrentItem.Email = "john@example.com";
// Read
var all = await uow.Get();
var customer = uow.Get("123");
// Update
customer.Name = "Jane Doe";
uow.Update(customer);
// Delete
uow.Delete(customer);
// Commit
var result = await uow.Commit();
if (result.Flag != Errors.Ok)
Console.WriteLine(result.Message);
Undo/Redo
uow.IsUndoEnabled = true;
uow.MaxUndoDepth = 50;
// Make changes
customer.Name = "Changed";
// Undo
uow.Undo(); // Name reverts to original
// Redo
uow.Redo(); // Name goes back to "Changed"
Validation
uow.IsAutoValidateEnabled = true;
uow.BlockCommitOnValidationError = true;
var result = uow.ValidateAll();
if (!result.IsValid)
{
foreach (var error in result.Errors)
Console.WriteLine($"{error.PropertyName}: {error.Message}");
}
DataView Examples
Create Federated View
var viewConnection = new DataViewConnection(editor);
viewConnection.AddConnection("CustomersDB", customerDs);
viewConnection.AddConnection("OrdersDB", ordersDs);
var viewDs = new DataViewDataSource("CustomerOrders", viewConnection, editor);
// Define entities
viewDs.AddEntity(new EntityStructure
{
EntityName = "CustomerView",
DataSourceID = "CustomersDB",
EntityID = "Customers"
});
viewDs.AddEntity(new EntityStructure
{
EntityName = "OrderView",
DataSourceID = "OrdersDB",
EntityID = "Orders"
});
// Define join
var joinGraph = new JoinGraph();
joinGraph.AddJoin(new EntityJoin
{
LeftEntity = "CustomerView",
RightEntity = "OrderView",
LeftField = "CustomerId",
RightField = "CustomerId",
JoinType = JoinType.Left
});
viewDs.SetJoinGraph(joinGraph);
// Query
var results = viewDs.GetEntity("CustomerView", new List<AppFilter>());
Caching Examples
Initialize Cache
// Simple in-memory cache
CacheManager.Initialize();
// Redis with fallback
CacheManager.Initialize(
new CacheConfiguration
{
DefaultExpiry = TimeSpan.FromMinutes(30),
MaxItems = 10000,
Redis = new RedisConfiguration
{
ConnectionString = "localhost:6379"
}
},
primaryProvider: CacheProviderType.Redis,
fallbackProvider: CacheProviderType.InMemory);
// Store data
await CacheManager.SetAsync("user:123", userData, TimeSpan.FromMinutes(30));
// Retrieve
var user = await CacheManager.GetAsync<UserData>("user:123");
// GetOrCreate
var data = await CacheManager.GetOrCreateAsync("expensive:key", async () =>
{
return await ComputeExpensiveOperation();
}, TimeSpan.FromHours(1));
Tagged Caching
// Tag items
await CacheManager.SetWithTagsAsync("item:1", data,
new[] { "user", "recent" });
// Invalidate by tag
await CacheManager.RemoveByTagAsync("user");
Proxy DataSource Examples
Basic Failover
var proxy = new ProxyDataSource(editor,
new List<string> { "PrimaryDB", "Replica1", "Replica2" });
// Query (automatically routes to healthy target)
var data = proxy.GetEntity("Customers", new List<AppFilter>());
// Failover event
proxy.OnFailover += (s, e) =>
Console.WriteLine($"Failover: {e.FromDataSource} -> {e.ToDataSource}");
Circuit Breaker
proxy.SetFailureThreshold(5);
proxy.SetCircuitResetTimeout(TimeSpan.FromMinutes(5));
// Check metrics
var metrics = proxy.GetMetrics();
Console.WriteLine($"Success rate: {metrics.SuccessRate:F1}%");
Console.WriteLine($"Avg latency: {metrics.AverageResponseTime}ms");
Rules Engine Examples
Define and Execute Rules
var engine = new RulesEngine(editor);
// Register rules
engine.RegisterRule("ValidateAge", "Age >= 18 AND Age <= 120");
engine.RegisterRule("ComputeDiscount", "Price * (1 - DiscountRate)");
// Execute
var result = engine.Execute("ValidateAge", new { Age = 25 });
if (result.Success)
Console.WriteLine("Age is valid");
// Execute with context
var context = new RuleContext
{
Data = customer,
Parameters = new Dictionary<string, object>
{
["MaxDiscount"] = 0.20
}
};
var discount = engine.Execute("ComputeDiscount", context);
Built-in Rules
// Data quality
var dqRule = new IsNotNullRule { FieldName = "Email" };
var result = dqRule.Execute(customer);
// Date operations
var dateRule = new DateDiffRule
{
FieldName = "BirthDate",
TargetDate = DateTime.Now,
OutputField = "Age"
};
// Transform
var transformRule = new StringReplaceRule
{
FieldName = "Phone",
Pattern = "-",
Replacement = ""
};
Service Registration Examples
Corrected (2026). These samples previously used
AddBeepForDesktop / AddBeepForWeb /
AddBeepForBlazorServer and app.UseBeepForWeb(). None of those
methods exist — nor do the MaxConnectionPoolSize and
EnableSignalRSupport options they set. The real entry point is
AddBeepServices(); pick the lifetime with AsSingleton() or
AsScoped().
Desktop Application
var builder = Host.CreateApplicationBuilder();
IBeepService beepService = builder.Services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory)
.WithAppRepo("MyDesktopApp")
.WithConfigType(BeepConfigType.Application)
.WithAssemblyLoading()
.WithMapping()
.AsSingleton() // singleton for desktop
.Build();
var host = builder.Build();
// Load plugins with progress reporting
var progress = new Progress<PassedArgs>(args =>
Console.WriteLine($"Loading: {args.Messege}"));
beepService.LoadAssemblies(progress);
Build() returns the IBeepService directly, so you do not need to
resolve it from the provider afterwards. Note PassedArgs.Messege is spelled that
way in the contract.
Web API
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBeepServices()
.WithDirectory(Path.Combine(AppContext.BaseDirectory, "Beep"))
.WithAppRepo("MyWebApi")
.WithConfigType(BeepConfigType.Application)
.AsScoped() // scoped for web
.Build();
var app = builder.Build();
// No UseBeepForWeb() middleware exists - nothing further to wire up.
Blazor Server
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory)
.WithAppRepo("MyBlazorApp")
.WithConfigType(BeepConfigType.Application)
.AsScoped() // scoped for Blazor Server
.Build();
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
With a scoped registration the components are resolved by key — e.g.
[Inject] IDMEEditor Editor requires
GetRequiredKeyedService<IDMEEditor>("Editor") semantics. See
BeepService → DI Service Registration
for why the singleton and scoped paths differ.
Migration Examples
Basic Migration
var migrationManager = new MigrationManager(editor);
// Create migration
var migration = new Migration
{
Name = "Add Customer Table",
Version = "1.0.0",
Up = async () =>
{
var ds = editor.GetDataSource("MyDB");
await ds.ExecuteSql(@"
CREATE TABLE Customers (
Id INTEGER PRIMARY KEY,
Name TEXT NOT NULL,
Email TEXT
)");
},
Down = async () =>
{
var ds = editor.GetDataSource("MyDB");
await ds.ExecuteSql("DROP TABLE Customers");
}
};
// Apply
await migrationManager.ApplyAsync(migration);
Migration with Validation
// Validate before applying
var validation = await migrationManager.ValidateAsync(migration);
if (!validation.IsValid)
{
foreach (var error in validation.Errors)
Console.WriteLine(error);
return;
}
// Apply with rollback on failure
await migrationManager.ApplyWithRollbackAsync(migration);