Back to Orchardcore

Orchard Core 3.0.0

src/docs/releases/3.0.0.md

2.2.138.2 KB
Original Source

Orchard Core 3.0.0

Release date: Not yet released

Before upgrading from version 2 to v3, it is important to first compile your project using the latest available v2 version, resolve any warnings, and then proceed with the upgrade to v3.

Breaking Changes

Upgrade to .NET 10.0 : Orchard Core 3.0.0 requires .NET 10.0. Please ensure that your development environment and hosting infrastructure are compatible with this version of .NET before proceeding with the upgrade.

Content Module

In the previous versions you need to use OrchardCore namespace in Razor pages or views whenever you want to access the content helpers that provided by IOrchardHelper which is unlike the other services that you can access directly without the need to use the namespace. In this version, we have removed the need to use the OrchardCore namespace in Razor pages or views to access the content helpers. You can now access the content helpers directly without the need to use the OrchardCore namespace.

The ContentRazorHelperExtensions has been replaced by ContentOrchardHelperExtensions.

Liquid Module

Liquid Tag Disabled by Default

For reliability and performance reasons, the liquid tag has been disabled by default in Liquid templates.

To re-enable the liquid tag, you can configure it in your appsettings.json:

json
{
  "OrchardCore_Liquid": {
    "AllowLiquidTags": true
  }
}

Localization Module

Previously, the ILocalizationService interface had a static default method called GetAllCulturesAsync(), which returned a list of all cultures available in the system with their aliases.

This method has been replaced in the current version and has become an instance method, allowing developers to customize implementations instead of relying on the default ones.

YesSql Changes

Previously, we configured YesSql with the ReadUncommitted isolation level. We have now set ReadCommitted as the default and made it configurable through settings.

Email Module

Mail Message Body

Previously, emails sent from Orchard Core could have either a plain text body, or an HTML body, but not both. Now, they can have both. This also brings some code-level API changes, see below.

When interacting with email-related services from code, MailMessage, the class representing an e-mail, exposed a string Body property. This could contain either plain text or HTML, which was indicated by IsHtmlBody.

These two properties have now been replaced by the TextBody and HtmlBody properties, which contains a plain text and/or HTML body.

Email Result

Previously, the EmailResult class was used to represent the result of sending an email. This class has been replaced by Result, which provides a more consistent and flexible way to handle operation results.

GraphQL Module

GraphQL Library Upgrade

The GraphQL libraries have been upgraded from version 7 to version 8. Below are important changes and considerations for your implementation:

  1. Removal of Default Implementation:
    The IContentTypeBuilder interface previously included a default implementation for the Clear() method. This implementation has been removed. If you have a custom implementation of IContentTypeBuilder, you must now provide your own Clear() method. The method can remain empty if no specific actions are needed.

  2. Sealed Classes:
    Several classes have been marked as sealed to prevent further inheritance. This change is intended to enhance stability and maintainability. The following classes are now sealed:

    • All implementations of InputObjectGraphType
    • All implementations of ObjectGraphType<>
    • All implementations of WhereInputObjectGraphType
    • All implementations of DynamicContentTypeBuilder
    • All implementations of IContentTypeBuilder
    • All implementations of GraphQLFilter
    • All implementations of ISchemaBuilder

Indexing Module

  • The interface IContentItemIndexHandler was renamed to IDocumentIndexHandler.
  • The IndexingConstants class was renamed to ContentIndexingConstants.
  • The BuildIndexContext class was renamed to BuildDocumentIndexContext.
  • In the BuildDocumentIndexContext class, the ContentItem property was removed. Instead, you should use the new Record property. You may check if Record in ContentItem like this:
if(context.Record is ContentItem contentItem) {
    // Do something with contentItem
})
  • The IIndexingTaskManager interface was changed to be use as a universal task manager not only for content items. If you want to queue the content items in the index manager, you'll need to pass Content in the category argument. You may also store non-content-items in the index manager by passing a different category name.

