Table of Contents


Controller Responses

Controllers communicate with users by returning different types of responses. This section provides a complete reference for all response types available in Magentrix, from rendering pages to generating files, streaming JSON data, and redirecting users.

Table of Contents

  1. Response Types Summary
  2. Response Types Overview
  3. View Responses
  4. PartialView Response
  5. Predefined Views
  6. Redirect Responses
  7. RedirectToAction
  8. Redirecting to Active Pages
  9. File Responses
  10. StorageFile Response
  11. PDF Response
  12. Data Responses
  13. Special Responses
  14. Response Type Decision Guide
  15. Practical Examples
  16. Best Practices
  17. Common Pitfalls
  18. Summary
  19. Next Steps
  20. Quick Reference

Response Types Summary

Response TypeSignature
Viewreturn View()
PartialViewreturn PartialView(model)
Redirectreturn Redirect("~/home")
RedirectToActionreturn RedirectToAction("Index")
Filereturn File(byte[], contentType, fileName)
StorageFilereturn StorageFile(blobId, contentType)
Pdfreturn Pdf(model, fileName)
Jsonreturn Json(object, JsonRequestBehavior.AllowGet)
Contentreturn Content("text")
UnauthorizedAccessResponse    return UnauthorizedAccessResponse()
PageNotFoundreturn PageNotFound()
RedirectToErrorreturn RedirectToError("message")

Response Types Overview

Every controller action must return an ActionResponse object. The type of response determines what the user sees or receives.

Response Type Comparison

Response TypePurposeCommon Use Cases
View()Render Active PageDisplay forms, dashboards, detail pages
PartialView()Render page fragmentWidgets, reusable components
Redirect()Navigate to URLPost-form submission, external links
RedirectToAction()Navigate to actionNavigate between controller actions
Json()Return JSON dataREST APIs, AJAX responses
File()Stream file downloadCSV exports, binary files
StorageFile()Stream from cloudDownload files from Magentrix Storage
Pdf()Generate PDFDynamic reports, invoices
Content()Return textPlain text, HTML, XML, CSS, JavaScript
UnauthorizedAccessResponse()  Access deniedSecurity violations
PageNotFound()404 errorMissing resources
RedirectToError()Error pageException handling

View Responses

View responses render Active Pages to display HTML user interfaces. They are the most common response type for Page Controllers.

Basic View Response

public override ActionResponse Index()
{
    return View();
}

This renders the Active Page associated with the controller.

View with Model

Pass data to the Active Page using a model:

public ActionResponse Details(string id)
{
    Contact contact = Database.Retrieve(id);
    return View(contact);
}

Accessing in Active Page:

<aspx:AspxPage runat='server' title='Contact Details'>
    <body>
        <h1>{!Model.FirstName} {!Model.LastName}</h1>
        <p>Email: {!Model.Email}</p>
    </body>
</aspx:AspxPage>

View with Collection Model

public override ActionResponse Index()
{
    List<Account> accounts = Database.Query<Account>()
        .OrderBy(a => a.Name)
        .ToList();
    
    return View(accounts);
}

Displaying in Active Page:

<aspx:Repeater runat='server' value='{!Model}' var='account'>
    <body>
        <table class='table'>
            <thead>
                <tr>
                    <th>Account Name</th>
                    <th>Type</th>
                    <th>Industry</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><aspx:Field runat='server' value='{!account.Name}'/></td>
                    <td><aspx:Field runat='server' value='{!account.Type}'/></td>
                    <td><aspx:Field runat='server' value='{!account.Industry}'/></td>
                </tr>
            </tbody>
        </table>
    </body>
</aspx:Repeater>

View with Specific Active Page

Render a different Active Page than the default:

public ActionResponse Confirm()
{
    return View(ActivePages.ConfirmationPage);
}

View with Active Page and Model

public ActionResponse ShowResults()
{
    var results = Database.Query<Opportunity>()
        .Where(o => o.Stage == "Closed Won")
        .ToList();
    
    return View(ActivePages.ResultsPage, results);
}

Available View() Overloads

// Uses default Active Page for the controller
View()

// Uses default Active Page with model
View(object model)

// Uses specific Active Page
View(ActivePage activePage)

// Uses specific Active Page with model
View(ActivePage activePage, object model)

PartialView Response

PartialView renders page fragments that can be embedded within other Active Pages or used as widgets.

Basic PartialView

public ActionResponse MyWidget()
{
    return PartialView();
}

PartialView with Model

public ActionResponse OpportunitySummary(string accountId)
{
    var opportunities = Database.Query<Opportunity>()
        .Where(o => o.AccountId == accountId)
        .ToList();
    
    return PartialView(opportunities);
}

Using PartialView in Active Pages

In the parent Active Page:

<aspx:AspxPage Id='ParentPage' runat='server' title='Account Dashboard'>
    <body>
        <h1>Account Dashboard</h1>
        
        <!-- Embed the partial view as a widget -->
        <aspx:PartialView area='aspx' action='opportunitySummary' 
                          controller='dashboard' 
                          accountId='{!Model.Id}' />
    </body>
</aspx:AspxPage>

Practical PartialView Examples

Example 1: Reusable Contact Card Widget

public class WidgetsController : AspxController
{
    public ActionResponse ContactCard(string contactId)
    {
        Contact contact = Database.Retrieve(contactId);
        return PartialView(contact);
    }
}

Example 2: Real-Time Statistics Widget

public ActionResponse LiveStats()
{
    var stats = new
    {
        ActiveUsers = Database.Query<User>().Where(u => u.IsActive).Count(),
        OpenOpportunities = Database.Query<Opportunity>().Where(o => !o.IsClosed).Count(),
        TodayRevenue = CalculateTodayRevenue()
    };
    
    return PartialView(stats);
}

Predefined Views

Magentrix provides several predefined views for common scenarios.

