Solving Barcode Printing Issues in RDLC Reports – Business Central On-Premise (v25)

When working with barcode printing in RDLC reports on Microsoft Dynamics 365 Business Central On-Premise, I recently ran into an issue that had me stumped for hours — and as it turns out, it all came down to a subtle but critical font installation step.

If you’re using Business Central and your barcodes refuse to show up in your reports (even after installing the right fonts), read on — this might just be your solution.

🚫 The Problem: Barcode Fonts Not Showing in RDLC

Here’s what I tried — the standard advice you’ll find across most forums:

  • ✅ Installed the barcode font (Code 128, Code 39, Free 3 of 9, etc.) on the service tier machine
  • ✅ Installed the same font on the user/client machine
  • ✅ Restarted the Business Central Server/NST
  • ✅ Restarted the entire machine
  • ✅ Checked that RDLC reports were using the correct font name

Still — no barcodes were rendered.

🕵️ The Hidden Detail: “Install for All Users”

After much trial and error, I stumbled across the real fix:

When installing a font on the Business Central service tier (server), you must choose “Install for all users” — not just a regular install.

Here’s why:

  • Business Central’s NST runs under a system account, not your logged-in user.
  • Fonts installed only for the current user aren’t visible to the NST process.
  • Unless the font is registered system-wide, RDLC won’t be able to use it.

Install the Barcode Font on the Server

  • Right-click the font file (e.g., Code128.ttf)
  • Choose ➡️ Install for all users

Install the Font on Client Machine (Optional but recommended)

  • This ensures previews and printed reports render properly when opened locally.

Restart the Server

  • Not just the NST service — a full restart helps Windows fully register system fonts.

It’s always the little things! A simple checkbox — “Install for all users” — was all it took to fix what seemed like a mysterious RDLC issue.

If you’re working with barcode fonts in RDLC reports on Business Central and nothing seems to work, double-check your font installation method — this could save you hours of frustration.

Hope this will help!!!

Upcoming Microsoft Business Central Pricing Changes – What You Need to Know

Microsoft has officially announced pricing changes for Dynamics 365 Business Central, set to take effect on October 1, 2025. This marks the first significant price adjustment in over five years, accompanied by enhanced storage and powerful feature upgrades. Whether you’re an existing customer or considering Business Central for the first time, understanding these changes is crucial for future planning.

New Pricing & Storage Overview

Starting October 1, 2025, the updated monthly subscription prices and storage allocations are as follows:

License TypeCurrent Price & StorageNew Price & Storage
Essentials$70/month with 2GB$80/month with 3GB
Premium$100/month with 3GB$110/month with 5GB
Device$40/month with 1GB$45/month with 1.5GB

The Team Member license remains unchanged in both pricing and storage.

These changes reflect a 10–15% price increase, while offering 33–50% more included storage—a move aimed at better aligning value with functionality.

Why Is Microsoft Adjusting Prices?

Microsoft attributes the pricing update to continuous investments in Business Central’s capabilities. Here’s what’s new and improved:

  • AI-Powered Features: Built-in Copilot functions, real-time financial insights, and automated reconciliation.
  • Advanced Analytics: Deepened analysis tools for finance and manufacturing teams.
  • Power Platform Integration: Seamless connectivity with Power BI, Power Automate, and Power Apps.
  • New Functionalities: Modules for sustainability tracking and master data management.
  • Global Support: More extensive localizations to support multi-national operations.

What This Means for Your Subscription

  • Current Customers: Your existing pricing remains in effect until your first renewal on or after October 1, 2025.
  • New Customers: Will be onboarded at the new pricing structure from the same date.

Currency & Regional Considerations

Though the pricing is listed in USD, local costs may vary depending on currency exchange rates and Microsoft’s regional pricing adjustments.

This update reinforces Microsoft’s commitment to keeping Business Central competitive and innovative. While pricing is going up modestly, users gain access to richer functionality, greater storage, and deeper integration within the Microsoft ecosystem.

Hope this will help!!!

Introducing ExcelLayoutMultipleDataSheets in Business Central 2025 Wave 1

With the release of Business Central 2025 Wave 1, business central continues to enhance developer and user experience in reporting and data analysis. One such powerful addition is the new property: ExcelLayoutMultipleDataSheets. This feature addresses a long-standing limitation in Excel export scenarios—allowing multiple datasets to be exported into separate sheets within a single Excel workbook.

What is ExcelLayoutMultipleDataSheets?

The ExcelLayoutMultipleDataSheets property is a new setting introduced for report objects that use Excel layouts. It enables developers to bind multiple data items or datasets to different worksheets in an Excel layout file (.xlsx), making reports more organized and structured when exported.

