The Wizard’s Lab: Serving web pages from AL and Business Central

Come visit me in my lab and see how web pages can be served out of Microsoft Dynamics 365 Business Central if you forget the rulebook and makes up your own.

https://youtu.be/SqazEmN5xeE

In this video, Erik takes us into “The Wizard’s Lab” — a late-night hacking session from pitch-black, rainy British Columbia — where he demonstrates how to serve web pages directly from AL code running inside Business Central. Using his custom AL compiler and a lightweight .NET-based proxy web server, Erik builds a server-side templating system reminiscent of PHP or Razor, but powered entirely by Business Central’s AL language. The result is a working web portal that renders customer data and ledger entries as standard HTML pages, served in real-time from BC.

The Problem: Portal Solutions and OData Limitations

If you need to build a customer-facing portal — a place where users log in, view data, and trigger business logic — you need some kind of portal technology that connects to Business Central. The go-to solution today is typically OData: you pull data from OData endpoints and trigger business logic through bound and unbound actions.

But OData has limitations. A single portal front page might need data from eight or ten different OData calls. That’s a lot of traffic. You risk getting throttled by Business Central. OData isn’t the fastest protocol in the world, and when you have multiple dependent queries, the latency compounds quickly.

Server-Side Templating: An Alternative Approach

Erik’s approach is server-side templating — a technique where hybrid pages containing a mix of HTML and server-side code are resolved on the server into standard HTML before being sent to the browser. This is the same concept behind PHP, ASP.NET Razor, and similar technologies.

Erik has history with this approach. He wrote what he believes was the first such solution for Navision (now Business Central) back in the early 2000s — a product called WSFN (Web Server for Navision). That product used a custom tag language evaluated inside Business Central to dynamically generate HTML from table data.

Architecture: The .NET Proxy Web Server

The architecture consists of a thin .NET-based web server — under 200 lines of C# — built on ASP.NET Core. This server acts as middleware: it receives HTTP requests from web browsers, packages up the request information (path, query string parameters, content types) into a JSON structure, and forwards it to Business Central via a web service call.

The flow works like this:

  1. A browser makes a request to the .NET web server
  2. The web server collects path segments, query parameters, and other request metadata into a JSON object
  3. It calls a Business Central web service function called Call, passing the JSON as a parameter
  4. Business Central processes the request, generates HTML, and returns it as a Base64-encoded response
  5. The .NET server decodes the response and sends the HTML back to the browser

The web service endpoint and configuration are defined in app settings. Erik notes he’s currently using SOAP for the web service call — and admits he actually likes SOAP, even though “I know I’m not supposed to say that out loud.”

Web Templates: Mixing HTML and AL

The core of the system is a web template — stored in a Business Central table — that contains a hybrid of HTML and AL code. The template uses a <?bc ... ?> tag syntax (similar to PHP’s <?php ?>) to delineate AL code sections within the HTML.

Here’s how the template works conceptually:

  • Code blocks starting with <?bc contain AL code — variable declarations, loops, filters, and business logic
  • Expression tags using <? ... ?> (without the bc prefix) output values inline — like <?cust.Name?>
  • Everything outside the tags is standard HTML, passed through as-is

For example, a template might declare customer and customer ledger entry record variables at the top, then loop through customers with a repeat...until loop, generating HTML table rows for each record. Inside the customer loop, it can set filters on ledger entries, loop through those, and output posting dates, descriptions, and amounts — all interleaved with HTML markup.

Erik grabbed a template from the Material Design Lite framework to demonstrate that there are no predefined design constraints — you have complete control over the HTML and CSS output. The template even references a stylesheet at /styles, which is itself served as a web template (potentially with dynamic AL-generated CSS).

A Note on Begin/End

One important constraint: because HTML is interspersed between AL statements, the single-statement-after-then pattern doesn’t work reliably. Erik enforces the use of begin...end blocks in templates to keep the code structure unambiguous when mixing the two languages.

Template Compilation and Execution

When a request comes in and matches a template, Business Central processes it through these steps:

  1. The template text is split on the <? ?> tag boundaries
  2. Even-numbered segments are HTML; odd-numbered segments starting with bc are AL code
  3. HTML segments get wrapped in calls to an html() function that appends to a text builder
  4. AL code segments are inserted directly
  5. Expression segments (without bc) are also wrapped in html() calls to output their values
  6. The first section serves as a “pre-section” where you can define procedures and variables
  7. The resulting composite code is passed to Erik’s custom AL compiler, which parses it
  8. The interpreter then executes the compiled code
  9. The accumulated HTML output is returned as the response

The html() function is implemented as a subscriber to an OnFunctionCall event in the compiler. When the interpreter encounters a function call that isn’t a built-in AL function (like StrLen, Round, Abs, etc.), it raises this event. The web functions subscriber handles the html function by appending content to an internal text builder, which is then retrieved at the end via GetHtml.

The “Hardened” Version: Compiled AL Templates

While the interpreted approach works (about 1.5 seconds per page render on Erik’s machine, which was also recording video), there’s a faster alternative: hardened templates.

The idea is simple: take the generated AL code that the compiler produces from a template, save it into a regular AL codeunit, and deploy it through normal means. This codeunit subscribes to an OnCallHardenedTemplate event, bypassing the compiler and interpreter entirely.

The hardened version runs as native, Microsoft-compiled AL code — cross-compiled to C#, then to IL, then to machine code. It’s essentially the same output but running at full native performance.

Erik demonstrated both versions side by side, producing identical pages. The hardened version runs between one-third and two times faster than the interpreted version, depending on the scenario. He argues that for real-time data from Business Central with multiple dependent queries, this is probably one of the fastest approaches possible.

Syntax Highlighting for the Hybrid Language

Erik also built a custom syntax highlighter that understands the <?bc ?> tag boundaries. It switches between HTML highlighting (outside the tags) and AL highlighting (inside the tags), correctly applying different keyword sets and color schemes depending on which language context you’re in. As Erik puts it: “I spent way too much time on this.”

Source Code: The AL Extension Skeleton

The provided source code includes the app manifest for the extension:

{
  "id": "3c903daa-695c-4dca-87eb-9571bf1cb145",
  "name": "AppIsAlsoAWebPage",
  "publisher": "Default publisher",
  "version": "1.0.0.0",
  "platform": "1.0.0.0",
  "application": "22.0.0.0",
  "idRanges": [
    {
      "from": 50100,
      "to": 50149
    }
  ],
  "runtime": "11.0",
  "features": [
    "NoImplicitWith"
  ]
}

Conclusion

Erik openly acknowledges this is an “unholy marriage” between two technologies that perhaps shouldn’t share the same file — and he doesn’t entirely disagree with that characterization. But the power of the approach is undeniable: in just a few lines of interleaved HTML and AL, you can build a fully functional web portal that renders real-time Business Central data with multiple dependent queries, all in a single server-side round trip.

The system offers two execution modes: an interpreted mode using Erik’s custom AL compiler (great for rapid prototyping and template editing) and a hardened mode using standard compiled AL codeunits (for production performance). Both produce identical output, giving developers a clear upgrade path from experimentation to deployment.

Whether this is brilliant or mad science is left as an exercise for the viewer — but as a proof of concept for serving web pages directly from Business Central, it’s a compelling demonstration of what’s possible when you push the platform in unconventional directions.