Search Results for

    Show / Hide Table of Contents

    Using native AOT

    Starting with FlexCel 7.23, we support .NET Native AOT, when using .NET 9.0. Native AOT (Ahead-of-Time) compilation allows you to compile your .NET applications into fully self-contained native executables, improving startup time and reducing runtime dependencies. However, there are some important considerations when using FlexCel with Native AOT.

    Supported Features in FlexCel under .NET Native AOT

    1. Excel File Manipulation:

      -   Creating, reading, and modifying Excel files is fully supported.
      -   Classes like XlsFile, and methods such as SetCellValue, GetCellValue, and Save work seamlessly under Native AOT.
    

    2. PDF, HTML, SVG and Image Rendering:

      -   Rendering Excel files to PDF or images is fully supported.
      -   Classes like FlexCelPdfExport and FlexCelImgExport function as expected.
    

    3. Core FlexCel Features:

      -   All non-report-related functionality, including working with formulas, charts, and cell formatting, is supported.
    

    Partially Supported Features: Reporting

    The FlexCel reporting engine is not fully supported under .NET Native AOT. Reports rely on runtime reflection, which may not work properly in Native AOT because of its aggressive trimming and because runtime-code generation is unavailable.

    Issues with Reports

    The reporting engine works with two kinds of data sources. DataSets and IQueryable objects like for example a List.

    • DataSets do not completely support AOT. Simple stuff will work, but for example, filtering by a column might not. This is also constantly changing: What doesn't work today might work tomorrow with newer .NET releases. So we can't provide a list of what works and what doesn't, but simple stuff should surely work.

    • LINQ is also not fully supported in AOT, and we also use Reflection to get the names of the fields. Still, most simple reports using LINQ will work, but there is an important thing to take into account:

    Important

    When using AOT, the linker aggressively removes classes and methods that aren't used. As FlexCelReport reads the properties via reflection, the classes you pass to FlexCelReport.AddTable must be annotated with the DynamicallyAccessedMembers attribute. For example:

     [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods
                                 | DynamicallyAccessedMemberTypes.PublicProperties)]
        class Customer
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }  
    
        ...
        Report.AddTable(CustomerList); //Customer is annotated to preserve both private and public properties.
      
    • Besides the issues with the two data sources we support, there are also a couple of things like sorting or filtering in the template, that won't work with AOT. Due to the dynamic nature of the reports, we can't know if a certain template is compatible or not with AOT before running the report, but if you keep them simple and annotate the classes you pass to AddTable, they should work.

      Note

      FlexCelReport uses warnings to let you know its limitations. Look at the example on this page for more information.

    Best Practices for Using FlexCel with .NET Native AOT

    1. Use .NET 9 or Later:

    • While Native AOT is also available in .NET 8, we use some features only available in .NET 9 and above.

    2. Check Reports:

    • If your application requires report generation, consider running it on a standard .NET runtime instead of Native AOT.
    • Alternatively, generate the reports in a separate process that doesn't use Native AOT.
    • If using reports directly, ensure that all the classes you use are annotated with the DynamicallyAccessedMembers attribute.

    3. Test Your Application:

    • Native AOT introduces unique runtime behaviors. Test your application thoroughly, especially if it involves reflection or dynamic operations.

    Example

    In this section, we will construct a Native AOT app using reports from scratch, and analyze what is happening.

    1. Create a new .NET console app, and name it native-aot.

    2. In the nuget package manager, add FlexCel.

    3. Type the following code into Program.cs:

    using FlexCel.Report;
    
    var Customers = new List<Customer>
    {
        new() { Name = "Microsoft", Address = "1 Microsoft Way, Redmond, WA 98052, US" },
        new() { Name = "Apple", Address = "Apple One Apple Park Way Cupertino, CA 95014" },
        new() { Name = "Google", Address = "1600 Amphitheatre Parkway in Mountain View, California" }
    };
    
    var report = new FlexCelReport(true);
    report.AddTable("customers", Customers);
    report.Run(Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\template.xlsx"),
               Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\result.xlsx"));
    
    class Customer
    {
        public required string Name { get; set; }
        public string UpperName => Name.ToUpper();
        public required string Address { get; set; }
    }
    

    4. Create a file in Excel:

    • In Cell A1, type <#customers.uppername>
    • In Cell B1, type <customers.address>
    • In Ribbon->Formulas->Name manager, create a new name. Name it __Customers__ and select =Sheet1!$A$1 in the "Refers to" field.
    • Save the file as "template.xlsx" in the same folder where Program.cs is.

    5. Make sure PublishAOT is true in your project options:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net9.0</TargetFramework>
        <PublishAot>true</PublishAot>
      </PropertyGroup>
    </Project>
    

    6. At the time of this writing, you can't run the app from Visual Studio. So open a console window, cd <folder where Programs.cs is> and type

     dotnet publish -r win-x64 -c Release .\native-aot.csproj
    

    Among others, you should see the following warnings:

    warning IL2026: Using member 'FlexCel.Report.FlexCelReport.FlexCelReport(Boolean)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. FlexCelReport is not fully compatible with Native AOT. See https://doc.tmssoftware.com/flexcel/net/tips/native-aot.html
    
    warning IL3050: Using member 'FlexCel.Report.FlexCelReport.FlexCelReport(Boolean)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. FlexCelReport is not fully compatible with Native AOT. See https://doc.tmssoftware.com/flexcel/net/tips/native-aot.html.
    

    This is us telling you that the reports might not work as expected. FlexCelReports is in itself a "compiler" that compiles and run a template written in Excel, so we can't give you more detailed warnings than this. We don't know which features your template will use. And the only way to find out, is to run the report and see if it works.

    Note

    If a report doesn't work, it will just crash. So there is no need to test for bugs in the generated files: If the report runs, the results are correct.

    Important

    To see all the warnings, you need to compile from the command line, using dotnet publish. While Visual Studio will show you some warnings, you can never be sure you are seeing them all.

    So let's try it! If everything went according to the plan, the app should run without issues.

    Done? Not really. There is some more stuff worth investigating. If you remember, we told you above to annotate your classes with DynamicallyAccessedMembers. But in this example we didn't, and the report run correctly. How did this happen?

    We specifically used a property, "UpperName" which isn't used anywhere, and so it should have been trimmed:

    upper name not used

    Still, it worked. What happens is that we called FlexCelReport.AddTable, the method itself is annotated with DynamicallyAccessedMembers, and so the trimmer knows that it shouldn't remove the property. If we removed that attribute from AddTable, we would get the following error:

    Unhandled exception. FlexCel.Core.FlexCelCoreException: Error in cell Sheet1!A1: "Column "uppername" does not exist on table "customers""
    ---> FlexCel.Core.FlexCelCoreException: Column "uppername" does not exist on table "customers"
       at FlexCel.Core.FlxMessages.ThrowException(FlxErr, Object[]) + 0x3b
       at FlexCel.Report.TSectionDataSet.Create(ExcelFile, TStackData, Int32, TOneCellValue, TRichString, TBand, Int32, FlexCelReport, Boolean) + 0x6c3
    

    But we can't always trust the code analyzer to figure it out by itself. In a more complex setting, for example if your code is in an assembly that is called by another one, the code analyzer might fail to discover that the property shouldn't be trimmed. So to be safe make sure to always annotate the classes you pass to FlexCelReport with DynamicallyAccessedMembers

    The code below is how we should have written the app:

    using FlexCel.Report;
    using System.Diagnostics.CodeAnalysis;
    
    var Customers = new List<Customer>
    {
        new() { Name = "Microsoft", Address = "1 Microsoft Way, Redmond, WA 98052, US" },
        new() { Name = "Apple", Address = "Apple One Apple Park Way Cupertino, CA 95014" },
        new() { Name = "Google", Address = "1600 Amphitheatre Parkway in Mountain View, California" }
    };
    
    var report = new FlexCelReport(true);
    report.AddTable("customers", Customers);
    report.Run(Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\template.xlsx"),
               Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\result.xlsx"));
    
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods
                                 | DynamicallyAccessedMemberTypes.PublicProperties)]
    class Customer
    {
        public required string Name { get; set; }
        public string UpperName => Name.ToUpper();
        public required string Address { get; set; }
    }
    
    In This Article
    Back to top FlexCel Studio for the .NET Framework v7.24.0.0
    © 2002 - 2025 tmssoftware.com