!!! warning The IndexingTask table in the database has been migrated to RecordIndexingTask to better reflect its purpose as a universal task manager. The IndexingTask table is kept intact to allow you to rollback your deployment if needed. If you no longer need that table, you can either manually delete it or create a migration in your project that deletes it.

Elasticsearch Module

Deprecation of the NEST Library

We previously relied on the NEST library to interface with the Elasticsearch service. However, due to the deprecation of NEST, we have migrated to its successor, Elastic.Clients.Elasticsearch. As part of this transition, the following interfaces and classes have been removed:

  • IElasticAnalyzer
  • IElasticSearchQueryService (use ElasticsearchQueryService as an alternative)
  • ElasticAnalyzer

To ensure consistency across our codebase, all classes and interfaces are now prefixed with Elasticsearch instead of Elastic or ElasticSearch. The only exception to this naming convention is for settings, which have been retained to minimize further breaking changes.

Additionally, the OrchardCore.Search.Elasticsearch.Abstractions project has been removed, and the following classes have been relocated to the OrchardCore.Search.Elasticsearch.Core project:

  • ElasticsearchOptions
  • ElasticsearchQueryResults
  • ElasticsearchTopDocs

The method ExecuteQueryAsync(string indexName, Query query, List<SortOptions> sort, int from, int size) has been removed from the ElasticsearchQueryService class. In its place, we have introduced the new method GetContentItemIdsAsync(ElasticsearchSearchContext request), which streamlines the query execution process by encapsulating the necessary parameters within a single context object.

Search Highlights

The latest update introduces support for Search Highlights in Elasticsearch queries. When highlights are enabled, Elasticsearch will return relevant text segments that match the search term, allowing for a more contextual and user-friendly search result display.

Example Elasticsearch Query

Here's an example of how to configure the Elasticsearch query to include highlights:

json
{
  "query": {
    "multi_match": {
      "fields": [
        "Content.ContentItem.FullText"
      ],
      "query": "{{ term }}",
      "fuzziness": "AUTO"
    }
  },
  "highlight": {
    "pre_tags": [
      "<span style='background-color: #FFF3CD;'>"
    ],
    "post_tags": [
      "</span>"
    ],
    "fields": {
      "Content.ContentItem.FullText": {
        "fragment_size": 150,
        "number_of_fragments": 3
      }
    }
  }
}

With this feature, Elasticsearch will return highlighted fragments wrapped in custom HTML tags, which can then be displayed in the Search module or other components. This enables the presentation of more relevant content that directly matches the search term.

For more information, check out the Elasticsearch documentation.

Total Hits Count Support

The latest update adds support for Total Hits Count in Elasticsearch queries. When a query includes track_total_hits: true, the response will report the total number of documents matching the query, rather than just the number of documents returned in the current page.

Search Feature

The signature in the ISearchService interface was changed from Task<SearchResult> SearchAsync(string indexName, string term, int start, int size) to Task<SearchResult> SearchAsync(IndexEntity index, string term, int start, int size).

The route /search/{indexName?} was change to accept index id instead of name. The route is now /search/{indexId?}. This change was made to ensure that the search functionality works correctly with the new IndexEntity class, which is now used to represent indexes in the system.

The default search settings was changed to require default index-id instead of a provider name.

Azure Search AI Module

With the improvement done to the Indexing module, managing Azure AI Search indexes is now part of the indexing module. This change reduced the code complexity and simplify the user experience since we now have one UI for all indexes. Another advantage is that we are now able to add data sources other than contents.

Lucene Module

With the improvement done to the Indexing module, managing Lucene indexes is now part of the indexing module. This change reduced the code complexity and simplify the user experience since we now have one UI for all indexes. Another advantage is that we are now able to add data sources other than contents.

Azure Search AI Breaking Change Summary

There are lots of binary breaking changes in the Azure Search AI module most won't impact you. The following change will impact you:

  • The permission AzureAISearchPermissions.ManageAzureAISearchIndexes was removed and the AzureAISearchPermissions.ManageAzureAISearchISettings was added.

SMS Module