🧩 Structured Reports
Separate sheets for different datasets make it easier for business users to navigate complex reports—such as Sales Orders on one sheet, Customer Info on another, and Totals on a summary sheet.

🛠️ Developer Control
You can name your data items and match them to sheet names in your Excel layout. This gives you more granular control and reduces the need for workarounds.

How to Use ExcelLayoutMultipleDataSheets

report 50100 MyMultiSheetReport
{
    UsageCategory = ReportsAndAnalysis;
    ApplicationArea = All;
    DefaultRenderingLayout = MyExcelLayout;
    ExcelLayoutMultipleDataSheets = false; // Global setting is to use a single sheet

    dataset
    {
        dataitem(Customer; Customer)
        {
            column(CustomerNo; "No.") { }
            column(CustomerName; Name) { }
        }
        dataitem(Vendor; Vendor)
        {
            column(VendorNo; "No.") { }
            column(VendorName; Name) { }
        }
    }

    rendering
    {
        layout(MyExcelLayout)
        {
            Type = Excel;
            ExcelLayoutMultipleDataSheets = true; // Override for this specific layout
        }
    }
}

In this example, even though the global ExcelLayoutMultipleDataSheets property for the report is set to false, the MyExcelLayout will render the output with two separate worksheets:

  • Data_Customer containing the customer data.
  • Data_Vendor containing the vendor data.

If the ExcelLayoutMultipleDataSheets property within the MyExcelLayout definition was set to false (or not specified), both datasets would be combined into a single “Data” sheet in the Excel output.

The enhancement of the ExcelLayoutMultipleDataSheets property in Business Central Wave 1 2025 offers developers greater flexibility and control over Excel report layouts. By enabling the creation of multi-sheet Excel files at the layout level, you can deliver more user-friendly and better-organized reports, ultimately empowering your users to gain deeper insights from their Business Central data.

Stay tuned for more ….

Optimizing Business Central Reports with the DataAccessIntent Property

When developing reports in Microsoft Dynamics 365 Business Central, performance and scalability are crucial—especially in cloud environments where system efficiency impacts everything from responsiveness to cost. One often-overlooked feature that can significantly enhance report performance is the DataAccessIntent property.

What Is DataAccessIntent?

The DataAccessIntent property is available on report objects in AL. It specifies how a report should access the database—whether it’s read-only or read-write.

The property supports two values:

  • DataAccessIntent = ReadOnly
  • DataAccessIntent = ReadWrite

ReadOnly

When you set DataAccessIntent = ReadOnly, you are explicitly telling the platform that your report only needs to read data from the database and will not perform any write operations.

Why is this important?

  • Better Performance: In Business Central SaaS, reports marked as ReadOnly can run on read-only replicas of the database. This reduces the load on the primary (read-write) database and enhances scalability.
  • Improved Report Execution Time: Since queries are routed to optimized replicas, report rendering can be faster and more efficient.

ReadWrite

If your report needs to modify data during execution—a rare scenario—you should use DataAccessIntent = ReadWrite. This forces the report to run on the primary database.

However, you should avoid using ReadWrite unless absolutely necessary because:

  • It eliminates the benefit of using read replicas.
  • It may degrade performance, especially under high concurrency.

When to Use Each

ScenarioUse ReadOnly?Use ReadWrite?
Standard data listing/reporting
Reports that update records
Diagnostic or audit reports

How to Set DataAccessIntent in AL

report 50100 "Customer Balance Report"
{
    DataAccessIntent = ReadOnly;

    dataset
    {
        dataitem(Customer; Customer)
        {
            column(Name; Name) { }
            column(Balance; "Balance (LCY)") { }
        }
    }

    layout
    {
        // Define RDLC or Word layout
    }
}

By default, if you don’t specify the property, it behaves as ReadWrite. So it’s a good practice to explicitly set it to ReadOnly when applicable.

Important Considerations

  • The DataAccessIntent property is only a hint to the Business Central server. The server may not always be able to use a read-only replica, even if the property is set to ReadOnly.
  • If a report with DataAccessIntent set to ReadOnly attempts to modify data, a runtime error will occur.
  • The DataAccessIntent property can be overridden by the user through the “Database Access Intent List” page in Business Central.

In short: if your report doesn’t write data, use DataAccessIntent = ReadOnly. It’s an easy win for performance and best practice compliance.

Stay tuned for more….

Boosting Performance in Business Central with SETLOADFIELDS

