πŸš€ Fractal Platform BaseApplication Guide

Complete guide to building applications with BaseApplication class

0. Overview

What is BaseApplication?

BaseApplication is the foundation class for building applications in Fractal Platform. When you create your application, you inherit from BaseApplication and override its event handler methods to implement your business logic.

var power = GetPowerInfo();

Log($"Battery: {power.BatteryPercent}%");
Log($"Plugged in: {power.IsOnline}");
Log($"Time remaining: {power.BatteryLifeTime}");

Properties Reference

Property Type Description
SessionID Guid Unique identifier for current session
Client FractalPlatformClient Database client for queries
REST RESTClient HTTP client for REST APIs
AI AIClient AI service client
Context Context Current execution context
User User Current user information
Name string Application name (class name without "Application")
DatabaseName string Default database name
HasDatabase bool Whether database is configured

Complete Example Application

Here's a complete example showing many features together:

public class TaskManagerApplication : BaseApplication
{
    public override void OnStart()
    {
        // Check if user is logged in
        if (User.IsGuest)
        {
            // Show login form
            FirstDocOf("LoginForm")
                .OpenForm("Login");
        }
        else
        {
            // Show main task list
            ShowTaskList();
        }
    }

    private void ShowTaskList()
    {
        DocsWhere("Tasks", new { OwnerID = User.ID })
            .OrderBy("{'DueDate':$}")
            .OpenForm("My Tasks");
    }

    public override bool OnEventDimension(EventInfo info)
    {
        switch (info.Action)
        {
            case "AddTask":
                CreateNewDocFor("TaskTemplate", "Tasks")
                    .OpenForm("New Task", result =>
                    {
                        if (result.Result)
                        {
                            RefreshForm();
                            MessageBox("Task created!");
                        }
                    });
                return true;

            case "CompleteTask":
                ModifyDocsWhere("Tasks", info.DocID)
                    .Update("{'Status':'Completed','CompletedDate':@Date}", 
                              GetNowDate());
                RefreshForm();
                return true;

            case "DeleteTask":
                MessageBox(
                    "Delete this task?",
                    MessageBoxButtonType.YesNo,
                    result =>
                    {
                        if (result.Result)
                        {
                            DelDoc("Tasks", info.DocID);
                            CloseForm();
                        }
                    });
                return true;

            case "Logout":
                ResetToGuest();
                CloseAllForms();
                OnStart();
                return true;
        }

        return false;
    }

    public override bool OnChangeDimension(ChangeInfo info)
    {
        // Auto-calculate priority based on due date
        if (info.ChangeName == "DueDate")
        {
            var dueDate = info.AfterValue.ToDateTime();
            var daysUntilDue = (dueDate - GetNowDate()).Days;

            string priority = daysUntilDue < 1 ? "Urgent" :
                               daysUntilDue < 7 ? "High" :
                               "Normal";

            ModifyDocsWhere("Tasks", info.DocID)
                .Update(DQL("{'Priority':@Priority}", priority));

            RefreshForm();
            return true;
        }

        return false;
    }

    public override object OnComputedDimension(ComputedInfo info)
    {
        if (info.Variable == "DaysRemaining")
        {
            var dueDate = info.FindFirstDateTimeValue("DueDate");
            var days = (dueDate - GetNowDate()).Days;
            
            return days > 0 ? $"{days} days left" : "Overdue";
        }

        return null;
    }

    public override bool OnSecurityDimension(SecurityInfo info)
    {
        // Users can only modify their own tasks
        if (info.OperationType == OperationType.Update ||
            info.OperationType == OperationType.Delete)
        {
            var ownerId = info.FindFirstValue("OwnerID");
            return ownerId == User.ID.ToString();
        }

        return true;
    }

    public override bool OnTimerDimension(TimerInfo info)
    {
        // Check for overdue tasks every minute
        if (info.Action == "CheckOverdue")
        {
            var overdueTasks = DocsWhere("Tasks", 
                "{'DueDate':Less(@Now),'Status':'Active'}",
                GetNowDate())
                .Count();

            if (overdueTasks > 0)
            {
                Log($"Warning: {overdueTasks} overdue tasks");
            }

            return true;
        }

        return false;
    }
}
πŸ’‘ Best Practices Summary:
  • Keep OnStart() lightweight - defer heavy operations
  • Return true from event handlers when you handle the event
  • Use transactions for multi-step operations
  • Cache expensive queries with UseCache()
  • Validate user input in OnChangeDimension()
  • Implement security checks in OnSecurityDimension()
  • Use Log() for debugging and monitoring
  • Provide user feedback with MessageBox() and RefreshForm()