Previously, the SmsResult class was used to represent the result of sending an SMS. This class has been replaced by Result, which provides a more consistent and flexible way to handle operation results.

Taxonomies Module

In previous releases, taxonomy listings on the frontend used a simplified pager with only Next and Previous buttons. As of this release, the pager has been upgraded to a full-featured pagination control, allowing users to jump directly to specific pages.

If your project overrides the TermPart view and modifies the Model.Shape, ensure your customization is compatible with the new shape type introduced by this change.

Additionally, a new interface, IContentsTaxonomyListFilter, has been introduced. This interface allows developers to customize or modify the query used when retrieving taxonomies, providing greater flexibility and control over taxonomy listings.

Users Module

The user registration and login functionalities have been refactored for better extensibility:

  • Registration Improvements:

    • The IRegistrationFormEvents interface now includes Task RegisteringAsync(UserRegisteringContext context) for streamlined customization.
    • A new base class, RegistrationFormEventsBase, allows developers to override only necessary methods.
  • Login Improvements:

    • The ILoginFormEvent interface has a new method: Task<IActionResult> ValidatingLoginAsync(IUser user).
    • The LoginFormEventBase class enables overriding relevant methods. Note that the base implementation of LoggingInAsync() has been removed; you must now implement this method if using LoginFormEventBase.
  • User Service Update:

    • A new method in IUserService interface: Task<IUser> RegisterAsync(RegisterUserForm model, Action<string, string> reportError) facilitates registration with error reporting.

These enhancements make the user management system more modular and customizable.

Removed Old Settings

The following obsolete settings were removed from RegistrationSettings class

  • NoPasswordForExternalUsers
  • NoUsernameForExternalUsers
  • NoEmailForExternalUsers
  • UseScriptToGenerateUsername
  • GenerateUsernameScript
  • UsersCanRegister

The following obsolete settings were removed from LoginSettings class

  • UseExternalProviderIfOnlyOneDefined
  • UseScriptToSyncRoles
  • SyncRolesScript

Login View Update

The ExternalLogin action has been removed from the Account controller. If you are using a custom Login.cshtml view or Login template, please update the external login form action. As of this update, the ExternalLogin action has been relocated to the ExternalAuthentications controller.

AssignRoleToUsers Permission Update

The AssignRoleToUsers permission is no longer implicitly granted by EditUsers. To maintain the same behavior, make sure to explicitly assign the AssignRoleToUsers permission to any role that already has the EditUsers permission.

The Behavior of 'has_claim' Liquid Filter Changed.

The Administrator role no longer registers permission-based claims by default during login. This means that directly checking for specific claims in Liquid, such as:

liquid
{% assign isAuthorized = User | has_claim: "Permission", "AccessAdminPanel" %}

will return false for administrators, even though they still have full access. Non-admin users, however, may return true if they have the claim. It's important to use the has_permission filter for permission checks going forward:

liquid
{% assign isAuthorized = User | has_permission: "AccessAdminPanel" %}

LoginForm_Edit Shape Type Modification

To simplify the LoginForm.Edit.cshtml view, the following code has been moved to Views/Account/Login.cshtml:

html
<h1 class="fs-4">@T["Log in"]</h1>
<hr />

Enabling & Disabling Users

To centralize user activation and deactivation, the "Is enabled?" checkbox has been removed from the Edit User form. Instead, you can now enable or disable a user directly from the Users List by clicking the Actions button next to the user and selecting "Enable" or "Disable".

To support this change, two new methods—EnableAsync() and DisableAsync()—have been added to IUserService, providing a more standardized approach to managing user status.

ReCaptcha

In the previous implementation, the ReCaptcha module supported two modes: AlwaysShow and PreventRobots. To simplify the module and enhance integration, the PreventRobots mode and its related components have been removed. Going forward, only the AlwaysShow mode will be supported.

As part of this update, the following components have been deprecated and removed:

  • IDetectRobots
  • IPAddressRobotDetector
  • ReCaptchaMode

