Open Closed

AuditLog remove MaxLength constraint on OriginalValue and New Value from EntityPropertyChanged #3625


0
p.j.keukens created

If you're creating a bug/problem report, please include followings:

  • ABP Framework version: v5.3.0 (Commercial)
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no

Hi,

We have created an entity with a field where we store a JSON object. On this entity we also use AuditLogging which is very important to us. The field where we store the JSON object is of type VARCHAR(MAX). When a change is written in the audit log the JSON is capped to 512 characters as the field "OriginalValue" and "NewValue" in the table "AbpEntityPropertyChanges" are only VARCHAR(512).

We changed the entity configuration to the config below, created a migration and applied changes to the database:

        builder.Entity< Volo.Abp.AuditLogging.EntityPropertyChange >().Property(x => x.OriginalValue).Metadata.RemoveAnnotation("MaxLength");
        builder.Entity< Volo.Abp.AuditLogging.EntityPropertyChange >().Property(x => x.NewValue).Metadata.RemoveAnnotation("MaxLength");
        builder.Entity< Volo.Abp.AuditLogging.EntityPropertyChange >().Property(x => x.OriginalValue).HasColumnType("nvarchar(max)");
        builder.Entity< Volo.Abp.AuditLogging.EntityPropertyChange >().Property(x => x.NewValue).HasColumnType("nvarchar(max)");

Also we changed the MaxNewValueLength and MaxOriginalValueLength to 1.000.000

        EntityPropertyChangeConsts.MaxNewValueLength = 1000000;
        EntityPropertyChangeConsts.MaxOriginalValueLength = 1000000;

In the Constructor (shown in codeblock below) of the EntityPropertyChange it truncates the value based upon MaxNewValueLength and MaxOriginalValueLength so setting it to 1000000 should store all info but in the database the original and new value are still 512 characters. Is there another place where the data is truncated? How can I fix this so that the full JSON object can be stored in the audit log?

public EntityPropertyChange(
        IGuidGenerator guidGenerator,
        Guid entityChangeId,
        EntityPropertyChangeInfo entityChangeInfo,
        Guid? tenantId = null)
    {
        Id = guidGenerator.Create();
        TenantId = tenantId;
        EntityChangeId = entityChangeId;
        NewValue = entityChangeInfo.NewValue.Truncate(EntityPropertyChangeConsts.MaxNewValueLength);
        OriginalValue = entityChangeInfo.OriginalValue.Truncate(EntityPropertyChangeConsts.MaxOriginalValueLength);
        PropertyName = entityChangeInfo.PropertyName.TruncateFromBeginning(EntityPropertyChangeConsts.MaxPropertyNameLength);
        PropertyTypeFullName = entityChangeInfo.PropertyTypeFullName.TruncateFromBeginning(EntityPropertyChangeConsts.MaxPropertyTypeFullNameLength);
    }

Also on the AuditLog we have a form which is multipart/form-data, this form is posted to the razorpage. In the audit log of the post we don't see all the data that is posted to the razorpage. Is there a way to show all the posted data in the audit log? We need this as 'proof' of what someone has posted. I see that when the ApplicationService is called it logs all data that is send to the ApplicationService method but we would like to log the posted data (without the posted files...)


10 Answer(s)
  • 0
    enisn created
    Support Team

    Hello,

    Truncate operation is done here: https://github.com/abpframework/abp/blob/e3e1779de6df5d26f01cdc8e99ac9cbcb3d24d3c/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs#L173

    Can you also try to set EntityPropertyChangeInfo.MaxValueLength static property?

    EntityPropertyChangeInfo.MaxValueLength = 1000000
    
  • 0
    p.j.keukens created

    Hi,

    EntityPropertyChangeInfo.MaxValueLength is not a static property so I can't change it.

    any other way to solve this problem?

  • 0
    malik.masis created
    Support Team

    Hi, I've checked it and it seems static variable.

    Could you look at it here, please?

    Regards.

  • 0
    p.j.keukens created

    Hi,

    Yeah I see that realLiangshiwei has changed it yesterday from const to static. In which release will these changes be available?

    Thanks.

  • 0
    malik.masis created
    Support Team

    Hi, ABP 6.0 stable release date to September 20, 2022 FYI.

  • 0
    enisn created
    Support Team

    Hi @p.j.keukens

    You can override the EntityHistoryHelper in your project to achieve solution in your app on your version.

    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(EntityHistoryHelper))]
    public class MyEntityHistoryHelper  : EntityHistoryHelper
    {
         protected override List<EntityPropertyChangeInfo> GetPropertyChanges(EntityEntry entityEntry)
        {
            var propertyChanges = new List<EntityPropertyChangeInfo>();
            var properties = entityEntry.Metadata.GetProperties();
            var isCreated = IsCreated(entityEntry);
            var isDeleted = IsDeleted(entityEntry);
    
            foreach (var property in properties)
            {
                var propertyEntry = entityEntry.Property(property.Name);
                if (ShouldSavePropertyHistory(propertyEntry, isCreated || isDeleted) && !IsSoftDeleted(entityEntry))
                {
                    propertyChanges.Add(new EntityPropertyChangeInfo
                    {
                        NewValue = isDeleted ? null : JsonSerializer.Serialize(propertyEntry.CurrentValue).TruncateWithPostfix(YOUR_CUSTOM_VALUE),
                        OriginalValue = isCreated ? null : JsonSerializer.Serialize(propertyEntry.OriginalValue).TruncateWithPostfix(YOUR_CUSTOM_VALUE),
                        PropertyName = property.Name,
                        PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName
                    });
                }
            }
    }
    

    Replace the YOUR_CUSTOM_VALUE with your requirement.

    Also you can remove TruncateWithPostfix() method completely.

  • 0
    p.j.keukens created

    Hi,

    I have overridden the EntityHistoryHelper and that works, larger JSON is now stored in the table. There is still one weird thing and that is that the Created event on the entity is not audited.

    I do see the updated event when I change it (in a webpage) but the created not so much.

    Could this be because the created is in a Hangfirejob?

    Job definition:

    public class InformationWorker : HangfireBackgroundWorkerBase
    

    Entity:

    [Audited]
    public class InformationResponse : FullAuditedEntity
    

    Repository:

    public class EfCoreInformationResponseRepository : EfCoreRepository<InformationDbContext, InformationResponse>, IInformationResponseRepository
    

    Insert action:

    await informationResponseRepository.InsertAsync(new InformationResponse(details.Id, jsonData));
    

    Any ideas on why the created event is not in the audit log?

  • 0
    p.j.keukens created

    Okay so I created my own audited scope

        using (var informationScope = auditingManager.BeginScope())
        {
            auditingManager.Current.Log.Url = "InformationWorker";
            auditingManager.Current.Log.UserName = "Hangfire";
            auditingManager.Current.Log.HttpStatusCode = 200;
    
            ..... get entities .....        
            ..... update entity .....
            ..... create entity .....
            
            await informationScope.SaveAsync(); 
        }       
    
    

    Now this shows one action which is fine, then it shows the entity changes but only the insert has properties. The entitities that are updated don't show the changed properties, the entitychange is empty. Do I need to log them manually?

  • 0
    gterdem created
    Support Team

    You can either log them manually or add to EntityHistorySelectors in AbpAuditingOptions.

  • 0
    p.j.keukens created

    You can either log them manually or add to EntityHistorySelectors in AbpAuditingOptions.

    @gterdem I have decorated the classes with [Audited] which should be the same as with the entityhistoryselectors isn't it?