Skip to content

Releases: RWS/dxa-core

DXA 2.4 — .NET 8 support

14 May 22:27

Choose a tag to compare

DXA 2.4 for .NET 8

DXA 2.4 is the first release of the Digital Experience Accelerator running on .NET 8. The framework has been ported from the .NET Framework 4.8 implementation that previously lived in RWS/dxa-web-application-dotnet and RWS/dxa-modules, and consolidated into the new RWS/dxa-core monorepo.

If you are running DXA 2.3 on .NET Framework 4.8 today, this is a major upgrade. Read the Migration from DXA 2.3 (.NET 4.8) and Breaking changes sections carefully before adopting.

CM compatibility: No changes required on the Content Manager side. Continue using DXA 2.3 TBBs and continue publishing DXA R2 JSON.

Highlights

Supported modules

Module NuGet Status
Core Tridion.Dxa.Module.Core Supported
Search Tridion.Dxa.Module.Search Supported
Dynamic Documentation Tridion.Dxa.Module.DynamicDocumentation Supported
Experience Optimization (XO) Not supported in DXA 2.4 / .NET 8

If your DXA 2.3 application depends on the XO module, plan accordingly before upgrading.

Project restructuring & assembly renames

The .NET Framework version was split across multiple repositories and many assemblies. On .NET 8 it consolidates into a single monorepo at RWS/dxa-core:

Repository layout

Component NuGet package Was previously in
dxa-framework-datamodel Tridion.Dxa.Framework.DataModel Embedded inside dxa-web-application-dotnet
dxa-pca-client-net Tridion.Dxa.Api.Client Standalone library, now versioned with DXA
dxa-framework-mvc-net Tridion.Dxa.Framework Sdl.Web.Mvc + Sdl.Web.Tridion (+ ModelService, Common) in dxa-web-application-dotnet
dxa-module-core-net Tridion.Dxa.Module.Core Sdl.Web.Modules.Core from dxa-modules
dxa-module-dynamicdocumentation-net Tridion.Dxa.Module.DynamicDocumentation Sdl.Web.Modules.DynamicDocumentation from dxa-modules
dxa-module-search-net Tridion.Dxa.Module.Search Sdl.Web.Modules.Search from dxa-modules
dxa-web-application-mvc-net (sample app — not published) The web project from dxa-web-application-dotnet

Assembly renames

Multiple .NET Framework assemblies were consolidated into Tridion.Dxa.Framework:

Old (.NET 4.8) New (.NET 8)
Sdl.Web.Common folded into Tridion.Dxa.Framework
Sdl.Web.ModelService folded into Tridion.Dxa.Framework
Sdl.Web.Mvc folded into Tridion.Dxa.Framework
Sdl.Web.Tridion folded into Tridion.Dxa.Framework
Sdl.Tridion.Api.Client renamed to Tridion.Dxa.Api.Client
Sdl.Dxa.DataModel renamed to Tridion.Dxa.Framework.DataModel

Namespaces inside each assembly are preserved (Sdl.Web.Common.*, Sdl.Web.Mvc.*, etc.) so most using directives in custom code keep working — you'll just be referencing different DLLs.

A single release script (Release-Dxa.ps1 at the repo root) drives the full dependency-ordered publish chain. See the README "Release" section.

Migration from DXA 2.3 (.NET 4.8)

This release is a runtime + framework migration, not just a version bump. Every public API surface that depended on System.Web has been replaced.

1. Configuration: web.configappsettings.json

The application setting model has changed entirely. web.config is now used only for IIS module / handler bindings; runtime configuration moves to appsettings.json.

Application settings move under a Dxa section:

{
  "Dxa": {
    "Services": { "Discovery": "http://your-discovery-service" },
    "OAuth": {
      "Enabled": true,
      "ClientId": "cduser",
      "ClientSecret": "..."
    },
    "Caching": { "ViewModelCaching": true },
    "DefaultModule": "Core",
    "AdminRefreshEnabled": true
  },
  "SdlWebDelivery": {
    "Caching": {
      "DefaultHandler": "regularCache",
      "Enabled": true,
      "Handlers": {
        "regularCache": { "Type": "DefaultMemCacheHandler", "Policy": { "AbsoluteExpiration": "300" } }
      },
      "Regions": {
        "PageModel": { "CacheName": "regularCache" }
      }
    }
  }
}

2. Dependency injection: Unity → built-in .NET DI

Unity.config is replaced by service registrations in Startup.cs. The provider mapping:

.NET 4.8 (Unity.config) .NET 8 (Startup.cs)
<type type="ILogger" mapTo="NLogLogger"> services.AddSingleton<ILogger, DefaultLogger>();
<type type="ICacheProvider" mapTo="DefaultCacheProvider"> services.AddSingleton<ICacheProvider>(p => new KeylockCacheProvider(new DefaultCacheProvider(...)));
<type type="IBinaryProvider" mapTo="GraphQLBinaryProvider"> services.AddTransient<IBinaryProvider, DefaultBinaryProvider>();
<type type="IMediaHelper" mapTo="BaseMediaHelper"> services.AddTransient<IMediaHelper, BaseMediaHelper>();
<type type="IContentProvider" mapTo="GraphQLContentProvider"> services.AddTransient<IContentProvider, DefaultContentProvider>();
<type type="IModelServiceProvider" mapTo="GraphQLModelServiceProvider"> services.AddTransient<IModelServiceProvider, DefaultModelServiceProvider>();
<type type="ILinkResolver" mapTo="GraphQLLinkResolver"> services.AddTransient<ILinkResolver, DefaultLinkResolver>();
<type type="INavigationProvider" mapTo="StaticNavigationProvider"> services.AddTransient<INavigationProvider, StaticNavigationProvider>();
<type type="ILocalizationResolver" mapTo="GraphQLLocalizationResolver"> services.AddTransient<ILocalizationResolver, DefaultLocalizationResolver>();

The bulk of the registrations are handled for you by services.AddDxa(Configuration); custom providers go alongside.

3. Middleware: HTTP modules → ASP.NET Core middleware

Startup.Configure():

app.UseForwardedHeaders();
app.UseStaticFiles();
app.UseRouting();

// DXA middleware
app.UseMiddleware<ADFContextMiddleware>(
    Configuration.GetSection("AmbientConfig").Get<AmbientDataConfig>());
app.UseDxa();

app.UseEndpoints(endpoints => {
    endpoints.ConfigureDxaEndpoints(serviceProvider);
});

DxaMiddleware resolves the Localization, initializes WebRequestContext, and serves static binary content.

4. Views

Partial views

@* Old (.NET 4.8) *@
@Html.Partial("Partials/Teaser")

@* New (.NET 8) *@
@await Html.PartialAsync("Partials/Teaser")

Resource localization

@* Old (.NET 4.8) *@
@Html.FormatResource("core.visitUsSocialLinkTitle", link.Tag.DisplayText)

@* New (.NET 8) — inject IStringLocalizer and pass it to FormatResource *@
@inject Microsoft.Extensions.Localization.IStringLocalizer<TridionStringLocalizer> Localizer
@Html.FormatResource(Localizer, "core.visitUsSocialLinkTitle", link.Tag.DisplayText)

Developer-mode check

@* Old *@
@if (WebRequestContext.IsDeveloperMode)

@* New *@
@if (WebRequestContext.Current.IsDeveloperMode)

Views\web.config_ViewImports.cshtml

The per-area web.config that declared default <add namespace="..."> is replaced by an _ViewImports.cshtml:

@* Areas/Core/Views/_ViewImports.cshtml *@
@using Sdl.Web.Modules.Core
@using Sdl.Web.Mvc.Configuration
@using Sdl.Web.Mvc.Html
@using Sdl.Web.Common.Models
@using Sdl.Web.Common.Configuration
@using Sdl.Web.Common.Extensions
@using Sdl.Web.Modules.Core.Models

5. Caching

DXA's per-region cache configuration in appsettings.json (SdlWebDelivery:Caching) is unchanged in shape. The implementation (DefaultCacheProvider) now uses IMemoryCache and IDistributedCache from the .NET runtime.

For Redis, register it in ConfigureServices:

services.AddStackExchangeRedisCache(options => {
    options.Configuration = "your-redis-host:6379";
    options.InstanceName  = "DXA-regular";
});

Session storage is now opt-in Redis via SdlWebDelivery:Caching:Session:UseRedis (defaults to in-memory). Suitable for single-instance deployments without Redis. See Startup.cs for the gating pattern.

6. Logging

Logs flow through Microsoft.Extensions.Logging. NLog integration is provided in the example web app via NLog.Extensions.Logging and NLog.Web.AspNetCore. The DXA Log static class (Sdl.Web.Common.Logging.Log) is still available and writes through the configured logger factory.

7...

Read more