Working with Controllers and Classes
Controllers and Classes represent the two primary code organization approaches for implementing business logic, data manipulation, and custom functionality within the Magentrix Integrated Development Environment. Understanding the distinct purposes, appropriate use cases, and proper implementation patterns for each code structure enables efficient development practices, maintainable code architecture, and optimal separation of concerns across portal customization implementations.
Controllers provide the logic layer behind Active Pages following Model-View-Controller architecture patterns, while Classes enable creation of modular, reusable code components that can be referenced across multiple controllers, triggers, and other classes. Proper utilization of both structures supports scalable development practices and reduces code duplication throughout customization projects.
Understanding Controllers vs. Classes
Controller Purpose and Function
Controllers implement the business logic layer that executes server-side before Active Pages are rendered to users. Each controller contains C# code that processes user inputs, queries entity data, performs calculations, validates information, executes business rules, prepares display data, and determines page behavior based on conditions and user context.
MVC Architecture Role: Controllers serve as the intermediary between data models (Magentrix entities) and views (Active Page HTML markup). This separation enables clean architecture where data access logic resides in controllers, presentation markup exists in pages, and shared business logic is centralized in classes.
Page-Specific Logic: Controllers should contain logic specific to their associated Active Page including data preparation for page display, handling of form submissions from that page, page-specific validation rules, and user interaction processing unique to that page's functionality.
Execution Lifecycle: When users request an Active Page, the associated controller's initialization methods execute first, performing necessary data operations and logic. After controller execution completes, the page HTML renders using data prepared by the controller, generating final output sent to the user's browser.
Single Page Association: Each Active Page can have one associated controller. Controllers are specifically designed to support their associated page and execute automatically when that page is requested by users without requiring explicit invocation.
Class Purpose and Function
Classes enable creation of modular, reusable code components that encapsulate business logic, utility functions, data operations, and common functionality needed across multiple controllers, triggers, or other classes. Classes support efficient code organization through centralized implementation of shared logic rather than duplicating code across multiple locations.
Code Reusability: Classes should contain logic that requires use in multiple places throughout the portal customization including common data validation rules, shared calculation methods, entity query patterns used in multiple contexts, integration logic for external systems, and utility functions for string manipulation, date handling, or data transformation.
Separation of Concerns: By extracting shared logic into classes, controllers remain focused on page-specific concerns while classes handle general-purpose operations. This separation improves code maintainability, testability, and reduces the risk of introducing errors when modifying shared functionality.
No Automatic Execution: Unlike controllers that execute automatically when their associated pages are requested, classes require explicit instantiation and method invocation from controllers, triggers, or other classes. This explicit usage enables flexible code organization and clear dependency relationships.
Multiple References: Classes can be referenced from multiple controllers, triggers, and other classes simultaneously. Updates to class methods automatically affect all code that uses those methods, ensuring consistent behavior and enabling centralized bug fixes and enhancements.
When to Use Controllers
Use Controllers when implementing logic that is specific to a particular Active Page including preparation of data displayed on that page, processing of form submissions from that page, handling user interactions unique to that page, validation rules specific to that page's inputs, and page-specific state management or session handling.
Single-Purpose Implementation: If functionality serves only one page and has no foreseeable reuse in other contexts, implementing it directly in the page's controller provides the simplest, most straightforward approach without unnecessary abstraction layers.
Direct Page Integration: Controllers have direct access to page lifecycle events, request parameters, response handling, and page-specific context that makes them ideal for logic tightly coupled to page rendering and user interaction patterns.
When to Use Classes
Use Classes when implementing logic that will be used in multiple controllers, triggers, or other classes including common validation rules applied across different forms, calculation methods used in multiple contexts, data access patterns for frequently queried entities, integration logic for external systems called from various locations, and utility functions for common operations like date formatting, string manipulation, or data transformation.
Reusability Requirement: If the same or similar logic appears in multiple controllers or triggers, extract it into a class to eliminate duplication and enable centralized maintenance. Future modifications affect all usage locations automatically without requiring updates to multiple files.
Independent Business Logic: Business rules and calculations that are independent of specific page rendering contexts work well as class methods. These operations can be tested and maintained separately from presentation concerns, improving code quality and reliability.
Creating Controllers
Creating Controllers from Active Pages
The recommended method for creating controllers is through the Active Page interface, which automatically creates properly named and associated controller files without manual naming management.
Open an existing Active Page in the editor to display the page content and editing interface. Locate the "+ Add Controller" button in the top-right corner of the page editor, positioned above the code editing area.
Click the "+ Add Controller" button to automatically create an associated controller class for the current Active Page. The IDE generates a new controller file with an automatically constructed name following mandatory naming conventions.
Automatic Naming: The controller name is created by appending "Controller" to the Active Page name. For example, an Active Page named "LandingPage" generates a controller named "LandingPageController." This naming convention is mandatory and enforced by the system during creation.
Immediate Association: The newly created controller is automatically associated with the Active Page. The "+ Add Controller" button is replaced with a clickable link displaying the controller name, enabling quick navigation between page markup and controller logic.
Creating Standalone Controllers
Controllers can also be created independently through the File menu, though this approach requires manual association with Active Pages through code references and is less commonly used than the integrated page-based creation method.
Access the File menu in the IDE and select New Controller to open the controller creation dialog. Enter a descriptive Name for the controller reflecting its purpose and functionality.
The system automatically appends "Controller" to the entered name to create the final class name. For example, entering "Admin" results in a controller class named "AdminController." This automatic suffix is mandatory and cannot be omitted or customized.
Click Create to generate the new controller. The IDE creates the controller file, adds it to the Controllers & Classes section in the sidebar navigation tree, and opens the controller in a new tab in the editor workspace.
Manual Page Association: Standalone controllers require manual association with Active Pages through code references in page markup. This approach provides flexibility for advanced scenarios but requires additional configuration compared to the integrated "+ Add Controller" method.
Controller Naming Requirements
Controller naming follows mandatory conventions enforced by the IDE to ensure consistency and proper functioning within the Magentrix platform architecture.
Mandatory "Controller" Suffix: All controller class names must end with "Controller." The system automatically appends this suffix during creation and prevents creation of controller classes without the proper suffix.
No Spaces or Special Characters: Controller names should use alphanumeric characters only, following C# class naming conventions. Use PascalCase naming where each word begins with a capital letter without spaces or underscores (e.g., "LandingPageController," "AdminDashboardController").
Descriptive Names: Choose controller names that clearly indicate their purpose and associated page functionality. Descriptive names improve code navigation and enable developers to quickly identify the appropriate controller for specific page logic.
Controller File Structure
Newly created controllers contain basic class structure with namespace declarations, using statements for required Magentrix SDK components, and empty class body ready for method and property implementation.
Default Methods: Controllers may include default initialization methods or constructor patterns that execute when the controller is instantiated during page request processing. These methods provide entry points for data loading and initial setup logic.
Property Declarations: Controllers typically include public properties that expose data to the associated Active Page. Page markup references these properties to display data prepared by controller logic.
Method Implementation: Controllers contain methods that implement business logic, data queries, input processing, and any operations necessary to support page functionality. Methods can be public (accessible from page markup) or private (internal controller logic only).
Creating Classes
Accessing Class Creation
Navigate to the File menu in the IDE and select New Class to open the class creation dialog. The dialog provides a simple interface requesting only the class name without additional configuration options.
Class Naming
Enter a descriptive Name that reflects the class purpose and functionality. Class names should clearly indicate the operations, business domain, or utility functions contained within the class.
No Automatic Suffix: Unlike controllers, classes do not have automatic suffix appending. The name entered becomes the complete class name without modification. This flexibility enables appropriate naming for different class purposes such as "AccountHelper," "ValidationUtilities," or "EmailService."
C# Naming Conventions: Follow standard C# class naming conventions using PascalCase format where each word begins with a capital letter. Avoid spaces, special characters, or underscores. Names should be nouns or noun phrases that describe the class's responsibility.
Purpose Indication: Include purpose indicators in class names to communicate functionality at a glance. Suffixes like "Helper," "Service," "Manager," "Validator," or "Processor" clarify class roles within the code architecture.
Class Creation Completion
Click Create to generate the new class. The IDE creates the class file, adds it to the Controllers & Classes section in the sidebar navigation tree (grouped with controllers despite different purposes), and opens the class in a new tab in the editor workspace.
Basic Structure: New classes contain minimal structure including namespace declaration, using statements for Magentrix SDK components, and empty class body ready for method and property implementation based on intended functionality.
Class Organization Patterns
Static Utility Classes: Classes containing utility methods that don't require instance state often use static class declarations with static methods. This pattern enables direct method invocation without class instantiation (e.g., StringUtilities.FormatPhoneNumber(phoneNumber)).
Instance-Based Classes: Classes that maintain state or encapsulate complex operations may use instance-based patterns where classes are instantiated with new keyword and methods are called on the instance. This pattern supports object-oriented design principles and dependency injection patterns.
Service Classes: Classes that encapsulate integration logic, data access patterns, or business service operations often follow service class patterns with methods that perform specific operations and return results without maintaining long-term state.
Opening and Editing Controllers and Classes
Accessing from Sidebar Navigation
Navigate to the Controllers & Classes section in the sidebar navigation tree. This section contains both controllers and classes grouped together, though they serve different purposes and follow different naming conventions.
Expand the Controllers & Classes section if necessary to display all available controllers and classes organized in the tree structure. Files are typically listed alphabetically by name.
Double-Click Opening: Double-click on any controller or class name to open that file in a new tab in the editor workspace. This method provides the fastest access for editing operations.
Right-Click Context Menu: Right-click on any controller or class name to display a context menu with available actions. Select Open from the context menu to open the file in a new tab. This method maintains consistency with other IDE element opening workflows.
Opening Controllers from Active Pages
When editing an Active Page that has an associated controller, the controller name appears as a clickable link in the top-right corner of the page editor, replacing the "+ Add Controller" button.
Click the controller name link to open the associated controller file in a new tab. This direct access method enables quick navigation between page markup and controller logic without searching through the sidebar navigation tree.
Efficient Workflow: The integrated page-to-controller navigation supports efficient development workflows where developers frequently switch between page markup and controller code while implementing or debugging functionality.
Code Editor Interface
Controllers and classes open in the code editor with syntax highlighting for C# code. The editor provides line numbering, code folding for methods and classes, and find/replace functionality for efficient code editing.
Syntax Highlighting: The editor automatically highlights C# keywords, strings, comments, and other language elements using visual color differentiation. Syntax highlighting improves code readability and helps identify syntax errors during development.
Line Numbers: Line numbers display in the left margin of the editor, supporting error message interpretation (which reference specific line numbers) and enabling efficient code navigation and discussion with team members.
Code Folding: Methods, classes, and other code blocks can be collapsed or expanded using folding controls in the editor margin. Code folding enables focus on specific portions of large files while temporarily hiding other sections.
Multiple File Editing
The IDE supports opening multiple controllers and classes simultaneously in separate tabs along with Active Pages, Templates, and other development elements. Each open tab maintains independent editing state.
Cross-File Reference: Multiple open tabs enable viewing controller code while editing class methods it calls, examining multiple class implementations simultaneously, or comparing implementation patterns across different controllers.
Context Switching: Switch between open controllers and classes by clicking tab headers at the top of the editor workspace. Tab labels display file names with visual indicators showing unsaved change status.
Saving and Validating Code
Manual Save Requirement
The IDE does not include automatic save functionality for controllers and classes. All changes must be saved explicitly through save buttons or keyboard shortcuts. Unsaved changes are indicated visually on tab labels.
Save Button: Each editor tab includes a save button in the toolbar or interface controls. Clicking this button saves the current file and triggers code compilation and validation.
Keyboard Shortcuts: Standard save keyboard shortcuts (Ctrl+S on Windows/Linux, Command+S on macOS) save the active file currently displayed in the editor. Keyboard shortcuts provide faster save access during active development.
Code Compilation and Validation
When saving controllers or classes, the IDE performs automatic code compilation and validation. The C# compiler checks syntax, verifies type correctness, validates method signatures, and identifies compilation errors.
Validation Results: Validation results appear at the bottom of the editor workspace immediately after save operations complete. Results indicate either successful compilation or list specific errors that prevent compilation.
Error Display: Compilation errors display with specific line numbers and error descriptions, enabling quick identification and correction of issues. Error messages describe the nature of the problem (syntax error, type mismatch, undefined reference, etc.) and the location where it was detected.
Error Resolution: Address compilation errors systematically by reviewing error messages, navigating to specified line numbers, correcting identified issues, and saving again to re-validate. Multiple iterations may be necessary when errors cascade from earlier issues.
Successful Compilation: When validation completes without errors, a success indicator confirms that the code compiles correctly and is ready for execution. Successful compilation does not guarantee correct logic or expected behavior, only that syntax and types are valid.
Common Compilation Errors
Syntax Errors: Missing semicolons, unmatched brackets, incorrect method declaration syntax, and other structural issues result in syntax errors. Review error messages carefully to identify the specific syntax problem and location.
Type Mismatches: Attempting to assign values of incompatible types, passing incorrect parameter types to methods, or returning wrong types from methods cause type mismatch errors. Verify that all assignments and method calls use compatible types.
Undefined References: References to undefined classes, methods, or properties generate compilation errors. Verify that class names are spelled correctly (case-sensitive), methods exist on referenced classes, and all necessary using statements are included.
Entity and Field Name Errors: Incorrect entity or field names (often due to case-sensitivity issues) cause compilation errors when code attempts to access non-existent entities or fields. Use the Entity Browser to verify correct names before coding references.
Implementing Controller Logic
Controller Structure and Methods
Controllers contain methods that execute during page request processing. Understanding method types and their execution timing enables proper implementation of page functionality.
Initialization Methods: Controllers may include initialization methods that execute when the controller is instantiated during page request processing. These methods provide appropriate locations for initial data loading, user context verification, and setup operations.
Action Methods: Action methods respond to specific user actions such as form submissions, button clicks, or other interactions. These methods process inputs, execute business logic, update data, and determine response behavior.
Helper Methods: Private helper methods contain logic shared across multiple action methods within the controller. Helper methods improve code organization and reduce duplication within the controller while remaining inaccessible from page markup.
Data Access Patterns
Controllers query Magentrix entities to retrieve data for display or manipulation. Efficient data access patterns minimize database operations and improve page performance.
Entity Queries: Use Magentrix SDK query methods to retrieve entity records based on filter criteria. Construct queries that return only necessary fields and apply appropriate filtering to minimize data transfer.
Relationship Traversal: Access related entity data through relationship properties on queried records. Understanding entity relationships enables efficient data retrieval without requiring separate queries for related information.
Data Transformation: Transform queried entity data into formats appropriate for page display. Controllers prepare data structures that page markup can easily consume through simple property references and loops.
Public Properties for Page Access
Controllers expose data to Active Pages through public properties. Page markup references these properties using data binding syntax to display information prepared by controller logic.
Property Declarations: Declare public properties with appropriate data types to hold information for page display. Properties can be simple types (strings, numbers, dates) or complex types (lists, custom objects).
Property Initialization: Initialize properties in controller initialization or action methods before page rendering occurs. Pages expect properties to contain valid data when markup executes, requiring proper initialization in controller code.
Computed Properties: Properties can include getter logic that computes values dynamically based on other data. Computed properties enable page markup to access derived information without implementing calculation logic in presentation code.
Implementing Class Logic
Static Utility Methods
Classes frequently implement static utility methods that provide general-purpose functionality without requiring class instantiation. Static methods offer convenient access patterns for utility operations.
Static Class Declaration: Declare the entire class as static when it contains only utility methods without instance state. Static classes cannot be instantiated and can only contain static members.
Method Signature: Static methods include the static keyword in their declaration and can be called directly using the class name without creating instances (e.g., ClassName.MethodName(parameters)).
Common Utility Patterns: String formatting and parsing, date manipulation and conversion, number formatting and calculations, validation logic for common patterns, and data transformation operations work well as static utility methods.
Instance-Based Service Classes
Classes that encapsulate complex operations, maintain state, or implement business services often use instance-based patterns where classes are instantiated before use.
Constructor Implementation: Implement constructors that initialize class state, accept dependencies through parameters, validate inputs, and prepare the instance for method invocation.
Instance Methods: Instance methods operate on instance state and can maintain context across multiple method calls. Instance methods support object-oriented design patterns and complex operation sequences.
Dependency Management: Classes can accept other classes or services through constructor parameters or method parameters, enabling flexible composition and testability through dependency injection patterns.
Business Logic Encapsulation
Classes should encapsulate complete business logic operations that can be called from multiple contexts. Well-designed class methods have clear inputs and outputs without dependencies on controller-specific or page-specific context.
Input Parameters: Accept all necessary information through method parameters rather than relying on external state or context. Clear parameter lists make methods self-documenting and testable.
Return Values: Return results through method return values or output parameters. Clear return values enable callers to use results without understanding internal implementation details.
Error Handling: Implement appropriate error handling within class methods including validation of input parameters, handling of exceptional conditions, and meaningful error messages or exceptions when operations cannot complete successfully.
Calling Classes from Controllers
Class Instantiation
Instance-based classes require instantiation using the new keyword before methods can be called. Instantiation creates a new instance of the class in memory with its own state.
Basic Instantiation:
ValidationHelper validator = new ValidationHelper();
bool isValid = validator.ValidateEmail(emailAddress);
Constructor Parameters:
EmailService emailService = new EmailService(smtpServer, port);
emailService.SendNotification(recipient, subject, body);
Static Method Invocation
Static class methods are called directly using the class name without instantiation. Static method calls provide simple syntax for utility operations.
Direct Method Call:
string formattedPhone = StringUtilities.FormatPhoneNumber(phoneNumber);
DateTime parsedDate = DateUtilities.ParseCustomFormat(dateString);
Chained Operations:
string result = StringUtilities.ToTitleCase(StringUtilities.RemoveSpecialCharacters(input));
Error Handling in Controllers
Controllers should handle exceptions that may be thrown by class methods to prevent unhandled errors from reaching users.
Try-Catch Blocks:
try {
ValidationResult result = validator.ValidateInput(userInput);
if (result.IsValid) {
// Process valid input
}
} catch (ValidationException ex) {
// Handle validation errors
errorMessage = ex.Message;
}
Graceful Degradation: When class method calls fail, implement graceful degradation that provides meaningful feedback to users rather than displaying technical error messages or causing page rendering failures.
Deleting Controllers and Classes
Deletion Process
Right-click on the controller or class name in the sidebar under the Controllers & Classes section to display the context menu. Select Delete from the context menu options to initiate the deletion process.
A confirmation dialog appears requesting verification of the deletion operation. Confirm the deletion to remove the controller or class from the sidebar navigation and mark it for deletion.
Recovery from Recycle Bin
Deleted controllers and classes can be recovered from the Recycle Bin if deletion was accidental or the code is needed again. The Recycle Bin provides a safety mechanism for recovering deleted code files before permanent removal.
Recycle Bin Access: Access the Recycle Bin through the Setup menu in the administrative interface. Navigate to the appropriate section for code files to locate deleted controllers and classes.
Recovery Process: Select the deleted controller or class in the Recycle Bin and use the restore function to return it to the active code files list. Restored files reappear in the sidebar navigation tree and can be opened and edited normally.
Deletion Impact Assessment
Before deleting controllers or classes, carefully assess the impact on other code that may reference the file being deleted.
Controller Dependencies: Deleting a controller orphans its associated Active Page, leaving the page without server-side logic. The page will still render but will not have access to controller-prepared data or processing capabilities. Consider whether the page should also be deleted or converted to a template or content page.
Class References: Deleting classes that are referenced from controllers, triggers, or other classes causes compilation errors in those dependent files. Search for references to the class before deletion to identify all usage locations.
Reference Search: Use the IDE's global search functionality to search for the class name across all controllers, classes, and triggers. Review search results to identify all files that reference the class being considered for deletion.
Compilation After Deletion: After deleting classes, open and save any controllers or classes that referenced the deleted class to trigger compilation and identify errors. Address compilation errors by removing references, replacing with alternative implementations, or restoring the deleted class.
Best Practices and Recommendations
Code Organization Principles
Single Responsibility: Each controller should be responsible for supporting its associated Active Page only. Each class should have a single, well-defined responsibility or domain of functionality. Focused classes and controllers improve maintainability and testability.
DRY Principle (Don't Repeat Yourself): When the same or similar logic appears in multiple controllers, extract it into a class to eliminate duplication. Shared classes enable centralized maintenance and ensure consistent behavior across usage locations.
Clear Naming: Use descriptive names for controllers, classes, methods, and properties that clearly indicate purpose and functionality. Clear names reduce the need for comments and enable developers to understand code quickly without extensive context.
Separation of Concerns
Page-Specific vs. Reusable: Keep page-specific logic in controllers and reusable logic in classes. This separation enables independent development and testing of business logic separate from presentation concerns.
Business Logic Isolation: Isolate business rules and calculations in classes separate from data access and presentation preparation. Clean separation enables business logic testing without requiring page or controller context.
Presentation Preparation: Controllers should focus on preparing data for specific page display requirements while delegating business logic, validation, and complex operations to classes. This division of responsibilities improves code clarity and maintainability.
Error Handling and Logging
Comprehensive Error Handling: Implement try-catch blocks around operations that may fail including data access operations, external API calls, file operations, and complex calculations. Graceful error handling prevents user-facing errors and enables meaningful error reporting.
Meaningful Error Messages: Provide clear, actionable error messages that help users understand what went wrong and how to correct issues. Avoid technical error details in user-facing messages while logging detailed information for debugging.
Debug Logging: Use Event Log statements during development to trace execution flow, verify variable values, and identify where logic deviates from expected behavior. Remove or disable logging statements after debugging to prevent performance impacts.
Performance Considerations
Minimize Controller Complexity: Keep controller logic efficient and focused on essential page preparation. Complex operations that delay page rendering impact user experience through increased response times.
Efficient Class Methods: Design class methods to perform operations efficiently without unnecessary database queries, loops, or processing. Efficient methods reduce overall system load and improve performance across all usage contexts.
Lazy Loading: Load data only when needed rather than preemptively loading all possible data in controller initialization. Lazy loading reduces unnecessary database operations and improves page response times.
Testing and Validation
Incremental Development: Develop and test controllers and classes incrementally, validating each new method or functionality before adding additional complexity. Incremental development enables early error detection and reduces debugging difficulty.
Compilation Discipline: Save and compile frequently during development to identify syntax and type errors early. Early error detection prevents complex debugging sessions when multiple errors compound.
Logic Verification: Test business logic in classes independently from page rendering when possible. Independent testing enables verification of correct calculations, validations, and operations without requiring full page execution context.
Code Documentation
Method Comments: Include comments above methods explaining purpose, parameters, return values, and any important behavior or exceptions. Method documentation helps future developers understand code without reading complete implementation details.
Complex Logic Explanation: Comment complex algorithms, business rules, or non-obvious implementation patterns. Clear explanations reduce maintenance time and prevent misunderstandings about code intent.
Usage Examples: For reusable classes, include usage examples in comments showing how to instantiate classes and call methods correctly. Examples accelerate adoption and reduce integration errors.
Jump to IDE Checklist
<< Working with Pages, Templates, and Content | Working with Triggers >>