When building customizations or integrations in Microsoft Dynamics 365 Business Central, performance is often a key concern—especially when working with large datasets. One powerful tool for improving performance is the SETLOADFIELDS method on record variables.

🚀 What is SETLOADFIELDS?

In Business Central, when you retrieve a record (using FIND, GET, NEXT, etc.), all fields of the record are loaded from the database by default. This includes fields you might never use, such as FlowFields (which are calculated on the fly). This can lead to unnecessary memory usage and slower data retrieval.

SETLOADFIELDS tells the system which fields to load, so it skips the rest. This can dramatically improve performance, particularly when:

  • You’re looping through large datasets
  • You’re only using a few fields per record
  • Your table includes FlowFields or BLOBs

📘 Syntax

Rec.SETLOADFIELDS(Field1, Field2, ...);

You place this line before reading the records. This tells the AL runtime engine to load only the specified fields when the records are retrieved.

Let’s say you need to loop through all items and check their No. and Inventory:

Item.SETLOADFIELDS("No.", Inventory);
if Item.FINDFIRST then
  repeat
    if Item.Inventory > 0 then
      // do something
  until Item.NEXT = 0;

  1. Use SETLOADFIELDS only when needed – Overusing it without understanding the data flow may result in missing fields or unexpected behavior.
  2. Calling CALCFIELDS still works – You can still explicitly calculate FlowFields after using SETLOADFIELDS.
  3. Resets on modification – If you call MODIFY, INSERT, or VALIDATE, the load fields context is reset. Use SETLOADFIELDS again if necessary.
  4. BLOB and FlowFields – Avoid loading BLOBs and FlowFields unless absolutely necessary. SETLOADFIELDS helps you skip them efficiently.

👨‍💻 Summary

FeatureWithout SETLOADFIELDSWith SETLOADFIELDS
Data LoadedAll fieldsOnly specified fields
Memory UsageHighLower
SpeedSlowerFaster

By leveraging SETLOADFIELDS, developers can significantly optimize the performance of their AL code in Business Central. It’s a small addition that can make a big difference in speed and scalability.

Avoid it when doing full record operations like MODIFY, unless you’re confident about which fields are required.

Stay Tuned for more…

How to Define Allowed Languages Per Environment in Business Central 2025 Wave 1

With the release of Business Central 2025 Wave 1, BC continues to enhance administrative control and governance features. One of the most welcome additions for global organizations is the ability to limit the available language options per environment. This is a game-changer for companies seeking better localization control, user experience consistency, and governance.

🚀 What’s New?

Until now, Business Central environments would display all installed languages by default, allowing users to switch freely. While flexibility is good, it posed problems in certain scenarios:

  • Local subsidiaries wanting only their national language.
  • Confusion due to long lists of unused language options.
  • Incorrect UI labels or translations due to unintended language selection.

Wave 1 2025 introduces the ability to define which languages are allowed per environment. Admins can now limit language choices for users based on the business unit, geography, or internal policy.

🔧 How to Configure Allowed Languages

To define allowed languages for a specific environment, follow these steps:

  1. Sign in to the Business Central
  2. Navigate to the new section: “Allowed Languages”.
  3. From the list of installed languages, check the boxes for only those you wish to allow.

Once applied, users in this environment will only see the allowed languages in their My Settings > Language dropdown.

This new feature may seem minor at first glance, but for global businesses and IT admins, it’s a powerful tool for consistency, control, and compliance. Whether you’re managing multiple countries, brands, or test environments, defining allowed languages per environment helps streamline operations and avoid confusion.

Stay tuned for more..

Understanding GETRANGEMIN() and GETRANGEMAX() in Business Central

When working with filters and record ranges in AL , two handy functions often come into play: GETRANGEMIN() and GETRANGEMAX(). These functions help you programmatically access the lower and upper bounds of a filter applied to a field in a record. This can be especially useful for creating reports, processing data, or passing filters between records.

What are GETRANGEMIN() and GETRANGEMAX()?

These two functions are part of the Record data type and help retrieve the range boundaries for a specific field filter.

  • GETRANGEMIN(Field): Returns the lowest value in the filter range for the specified field.
  • GETRANGEMAX(Field): Returns the highest value in the filter range for the specified field.

If there is no filter set for the field, both functions return blank.

SalesHeader.SETFILTER("No.", '1000..2000');

MinNo := SalesHeader.GETRANGEMIN("No."); // Returns '1000'
MaxNo := SalesHeader.GETRANGEMAX("No."); // Returns '2000'

Use Cases

1. Transferring Filter Ranges

