Skip to main content
A newer version of this page is available. .
All docs

Audit Trail Module (EF Core)

  • 4 minutes to read

This topic describes how to add the Audit Trail Module to your ASP.NET Core Blazor application and explains the Module’s ORM-specific features. EF Core-based WinForms applications do not support this Module.

Audited Objects

The Audit Trail Module logs changes in the following objects and properties:

  • Persistent classes registered as DbSet<TEntity> properties in DbContext.
  • Public writable simple and reference properties defined in persistent classes. The Module does not log changes in read-only properties (properties without the set accessor).
  • Public collection properties defined in persistent classes.

Add the Audit Trail Module to an ASP.NET Core Blazor Application

Follow the steps below to add the Audit Trail Module to your application. If you added this Module when you created an XAF application, the Solution Wizard generates the following code automatically:

  1. Add the DevExpress.ExpressApp.AuditTrail.EFCore NuGet package to the ASP.NET Core Blazor application project (MySolution.Blazor.Server).
  2. In the ASP.NET Core Blazor application constructor, add the Audit Trail Module to the Modules collection (the MySolution.Blazor.Server\BlazorApplication.cs file).

    using DevExpress.ExpressApp.AuditTrail.EFCore;
    // ...
    public partial class MySolutionBlazorApplication : BlazorApplication {
        public MySolutionBlazorApplication() {
            // ...
            Modules.Add(new AuditTrailModule());
        // ...

    Alternatively, you can add the Audit Trail Module to the ModuleBase.RequiredModuleTypes collection of the platform-agnostic or ASP.NET Core Blazor-specific Module.

  3. In the Startup.ConfigureServices method (the MySolution.Blazor.Server\Startup.cs file), do the following:

    • call the AddAuditTrail method to register the required Audit Trail services in IServiceCollection;
    • call the AddAuditedDbContextFactory method to register IXafDbContextFactory with an Audit Trail service factory in the IServiceCollection.
    using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail;
    // ...
    public class Startup {
        // ...
        public void ConfigureServices(IServiceCollection services){
            services.AddDbContextFactory<MySolutionEFCoreDbContext>((serviceProvider, options) => {
                string connectionString = Configuration.GetConnectionString("ConnectionString");
                // Uncomment the following line if your application uses the Security System.
                // options.UseSecurity(serviceProvider);
            }, ServiceLifetime.Scoped);
  4. In the application’s CreateDefaultObjectSpaceProvider overridden method (the MySolution.Blazor.Server\BlazorApplication.cs file), create EFCoreObjectSpaceProvider or SecuredEFCoreObjectSpaceProvider with the IXafDbContextFactory parameter.

    public class MySolutionBlazorApplication : BlazorApplication {
        // ...
        protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
            IXafDbContextFactory<MySolutionEFCoreDbContext> dbFactory = 
            EFCoreObjectSpaceProvider efCoreObjectSpaceProvider = new EFCoreObjectSpaceProvider(dbFactory, TypesInfo);
            // or
            // SecuredEFCoreObjectSpaceProvider efCoreObjectSpaceProvider = 
            // new SecuredEFCoreObjectSpaceProvider((ISelectDataSecurityProvider)Security, dbFactory, TypesInfo);
            // ...
  5. Register the AuditDataItemPersistent and AuditEFCoreWeakReference types in the application DbContext (the MySolution.Module\BusinessObjects\MySolutionDbContext.cs file).

    public class MySolutionEFCoreDbContext : DbContext {
        // ...
        public DbSet<AuditDataItemPersistent> AuditData { get; set; }
        public DbSet<AuditEFCoreWeakReference> AuditEFCoreWeakReferences { get; set; }
        // ...

    For more information on these classes, refer to the following help topic: Access the Audit Log In the Database.

  6. In applications with the Security System, configure permissions for non-administrative roles. This allows the Module to create audit records for changes that non-administrative users make. Additionally, you can allow users to read the information on their changes only.

    File: MySolution.Module\DatabaseUpdater\Updater.cs.

    using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail;
    // ...
    public class Updater : ModuleUpdater {
        // ...
        public override void UpdateDatabaseAfterUpdateSchema() {
            // ...
            PermissionPolicyRole userRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Users");
            if(userRole == null) {
                // ...
                defaultRole.AddTypePermission<AuditDataItemPersistent>(SecurityOperations.Read, SecurityPermissionState.Deny);
                defaultRole.AddObjectPermissionFromLambda<AuditDataItemPersistent>(SecurityOperations.ReadWriteAccess, a => a.UserObject.Key == CurrentUserIdOperator.CurrentUserId().ToString(), SecurityPermissionState.Allow);
                defaultRole.AddTypePermission<AuditDataItemPersistent>(SecurityOperations.Create, SecurityPermissionState.Allow);
                defaultRole.AddTypePermission<AuditEFCoreWeakReference>(SecurityOperations.ReadWriteAccess, SecurityPermissionState.Allow);
                defaultRole.AddTypePermission<AuditEFCoreWeakReference>(SecurityOperations.Create, SecurityPermissionState.Allow);
  7. Run the application and click the Reports | Audit Event navigation item. The invoked List View contains change history for audited objects.


The AuditInformationReadonlyViewController denies users the ability to create, edit, and delete IAuditDataItemPersistent objects in the UI.

Display Change History in the Object Detail View

Follow the steps below to show the history of an object in its Detail View:

  1. Implement the IObjectSpaceLink interface in your business class.
  2. Add the AuditDataItemPersistent collection property to your business class.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations.Schema;
    using DevExpress.ExpressApp;
    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.BaseImpl.EFCore.AuditTrail;
    // ...
    public class MyBusinessObject : IObjectSpaceLink {
        public Int32 ID { get; protected set; }
        public string StringProperty { get; set; }
        IObjectSpace objectSpace;
        IObjectSpace IObjectSpaceLink.ObjectSpace {
            get { return objectSpace; }
            set { objectSpace = value; }
        [CollectionOperationSet(AllowAdd = false, AllowRemove = false)]
        public virtual IList<AuditDataItemPersistent> ChangeHistory {
            get { return AuditDataItemPersistent.GetAuditTrail(objectSpace, this); }

The following image demonstrates the result.


You can also access the audit log in the database directly if you do not want to display history in the UI.