PageNotFound

Display a user-friendly 404 error:

public ActionResponse ViewResource(string id)
{
    var resource = Database.Query<Resource>()
        .Where(r => r.Id == id)
        .FirstOrDefault();
    
    if (resource == null)
    {
        return PageNotFound();
    }
    
    return View(resource);
}

RecordDeleted

Show message when a record has been deleted or is no longer accessible:

public ActionResponse Details(string id)
{
    Contact contact = Database.Query<Contact>()
        .Where(c => c.Id == id)
        .FirstOrDefault();
    
    if (contact == null)
    {
        return RecordDeleted();
    }
    
    return View(contact);
}

UnderMaintenance

Display maintenance page:

public ActionResponse Index()
{
    bool isMaintenanceMode = CheckMaintenanceMode();
    
    if (isMaintenanceMode)
    {
        return UnderMaintenance();
    }
    
    return View();
}

Error View with Custom Message

public ActionResponse ProcessData()
{
    try
    {
        // Processing logic
        return View();
    }
    catch (Exception ex)
    {
        return RedirectToError("An error occurred while processing your request. Please try again.");
    }
}

Redirect Responses

Redirect responses navigate users to different URLs or actions.

Basic Redirect

Redirect to any URL:

public ActionResponse GoHome()
{
    return Redirect("~/home/index");
}

The ~ symbol resolves to the application root.

Redirect to External URL

public ActionResponse GoToExternal()
{
    return Redirect("https://www.example.com");
}

Permanent Redirect (301)

Use for permanently moved resources:

public ActionResponse OldPage()
{
    return RedirectPermanent("/home/newpage");
}

This sends HTTP status code 301, which tells search engines the resource has permanently moved.


RedirectToAction

Redirect to another action in the same or different controller.

Redirect to Action in Same Controller

[HttpPost]
public ActionResponse Create(Contact model)
{
    if (ModelState.IsValid)
    {
        Database.Insert(model);
        return RedirectToAction("Index");
    }
    
    return View(model);
}

Redirect to Action with Parameters

[HttpPost]
public ActionResponse Create(Contact model)
{
    if (ModelState.IsValid)
    {
        Database.Insert(model);
        
        // Redirect to Details action with the new record's ID
        return RedirectToAction("Details", new { id = model.Id });
    }
    
    return View(model);
}

Redirect to Action in Different Controller

public ActionResponse ProcessComplete()
{
    return RedirectToAction("Edit", "Contact", new { id = "003R000000haXk3IAE" });
}

Parameters:

  • "Edit" - Action name
  • "Contact" - Controller name
  • new { id = "..." } - Route values (parameters)

Permanent Redirect to Action

public ActionResponse OldAction()
{
    return RedirectToActionPermanent("NewAction", "NewController");
}

Available RedirectToAction() Overloads

// Redirect to action in same controller
RedirectToAction(string actionName)

// Redirect to action with parameters
RedirectToAction(string actionName, object routeValues)

// Redirect to action in different controller
RedirectToAction(string actionName, string controllerName, object routeValues)

// Permanent redirect versions
RedirectToActionPermanent(string actionName, object routeValues)
RedirectToActionPermanent(string actionName, string controllerName, object routeValues)

Redirecting to Active Pages

Use the ActivePages helper to redirect to specific Active Pages with type safety:

public ActionResponse GoToContactPage()
{
    return Redirect(ActivePages.ContactManager);
}

Redirect to Active Page with Parameters

public ActionResponse ViewContact(string id)
{
    return Redirect(ActivePages.ContactDetails, new { id = id });
}

This approach is recommended because:

  • Maintains system dependencies
  • Provides compile-time checking
  • System notifies you if Active Page is referenced elsewhere

File Responses

File responses stream binary files to the user's browser for download.

Basic File Response

public ActionResponse DownloadFile()
{
    byte[] fileBytes = GetFileContent();
    return File(fileBytes, "application/pdf", "document.pdf");
}

Parameters:

  • fileBytes - The file content as byte array
  • "application/pdf" - MIME content type
  • "document.pdf" - Suggested filename for download

Common MIME Types

File TypeMIME Type
PDFapplication/pdf
Word (.docx)application/vnd.openxmlformats-officedocument.wordprocessingml.document
Excel (.xlsx)application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
CSVtext/csv
Plain Texttext/plain
JSONapplication/json
XMLapplication/xml
ZIPapplication/zip
PNGimage/png
JPEGimage/jpeg

CSV Export Example

public ActionResponse ExportContactsCsv()
{
    var contacts = Database.Query<Contact>().ToList();
    
    var csv = new StringBuilder();
    csv.AppendLine("First Name,Last Name,Email,Phone");
    
    foreach (var contact in contacts)
    {
        csv.AppendLine($"{contact.FirstName},{contact.LastName},{contact.Email},{contact.Phone}");
    }
    
    byte[] fileBytes = Encoding.UTF8.GetBytes(csv.ToString());
    return File(fileBytes, "text/csv", "contacts.csv");
}

Excel Export Example

public ActionResponse ExportAccountsExcel()
{
    var accounts = Database.Query<Account>().ToList();
    
    // Use external libraries generate Excel
    byte[] excelBytes = GenerateExcelFile(accounts);
    
    return File(excelBytes, 
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "accounts.xlsx");
}

Reading Note and Attachment Files

public ActionResponse OpenAttachment(string id)
{
    var attachment = Database.Retrieve(id);
    
    // Read file from Magentrix Storage
    byte[] fileBytes = Storage.ReadFileBytes(id);
    
    return File(fileBytes, attachment.ContentType, attachment.Name);
}

File Response with Stream

public ActionResponse DownloadLargeFile()
{
    var fileStream = GetLargeFileStream();
    return File(fileStream, "application/octet-stream", "largefile.dat");
}

Open File Inline (in Browser)

