Exploring .NET 9’s Sequential GUIDs: A Game-Changer for XAF/XPO Developers

Exploring .NET 9’s Sequential GUIDs: A Game-Changer for XAF/XPO Developers

While researching useful features in .NET 9 that could benefit XAF/XPO developers, I discovered something particularly interesting: Version 7 GUIDs (RFC 9562 specification). These new GUIDs offer a crucial feature – they’re sortable.

This discovery brought me back to an issue I encountered two years ago while working on the SyncFramework. We faced a peculiar problem where Deltas were correctly generated but processed in the wrong order in production environments. The occurrences seemed random, and no clear pattern emerged. Initially, I thought using Delta primary keys (GUIDs) to sort the Deltas would ensure they were processed in their generation order. However, this assumption proved incorrect. Through testing, I discovered that GUID generation couldn’t be trusted to be sequential. This issue affected multiple components of the SyncFramework. Whether generating GUIDs in C# or at the database level, there was no guarantee of sequential ordering. Different database engines could sort GUIDs differently. To address this, I implemented a sequence service as a solution.Enter .NET 9 with its Version 7 GUIDs (conforming to RFC 9562 specification). These new GUIDs are genuinely sequential, making them reliable for sorting operations.

To demonstrate this improvement, I created a test solution for XAF with a custom base object. The key implementation occurs in the OnSaving method:


protected override void OnSaving()
{
    base.OnSaving();
    if (!(Session is NestedUnitOfWork) && Session.IsNewObject(this) && oid.Equals(Guid.Empty))
    {
        oid = Guid.CreateVersion7();
    }
}
        

Notice the use of CreateVersion7() instead of the traditional NewGuid(). For comparison, I also created another domain object using the traditional GUID generation:


protected override void OnSaving()
{
    base.OnSaving();
    if (!(Session is NestedUnitOfWork) && Session.IsNewObject(this) && oid.Equals(Guid.Empty))
    {
        oid = Guid.NewGuid();
    }
}
        

When creating multiple instances of the traditional GUID domain object, you’ll notice that the greater the time interval between instance creation, the less likely the GUIDs will maintain sequential ordering.

GUID Version 7

 

GUID Old Version

This new feature in .NET 9 could significantly simplify scenarios where sequential ordering is crucial, eliminating the need for additional sequence services in many cases. Here is the repo on GitHubHappy coding until next time!

Related article

On my GUID, common problems using GUID identifiers | Joche Ojeda

 

Understanding XtraReports: A Windows Forms Developer’s Guide

Understanding XtraReports: A Windows Forms Developer’s Guide

Introduction 🎯

If you’re familiar with Windows Forms development, transitioning to XtraReports will feel remarkably natural. This guide explores how XtraReports leverages familiar Windows Forms concepts while extending them for robust reporting capabilities.

💡 Quick Tip: Think of XtraReports as Windows Forms optimized for paper output instead of screen output!

A Personal Journey ✨

Microsoft released .NET Framework in late 2002. At the time, I was a VB6 developer, relying on Crystal Reports 7 for reporting. By 2003, my team was debating whether to transition to this new thing called .NET. We were concerned about VB6’s longevity—thinking it had just a couple more years left. How wrong we were! Even today, VB6 applications are still running in some places (it’s January 2, 2025, as I write this).

Back in the VB6 era, we used the Crystal Reports COM object to integrate reports. When we finally moved to .NET Framework, we performed some “black magic” to continue using our existing 700 reports across nine countries. The decision to fully embrace .NET was repeatedly delayed due to the sheer volume of reports we had to manage. Our ultimate goal was to unify our reporting and parameter forms within a single development environment.

This led us to explore other technologies. While considering Delphi, we discovered DevExpress. My boss procured our first DevExpress .NET license for Windows Forms, marking the start of my adventure with DevExpress and XtraReports. Initially, transitioning from the standalone Crystal Report Designer to the IDE-based XtraReports Designer was challenging. To better understand how XtraReports worked, I decided to write reports programmatically instead of using the visual designer.

Architectural Similarities 🗽️

XtraReports mirrors many fundamental Windows Forms concepts:

Source Destination
XtraReport Class Report Designer Surface
XtraReport Class Control Container
XtraReport Class Event System
XtraReport Class Properties Window
Control Container Labels & Text
Control Container Tables & Grids
Control Container Images & Charts
Report Designer Surface Control Toolbox
Report Designer Surface Design Surface
Report Designer Surface Preview Window

Like how Windows Forms applications start with a Form class, XtraReports begin with an XtraReport base class. Both serve as containers that can:

  • Host other controls
  • Manage layout
  • Handle events
  • Support data binding

Visual Designer Experience 🎨

The design experience remains consistent with Windows Forms:

Windows Forms XtraReports
Form Designer Report Designer
Toolbox Report Controls
Properties Window Properties Grid
Component Tray Component Tool

Control Ecosystem 🧰

XtraReports provides analogous controls to Windows Forms:


// Windows Forms
public partial class CustomerForm : Form
{
    private Label customerNameLabel;
    private DataGridView orderDetailsGrid;
}

// XtraReports
public partial class CustomerReport : XtraReport
{
    private XRLabel customerNameLabel;
    private XRTable orderDetailsTable;
}
    

Common control mappings:

  • Label ➡️ XRLabel
  • Panel ➡️ XRPanel
  • PictureBox ➡️ XRPictureBox
  • DataGridView ➡️ XRTable
  • GroupBox ➡️ Band
  • UserControl ➡️ Subreport

Data Binding Patterns 📊

The data binding syntax maintains familiarity:


// Windows Forms data binding
customerNameLabel.DataBindings.Add("Text", customerDataSet, "Customers.Name");

// XtraReports data binding
customerNameLabel.ExpressionBindings.Add(
    new ExpressionBinding("Text", "[Name]"));
    

Code Architecture 🗍️

The code-behind model remains consistent:


public partial class CustomerReport : DevExpress.XtraReports.UI.XtraReport
{
    public CustomerReport()
    {
        InitializeComponent(); // Familiar Windows Forms pattern
    }

    private void CustomerReport_BeforePrint(object sender, PrintEventArgs e)
    {
        // Event handling similar to Windows Forms
        // Instead of Form_Load, we have Report_BeforePrint
    }
}
    

Key Differences ⚡

While similarities abound, important differences exist:

  1. Output Focus 🖨️
    • Windows Forms: Screen-based interaction
    • XtraReports: Print/export optimization
  2. Layout Model 📜
    • Windows Forms: Flexible screen layouts
    • XtraReports: Page-based layouts with bands
  3. Control Behavior 🎮
    • Windows Forms: Interactive controls
    • XtraReports: Display-oriented controls
  4. Data Processing 🗄️
    • Windows Forms: Real-time data interaction
    • XtraReports: Batch data processing

Some Advices 🌟

  1. Design Philosophy
    
    // Think in terms of paper output
    public class InvoiceReport : XtraReport
    {
        protected override void OnBeforePrint(PrintEventArgs e)
        {
            // Calculate page breaks
            // Optimize for printing
        }
    }
                
  2. Layout Strategy
    • Use bands for logical grouping
    • Consider paper size constraints
    • Plan for different export formats
  3. Data Handling
    • Pre-process data when possible
    • Use calculated fields for complex logic
    • Consider subreports for complex layouts