Furthermore, the ReCaptchaService class has been sealed to prevent inheritance. The following methods have also been removed:

  • MaybeThisIsARobot
  • IsThisARobot
  • ThisIsAHuman

Previously, the FormReCaptcha view was available to inject a ReCaptcha challenge from any display driver. This view has been removed. The recommended approach now is to return a shape directly, as shown below:

csharp
return Dynamic("ReCaptcha", (m) =>
{
    m.language = CultureInfo.CurrentUICulture.Name;
}).Location("Content:after");

Instead of using this approach:

csharp
return View("FormReCaptcha", model).Location("Content:after");

If you still need to render ReCaptcha using the deprecated FormReCaptcha, you can manually add the FormReCaptcha.cshtml view to your project. Here's the code for this:

html
<div class="mb-3">
    <captcha mode="AlwaysShow" language="@Orchard.CultureName()" />
</div>

This change is designed to simplify your integration process and make it easier to manage ReCaptcha usage in your project.

Content Types Module

IContentDefinitionService Moved to Abstractions

The IContentDefinitionService interface has been moved from OrchardCore.ContentTypes module to OrchardCore.ContentTypes.Abstractions. This allows other modules to use content definition operations without requiring a reference to the full OrchardCore.ContentTypes module.

The following methods now use DTOs instead of ViewModels:

  • AlterFieldAsync - Now takes AlterFieldContext instead of EditPartViewModel and EditFieldViewModel
  • AlterTypePartAsync - Now takes AlterTypePartContext instead of EditTypePartViewModel

The following methods have been removed from IContentDefinitionService and are now private helpers within the AdminController:

  • LoadTypesAsync, GetTypesAsync, LoadTypeAsync, GetTypeAsync
  • LoadPartsAsync, GetPartsAsync, LoadPartAsync, GetPartAsync
  • GetFieldsAsync

Content Module

UpdateAsync No Longer Triggered During Creation

Previously, the IContentHandler.UpdatingAsync and IContentHandler.UpdatedAsync methods were triggered for both creation and update events. This behavior has been corrected in this release. Now, if you are modifying or altering content items within the UpdatingAsync or UpdatedAsync handlers, you must also implement the Creating or Created events to maintain the previous functionality.

Additionally, when manually creating or updating content items in your project, ensure that you use ContentManager.CreateAsync exclusively for creating new items and ContentManager.UpdateAsync for updating existing ones. This guarantees that the Creating, Created, Updating, and Updated events are triggered appropriately.

New CollapseContainedItems Setting for Contained Item Behavior

A new CollapseContainedItems setting has been added to BagPartSettings and FlowPartSettings, allowing users to control whether contained items are collapsed or expanded by default. To ensure consistency, both BagPart and FlowPart now default to expanding contained items when the page loads.

GitHub Module

We have migrated to using the AspNet.Security.OAuth.GitHub package to simplify and reduce the amount of custom code required for GitHub integration. As part of this change, the following classes have been removed:

  • GithubDefault — replaced by the library's GitHubAuthenticationDefaults.
  • GithubOptions — replaced by the library's GitHubAuthenticationOptions.
  • GithubHandler — replaced by the library's GitHubAuthenticationHandler.

In addition, the IGithubAuthenticationService interface has been removed.
If you need to access the GitHub authentication settings, you can now do so by:

  • Resolving IOptions<GitHubAuthenticationOptions>, or
  • Using ISiteService to retrieve the site's configuration.

OrchardRazorHelperExtensions Class Names

To resolve CS0433 naming conflicts, the OrchardRazorHelperExtensions classes across multiple modules have been renamed to follow a consistent naming pattern:

  • OrchardCore.ContentManagement.DisplayContentOrchardRazorHelperExtensions
  • OrchardCore.MediaMediaOrchardRazorHelperExtensions
  • OrchardCore.ShortcodesShortcodesOrchardRazorHelperExtensions

Impact: Extension methods continue to work identically in Razor views (@Orchard.AssetUrl(), @Orchard.ConsoleLog(), etc.). This change only affects projects that directly reference these class names in code.