By default, files are downloaded. To open them in the browser:

public ActionResponse ViewPdf(string id)
{
    byte[] pdfBytes = GetPdfContent(id);
    
    // Fourth parameter: true = open inline, false = download
    return File(pdfBytes, "application/pdf", "document.pdf", true);
}

Available File() Overloads

// Basic file download
File(byte[] fileContents, string contentType)

// File download with filename
File(byte[] fileContents, string contentType, string fileName)

// File with inline/download control
File(byte[] fileContents, string contentType, string fileName, bool openInline)

// Stream-based file download
File(Stream fileStream, string contentType)

// Stream with filename
File(Stream fileStream, string contentType, string fileName)

StorageFile Response

Stream files directly from Magentrix Cloud Storage without loading them into memory.

Basic StorageFile

public ActionResponse DownloadStorageFile(string blobId)
{
    return StorageFile(blobId, "application/pdf");
}

StorageFile with Filename

public ActionResponse OpenAttachment(string id)
{
    var attachment = Database.Retrieve<NoteAndAttachment>(id);
    
    return StorageFile(id, attachment.ContentType, attachment.Name);
}

StorageFile Opened Inline

public ActionResponse ViewDocument(string id)
{
    var document = Database.Retrieve<Document>(id);
    
    // Fourth parameter: true = open inline in browser
    return StorageFile(id, document.ContentType, document.Name, true);
}

Available StorageFile() Overloads

// Basic storage file stream
StorageFile(string blobId, string contentType)

// Storage file with filename
StorageFile(string blobId, string contentType, string fileName)

// Storage file with inline/download control
StorageFile(string blobId, string contentType, string fileName, bool inline)
💡 When to use StorageFile vs File:
  • StorageFile: When file is already stored in Magentrix Cloud Storage
  • File: When generating files dynamically or reading from external sources

PDF Response

Generate dynamic PDF files from HTML content or Active Page models.

PDF from Current Active Page

public ActionResponse ExportToPdf()
{
    var accounts = Database.Query<Account>().Limit(5).ToList();
    
    // Renders current Active Page as PDF
    return Pdf(accounts, "accounts_list.pdf");
}
💡 Note: The Active Page associated with this controller is converted to PDF.

PDF from String Content

public ActionResponse GenerateSimplePdf()
{
    string htmlContent = @"
        <html>
            <head>
                <style>
                    body { font-family: Arial; }
                    h1 { color: navy; }
                </style>
            </head>
            <body>
                <h1>Sales Report</h1>
                <p>Total Revenue: $1,234,567</p>
            </body>
        </html>
    ";
    
    return Pdf(htmlContent, "sales_report.pdf");
}

PDF from Model with Custom HTML

public ActionResponse InvoicePdf(string opportunityId)
{
    var opp = Database.Retrieve<Opportunity>(opportunityId);
    var account = Database.Retrieve<Account>(opp.AccountId);
    
    var invoiceHtml = $@"
        <html>
            <head>
                <style>
                    body {{ font-family: Arial; padding: 20px; }}
                    .header {{ border-bottom: 2px solid navy; padding-bottom: 10px; }}
                    .total {{ font-size: 20px; font-weight: bold; }}
                </style>
            </head>
            <body>
                <div class='header'>
                    <h1>Invoice</h1>
                    <p>Date: {DateTime.Now:MM/dd/yyyy}</p>
                </div>
                <h2>Bill To:</h2>
                <p>{account.Name}</p>
                <p>{account.BillingStreet}</p>
                <h2>Invoice Details:</h2>
                <p>Opportunity: {opp.Name}</p>
                <p class='total'>Total: ${opp.Amount:N2}</p>
            </body>
        </html>
    ";
    
    return Pdf(invoiceHtml, $"Invoice_{opp.Name}.pdf");
}

PDF with Options

Control PDF generation with PdfOptions:

public ActionResponse CustomPdf()
{
    var accounts = Database.Query<Account>().ToList();
    
    var options = new PdfOptions
    {
        PageSize = PdfPageSize.Letter,
        Orientation = PdfOrientation.Landscape,
        MarginTop = 20,
        MarginBottom = 20,
        MarginLeft = 15,
        MarginRight = 15,
        CompressionLevel = PdfCompressionLevel.High
    };
    
    return Pdf(accounts, "accounts.pdf", options);
}

PDF Opened Inline

public ActionResponse ViewPdfInline()
{
    var data = GetReportData();
    
    // Fourth parameter: true = open in browser, false = download
    return Pdf(data, "report.pdf", null, true);
}

Available Pdf() Overloads

// PDF from model using current Active Page
Pdf(object model, string filename)

// PDF from model with options
Pdf(object model, string filename, PdfOptions exportOptions)

// PDF from model with inline control
Pdf(object model, string filename, PdfOptions exportOptions, bool inline)

// PDF from HTML string
Pdf(string content, string filename)

// PDF from HTML with options
Pdf(string content, string filename, PdfOptions exportOptions)

// PDF from HTML with inline control
Pdf(string content, string filename, PdfOptions exportOptions, bool inline)

Important PDF Notes

Use Absolute Paths for Resources: When generating PDFs, CSS and images must use absolute URLs:
<!-- ❌ Relative paths don't work in PDFs -->
<img src="/images/logo.png" />
<link rel="stylesheet" href="/css/styles.css" />

<!-- ✅ Use absolute paths -->
<img src="https://yourportal.magentrix.com/images/logo.png" />
<link rel="stylesheet" href="https://yourportal.magentrix.com/css/styles.css" />

Data Responses

Json Response

Return JSON data for APIs and AJAX calls.

Basic JSON Response:

[HandleExceptionsForJson]
public ActionResponse GetContacts()
{
    var contacts = Database.Query<Contact>().ToList();
    return Json(contacts, JsonRequestBehavior.AllowGet);
}
Always use [HandleExceptionsForJson] attribute to ensure errors are returned as JSON.