⚠️ Common Pitfalls:
  • Forgetting to return true after handling events (causes event to propagate)
  • Not refreshing forms after updates (users won't see changes)
  • Performing heavy operations in OnStart() (slow startup)
  • Not checking user permissions before operations
  • Forgetting to commit or rollback transactions

1. Initialization & Setup

OnStart() - Application Initialization

This is the first method called when your application starts. Use it to initialize data, load settings, or show the initial form.

public virtual void OnStart()
public override void OnStart()
{
    // Load initial data
    var users = DocsOf("Users")
        .Select<User>();

    // Show welcome message
    MessageBox("Welcome to the application!");

    // Open main form
    FirstDocOf("MainMenu")
        .OpenForm("Main Menu");
}
πŸ’‘ Best Practice: Keep OnStart() lightweight. Load only essential data and defer heavy operations until they're needed.

Setting User Preferences

SetUserLanguage()

Change the application language for the current user.

SetUserLanguage("en"); // English
SetUserLanguage("uk"); // Ukrainian

SetUserTheme()

Change the visual theme.

SetUserTheme(ThemeType.Dark);
SetUserTheme(ThemeType.Light);

2. Event Handlers (On* Methods)

OnEventDimension() - Handle User Actions

This is the most important event handler. It's called when users click buttons, select items, or trigger any action in your forms.

public virtual bool OnEventDimension(EventInfo info)
public override bool OnEventDimension(EventInfo info)
{
    // Get the action name
    var action = info.Action;

    if (action == "SaveUser")
    {
        // Get values from the form
        var name = info.FindFirstValue("Name");
        var age = info.FindFirstIntValue("Age");

        // Save to database
        AddDoc("Users", new { Name = name, Age = age });

        MessageBox("User saved successfully!");

        return true; // Event was handled
    }

    if (action == "DeleteUser")
    {
        var userId = info.DocID;
        
        DelDoc("Users", userId);
        
        CloseForm();
        
        return true;
    }

    return false; // Event not handled, continue to other handlers
}
πŸ“Œ EventInfo Properties:
  • Action: Name of the action (button name, menu item)
  • Collection: The collection being displayed
  • DocID: ID of the current document
  • AttrPath: Path to the field that triggered the event
  • EventType: Type of event (Click, Change, etc.)

Finding Values in EventInfo

// Get single values
string name = info.FindFirstValue("Name");
int age = info.FindFirstIntValue("Age");
bool isActive = info.FindFirstBoolValue("IsActive");
double price = info.FindFirstDoubleValue("Price");
DateTime date = info.FindFirstDateTimeValue("CreatedDate");

// Get multiple values at once
var values = info.FindFirstValues("Name", "Email", "Phone");

OnChangeDimension() - Handle Field Changes

Called when a field value changes in a form. Use this to implement validation, calculations, or dynamic behavior.

public virtual bool OnChangeDimension(ChangeInfo info)
public override bool OnChangeDimension(ChangeInfo info)
{
    // ChangeName is the field that changed
    if (info.ChangeName == "Quantity")
    {
        var quantity = info.AfterValue.ToInt();
        var price = info.FindFirstDoubleValue("Price");
        
        // Calculate total automatically
        var total = quantity * price;
        
        ModifyDocsWhere("Orders", info.DocID)
            .Update("{'Total':@Total}", total);
        
        RefreshForm();
        
        return true;
    }

    if (info.ChangeName == "Email")
    {
        var email = info.AfterValue.ToString();
        
        // Validate email format
        if (!email.Contains("@"))
        {
            MessageBox("Please enter a valid email address");
            return false; // Reject the change
        }
    }

    return false;
}
πŸ“Œ ChangeInfo Properties:
  • ChangeName: Name of the field that changed
  • BeforeValue: Previous value
  • AfterValue: New value
  • ChangeType: Type of change (Update, Insert, Delete)

OnOpenForm() - Form Opening Event

Called before a form opens. Use it to prepare data or prevent form opening.

public virtual bool OnOpenForm(FormInfo info)
public override bool OnOpenForm(FormInfo info)
{
    // Check if user has permission
    if (info.Collection.Name == "AdminPanel")
    {
        if (!User.IsAdmin)
        {
            MessageBox("Access denied. Admin rights required.");
            return false; // Prevent opening
        }
    }

    // Load related data before showing form
    if (info.Collection.Name == "OrderDetails")
    {
        var orderId = info.DocID;
        // Prepare order items, customer info, etc.
    }

    return true; // Allow form to open
}

OnCloseForm() - Form Closing Event

Called before a form closes. Use it to save changes or confirm closing.

public virtual bool OnCloseForm(FormInfo info)
public override bool OnCloseForm(FormInfo info)
{
    // Ask for confirmation before closing
    var hasChanges = /* check if form has unsaved changes */ true;
    
    if (hasChanges)
    {
        MessageBox(
            "You have unsaved changes. Close anyway?",
            MessageBoxButtonType.YesNo,
            result =>
            {
                if (result.Result)
                {
                    CloseForm();
                }
            });
        
        return false; // Wait for user confirmation
    }

    return true; // Allow closing
}

OnComputedDimension() - Dynamic Field Values

Called when a computed field needs to be calculated. Use variables like @VariableName in your data.

public virtual object OnComputedDimension(ComputedInfo info)
public override object OnComputedDimension(ComputedInfo info)
{
    if (info.Variable == "FullName")
    {
        var firstName = info.FindFirstValue("FirstName");
        var lastName = info.FindFirstValue("LastName");
        
        return $"{firstName} {lastName}";
    }

    if (info.Variable == "Age")
    {
        var birthDate = info.FindFirstDateTimeValue("BirthDate");
        
        return DateTime.Now.Year - birthDate.Year;
    }

    if (info.Variable == "OrderTotal")
    {
        var quantity = info.FindFirstIntValue("Quantity");
        var price = info.FindFirstDoubleValue("Price");
        
        return quantity * price;
    }

    return null; // Variable not found
}

OnSecurityDimension() - Access Control

Control access to data based on user permissions.

public virtual bool OnSecurityDimension(SecurityInfo info)
public override bool OnSecurityDimension(SecurityInfo info)
{
    // Only admins can delete
    if (info.OperationType == OperationType.Delete)
    {
        return User.IsAdmin;
    }

    // Users can only edit their own data
    if (info.OperationType == OperationType.Update)
    {
        var ownerId = info.FindFirstValue("OwnerID");
        return ownerId == User.ID.ToString();
    }

    return true; // Allow by default
}

OnEnumDimension() - Dynamic Dropdown Lists

Provide options for dropdown lists dynamically.

public virtual List OnEnumDimension(EnumInfo info)
public override List<string> OnEnumDimension(EnumInfo info)
{
    if (info.Variable == "Countries")
    {
        return new List<string>
        {
            "USA", "Canada", "UK", "Germany"
        };
    }

    if (info.Variable == "Categories")
    {
        // Load from database
        var categories = DocsOf("Categories")
            .Select<string>("{'Name':$}");
        
        return categories.ToList();
    }

    return new List<string>();
}

OnTimerDimension() - Periodic Tasks

Called at regular intervals for background tasks.

public virtual bool OnTimerDimension(TimerInfo info)
public override bool OnTimerDimension(TimerInfo info)
{
    if (info.Action == "RefreshData")
    {
        // Refresh data every 30 seconds
        var newData = DocsOf("RealTimeData")
            .Select<DataItem>();
        
        RefreshForm();
        
        return true;
    }

    return false;
}

OnUploadFiles() - File Upload Handler

Handle file uploads from users.

public virtual bool OnUploadFiles(IEnumerable fileInfos)
public override bool OnUploadFiles(IEnumerable<UploadFileInfo> fileInfos)
{
    foreach (var fileInfo in fileInfos)
    {
        Log($"Uploaded: {fileInfo.FileName}");
        Log($"New name: {fileInfo.NewFileName}");
        Log($"Size: {fileInfo.Length} bytes");
        
        // Save file information to database
        AddDoc("Files", new
        {
            FileName = fileInfo.FileName,
            StoredName = fileInfo.NewFileName,
            Size = fileInfo.Length,
            UploadDate = GetNowDate()
        });
    }
    
    return true;
}

OnReceiveMessage() - Inter-Application Communication

Receive messages from other applications.

public virtual bool OnReceiveMessage(MessageInfo info)
public override bool OnReceiveMessage(MessageInfo info)
{
    Log($"Message from {info.FromAppName}: {info.Message}");
    
    // Handle message based on sender
    if (info.FromAppName == "NotificationService")
    {
        var notification = info.Message.ToString();
        MessageBox(notification);
    }
    
    return true;
}
πŸ’‘ Sending Messages: Use SendMessage() to communicate with other applications: SendMessage("OtherApp", myData)

OnAuthDimension() - Authentication Handler

Handle authentication events like login, logout, or registration.

public virtual bool OnAuthDimension(AuthInfo info)
public override bool OnAuthDimension(AuthInfo info)
{
    if (info.Action == "Login")
    {
        var username = info.FindFirstValue("Username");
        var password = info.FindFirstValue("Password");
        
        // Validate credentials
        var user = DocsWhere("Users", new 
        {
            Username = username,
            Password = password
        })
        .Select<User>()
        .FirstOrDefault();
        
        if (user != null)
        {
            // Set current user
            Context.User = user;
            MessageBox("Login successful!");
            return true;
        }
        else
        {
            MessageBox("Invalid credentials");
            return false;
        }
    }
    
    if (info.Action == "Register")
    {
        var username = info.FindFirstValue("Username");
        var email = info.FindFirstValue("Email");
        
        // Check if username exists
        var exists = DocsWhere("Users", new { Username = username })
            .Any();
        
        if (exists)
        {
            MessageBox("Username already taken");
            return false;
        }
        
        // Create new user
        AddDoc("Users", info.Collection.ToJson(info.DocID));
        MessageBox("Registration successful!");
        return true;
    }
    
    return false;
}
πŸ“Œ AuthInfo Properties:
  • Action: Auth action (Login, Register, Logout, etc.)
  • Collection: Form collection with user data
  • DocID: Document ID
  • AttrPath: Path to relevant field

OnCodeConfirmed() - Confirmation Code Handler

Called when a user confirms a code sent via SMS or email.

public virtual bool OnCodeConfirmed(CodeConfirmedInfo info)
public override bool OnCodeConfirmed(CodeConfirmedInfo info)
{
    if (info.EventType == "PhoneVerification")
    {
        // Mark phone as verified
        ModifyDocsWhere("Users", info.DocID)
            .Update("{'PhoneVerified':true}");
        
        MessageBox("Phone number verified successfully!");
        return true;
    }
    
    if (info.EventType == "EmailVerification")
    {
        // Mark email as verified
        ModifyDocsWhere("Users", info.DocID)
            .Update("{'EmailVerified':true}");
        
        MessageBox("Email verified successfully!");
        return true;
    }
    
    if (info.EventType == "TwoFactorAuth")
    {
        // Complete login process
        Log("Two-factor authentication successful");
        ShowTaskList();
        return true;
    }
    
    return false;
}
πŸ“Œ CodeConfirmedInfo Properties:
  • EventType: Type of verification event
  • Collection: Collection being verified
  • DocID: Document ID
  • Tag: Additional tag/context for verification

OnMenuDimension() - Menu Handler

Handle menu actions and customize menu behavior.

public virtual bool OnMenuDimension(MenuInfo info)
public override bool OnMenuDimension(MenuInfo info)
{
    if (info.Action == "Export")
    {
        // Export current data
        var data = info.Collection.ToJson(info.DocID);
        WriteFileText("export.json", data);
        MessageBox("Data exported successfully!");
        return true;
    }
    
    if (info.Action == "Print")
    {
        // Generate printable report
        Log("Generating print report...");
        return true;
    }
    
    return false;
}

OnMenuItemsDimension() - Dynamic Menu Items

Provide dynamic menu items based on context.

public virtual List OnMenuItemsDimension(MenuInfo info)
public override List<MenuItem> OnMenuItemsDimension(MenuInfo info)
{
    var menuItems = new List<MenuItem>();
    
    // Add different items based on user role
    if (User.IsAdmin)
    {
        menuItems.Add(new MenuItem 
        { 
            Name = "Admin Panel",
            Action = "OpenAdminPanel" 
        });
        
        menuItems.Add(new MenuItem 
        { 
            Name = "View Logs",
            Action = "ViewLogs" 
        });
    }
    
    // Add context-specific items
    if (info.Collection.Name == "Orders")
    {
        menuItems.Add(new MenuItem 
        { 
            Name = "Generate Invoice",
            Action = "GenerateInvoice" 
        });
    }
    
    return menuItems;
}

OnMovePageDimension() - Pagination Handler

Control pagination behavior when user navigates between pages.

public virtual bool OnMovePageDimension(MoveInfo info)
public override bool OnMovePageDimension(MoveInfo info)
{
    // Log page navigation
    Log($"Moving to page {info.CurrentPage}");
    
    // Check if user can navigate
    if (info.IsNextPage)
    {
        // Validate before moving to next page
        var isValid = ValidateCurrentPage(info);
        
        if (!isValid)
        {
            MessageBox("Please complete all required fields");
            return false; // Prevent navigation
        }
    }
    
    // Custom logic for specific pages
    if (info.CurrentPage == 3)
    {
        // Load additional data for page 3
        LoadPageData(3);
    }
    
    return true; // Allow navigation
}
πŸ“Œ MoveInfo Properties:
  • CurrentPage: Current page number
  • IsPrevPage: True if navigating to previous page
  • IsNextPage: True if navigating to next page
  • Collection: Collection being paginated
  • DocID: Current document ID
⚠️ Return Values: Return false from event handlers to prevent the action. Return true to allow it or indicate the event was handled successfully.

3. Query Methods

BaseApplication provides convenient wrapper methods for database operations. All these methods are documented in the Query Guide, but here's a quick reference.

Reading Data

DocsOf() - Get All Documents

// Get all users
var users = DocsOf("Users")
    .Select<User>();

// Count documents
var count = DocsOf("Orders")
    .Count();

DocsWhere() - Filter Documents

// Find by ID
var user = DocsWhere("Users", 123)
    .Select<User>()
    .FirstOrDefault();

// Find by criteria
var activeUsers = DocsWhere("Users", "{'IsActive':true}")
    .Select<User>();

// Find by object
var admins = DocsWhere("Users", new { Role = "Admin" })
    .Select<User>();

FirstDocOf() - Get First Document

// Get first document from collection
var settings = FirstDocOf("Settings")
    .Select<AppSettings>()
    .FirstOrDefault();

Writing Data

AddDoc() - Create New Document

// Add with JSON
uint newId = AddDoc("Users", "{'Name':'John','Age':30}");

// Add with object
uint id = AddDoc("Users", new 
{
    Name = "Jane",
    Age = 25,
    Email = "jane@example.com"
});

ModifyDocsWhere() - Update Documents

// Update specific document
ModifyDocsWhere("Users", userId)
    .Update("{'Age':31}");

// Update multiple documents
ModifyDocsWhere("Users", "{'Status':'Inactive'}")
    .Update("{'Status':'Archived'}");

// Add to array
ModifyDocsWhere("Users", userId)
    .Update("{'Tags':[Add,'VIP']}");

DelDoc() - Delete Document

DelDoc("Users", userId);

Form Operations

CreateNewDocFor() - Create Document in Form

// Open form to create new user
CreateNewDocFor("UserTemplate", "Users")
    .OpenForm("New User", result =>
    {
        if (result.Result)
        {
            MessageBox("User created!");
        }
    });
πŸ’‘ Note: See the Query Guide document for complete documentation of all query operators and methods.

4. UI & User Interaction

MessageBox() - Show Messages

Display messages to the user with different button combinations.

// Simple message (Cancel button only)
MessageBox("Operation completed successfully");

// OK button
MessageBox("Welcome!", MessageBoxButtonType.Ok);

// Yes/No buttons with callback
MessageBox(
    "Delete this item?",
    MessageBoxButtonType.YesNo,
    result =>
    {
        if (result.Result)
        {
            // User clicked Yes
            DelDoc("Items", itemId);
        }
    });

// With custom title
MessageBox(
    "Changes saved",
    "Success",
    MessageBoxButtonType.Ok);
πŸ“Œ MessageBoxButtonType Options:
  • Cancel: Only Cancel button (default)
  • Ok: Only OK button
  • OkCancel: OK and Cancel buttons
  • YesNo: Yes and No buttons

InputBox() - Get User Input

Prompt the user to enter text.

// Simple input
InputBox(
    "Enter your name:",
    result =>
    {
        if (result.Result)
        {
            var name = result.FindFirstValue("Enter your name:");
            MessageBox($"Hello, {name}!");
        }
    });

// With title and default value
InputBox(
    "New filename:",
    "Rename File",
    result =>
    {
        if (result.Result)
        {
            var newName = result.FindFirstValue("New filename:");
            // Rename file...
        }
    },
    "document.txt"); // default value

Form Control Methods

CloseForm()

Close the currently active form.

CloseForm();

SaveForm()

Save the current form (triggers save handlers).

SaveForm();

RefreshForm()

Refresh the current form to show updated data.

// After updating data
ModifyDocsWhere("Users", userId)
    .Update("{'Status':'Active'}");

RefreshForm(); // Show the changes

CloseAllForms()

Close all open forms.

CloseAllForms();

CloseIfOpenedForm() / SaveIfOpenedForm()

Conditionally close or save a specific form if it's open.

// Close user form if it's open
CloseIfOpenedForm("UserDetails");

// Save settings form if it's open
SaveIfOpenedForm("Settings");

Password Protection

UsePassword()

Protect actions with password verification.

UsePassword("secret123", () =>
{
    // This code only runs if password is correct
    FirstDocOf("AdminPanel")
        .OpenForm("Admin Panel");
});

5. File Operations

Reading Files

ReadFileText()

Read text content from a file.

var content = ReadFileText("config.json");
var data = JsonConvert.Deserialize(content);

ReadFileBytes()

Read binary content from a file.

byte[] imageData = ReadFileBytes("logo.png");

Writing Files

WriteFileText()

Write text content to a file.

var settings = new { Theme = "Dark", Language = "en" };
var json = JsonConvert.Serialize(settings);

WriteFileText("settings.json", json);

WriteFileBytes()

Write binary content to a file.

WriteFileBytes("backup.dat", dataBytes);

File Paths

GetFilesPath()

Get the base path where application files are stored.

var basePath = GetFilesPath();
Log($"Files stored in: {basePath}");

GetFilePath()

Get full path to a specific file.

var fullPath = GetFilePath("data.csv");

GetFileUrl()

Get URL to access a file through the web interface.

var imageUrl = GetFileUrl("profile.jpg");
// Returns: https://yourserver/files/YourApp/profile.jpg

6. Utility Methods

Logging

Log()

Log messages for debugging and monitoring.

// Simple message
Log("Application started");

// Multiple values
Log("User:", userName, "Age:", userAge);

// With formatting
Log("Processing {0} items", count);

Date & Time

GetNowDate()

Get the current date and time in the server's timezone.

var now = GetNowDate();

AddDoc("Events", new 
{
    Name = "UserLogin",
    Timestamp = now
});

Caching

UseCache()

Cache expensive operations to improve performance.

// Cache for 15 minutes (default)
var categories = UseCache(() =>
{
    return DocsOf("Categories")
        .Select<Category>()
        .ToList();
});

// Cache for custom duration
var stats = UseCache(
    () => CalculateStatistics(),
    TimeSpan.FromHours(1)
);

// Named cache
var data = UseCache(
    () => LoadData(),
    TimeSpan.FromMinutes(30),
    "MyDataCache"
);

// Force refresh
var freshData = UseCache(
    () => LoadData(),
    TimeSpan.FromMinutes(30),
    "MyDataCache",
    isForceUpdate: true
);
πŸ’‘ Performance Tip: Use caching for data that doesn't change frequently, like categories, settings, or statistics.

DQL Helper

DQL()

Build dynamic query language strings with parameters.

var name = "John";
var age = 30;

// Create JSON with parameters
var json = DQL("{'Name':@Name,'Age':@Age}", name, age);

// Use in queries
AddDoc("Users", DQL("{'Name':@Name}", name));

User Management

ResetToGuest()

Reset the user session to guest user (logout).

// Logout and remove auto-login
ResetToGuest(true);

// Logout but keep auto-login
ResetToGuest(false);

Code Confirmation

ConfirmCode()

Verify SMS or email confirmation codes.

var isValid = ConfirmCode("Users", userId, code);

if (isValid)
{
    MessageBox("Code confirmed!");
}
else
{
    MessageBox("Invalid code");
}

Localization

GetLocalizedValue()

Get localized text based on current user language.

var welcomeText = GetLocalizedValue("Welcome");
// Returns "Welcome" for English, "Ласкаво просимо" for Ukrainian

7. Advanced Features

Transactions

Execute multiple database operations atomically.

BeginTran() / CommitTran() / RollbackTran()

try
{
    BeginTran(TranType.ReadCommited);
    
    // Multiple operations
    var orderId = AddDoc("Orders", orderData);
    AddDoc("OrderItems", itemsData);
    ModifyDocsWhere("Products", productId)
        .Update("{'Stock':Sub(1)}");
    
    CommitTran(); // All succeed together
}
catch
{
    RollbackTran(); // Undo all changes
    throw;
}
πŸ“Œ Transaction Types:
  • TranType.ReadCommited: Default isolation level
  • TranType.Serializable: Highest isolation (slowest)
  • TranType.ReadUncommitted: Lowest isolation (fastest)

Context Management

ExecuteWithSaveContext()

Execute code while preserving the current context state.

var result = ExecuteWithSaveContext(Context, () =>
{
    // Change collection or context here
    Client.SetDefaultCollection("TempData");
    
    // Do operations...
    var data = DocsOf("TempData").Select();
    
    return data;
    
    // Context automatically restored after this block
});

Additional Helper Methods

NotImplementedMessageBox()

Quick way to show "Not Implemented" message.

public override bool OnEventDimension(EventInfo info)
{
    if (info.Action == "NewFeature")
    {
        NotImplementedMessageBox();
        return true;
    }
    
    return false;
}

CreateRenderForm()

Override this to customize form rendering.

public override BaseRenderForm CreateRenderForm(DOMForm form)
{
    // Return custom render form implementation
    return new CustomRenderForm(this, form);
}

SetUserContext()

Set the current user context (internal use).

SetUserContext();

SetGlobalDimensions()

Apply global dimensions to a collection.

var collection = new Collection(documentStorage);

// Set all global dimensions
SetGlobalDimensions(collection);

// Set specific dimensions only
SetGlobalDimensions(collection, dimType => 
    dimType != DimensionType.Security);

REST API Integration

Using REST Client

Make HTTP requests to external APIs.

// GET request
var response = REST.Get("https://api.example.com/users");

// POST request
var result = REST.Post(
    "https://api.example.com/users",
    new { Name = "John", Email = "john@example.com" }
);

// With headers
REST.AddHeader("Authorization", "Bearer token123");
var data = REST.Get("https://api.example.com/protected");

AI Integration

Using AI Client

Integrate AI capabilities into your application.

// Generate text
var prompt = "Write a welcome message for new users";
var message = AI.Generate(prompt);

MessageBox(message);

Inter-Application Messaging

SendMessage()

Send messages to other applications.

// Send to specific app
SendMessage("NotificationService", new 
{
    Type = "Alert",
    Message = "New order received"
});

// Notify all open instances
SendMessage(
    "Dashboard",
    new { Action = "Refresh" },
    isNotifyAllOpenApps: true
);

// Auto-open app if not running
SendMessage(
    "ReportGenerator",
    reportData,
    isOpenAppToNotify: true
);

Power Management (Windows)

GetPowerInfo()

Get battery and power status on Windows devices.

var power = GetPowerInfo();

Log($"Battery: {power.BatteryPercent}%");
Log($"Plugged in: {power.IsOnline}");
Log($"Time remaining: {power.BatteryLifeTime}");

Properties Reference

Property Type Description
SessionID Guid Unique identifier for current session
Client FractalPlatformClient Database client for queries
REST RESTClient HTTP client for REST APIs
AI AIClient AI service client
Context Context Current execution context
InternalContext Context Internal context (private)
User User Current user information
Name string Application name (class name without "Application")
DatabaseName string Default database name
HasDatabase bool Whether database is configured
Instance FractalPlatformInstance Platform instance reference
Logs List Application log messages

Complete Example Application

Here's a complete example showing many features together:

public class TaskManagerApplication : BaseApplication
{
    public override void OnStart()
    {
        // Check if user is logged in
        if (User.IsGuest)
        {
            // Show login form
            FirstDocOf("LoginForm")
                .OpenForm("Login");
        }
        else
        {
            // Show main task list
            ShowTaskList();
        }
    }

    private void ShowTaskList()
    {
        DocsWhere("Tasks", new { OwnerID = User.ID })
            .OrderBy("{'DueDate':$}")
            .OpenForm("My Tasks");
    }

    public override bool OnEventDimension(EventInfo info)
    {
        switch (info.Action)
        {
            case "AddTask":
                CreateNewDocFor("TaskTemplate", "Tasks")
                    .OpenForm("New Task", result =>
                    {
                        if (result.Result)
                        {
                            RefreshForm();
                            MessageBox("Task created!");
                        }
                    });
                return true;

            case "CompleteTask":
                ModifyDocsWhere("Tasks", info.DocID)
                    .Update("{'Status':'Completed','CompletedDate':@Date}", 
                              GetNowDate());
                RefreshForm();
                return true;

            case "DeleteTask":
                MessageBox(
                    "Delete this task?",
                    MessageBoxButtonType.YesNo,
                    result =>
                    {
                        if (result.Result)
                        {
                            DelDoc("Tasks", info.DocID);
                            CloseForm();
                        }
                    });
                return true;

            case "Logout":
                ResetToGuest();
                CloseAllForms();
                OnStart();
                return true;
        }

        return false;
    }

    public override bool OnChangeDimension(ChangeInfo info)
    {
        // Auto-calculate priority based on due date
        if (info.ChangeName == "DueDate")
        {
            var dueDate = info.AfterValue.ToDateTime();
            var daysUntilDue = (dueDate - GetNowDate()).Days;

            string priority = daysUntilDue < 1 ? "Urgent" :
                               daysUntilDue < 7 ? "High" :
                               "Normal";

            ModifyDocsWhere("Tasks", info.DocID)
                .Update(DQL("{'Priority':@Priority}", priority));

            RefreshForm();
            return true;
        }

        return false;
    }

    public override object OnComputedDimension(ComputedInfo info)
    {
        if (info.Variable == "DaysRemaining")
        {
            var dueDate = info.FindFirstDateTimeValue("DueDate");
            var days = (dueDate - GetNowDate()).Days;
            
            return days > 0 ? $"{days} days left" : "Overdue";
        }

        return null;
    }

    public override bool OnSecurityDimension(SecurityInfo info)
    {
        // Users can only modify their own tasks
        if (info.OperationType == OperationType.Update ||
            info.OperationType == OperationType.Delete)
        {
            var ownerId = info.FindFirstValue("OwnerID");
            return ownerId == User.ID.ToString();
        }

        return true;
    }

    public override bool OnTimerDimension(TimerInfo info)
    {
        // Check for overdue tasks every minute
        if (info.Action == "CheckOverdue")
        {
            var overdueTasks = DocsWhere("Tasks", 
                "{'DueDate':Less(@Now),'Status':'Active'}",
                GetNowDate())
                .Count();

            if (overdueTasks > 0)
            {
                Log($"Warning: {overdueTasks} overdue tasks");
            }

            return true;
        }

        return false;
    }

    public override bool OnAuthDimension(AuthInfo info)
    {
        if (info.Action == "Login")
        {
            var username = info.FindFirstValue("Username");
            var password = info.FindFirstValue("Password");
            
            // Validate and login user
            return ValidateAndLogin(username, password);
        }
        
        return false;
    }
}
πŸ’‘ Best Practices Summary:
  • Keep OnStart() lightweight - defer heavy operations
  • Return true from event handlers when you handle the event
  • Use transactions for multi-step operations
  • Cache expensive queries with UseCache()
  • Validate user input in OnChangeDimension()
  • Implement security checks in OnSecurityDimension()
  • Use Log() for debugging and monitoring
  • Provide user feedback with MessageBox() and RefreshForm()
  • Handle errors gracefully with try-catch blocks
  • Use meaningful action names in your UI dimensions
⚠️ Common Pitfalls:
  • Forgetting to return true after handling events (causes event to propagate)
  • Not refreshing forms after updates (users won't see changes)
  • Performing heavy operations in OnStart() (slow startup)
  • Not checking user permissions before operations
  • Forgetting to commit or rollback transactions
  • Not handling null values in computed dimensions
  • Blocking UI with long-running operations
  • Not providing user feedback for actions

Event Handler Return Values Summary

Event Handler Return true Return false
OnEventDimension Event handled Event not handled, continue propagation
OnChangeDimension Change accepted Change rejected/not handled
OnOpenForm Allow form to open Prevent form from opening
OnCloseForm Allow form to close Prevent form from closing
OnSecurityDimension Allow access Deny access
OnTimerDimension Timer event handled Timer event not handled
OnAuthDimension Authentication successful Authentication failed
OnMovePageDimension Allow navigation Prevent navigation
OnMenuDimension Menu action handled Menu action not handled
OnUploadFiles Upload processed Upload rejected
OnReceiveMessage Message handled Message not handled
OnCodeConfirmed Code confirmation handled Code confirmation not handled