Display Management

The Display Management subsystem received performance-focused refactoring. The following API changes may require code updates:

  • FeatureShapeDescriptor sealed: FeatureShapeDescriptor is now sealed. Do not inherit from it.
  • Removed BindingSources properties:
    • Removed ShapeMetadata.BindingSources.
    • Removed ShapeDescriptor.BindingSources and the corresponding override on descriptor index types. If you relied on these, inspect ShapeDescriptor.Bindings to infer binding sources.
  • ShapeBinding sealed: ShapeBinding is now sealed and its BindingAsync property is no longer virtual. Do not inherit from ShapeBinding or override its members.
  • Non-virtual Binding members: ShapeDescriptor.BindingSource and ShapeDescriptor.Binding are no longer virtual. Use the ShapeAlterationBuilder events or display drivers to customize binding behavior.
  • Binding behavior: ShapeDescriptor.Binding now returns null if no binding exists instead of throwing. Add null checks when accessing a shape's binding.
  • Placement default initialization changed: ShapeDescriptor.Placement now lazily falls back to the default placement action if not set. This should be transparent, but code that assumed Placement was preset may need to handle a possibly null delegate before first access.
  • ShapeDescriptorIndex sealed: ShapeDescriptorIndex is now sealed. Do not inherit from it.

Removed APIs

The following APIs have been removed from Orchard Core:

  • OrchardCore.Modules.Manifest.FeatureAttribute.GetValues(): This protected method has been removed. If you have custom implementations that rely on this method, you will need to refactor your code to avoid using it.

Removed Interfaces and Default Implementations

The following interfaces, classes, and default implementations have been removed to clean up deprecated code:

Data Migration Module

  • The obsolete IDataMigrationManager.UpdateAsync(string feature) method with its default implementation has been removed. Use UpdateAsync(params string[] features) instead.

Time/Clock Module

  • The obsolete ILocalClock.LocalNowAsync property has been removed along with its default implementation in GetLocalNowAsync(). Use GetLocalNowAsync() method instead.

Email Module

  • The obsolete ISmtpService interface has been removed. Use IEmailService instead.
  • The obsolete SmtpResult class has been removed. Use EmailResult instead.
  • The obsolete SmtpService class has been removed. Use the email providers registered with IEmailService instead.

Admin Menu Module

  • The obsolete IAdminMenuPermissionService interface has been removed. Use IPermissionService instead.
  • The obsolete AdminMenuPermissionService class has been removed.

Roles Module

  • The obsolete CommonPermissions class in OrchardCore.Roles namespace has been removed. The ManageRoles permission is now available in RolesPermissions.ManageRoles. For assigning roles to users, use OrchardCore.Users.UsersPermissions.AssignRoleToUsers or OrchardCore.Users.UsersPermissions.CreateAssignRoleToUsersPermission(roleName).

Content Management Module

  • The obsolete StringExtensions.IsLetter(char) extension method has been removed from OrchardCore.ContentManagement.Utilities. Use char.IsLetter() instead.
  • The obsolete StringExtensions.IsSpace(char) extension method has been removed from OrchardCore.ContentManagement.Utilities. Use char.IsWhiteSpace() instead.

Change Log

Infrastructure

  • The MediaTypeNamesExtended has been added to extend the MediaTypeNames class with additional media type constants. This allows for easier reference to a wider range of media types within the application.

Localization Module

Fallback to Parent Culture

The Localization module allows the user to control the fallback to the parent culture when a translation is not available in the current culture. The default behavior in ASP.NET Core is that the culture automatically falls back to its parent if not exist, but now you have the control to make this feature on or off.

Reverse Proxy Module

Known Networks & Proxies

The Reverse Proxy module has been updated to include a new setting called Known Networks & Proxies. This setting allows you to specify trusted networks and proxies that can be used to determine the user's IP address. This is particularly useful when your application is behind a reverse proxy or load balancer, ensuring that the correct client IP address is captured.

Roles Module

Permission Behavior Added to Roles Recipe Step

