Serenity 10.1.0 Release Notes (2026-01-12)

Note: This is the first major release targeting .NET 10. Version 10.0.0 requires .NET 10 and Visual Studio 2026. You may stay at 9.2.x versions if you need Visual Studio 2022 and .NET 8.

These release notes detail the significant changes made in Serenity and StartSharp from version 10.0.0 to 10.1.0. For a complete list of changes, please refer to the Serenity Change Log.

.NET 10 Migration (10.0.0)

Serenity 10.0.0 is the first version targeting .NET 10. This means you'll need Visual Studio 2026 and the .NET 10 SDK. If you still need Visual Studio 2022 with .NET 8, please stay at the 9.2.x versions.

Key Changes for .NET 10

  • Disabled AllowSynchronousIO: The JsonRequest attribute has been converted to async, and AllowSynchronousIO is no longer enabled in Startup.cs. This was also causing crashes in .NET 10 under Ubuntu.
  • IActionContextAccessor made obsolete: The report .cshtml file location logic was updated to use GetView directly instead of relying on IActionContextAccessor, which was obsoleted in .NET 10.
  • AddServiceEndpointConventions simplifies the Startup.cs configuration (see below).

New AddServiceEndpointConventions Extension

Instead of manually adding ServiceEndpointActionModelConvention and ServiceEndpointBindingMetadataProvider to MvcOptions.Conventions, you can now use the AddServiceEndpointConventions extension method:

// Before:
services.AddControllersWithViews(options =>
{
    options.Filters.Add(typeof(AutoValidateAntiforgeryIgnoreBearerAttribute));
    options.Filters.Add(typeof(AntiforgeryCookieResultFilterAttribute));
    options.Conventions.Add(new ServiceEndpointActionModelConvention());
    options.ModelMetadataDetailsProviders.Add(new ServiceEndpointBindingMetadataProvider());
});

// After:
services.AddControllersWithViews(options =>
{
    options.Filters.Add<AutoValidateAntiforgeryIgnoreBearerAttribute>();
    options.Filters.Add<AntiforgeryCookieResultFilterAttribute>();
});
services.AddServiceEndpointConventions();

This is cleaner and also introduces a ServiceEndpointApplicationModelProvider that automatically applies the necessary action model conventions for ServiceEndpoint controllers.

Import Map System

We introduced a new import map system that allows you to manage module resolution for JavaScript modules more flexibly. This is especially useful for strict CSP scenarios and for managing dependencies from Serenity.Assets.

AddImportMapEntry and RenderImportMap

New extension methods in HtmlScriptExtensions allow preparing import maps in layout pages:

@{
    // Add individual import map entries
    Html.AddImportMapEntry("jspdf", "~/Serenity.Assets/jspdf/jspdf-autotable.bundle.js");
    Html.AddImportMapEntry("@serenity-is/tiptap", "~/Serenity.Assets/tiptap/tiptap.bundle.js");
}

@* Render the import map somewhere in the head section *@
@Html.RenderImportMap()

The RenderImportMap renders an HTML <script type="importmap"> element with the accumulated entries. External URLs added via import map entries are automatically included in the CSP script-src directive by default.

AddSerenityAssetsImportMapEntries

A convenience method that adds import map entries for modules provided via Serenity.Assets like jspdf, jspdf-autotable, and @serenity-is/tiptap:

@{
    Context.AddSerenityAssetsImportMapEntries();
}

This replaces the need to manually specify individual entries in _ImportMap.cshtml.

jspdf and jspdf-autotable via Local Bundle

Instead of loading jspdf and jspdf-autotable from CDN (which can be problematic for strict CSP and disconnected scenarios), they are now exported from ~/Serenity.Assets/jspdf/jspdf-autotable.bundle.js and used from there by PdfExportHelper. They can also be overridden via import map entries.

Tiptap Bundle

We also build ~/Serenity.Assets/tiptap/tiptap.bundle.js to make it easier to update tiptap packages for applications. This can be overridden or mapped via an import map entry for @serenity-is/tiptap. Local npm installations for tiptap modules in templates are removed.

CSP Improvements

AddCspDirective Overloads for ControllerBase and HttpContext (10.0.1)

We added new overloads of AddCspDirective for ControllerBase and HttpContext to provide more flexibility in adding CSP directives from controllers and middleware:

// From a controller:
this.AddCspDirective("style-src", "unsafe-inline", "https://cdnjs.cloudflare.com/ajax/libs/ckeditor/");

// From middleware or any HttpContext access:
httpContext.AddCspDirective("script-src", "https://cdnjs.cloudflare.com/ajax/libs/ckeditor/");

CSP Fixes in Sample Pages

Several CSP-related issues in sample pages have been fixed, including external logins CSP issues.

Build System & TSBuild Enhancements

buildGlobalBundles Option

A new buildGlobalBundles option was added to tsbuild to automatically bundle files under Modules/Common/bundles/*.bundle(.css|.ts) to wwwroot/bundles/. If enabled, it creates global IIFE bundles that can be loaded traditionally:

// tsbuild configuration
build({
    buildGlobalBundles: true,
    // or with custom options:
    buildGlobalBundles: { /* tsbuild options for global bundles */ }
});