If you’re applying a filter on one table and want to use the same range on another:

Customer.SETFILTER("No.", 'C00010..C00020');
SalesHeader.SETRANGE("Sell-to Customer No.", Customer.GETRANGEMIN("No."), Customer.GETRANGEMAX("No."));

2. Generating Custom Reports

SalesHeader.SETFILTER("Posting Date", '2024-01-01..2024-01-31');

StartDate := SalesHeader.GETRANGEMIN("Posting Date");
EndDate := SalesHeader.GETRANGEMAX("Posting Date");

MESSAGE('Report for: %1 to %2', StartDate, EndDate);

3. Validating Filtered Data

IF (SalesHeader.GETRANGEMIN("Posting Date") < AllowedStartDate) OR
   (SalesHeader.GETRANGEMAX("Posting Date") > AllowedEndDate) THEN
    ERROR('Filter range is outside allowed period.');

The GETRANGEMIN() and GETRANGEMAX() functions are powerful tools when working with dynamic filters in AL. They enable developers to write cleaner, more adaptable code by directly accessing the boundaries of filter conditions.

Stay Tuned for more updates.

Boosting Performance in Business Central with SetAutoCalcFields

In today’s fast-paced business environments, performance optimization is not a luxury — it’s a necessity. Whether you’re building custom reports, extending pages, or writing integration APIs in Microsoft Dynamics 365 Business Central, slow operations can frustrate users and strain resources.

One simple but powerful technique to improve performance is using the SetAutoCalcFields method.

Why FlowFields Matter for Performance

In Business Central, FlowFields are virtual fields calculated on the fly, not stored physically in the database. Examples include:

  • Inventory on Item
  • Balance on Customer

When you retrieve a record, FlowFields are not calculated automatically unless you explicitly call CalcFields().

Manually calculating FlowFields for every record during loops, leading to multiple SQL queries — one for each record — causing heavy load and slower performance.

SetAutoCalcFields solves this by batch-calculating FlowFields along with the record fetch.
Instead of running one query per record, it combines the calculation in a single optimized query.

Imagine fetching 1,000 customers and displaying their balances without SetAutoCalcfields:

CustomerRec.FindSet();
repeat
    CustomerRec.CalcFields(CustomerRec.Balance); // Triggers a DB call every time!
    DisplayBalance(CustomerRec."No.", CustomerRec.Balance);
until CustomerRec.Next() = 0;

Result:
  • 1 SQL query to get Customers
  • + 1,000 SQL queries for Balances

With SetAutoCalcFields:

CustomerRec.SetAutoCalcFields(CustomerRec.Balance);
CustomerRec.FindSet();
repeat
    DisplayBalance(CustomerRec."No.", CustomerRec.Balance);
until CustomerRec.Next() = 0;

Result:
  • 1 SQL query to get Customers and Balances together

Benefits of Using SetAutoCalcFields

  • Improved Page Load Times: By deferring calculations, pages with numerous records and calculated fields will load significantly faster.
  • Faster Report Generation: Reports that rely on calculated fields will be generated more quickly as the calculations are performed only when the field’s value is actually needed for display or processing.
  • Reduced Database Load: Fewer automatic calculations translate to fewer database queries, reducing the overall load on your Business Central database.
  • Enhanced User Experience: Snappier performance leads to a more responsive and enjoyable user experience.

Best Practices for Performance Gains

To maximize the benefits of SetAutoCalcFields:

  • Only specify necessary FlowFields:
    Don’t auto-calculate every FlowField — focus on what your process needs.
  • Use it before data retrieval:
    Call SetAutoCalcFields before FindSet(), FindFirst(), or FindLast()
  • Avoid unnecessary recalculations:
    Once FlowFields are set to auto-calculate, do not manually call CalcFields() again for the same fields.
  • Monitor heavy FlowFields:
    Some FlowFields (e.g., Inventory) involve complex sums across tables — only auto-calculate when really needed.
  • Profile your code:
    Use Performance Profiler to measure improvements.

Using SetAutoCalcFields properly can lead to dramatic performance improvements in Business Central.
By reducing SQL traffic, simplifying code, and batch-fetching FlowFields intelligently, you can create faster, cleaner, and more scalable applications.

A small change in your coding habits can create a big impact for your users.

Hope this will help..

How to Make a Report Layout Obsolete in Business Central (Wave 1 2025)

With the release of Microsoft Dynamics 365 Business Central Wave 1 2025, it continues to refine the AL development experience — and one of the key improvements is the ability to obsolete report layouts cleanly and officially.