The Roles recipe now includes the ability to define specific permission behaviors, allowing you to control how permissions are managed within a role. The following behaviors are available:

  • Replace: This behavior removes all existing permissions associated with the role and replaces them with the new permissions from the Permissions collection. This is the default behavior.
  • Add: This behavior adds the new permission(s) from the Permissions collection to the role, but only if they do not already exist. It does not affect the existing permissions.
  • Remove: This behavior removes the specified permission(s) in the Permissions collection from the role's existing permissions.

For more info about the new PermissionBehavior, check out the documentation.

Users Module

Email Confirmation Process Update

In the past, administrators could confirm user's email by editing their details and checking the Confirm Email box. This process has now been updated.

To confirm a user's email, follow these steps:

  1. Navigate to the Users List.
  2. Locate the user you wish to confirm.
  3. Click on the Actions menu next to the user.
  4. Select the Confirm email option.

This change streamlines the email confirmation process by moving it out of the user edit form, offering a more straightforward approach to user management.

!!! note The Confirm email option will only be visible if the user has not yet been confirmed.

Search Module

The Search Module now supports Highlights. If the search service provider supports Highlights, they will be rendered by default. If Highlights are unavailable, the module will fall back to displaying the ContentItem in a Summary display type.

ReCaptcha Module

New ReCaptcha Shape

A new ReCaptcha shape has been introduced, enabling you to render the ReCaptcha challenge using a customizable shape. For more details, please refer to the documentation.

Permission-Based Menu Visibility

The Menu module enables you to build frontend menus for your users through a user-friendly interface. We've enhanced this feature by allowing you to require one or more permissions before a menu item becomes visible to the user.

If you're using a custom MenuItem in your project and want to incorporate this functionality, you can achieve it by attaching the MenuItemPermissionPart to your custom MenuItem content type.

When caching your menu, it's crucial to include the cache-context to ensure the menu is properly cached and invalidated based on the user's roles. This ensures the menu is displayed correctly for each logged-in user, based on their specific roles.

For example, here's how you can add the menu with cache-context using Razor:

razor
<menu alias="alias:main-menu" cache-id="main-menu" cache-fixed-duration="00:05:00" cache-tag="alias:main-menu" cache-context="user.roles" />

Notice the cache-context="user.roles" attribute.

Alternatively, here's how you can implement the same functionality using Liquid:

liquid
{% shape "menu", alias: "alias:main-menu", cache_id: "main-menu", cache_fixed_duration: "00:05:00", cache_tag: "alias:main-menu", cache_context: "user.roles" %}

Again, notice the inclusion of cache_context: "user.roles".

By default, permissions are enabled for new tenants. However, if you'd like to add permissions to an existing tenant, you can use the "Add Permissions to Menus" recipe either through the UI or by executing the recipe programmatically as shown below:

json
{
  "steps": [
    {
      "name": "recipes",
      "Values": [
        {
          "executionid": "MenuAddPermissions",
          "name": "MenuAddPermissions"
        }
      ]
    }
  ]
}

!!! note Be sure to update all instances where you create a menu shape by adding the cache-context attribute. This ensures the menu is properly cached and tailored based on the user's roles.

Permission-Based Content Menu Visibility

A new option, Check content permissions, has been added to the Content Menu Item. This feature allows you to control the visibility of a menu item based on the user's permissions. When this option is enabled, the system ensures that the current user has the View Content permission for the selected item before displaying it.

Asset Manager

Orchard Core now features a new Asset Manager, set to gradually replace the Gulp pipeline. While the Gulp pipeline remains for backward compatibility during the transition and refactoring period, a comprehensive documentation is available to guide users on the new Asset Manager.

The Gulp pipeline is being phased out as it is no longer suitable for bundling assets with tools like Webpack. The new Asset Manager leverages Concurrently, enabling the execution of shell commands directly from Node.js.This provides flexibility to use APIs from bundlers, compilers, and transpilers to perform various actions seamlessly.

For more information, see the corresponding page.

Admin Theme