JSON for POST Requests:

[HttpPost]
[HandleExceptionsForJson]
public ActionResponse CreateContact(Contact model)
{
    if (ModelState.IsValid)
    {
        Database.Insert(model);
        return Json(new { success = true, id = model.Id });
    }
    
    return Json(new { success = false, errors = ModelState });
}

JSON with Custom Status Code:

[HandleExceptionsForJson]
public ActionResponse GetContact(string id)
{
    Contact contact = Database.Retrieve<Contact>(id);
    
    if (contact == null)
    {
        return Json(new { error = "Contact not found" }, 404);
    }
    
    return Json(contact, JsonRequestBehavior.AllowGet);
}

Available Json() Overloads:

// POST only (default behavior)
Json(object model)

// POST with custom status code
Json(object model, int statusCode)

// GET or POST based on behavior parameter
Json(object model, JsonRequestBehavior behavior)

// GET or POST with custom status code
Json(object model, int statusCode, JsonRequestBehavior behavior)

// POST with custom content type
Json(object model, string contentType)

// POST with content type and encoding
Json(object model, string contentType, Encoding contentEncoding)

// Simplified overload for GET requests
Json(object model, bool allowGet)
💡 Use JsonRequestBehavior.AllowGet to allow GET requests to return JSON.

Content Response

Return plain text, HTML, XML, CSS, JavaScript, or any text-based content.

Plain Text:

public ActionResponse GetText()
{
    return Content("Hello, World!");
}

HTML Content:

public ActionResponse GetHtml()
{
    string html = "<h1>Welcome</h1><p>This is dynamic HTML.</p>";
    return Content(html, "text/html");
}

XML Content:

public ActionResponse GetXml()
{
    string xml = @"
        <contact>
            <firstName>John</firstName>
            <lastName>Doe</lastName>
            <email>john.doe@example.com</email>
        </contact>
    ";
    
    return Content(xml, "application/xml");
}

JSON as Content (Alternative to Json()):

public ActionResponse GetJsonAsText()
{
    var data = new { name = "John", age = 30 };
    var json = JsonConvert.SerializeObject(data);
    
    return Content(json, "application/json");
}

CSS Content:

public ActionResponse GetCustomCss()
{
    var css = @"
        body { background-color: #f0f0f0; }
        h1 { color: navy; }
    ";
    
    return Content(css, "text/css");
}

JavaScript Content:

public ActionResponse GetScript()
{
    var js = "alert('Hello from controller!');";
    return Content(js, "application/javascript");
}

Available Content() Overloads:

// Plain text with default content type
Content(string content)

// Content with specific MIME type
Content(string content, string contentType)

// Content with MIME type and encoding
Content(string content, string contentType, Encoding contentEncoding)
💡 Note: If your action returns a primitive type (string, int, etc.), Magentrix automatically converts it to a Content response:
public string MyAction()
{
    return "<Contact><FirstName>Sam</FirstName></Contact>";
}

This is equivalent to:

public ActionResponse MyAction()
{
    return Content("<Contact><FirstName>Sam</FirstName></Contact>");
}

Special Responses

UnauthorizedAccessResponse

Return when a user doesn't have permission to access a resource:

public ActionResponse AdminDashboard()
{
    if (SystemInfo.IsGuestUser)
        return UnauthorizedAccessResponse();
    
    if (UserInfo.IsPortalUser)
        return UnauthorizedAccessResponse();
    
    // Employee-only logic
    return View();
}

PageNotFound

Return a user-friendly 404 error:

public ActionResponse ViewResource(string id)
{
    var resource = Database.Query<Resource>()
        .Where(r => r.Id == id)
        .FirstOrDefault();
    
    if (resource == null)
        return PageNotFound();
    
    return View(resource);
}

RedirectToError

Redirect to an error page with a custom message:

public ActionResponse ProcessPayment()
{
    try
    {
        // Payment processing logic
        return View();
    }
    catch (PaymentException ex)
    {
        return RedirectToError("Payment processing failed. Please try again or contact support.");
    }
}

Response Type Decision Guide

Use this guide to choose the right response type:

┌─────────────────────────────────────┐
│   What are you trying to do?        │
└──────────────┬──────────────────────┘
               │
        ┌──────┴──────┐
        │             │
  ┌─────▼──────┐  ┌──▼───────────────┐
  │ Show HTML  │  │ Return Data      │
  │ Page?      │  │ or Files?        │
  └─────┬──────┘  └───┬──────────────┘
        │             │
        │             │
┌───────▼─────────────▼────────────────┐
│                                      │
│ HTML Page Options:                   │
│ • View() - Full page                 │
│ • PartialView() - Widget/fragment    │
│ • Predefined views - Error pages     │
│                                      │
│ Data/File Options:                   │
│ • Json() - API responses             │
│ • File() - Download files            │
│ • StorageFile() - Cloud files        │
│ • Pdf() - Generate PDFs              │
│ • Content() - Text/HTML/XML          │
│                                      │
│ Navigation Options:                  │
│ • Redirect() - Go to URL             │
│ • RedirectToAction() - Go to action  │
│                                      │
│ Error Options:                       │
│ • UnauthorizedAccessResponse()       │
│ • PageNotFound()                     │
│ • RedirectToError()                  │
└──────────────────────────────────────┘

Practical Examples

Example 1: Complete CRUD Controller with Mixed Responses

public class ContactManagerController : AspxController
{
    // GET: List all contacts (View response)
    public override ActionResponse Index()
    {
        var contacts = Database.Query<Contact>()
            .OrderBy(c => c.LastName)
            .ToList();
        
        return View(contacts);
    }
    
    // GET: Show create form (View response)
    public ActionResponse New()
    {
        return View(new Contact());
    }
    
    // POST: Create contact (Redirect response)
    [HttpPost]
    public ActionResponse New(Contact model)
    {
        if (ModelState.IsValid)
        {
            Database.Insert(model);
            AspxPage.AddMessage("Contact created successfully!");
            return RedirectToAction("Details", new { id = model.Id });
        }
        
        return View(model);
    }
    
    // GET: Show contact details (View response)
    public ActionResponse Details(string id)
    {
        var contact = Database.Retrieve(id);
        
        if (contact == null)
            return PageNotFound();
        
        return View(contact);
    }
    
    // GET: Show edit form (View response)
    public ActionResponse Edit(string id)
    {
        Contact contact = Database.Retrieve(id);
        
        if (contact == null)
            return PageNotFound();
        
        return View(contact);
    }
    
    // POST: Update contact (Redirect response)
    [HttpPost]
    public ActionResponse Edit(Contact model)
    {
        if (ModelState.IsValid)
        {
            Database.Update(model);
            AspxPage.AddMessage("Contact updated successfully!");
            return RedirectToAction("Details", new { id = model.Id });
        }
        
        return View(model);
    }
    
    // POST: Delete contact (Redirect response)
    [HttpPost]
    public ActionResponse Delete(string id)
    {
        try
        {
            Database.Delete(id);
            AspxPage.AddMessage("Contact deleted successfully.");
            return RedirectToAction("Index");
        }
        catch (Exception ex)
        {
            return RedirectToError("An error occurred while deleting the contact.");
        }
    }
    
    // GET: Export to CSV (File response)
    public ActionResponse ExportCsv()
    {
        var contacts = Database.Query<Contact>().ToList();
        var csv = new StringBuilder();

        csv.AppendLine("First Name,Last Name,Email,Phone");
        
        foreach (var contact in contacts)
            csv.AppendLine($"{contact.FirstName},{contact.LastName},{contact.Email},{contact.Phone}");
        
        var bytes = Encoding.UTF8.GetBytes(csv.ToString());
        return File(bytes, "text/csv", "contacts.csv");
    }
    
    // GET: Export to PDF (PDF response)
    public ActionResponse ExportPdf()
    {
        var contacts = Database.Query<Contact>().ToList();
        return Pdf(contacts, "contacts.pdf");
    }
}

Example 2: API Controller with JSON Responses

public class ContactApiController : AspxController
{
    // GET: /acls/ContactApi/GetAll
    [HandleExceptionsForJson]
    public ActionResponse GetAll()
    {
        var contacts = Database.Query<Contact>()
            .OrderBy(c => c.LastName)
            .ToList();
        
        return Json(contacts, JsonRequestBehavior.AllowGet);
    }
    
    // GET: /acls/ContactApi/Get?id=003R000000haXk3IAE
    [HandleExceptionsForJson]
    public ActionResponse Get(string id)
    {
        var contact = Database.Retrieve(id);
        
        if (contact == null)
            return Json(new { error = "Contact not found" }, 404, JsonRequestBehavior.AllowGet);
        
        return Json(contact, JsonRequestBehavior.AllowGet);
    }
    
    // POST: /acls/ContactApi/Create
    [HttpPost]
    [HandleExceptionsForJson]
    public ActionResponse Create(Contact model)
    {
        if (ModelState.IsValid)
        {
            Database.Insert(model);
            return Json(new { success = true, id = model.Id, message = "Contact created successfully" });
        }

        return Json(new { success = false, errors = ModelState }, 400);
    }

    // POST: /acls/ContactApi/Update
    [HttpPost]
    [HandleExceptionsForJson]
    public ActionResponse Update(Contact model)
    {
        if (ModelState.IsValid)
        {
            var existing = Database.Retrieve(model.Id);
        
            if (existing == null)
                return Json(new { success = false, error = "Contact not found" }, 404);
        
            Database.Update(model);
            return Json(new { success = true, message = "Contact updated successfully" });
        }
    
        return Json(new { success = false, errors = ModelState }, 400);
    }

    // POST: /acls/ContactApi/Delete?id=003R000000haXk3IAE
    [HttpPost]
    [HandleExceptionsForJson]
    public ActionResponse Delete(string id)
    {
        var contact = Database.Retrieve(id);
    
        if (contact == null)
            return Json(new { success = false, error = "Contact not found" }, 404);
    
        Database.Delete(id);
        return Json(new { success = true, message = "Contact deleted successfully" });
    }

    // GET: /acls/ContactApi/Search?query=john
    [HandleExceptionsForJson]
    public ActionResponse Search(string query)
    {
        if (string.IsNullOrEmpty(query))
            return Json(new { success = false, error = "Query parameter is required" }, 400, JsonRequestBehavior.AllowGet);
    
        var contacts = Database.Query<Contact>()
            .Where(c => c.FirstName.Contains(query) || 
                        c.LastName.Contains(query) || 
                        c.Email.Contains(query))
            .OrderBy(c => c.LastName)
            .ToList();
    
        return Json(new { success = true, count = contacts.Count, data = contacts }, 
            JsonRequestBehavior.AllowGet);
    }
}

Example 3: Report Generator with Multiple Export Formats


public class ReportsController : AspxController
{
    // GET: /aspx/Reports - Show report page (View response)
    public override ActionResponse Index()
    {
        var accounts = Database.Query<Account>()
            .Where(a => a.Type == "Customer")
            .ToList();
        
        return View(accounts);
    }
    
    // GET: /acls/Reports/ExportCsv - CSV export (File response)
    public ActionResponse ExportCsv(string type)
    {
        var accounts = Database.Query<Account>()
            .Where(a => a.Type == type)
            .OrderBy(a => a.Name)
            .ToList();
        
        var csv = new StringBuilder();
        csv.AppendLine("Account Name,Type,Industry,Annual Revenue");
        
        foreach (var account in accounts)
            csv.AppendLine($"{account.Name},{account.Type},{account.Industry},{account.AnnualRevenue}");
        
        byte[] bytes = Encoding.UTF8.GetBytes(csv.ToString());
        return File(bytes, "text/csv", $"accounts_{type}.csv");
    }
    
    // GET: /acls/Reports/ExportPdf - PDF export (PDF response)
    public ActionResponse ExportPdf(string type)
    {
        var accounts = Database.Query<Account>()
            .Where(a => a.Type == type)
            .OrderBy(a => a.Name)
            .ToList();
        
        var html = GenerateReportHtml(accounts, type);
        return Pdf(html, $"accounts_{type}.pdf");
    }
    
    // GET: /acls/Reports/ExportJson - JSON export (Json response)
    [HandleExceptionsForJson]
    public ActionResponse ExportJson(string type)
    {
        var accounts = Database.Query<Account>()
            .Where(a => a.Type == type)
            .OrderBy(a => a.Name)
            .Select(a => new
            {
                a.Name,
                a.Type,
                a.Industry,
                a.AnnualRevenue,
                a.Phone,
                a.Website
            })
            .ToList();
        
        return Json(new { 
            reportType = type, 
            generatedDate = DateTime.Now,
            totalCount = accounts.Count,
            data = accounts 
        }, JsonRequestBehavior.AllowGet);
    }
    
    // GET: /acls/Reports/ExportXml - XML export (Content response)
    public ActionResponse ExportXml(string type)
    {
        var accounts = Database.Query<Account>()
            .Where(a => a.Type == type)
            .OrderBy(a => a.Name)
            .ToList();
        
        var xml = new StringBuilder();
        xml.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xml.AppendLine("<accounts>");
        
        foreach (var account in accounts)
        {
            xml.AppendLine("  <account>");
            xml.AppendLine($"    <name>{SecurityElement.Escape(account.Name)}</name>");
            xml.AppendLine($"    <type>{SecurityElement.Escape(account.Type)}</type>");
            xml.AppendLine($"    <industry>{SecurityElement.Escape(account.Industry)}</industry>");
            xml.AppendLine($"    <revenue>{account.AnnualRevenue}</revenue>");
            xml.AppendLine("  </account>");
        }
        
        xml.AppendLine("</accounts>");
        
        return Content(xml.ToString(), "application/xml");
    }
    
    private string GenerateReportHtml(List<Account> accounts, string type)
    {
        return $@"
            <html>
                <head>
                    <style>
                        body {{ font-family: Arial; padding: 20px; }}
                        h1 {{ color: navy; border-bottom: 2px solid navy; }}
                        table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
                        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                        th {{ background-color: navy; color: white; }}
                        .footer {{ margin-top: 20px; font-size: 12px; color: gray; }}
                    </style>
                </head>
                <body>
                    <h1>{type} Accounts Report</h1>
                    <p>Generated: {DateTime.Now:MM/dd/yyyy hh:mm tt}</p>
                    <p>Total Accounts: {accounts.Count}</p>
                    
                    <table>
                        <thead>
                            <tr>
                                <th>Account Name</th>
                                <th>Industry</th>
                                <th>Annual Revenue</th>
                            </tr>
                        </thead>
                        <tbody>
                            {string.Join("", accounts.Select(a => $@"
                                <tr>
                                    <td>{a.Name}</td>
                                    <td>{a.Industry}</td>
                                    <td>${a.AnnualRevenue:N2}</td>
                                </tr>
                            "))}
                        </tbody>
                    </table>
                    
                    <div class='footer'>
                        <p>Generated by Magentrix Portal</p>
                    </div>
                </body>
            </html>
        ";
    }
}

Example 4: File Management Controller

public class FileManagerController : AspxController
{
    // GET: /aspx/FileManager - Show file list (View response)
    public override ActionResponse Index()
    {
        var files = Database.Query<Document>()
            .OrderByDescending(d => d.CreatedDate)
            .ToList();
        
        return View(files);
    }
    
    // GET: /acls/FileManager/Download?id=xxx - Download file (File response)
    public ActionResponse Download(string id)
    {
        try
        {
            var document = Database.Retrieve(id);
            
            if (document == null)
                return PageNotFound();
            
            // Read file from storage
            var fileBytes = Storage.ReadFileBytes(document.StorageId);
            
            return File(fileBytes, document.ContentType, document.FileName);
        }
        catch (Exception ex)
        {
            SystemInfo.Debug($"Download error: {ex.Message}");
            return RedirectToError("An error occurred while downloading the file.");
        }
    }
    
    // GET: /acls/FileManager/DownloadFromStorage?blobId=xxx - Stream from storage (StorageFile response)
    public ActionResponse DownloadFromStorage(string blobId)
    {
        try
        {
            var document = Database.Query<Document>()
                .Where(d => d.StorageId == blobId)
                .FirstOrDefault();
            
            if (document == null)
                return PageNotFound();
            
            // Stream directly from cloud storage
            return StorageFile(blobId, document.ContentType, document.FileName);
        }
        catch (Exception ex)
        {
            SystemInfo.Debug($"Storage download error: {ex.Message}");
            return RedirectToError("An error occurred while accessing the file.");
        }
    }
    
    // GET: /acls/FileManager/ViewPdf?id=xxx - View PDF inline (StorageFile response)
    public ActionResponse ViewPdf(string id)
    {
        var document = Database.Retrieve<Document>(id);
        
        if (document == null)
            return PageNotFound();
        
        if (document.ContentType != "application/pdf")
            return RedirectToError("Only PDF files can be viewed inline.");
        
        // Fourth parameter: true = open inline in browser
        return StorageFile(document.StorageId, document.ContentType, document.FileName, true);
    }
    
    // POST: /acls/FileManager/Upload - Upload file (Json response)
    [HttpPost]
    [HandleExceptionsForJson]
    public ActionResponse Upload(HttpPostedFileBase file, string description)
    {
        try
        {
            if (file == null || file.ContentLength == 0)
                return Json(new { success = false, error = "No file uploaded" }, 400);
            
            // Read file content
            var fileBytes = new byte[file.ContentLength];
            file.InputStream.Read(fileBytes, 0, file.ContentLength);
            
            // Save to storage
            var storageId = Storage.WriteFile(fileBytes, file.FileName, file.ContentType);
            
            // Create document record
            var document = new Document
            {
                FileName = file.FileName,
                ContentType = file.ContentType,
                FileSize = file.ContentLength,
                StorageId = storageId,
                Description = description,
                UploadedBy = UserInfo.Name,
                UploadedDate = DateTime.Now
            };
            
            Database.Insert(document);
            
            return Json(new { 
                success = true, 
                documentId = document.Id,
                message = "File uploaded successfully" 
            });
        }
        catch (Exception ex)
        {
            SystemInfo.Debug($"Upload error: {ex.Message}");
            return Json(new { success = false, error = "Upload failed" }, 500);
        }
    }
}

Example 5: Dashboard with AJAX Integration

public class DashboardController : AspxController
{
    // GET: /aspx/Dashboard - Main dashboard page (View response)
    public override ActionResponse Index()
    {
        return View();
    }
    
    // GET: /acls/Dashboard/GetStats - Get dashboard statistics (Json response)
    [HandleExceptionsForJson]
    public ActionResponse GetStats()
    {
        var stats = new
        {
            totalAccounts = Database.Query<Account>().Count(),
            totalContacts = Database.Query<Contact>().Count(),
            openOpportunities = Database.Query<Opportunity>()
                .Where(o => !o.IsClosed)
                .Count(),
            totalRevenue = Database.Query<Opportunity>()
                .Where(o => o.Stage == "Closed Won")
                .ToList()
                .Sum(o => o.Amount),
            thisMonthRevenue = Database.Query<Opportunity>()
                .Where(o => o.Stage == "Closed Won" && 
                           o.CloseDate >= DateTime.Now.AddMonths(-1))
                .ToList() 
                .Sum(o => o.Amount)
        };
        
        return Json(stats, JsonRequestBehavior.AllowGet);
    }
    
    // GET: /acls/Dashboard/GetRecentActivity - Get recent activities (Json response)
    [HandleExceptionsForJson]
    public ActionResponse GetRecentActivity(int count = 10)
    {
        var recentOpportunities = Database.Query<Opportunity>()
            .OrderByDescending(o => o.LastModifiedDate)
            .Take(count)
            .Select(o => new
            {
                id = o.Id,
                name = o.Name,
                stage = o.Stage,
                amount = o.Amount,
                accountName = o.Account.Name,
                lastModified = o.LastModifiedDate
            })
            .ToList();
        
        return Json(new { 
            success = true, 
            data = recentOpportunities 
        }, JsonRequestBehavior.AllowGet);
    }
    
    // GET: /acls/Dashboard/ExportSnapshot - Export dashboard snapshot (PDF response)
    public ActionResponse ExportSnapshot()
    {
        var stats = new
        {
            TotalAccounts = Database.Query<Account>().Count(),
            TotalContacts = Database.Query<Contact>().Count(),
            OpenOpportunities = Database.Query<Opportunity>().Where(o => !o.IsClosed).Count(),
            TotalRevenue = Database.Query<Opportunity>()
                .Where(o => o.Stage == "Closed Won")
                .ToList()
                .Sum(o => o.Amount)
        };
        
        var html = $@"
            <html>
                <head>
                    <style>
                        body {{ font-family: Arial; padding: 20px; }}
                        h1 {{ color: navy; }}
                        .metric {{ background: #f0f0f0; padding: 15px; margin: 10px 0; }}
                        .metric-value {{ font-size: 24px; font-weight: bold; color: navy; }}
                    </style>
                </head>
                <body>
                    <h1>Dashboard Snapshot</h1>
                    <p>Generated: {DateTime.Now:MM/dd/yyyy hh:mm tt}</p>
                    
                    <div class='metric'>
                        <div>Total Accounts</div>
                        <div class='metric-value'>{stats.TotalAccounts}</div>
                    </div>
                    
                    <div class='metric'>
                        <div>Total Contacts</div>
                        <div class='metric-value'>{stats.TotalContacts}</div>
                    </div>
                    
                    <div class='metric'>
                        <div>Open Opportunities</div>
                        <div class='metric-value'>{stats.OpenOpportunities}</div>
                    </div>
                    
                    <div class='metric'>
                        <div>Total Revenue (Closed Won)</div>
                        <div class='metric-value'>${stats.TotalRevenue:N2}</div>
                    </div>
                </body>
            </html>
        ";
        
        return Pdf(html, $"Dashboard_Snapshot_{DateTime.Now:yyyyMMdd}.pdf");
    }
}

JavaScript in Active Page calls the AJAX endpoints:

// Fetch dashboard statistics
fetch('/acls/Dashboard/GetStats')
    .then(response => response.json())
    .then(data => {
        document.getElementById('totalAccounts').textContent = data.totalAccounts;
        document.getElementById('totalContacts').textContent = data.totalContacts;
        document.getElementById('openOpportunities').textContent = data.openOpportunities;
        document.getElementById('totalRevenue').textContent = '$' + data.totalRevenue.toLocaleString();
    });

// Fetch chart data
fetch('/acls/Dashboard/GetChartData?chartType=revenue-by-month')
    .then(response => response.json())
    .then(result => {
        if (result.success) {
            renderChart(result.data);
        }
    });

Best Practices

1. Choose the Right Response Type

Use View() for user-facing pages

public override ActionResponse Index()
{
    return View(model);
}

Use Json() for APIs

[HandleExceptionsForJson]
public ActionResponse GetData()
{
    return Json(data, JsonRequestBehavior.AllowGet);
}

Use Redirect() after POST to prevent resubmission

[HttpPost]
public ActionResponse Create(Contact model)
{
    Database.Insert(model);
    return RedirectToAction("Index"); // ✅ Correct
    // return View(model); // ❌ Avoid - causes form resubmission
}

2. Always Use [HandleExceptionsForJson] for JSON Responses

Without attribute:

public ActionResponse GetContact(string id)
{
    var contact = Database.Retrieve<Contact>(id);
    return Json(contact, JsonRequestBehavior.AllowGet);
}
// If an exception occurs, response is HTML error page, not JSON

With attribute:

[HandleExceptionsForJson]
public ActionResponse GetContact(string id)
{
    var contact = Database.Retrieve<Contact>(id);
    return Json(contact, JsonRequestBehavior.AllowGet);
}
// Exceptions are automatically returned as JSON

3. Use Absolute URLs for PDF Resources

Incorrect:

<img src="/images/logo.png" />
<link rel="stylesheet" href="/css/styles.css" />

Correct:

<img src="https://yourportal.magentrix.com/images/logo.png" />
<link rel="stylesheet" href="https://yourportal.magentrix.com/css/styles.css" />

4. Set Appropriate Content Types

// CSV files
return File(bytes, "text/csv", "data.csv");

// Excel files
return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx");

// JSON text
return Content(json, "application/json");

// XML text
return Content(xml, "application/xml");

5. Use StorageFile for Cloud-Stored Files

Inefficient:

public ActionResponse Download(string id)
{
    // Loads entire file into memory
    var fileBytes = Storage.ReadFileBytes(id); 
    return File(fileBytes, contentType, fileName);
}

Efficient:

public ActionResponse Download(string id)
{
    // Streams directly
    return StorageFile(id, contentType, fileName);
}

6. Provide Meaningful Filenames

Generic:

return File(bytes, "text/csv", "export.csv");

Descriptive:

return File(bytes, "text/csv", $"Contacts_Export_{DateTime.Now:yyyyMMdd}.csv");

7. Handle Errors Gracefully

public ActionResponse Download(string id)
{
    try
    {
        var document = Database.Retrieve<Document>(id);
        
        if (document == null)
            return PageNotFound();
        
        var fileBytes = Storage.ReadFileBytes(document.StorageId);
        return File(fileBytes, document.ContentType, document.FileName);
    }
    catch (Exception ex)
    {
        SystemInfo.Error(ex);
        return RedirectToError("An error occurred while downloading the file.");
    }
}

Common Pitfalls

❌ Pitfall 1: Using View() in Standalone Controllers

// URL: /acls/MyApi/GetData
public class MyApiController : AspxController
{
    public ActionResponse GetData()
    {
        // ❌ ERROR: No Active Page exists!
        return View(); 
    }
}

Solution:

[HandleExceptionsForJson]
public ActionResponse GetData()
{
    var data = Database.Query<Contact>().ToList();

    // ✅ Correct
    return Json(data, JsonRequestBehavior.AllowGet); 
}

❌ Pitfall 2: Returning View After POST

[HttpPost]
public ActionResponse Create(Contact model)
{
    Database.Insert(model);

    // ❌ Causes form resubmission on refresh
    return View(model);
}

Solution:

[HttpPost]
public ActionResponse Create(Contact model)
{
    Database.Insert(model);

    // ✅ Correct - PRG pattern
    return RedirectToAction("Index"); 
}

❌ Pitfall 3: Forgetting JsonRequestBehavior.AllowGet

public ActionResponse GetContacts()
{
    var contacts = Database.Query<Contact>().Limit(10).ToList();

    // ❌ Only works for POST
    return Json(contacts); 
}

Solution:

[HandleExceptionsForJson]
public ActionResponse GetContacts()
{
    var contacts = Database.Query<Contact>().Limit(10).ToList();

    // ✅ Works for GET
    return Json(contacts, JsonRequestBehavior.AllowGet); 
}

❌ Pitfall 4: Not Checking for Null Before Returning View

public ActionResponse Details(string id)
{
    var contact = Database.Retrieve<Contact>(id);

    // ❌ Crashes if contact is null
    return View(contact); 
}

Solution:

public ActionResponse Details(string id)
{
    var contact = Database.Retrieve<Contact>(id);
    
    // ✅ Graceful error handling
    if (contact == null)
        return PageNotFound(); 
    
    return View(contact);
}

Summary

This section covered all response types available in Magentrix controllers:

View Responses - Render Active Pages for user-facing interfaces

PartialView Responses - Render page fragments and widgets

Redirect Responses - Navigate to URLs or controller actions

File Responses - Stream binary files for download

StorageFile Responses - Stream files from Magentrix Cloud Storage

PDF Responses - Generate dynamic PDF documents

Json Responses - Return JSON data for APIs

Content Responses - Return text, HTML, XML, or other content

Special Responses - Handle errors and unauthorized access


Next Steps

Continue your learning journey:


Quick Reference

Response Type Cheat Sheet

// View responses
return View();
return View(model);
return PartialView(model);
return PageNotFound();
return RecordDeleted();

// Redirect responses
return Redirect("~/home/index");
return RedirectToAction("Index");
return RedirectToAction("Edit", "Contact", new { id = "123" });
return Redirect(ActivePages.MyPage, new { id = "123" });

// File responses
return File(bytes, "text/csv", "data.csv");
return StorageFile(blobId, contentType, fileName);
return Pdf(model, "report.pdf");

// Data responses
return Json(data, JsonRequestBehavior.AllowGet);
return Content("Hello World");
return Content(html, "text/html");

// Error responses
return UnauthorizedAccessResponse();
return RedirectToError("Error message");

💡 Mastering response types is essential for building robust controllers! Choose the right response type for each scenario to create efficient, user-friendly applications.