StartSharp now uses this feature. The old appsettings.bundles.json approach is deprecated in favor of creating bundle files under Modules/Common/bundles/:

// Modules/Common/bundles/script.bundle.ts
import bootstrap from "@serenity-is/assets/bootstrap/js/bootstrap.bundle.js";
import glightbox from "@serenity-is/assets/glightbox/js/glightbox.js";
import * as corelib from "@serenity-is/corelib";
import * as extensions from "@serenity-is/extensions";
import * as proextensions from "@serenity-is/pro.extensions";
import * as sleekgrid from "@serenity-is/sleekgrid";
import flatpickr from "flatpickr";
import "flatpickr/dist/l10n";

corelib.initGlobalMappings({
    corelib,
    sleekgrid,
    extensions,
    proextensions,
    bootstrap,
    flatpickr,
    glightbox,
    // ...
});

This results in bundles being created at build time, so there is no need to enable ScriptBundling for most cases.

ESM-Style External Globals Plugin

The externalGlobals plugin in tsbuild now generates an ESM-style mock script for Serenity modules by parsing .js files via es-module-lexer, instead of the previous CommonJS approach. This results in more optimized output.

ES2022 Target

All scripts now target ES2022, which is supported by all current major browsers. The tsconfig.json files have been updated accordingly.

Source Maps

Source maps have been added for corelib. The sourceRoot option is set for esbuild to point to the Serenity source repository URL on packages.serenity.is.

Compression Options

The writeIfChanged plugin and tsbuild now support a compress property to automatically create gzip-compressed versions of output files. Brotli is also supported but is too slow (15x slower than gzip even at quality 4) for build-time use.

Clean Plugin

The cleanPlugin now supports include/exclude glob patterns. A warning is shown when the plugins option is set to something other than undefined (which disables the built-in clean plugin).

initGlobalMappings Helper

We introduced a new initGlobalMappings helper in @serenity-is/corelib that sets up global variables for Serenity libraries (corelib, sleekgrid, extensions, pro.extensions) in addition to optionally third-party libraries like Bootstrap, flatpickr, etc.:

import { initGlobalMappings } from "@serenity-is/corelib";
import * as corelib from "@serenity-is/corelib";
import * as extensions from "@serenity-is/extensions";
import bootstrap from "bootstrap";

initGlobalMappings({
    corelib,
    extensions,
    bootstrap,
});

This can be used to potentially remove appsettings.bundles.json and pass globals to feature packages that require them.

The legacy Q namespace references have been removed, and the Serenity global namespace now serves as the single entry point.

PreCompressedFileProvider

A new PreCompressedFileProvider has been added to Serenity.Pro.Extensions that can serve pre-compressed .gz and .br files if available. These are produced by the static web assets SDK during build and publish:

// In Startup.cs:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IFileProvider>(sp =>
{
    var env = sp.GetRequiredService<IWebHostEnvironment>();
    var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
    return new PreCompressedFileProvider(env.WebRootFileProvider, httpContextAccessor, new()
    {
        Gzip = true,
        Brotli = true,
        Extensions = new() { ".js", ".css", ".svg", ".json" }
    });
});

Export domwise from corelib

@serenity-is/domwise is now re-exported from @serenity-is/corelib so that its code is not duplicated by every feature project that requires it. Feature projects can simply import from @serenity-is/corelib instead of adding a separate dependency on @serenity-is/domwise.

.slnx Format Migration

Both Serenity and StartSharp have migrated from .sln to .slnx format, which is simpler and more readable. The .slnx format uses XML and is the recommended format for Visual Studio 2026.

New AntiforgeryFilterOptions

We added AntiforgeryFilterOptions that allow skipping CSRF validation via a custom HTTP header. This makes it easier to work with clients that use cookie authentication (not bearer tokens) to call into services:

// In appsettings.json:
{
    "AntiforgeryFilter": {
        "SkipValidationHeaderName": "X-CSRF-SKIP",
        "SkipValidationHeaderValue": "true"
    }
}

When the header X-CSRF-SKIP: true is present in a request, the AutoValidateAntiforgeryIgnoreBearerFilter will skip CSRF validation. The header name and value are configurable.

Legacy Namespace Cleanup

Q Namespace Removal

All remaining references to the legacy Q namespace have been removed from the codebase. The Serenity global namespace is now the single entry point. The Q namespace will be completely removed in the next major version.

Renamed Private Members

For better consistency, the following internal members have been renamed:

Old Name New Name
FieldAssignedValue OnFieldSet
CheckUnassignedRead OnFieldGet
Field.GetIsNull Field.IsNullNoCheck

These are internal methods used for field tracking and should not affect most user code.

PageAuthorizeAttribute Equality Fix (10.1.1)

Fixed an issue where PageAuthorizeAttribute's default Equals implementation throws a stack overflow when the permission keys are the same for the action and controller, causing Swagger to fail when enumerating attributes for the action. Equals and GetHashCode are now properly overridden.