The Admin Theme ResourceManagementOptionsConfiguration.cs file is now changed. We renamed "admin" assets to "the-admin" for ease of maintenance of dependencies in the solution.

Indexing Module

The Indexing module has been refactored to improve extensibility and maintainability. Key enhancements include:

  • Introduced new Vector and Complex data types for indexing, enabling advanced search capabilities.

    • The Vector type supports vector-based indexing and similarity search, allowing efficient retrieval based on vector embeddings.
    • The Complex type enables indexing of structured or nested objects, offering greater flexibility for modeling rich data schemas.
  • All indexes from multiple providers—such as Elasticsearch, Azure AI Search, and Lucene—are now centrally registered and managed through the new Indexes interface, accessible via Search > Indexes.

The following recipe steps were added to allow you to manage any index profile.

  • CreateOrUpdateIndexProfile allows you to create or update index profile.
  • ResetIndex allows you to reset an index.
  • RebuildIndex allows you to rebuild an index.

Search index-specific permissions were centralized into the Indexing module. Thus every index gets a dynamically created "Query 'index name' Index" permission. Use these to allow specific user roles to query the index, and thus also use the frontend search feature.

!!! warning You need to update user roles and recipes to use the new permissions. If you e.g. allow Anonymous users to use the frontend search feature, not doing so will prevent such users from searching.

Enhanced Multi-Source Indexing

To create a custom source, you'll need to implement the IIndexManager, IDocumentIndexManager and IIndexNameProvider interfaces and register them as following

To register a new source, you can add the following code to your Startup.cs file:

csharp
// Currently we support 'AzureAISearch', 'Elasticsearch', and 'Lucene' providers.
services.AddIndexingSource<CustomSourceIndexManager, CustomSourceDocumentIndexManager, CustomSourceIndexNameProvider>("ProviderName", "CustomSource", o =>
{
    o.DisplayName = S["Custom Source in Provider"];
    o.Description = S["Create a Provider index based on custom source."];
});

Elasticsearch Module

The following recipe steps were deprecated:

  • Both elastic-index and ElasticIndexSettings steps, which was used to create a Elasticsearch index. Instead, please use the CreateOrUpdateIndexProfile step to create or update an index.
  • elastic-index-reset step, which was used to create a Elasticsearch query. Instead, please use the ResetIndex step to create a query.
  • elastic-index-rebuild step, which was used to create a Elasticsearch query. Instead, please use the RebuildIndex step to create a query.

!!! note The elastic-index, ElasticIndexSettings, elastic-index-reset, and elastic-index-rebuild steps are still available for backward compatibility, but they are deprecated and will be removed in a future release. We recommend you update your recipes by setting up a site with your current ones, then creating a Deployment Plan with the new steps to export the configuration in the new format.

Multiple Authentication Types for Elasticsearch

Now, the Elasticsearch module supports multiple authentication types for connecting to the Elasticsearch server. You can now choose between the following authentication methods:

  • Basic: For basic authentication, you need to provide a Username and Password.
  • ApiKey: For API key authentication, you need to provide an ApiKey.
  • Base64ApiKey: For base64-encoded API key authentication, you need to provide a Base64ApiKey API key.
  • KeyIdAndKey: For key ID and key authentication, you need to provide a KeyId and Key.

Lucene Module

The following recipe steps were deprecated:

  • Both lucene-index and LuceneIndexSettings steps, which was used to create a Lucene index. Instead, please use the CreateOrUpdateIndexProfile step to create or update an index.
  • lucene-index-reset step, which was used to create a Lucene query. Instead, please use the ResetIndex step to create a query.
  • lucene-index-rebuild step, which was used to create a Lucene query. Instead, please use the RebuildIndex step to create a query.

!!! note The lucene-index, LuceneIndexSettings, lucene-index-reset, and lucene-index-rebuild steps are still available for backward compatibility, but they are deprecated and will be removed in a future release. We recommend you update your recipes by setting up a site with your current ones, then creating a Deployment Plan with the new steps to export the configuration in the new format.