If you’re managing a growing list of custom layouts or updating reports across multiple extensions, this new feature will help you deprecate old layouts safely, keep your solution clean, and guide developers or users toward better alternatives.

Why Obsoleting Layouts Matters

In real-world implementations, layouts evolve:

  • Data fields change.
  • Users request better designs.
  • Old layouts become unsupported.

Without a proper way to deprecate these layouts, organizations risk:

  • Confusion about which layout to use
  • Broken printouts
  • Technical debt piling up over time

Now, with Wave 1 2025, you can mark layouts as obsolete similarly to how you obsolete fields, tables, or procedures.

report 50100 "Sales Invoice Custom"
{
    Caption = 'Sales Invoice Custom';
    UsageCategory = ReportsAndAnalysis;
    ApplicationArea = All;
rendering
{
    layout(CustomLayout)
    {
        Type = RDLC;
        LayoutFile = 'Layouts\CustomSalesInvoice.rdl';
        ObsoleteState = Pending;
        ObsoleteReason = 'Replaced by layout NewCustomLayout in report 50101.';
        ObsoleteTag = 'BC-2025';
    }
}
}

ObsoleteState: Can be Pending (warning) or Removed (error).

ObsoleteReason: Brief explanation for developers/users.

ObsoleteTag: Identifies when/why it was marked obsolete (your own versioning or tag).

What Happens to Users When a Layout is Obsoleted?

  • ObsoleteState = Pending:
    • Users and developers get compiler warnings.
    • The layout is still selectable and usable.
  • ObsoleteState = Removed:
    • The system throws compiler errors if any report layout tries to use it.
    • Users can no longer select it at runtime.

The ability to obsolete report layouts in Business Central Wave 1 2025 is a small but powerful feature that can dramatically improve the quality, maintainability.

Whether you’re cleaning up old customer-specific layouts or modernizing your extensions, using Obsolete State strategically will help future-proof your solutions.

Stay Tuned for more updates!!!

Convert Simple Type Values to Text Using the New ToText Method in Business Central 2025 Wave 1

With the release of Business Central 2025 Wave 1, Business Central continues to simplify AL development by introducing intuitive and developer-friendly features. One such small yet powerful enhancement is the ToText method — designed to streamline how simple type values are converted to text.

In previous versions, we developers often relied on FORMAT() for converting simple types like integers, decimals, booleans, and option values into text. While FORMAT() has been effective, it comes with localization considerations and sometimes produces inconsistent results depending on the environment or the formatting settings.

✨ What’s New: ToText Method

The new ToText method is a type extension method introduced for simple AL types. It provides a clearer, more consistent way to convert values to string representations without the overhead of full formatting logic.

Supported Types

The ToText method supports the following simple types:

  • Integer
  • Decimal
  • Boolean
  • Char
  • Option
  • Date
  • Time
  • DateTime
  • GUID

Let’s look at some examples of how the ToText() method can simplify your code:

var
    myInteger: Integer := 42;
    myDecimal: Decimal := 2.71828;
    myDate: Date := TODAY;
    myTime: Time := TIME(10, 30, 0);
    myBoolean: Boolean := true;
    myOption: Option Alpha,Beta,Gamma := Option::Beta;
    integerAsText: Text;
    decimalAsText: Text;
    dateAsText: Text;
    timeAsText: Text;
    booleanAsText: Text;
    optionAsText: Text;
begin
    integerAsText := myInteger.ToText(); // integerAsText will be '42'
    decimalAsText := myDecimal.ToText(); // decimalAsText will be '2.71828' (or similar based on locale)
    dateAsText := myDate.ToText();       // dateAsText will be the default short date format
    timeAsText := myTime.ToText();       // timeAsText will be the default time format
    booleanAsText := myBoolean.ToText(); // booleanAsText will be 'true'
    optionAsText := myOption.ToText();   // optionAsText will be 'Beta'
    Message('Integer: %1', integerAsText);
    Message('Decimal: %1', decimalAsText);
    Message('Date: %1', dateAsText);
    Message('Time: %1', timeAsText);
    Message('Boolean: %1', booleanAsText);
    Message('Option: %1', optionAsText);
end;

Prefer ToText() when you want predictable results across environments (e.g., when storing values in logs or metadata).

Continue using FORMAT() when you need locale-aware output, such as in printed documents or user-facing formatted messages.

It simplifies the process of converting simple data types to their default text representations, leading to cleaner, more readable, and potentially more efficient code. While FORMAT() remains the go-to for advanced formatting needs, ToText() will undoubtedly become a frequently used tool in your Business Central development.

Stay tuned for more…