New GridUtils.addQuickSearch Method (10.1.2)

A new GridUtils.addQuickSearch method with named arguments has been introduced, replacing the deprecated addQuickSearchInput and addQuickSearchInputCustom methods:

import { GridUtils } from "@serenity-is/corelib";

GridUtils.addQuickSearch(grid, container, {
    field: "Name",
    placeholder: "Search...",
    onSearch: (value, done) => {
        // custom search logic
        done();
    }
});

PropertyProcessor: DefaultSummaryType (10.1.4)

Added a DefaultSummaryType setting to PropertyProcessorOptions that allows overriding the default aggregate type for numeric columns:

services.Configure<PropertyProcessorOptions>(options =>
    options.DefaultSummaryType = SummaryType.None);

This sets the default to None but still allows users to choose an aggregate type via the column header menu.

TransformIgnore on Methods (10.0.5)

The TransformIgnore attribute (formerly ScriptSkip) can now be applied to methods in addition to classes and properties. This allows fine-grained control over what gets generated in server typings:

public class MyService
{
    [TransformIgnore]
    public SomeResponse InternalMethod(SomeRequest request)
    {
        // This method won't be generated in TypeScript
    }
}

Additionally, the server types generator now handles complex or unresolvable types better by using "unknown" as the type and printing the problematic type as an inline comment. Non-standard types like interfaces and abstract types are now included (they were previously skipped).

Miscellaneous Improvements

Serenity.Assets Package Rework

Most of the static files inside the Serenity.Assets package are now generated from npm packages instead of via libman.json. Libraries like jQuery, Bootstrap, mousetrap, nprogress, sortable, and glightbox are now built from node_modules during the build process. A patched local copy of glightbox is included as it has issues with CSP.

Row Property Generation Optimizations

Faster property get/set methods have been implemented for partial row properties generated via the [GenerateFields] attribute. This lets the generated code skip the getter/setter delegate inside the field object for direct reads/assignments.

initGlobalMappings Case Fix

Fixed a casing issue in initGlobalMappings where the Serenity.Pro.Extensions global init script was passing an invalid case proExtensions instead of proextensions.

Shift+Wheel for Horizontal Scrolling (10.1.2)

SleekGrid now handles Shift+Wheel for horizontal scrolling.

Sortable(false) Fix (10.1.3)

Fixed an issue where a column with Sortable(false) was incorrectly included in the server-side generated sorted column list.

Fixed an issue where the summary footer value was not shown the first time when no columns have summaries and one is set via the column header menu.

DateOnly Field Fix (10.1.5)

Fixed an issue with DateOnly field due to an extra quote in the format string. Also reverted Sergen to generate DateTime fields as before for SQL date columns, as DateOnlyField is not yet stable.

Header Filter Dropdown Fix (10.1.6)

Fixed an issue where header filter dropdown contents were not emptied before appending new search results.

Package Updates

Updated NPM packages:

  • @serenity-is/tsbuild to 10.0.7 (with fixed clean plugin)
  • @preact/signals to 2.5.1
  • preact to 10.28.0 / 10.282
  • @tiptap to 3.14.0 / 3.15.3
  • vitest to 4.0.15 / 4.0.16
  • esbuild to 0.27.2
  • dompurify to 3.3.1
  • glob to 13.0.0
  • jspdf to 4.0.0
  • jspdf-autotable to 5.0.7
  • jsdom to 27.3.0 / 27.4.0

Updated NuGet packages:

  • System/ASP.NET Core packages to 10.0.1
  • FluentMigrator to 7.2.0 (using individual Runner packages instead of the full package)
  • Scriban to 6.5.2
  • Npgsql to 10.0.1
  • FirebirdSql.Data.FirebirdClient to 10.3.4

Upgrading to 10.1.0

  1. Install .NET 10 SDK and Visual Studio 2026 (required)
  2. Update NuGet packages to 10.1.0
  3. Update npm packages:
    • @serenity-is/tsbuild to 10.0.7
  4. Review Startup.cs: Replace manual convention setup with services.AddServiceEndpointConventions()
  5. Review import map setup: Consider using the new AddImportMapEntry/RenderImportMap helpers instead of manual <script type="importmap"> elements
  6. Review bundling: If using appsettings.bundles.json, consider migrating to the new buildGlobalBundles approach with files under Modules/Common/bundles/
  7. Remove AllowSynchronousIO configuration: If you had services.Configure<KestrelServerOptions>(options => options.AllowSynchronousIO = true) in your Startup.cs, it can be removed as the JsonRequest attribute now works asynchronously
  8. Remove flatpickr-init.ts script init import if you have it — it's no longer needed as flatpickr is initialized via the global script-bundle
  9. Review CSP directives: If you have CSP enabled, review the new AddCspDirective overloads for controllers and HttpContext
  10. Review any direct references to FieldAssignedValue/CheckUnassignedRead: These have been renamed to OnFieldSet/OnFieldGet
  11. Replace ScriptSkip with TransformIgnore: The old attribute name is deprecated
  12. Replace .sln with .slnx: If you have your own solution files, consider migrating to the simpler .slnx format