Font Awesome

Font Awesome was updated to version 7.0.0. Some changes may be required in your templates. Please follow the instructions from the changelog.

Display Management

Fluent Placement Location Builder

A new PlacementLocationBuilder fluent API has been added as a type-safe alternative to manually constructing placement location strings in display drivers. The builder uses a single class where all methods return the same instance for easy chaining, following the placement nesting hierarchy (Zone → Tab → Card → Column).

csharp
// Before (string-based — error-prone and hard to read):
.Location("Parameters:5#Settings;1%Details;2|Left_9;3")

// After (fluent API — type-safe and self-documenting):
.Location(l => l
    .Zone("Parameters", "5")
    .Tab("Settings", "1")
    .Card("Details", "2")
    .Column("Left", "3", "9"))

Each method in the chain returns the same builder instance, so all methods are available at any point after .Zone(). Levels can be skipped (e.g., .Zone().Card() without a .Tab() is valid).

For more details, see the Placement documentation.

Media Library

The Admin → Media → Library screen now includes an "Available Storage" indicator. If the media items are stored on the local file system, it automatically shows the free disk space on the drive used for storage. The available storage is checked when uploading or copying files in the media store, to give a more informative warning when the space is exhausted.

If you use a different underlying file store (e.g., Azure Blob storage, Amazon AWS), or if you want to enforce additional storage constraints (i.e., usage quotas), that's also possible. Create a new event handler that implements the IMediaEventHandler.MediaPermittedStorageAsync(MediaPermittedStorageContext) method. Note that if you want to use multiple event handlers, you should update the PermittedStorage value using the MediaPermittedStorageContext.Constrain(long) method rather than manually editing the PermittedStorage value.

Miscellaneous

Shapes

A new Razor helper method has been introduced to simplify morphing shapes directly within Razor views. You can now use @DisplayAsAsync(Model, "NewShapeType") to render the current model as a different shape type.

Sealing Types

Many type commonly used by classes can be sealed, which improves runtime performance. While it's not mandatory, we recommend that you consider applying this improvement to your own extensions as well. We've implemented this enhancement in pull request #16897.

New Extension Method for Adding IConfigureOptions<ResourceManagementOptions> Implementations

When adding an IConfigureOptions<ResourceManagementOptions> implementation, used to add static resources and commonly named ResourceManagementOptionsConfiguration, you previously had to do the following in the Startup classes:

csharp
services.AddTransient<IConfigureOptions<ResourceManagementOptions>, ResourceManagementOptionsConfiguration>();

To simplify this, we introduced a new extension method to do the same in a shorter form:

csharp
services.AddResourceConfiguration<ResourceManagementOptionsConfiguration>();

You can utilize this in your codebase by searching the AddTransient<IConfigureOptions<ResourceManagementOptions>, (.+)>\(\) regex pattern and replacing it with AddResourceConfiguration<$1>(). Projects using this have to reference the OrchardCore.ResourceManagement package.

Shapes

User Display Name Shape

A new shape, UserDisplayName has been introduced to render a user's display name. For more info, see the documentation.

Content Manager ValidateAsync Behavior

Previously, the IContentManager.ValidateAsync() method would silently call ISession.CancelAsync() when validation failed, cancelling the entire database session without the caller's knowledge. This could discard unrelated pending changes from other components sharing the same session.

Now, ValidateAsync() only performs validation and returns the result. It no longer cancels the session on failure. Callers who need to cancel the session on validation failure must do so explicitly:

csharp
var result = await _contentManager.ValidateAsync(contentItem);

if (!result.Succeeded)
{
    await _session.CancelAsync();
}

Content Manager Delete Behavior

The IContentManager.RemoveAsync() method now supports cancelable deletes and returns a bool indicating whether the delete operation actually occurred or was cancelled by a handler.

Result Pattern

Introduces a lightweight Result pattern to represent operation outcomes without throwing exceptions for control flow. The new Result and Result<T> types surface success/failure and carry zero or more ResultError entries (supports LocalizedString for localized messages).