Create Behavior file in common module.

using Serenity.ComponentModel;
using Serenity.Data;
using Serenity.Data.Mapping;
using Serenity.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Web;
using Serenity;
using Serene.Administration;

namespace Serene.Modules.Common.Audit
{
    public interface IAuditLog

    {

    }
    public interface IExAuditLog

    {
        Int32Field IdField { get; }

    }

    [EnumKey("Enum.Audit.AuditActionType")]

    public enum AuditActionType

    {

        [Description("INSERT")]

        Insert = 1,

        [Description("UPDATE")]

        Update = 2,

        [Description("DELETE")]

        Delete = 3

    }
    public class IgnoreAuditLog : Attribute

    {

    }
    public class InsertField

    {

        //Field Name

        public string F { get; set; }

        //Field Value

        public string V { get; set; }

    }
    public class UpdateField
    {
        //Field Name
        public string F { get; set; }

        //Old Value
        public string O { get; set; }

        //Current Value
        public string V { get; set; }

    }
    public static class ExtensionMethods
    {
        public static string ToIndianDateFormat(this DateTime? dateTime)

        {

            if (!dateTime.HasValue)

                return "";

            return dateTime.Value.ToString("dd/MM/yyyy");

        }
        public static string GetEnumText(this object EnumObj)

        {

            Type type = EnumObj.GetType();

            if (!type.IsEnum)

            {

                throw new ArgumentException("EnumerationValue must be of Enum type", "EnumObj");

            }



            //Tries to find a DescriptionAttribute for a potential friendly name

            //for the enum

            MemberInfo[] memberInfo = type.GetMember(EnumObj.ToString());

            if (memberInfo != null && memberInfo.Length > 0)

            {

                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);



                if (attrs != null && attrs.Length > 0)

                {

                    //Pull out the description value

                    return ((DescriptionAttribute)attrs[0]).Description;

                }

            }

            //If we have no description attribute, just return the ToString of the enum

            return EnumObj.ToString();



        }
    }
    public class AuditRowBehavior : IImplicitBehavior, ISaveBehavior, IDeleteBehavior
    {
        const string FieldSeperator = "; ";
        string IdFieldName = null;
        public bool ActivateFor(Row row)
        {
            var auditLog = row as IAuditLog;
            if (auditLog == null)

            {

                var exauditLog = row as IExAuditLog;

                if (exauditLog == null)

                    return false;

                else

                    IdFieldName = exauditLog.IdField.PropertyName;

            }

            return true;

        }

        public void OnAfterSave(ISaveRequestHandler handler) { }

        public void OnAudit(ISaveRequestHandler handler)
        {

            string auditLog = "";

            AuditActionType AuditAction = AuditActionType.Delete;

            if (handler.IsCreate)

            {

                 auditLog = GetInsertAuditLog(handler.Row);

                AuditAction = AuditActionType.Insert;

            }



            if (handler.IsUpdate)

            {

                  auditLog = GetUpdateAuditLog(handler.Row, handler.Old);

                AuditAction = AuditActionType.Update;

            }

             ExecuteAuditLogProc(handler.Connection, AuditAction, handler.Row, auditLog);

        }

        public void OnBeforeSave(ISaveRequestHandler handler) { }

        public void OnPrepareQuery(ISaveRequestHandler handler, SqlQuery query) { }

        public void OnReturn(ISaveRequestHandler handler) { }

        public void OnSetInternalFields(ISaveRequestHandler handler) { }

        public void OnValidateRequest(ISaveRequestHandler handler) { }

        public void OnAfterDelete(IDeleteRequestHandler handler) { }

        public void OnAudit(IDeleteRequestHandler handler)
        {

            var auditLog = GetInsertAuditLog(handler.Row);

            ExecuteAuditLogProc(handler.Connection, AuditActionType.Delete, handler.Row, auditLog);

        }

        public void OnBeforeDelete(IDeleteRequestHandler handler) { }

        public void OnPrepareQuery(IDeleteRequestHandler handler, SqlQuery query) { }

        public void OnReturn(IDeleteRequestHandler handler) { }

        public void OnValidateRequest(IDeleteRequestHandler handler) { }

        private string GetUpdateAuditLog(Row CurrentRow, Row OldRow)

        {

            List<UpdateField> audiDataList = new List<UpdateField>();

            var tableFields = CurrentRow.GetTableFields();

            foreach (var tfield in tableFields)

            {

                var propInfo = CurrentRow.GetType().GetProperty(tfield.ColumnAlias);



                if (propInfo.GetCustomAttribute(typeof(IgnoreAuditLog)) != null)

                    continue;

                if (propInfo.GetCustomAttribute(typeof(IdentityAttribute)) != null)

                    IdFieldName = propInfo.Name;



                if (propInfo.PropertyType == typeof(DateTime?))

                {

                    var currDate = ((DateTime?)propInfo.GetValue(CurrentRow));

                    var oldDate = ((DateTime?)propInfo.GetValue(OldRow));

                    if ((oldDate.HasValue || currDate.HasValue) && oldDate != currDate)

                        audiDataList.Add(new UpdateField { F = propInfo.Name, V = (currDate.HasValue ? currDate.ToIndianDateFormat() : "&lt;empty&gt;"), O = (oldDate.HasValue ? oldDate.ToIndianDateFormat() : "&lt;empty&gt;") });

                }

                else if (propInfo.PropertyType == typeof(Decimal?))

                {

                    var currValue = ((Decimal?)propInfo.GetValue(CurrentRow));

                    var oldValue = ((Decimal?)propInfo.GetValue(OldRow));

                    if ((currValue.HasValue || oldValue.HasValue) && (Convert.ToDecimal(currValue) - Convert.ToDecimal(oldValue)) != 0)

                        audiDataList.Add(new UpdateField { F = propInfo.Name, O = (oldValue.HasValue ? oldValue.Value.ToString() : "&lt;empty&gt;"), V = (currValue.HasValue ? currValue.Value.ToString() : "&lt;empty&gt;") });

                }

                else

                {

                    var currValue = Convert.ToString(propInfo.GetValue(CurrentRow));

                    var oldValue = Convert.ToString(propInfo.GetValue(OldRow));

                    if (currValue != oldValue)

                        audiDataList.Add(new UpdateField { F = propInfo.Name, O = (oldValue.IsNullOrEmpty() ? "&lt;empty&gt;" : oldValue), V = (currValue.IsNullOrEmpty() ? "&lt;empty&gt;" : currValue) });

                }

            }

            //return auditLog;

            return audiDataList.ToJson(); ;

        }

        private string GetInsertAuditLog(Row CurrentRow)

        {

            List<InsertField> audiDataList = new List<InsertField>();

            var tableFields = CurrentRow.GetTableFields();

            foreach (var tfield in tableFields)

            {

                var propInfo = CurrentRow.GetType().GetProperty(tfield.ColumnAlias);

                if (propInfo.GetCustomAttribute(typeof(IgnoreAuditLog)) != null)

                    continue;

                if (propInfo.GetCustomAttribute(typeof(IdentityAttribute)) != null)

                    IdFieldName = propInfo.Name;

                //Check if field is of DateTime type to convert it in desired format.

                if (propInfo.PropertyType == typeof(DateTime?))

                {

                    var currDate = ((DateTime?)propInfo.GetValue(CurrentRow));

                    if (currDate.HasValue)

                        audiDataList.Add(new InsertField { F = propInfo.Name, V = currDate.ToIndianDateFormat() });

                }

                else

                {

                    var fieldValue = Convert.ToString(propInfo.GetValue(CurrentRow));

                    //Insert in log if values is defined for field.

                    if (!fieldValue.IsNullOrEmpty())

                        audiDataList.Add(new InsertField { F = propInfo.Name, V = fieldValue });

                }

            }

            return audiDataList.ToJson();

        }
        public void ExecuteAuditLogProc(IDbConnection Connection, AuditActionType AuditAction, Row CurrentRow, string AuditLog)

        {

            using (IDbCommand command = Connection.CreateCommand())

            {

                IDbDataParameter pUserId = command.CreateParameter();

                pUserId.ParameterName = "@UserId";

                pUserId.Value = ((UserDefinition)Authorization.UserDefinition).UserId;

                command.Parameters.Add(pUserId);



                IDbDataParameter pUserName = command.CreateParameter();

                pUserName.ParameterName = "@UserName";

                pUserName.Value = ((UserDefinition)Authorization.UserDefinition).Username;

                command.Parameters.Add(pUserName);



                IDbDataParameter pAction = command.CreateParameter();

                pAction.ParameterName = "@Action";

                pAction.Value = AuditAction.GetEnumText();

                command.Parameters.Add(pAction);



                IDbDataParameter pTableName = command.CreateParameter();

                pTableName.ParameterName = "@TableName";

                pTableName.Value = CurrentRow.Table;

                command.Parameters.Add(pTableName);



                IDbDataParameter pRowId = command.CreateParameter();

                pRowId.ParameterName = "@RowId";

                pRowId.Value = Convert.ToString(CurrentRow.GetType().GetProperty(IdFieldName == null ? "Id" : IdFieldName).GetValue(CurrentRow));

                command.Parameters.Add(pRowId);



                IDbDataParameter pModule = command.CreateParameter();

                pModule.ParameterName = "@Module";

                pModule.Value = CurrentRow.GetType().Name;

                command.Parameters.Add(pModule);



                IDbDataParameter pPage = command.CreateParameter();

                pPage.ParameterName = "@Page";

                //Sometimes same module is used for different pages for reusablity. So save page url to know the exact action page.

                pPage.Value = GetPageUrl();

                command.Parameters.Add(pPage);



                IDbDataParameter pChanges = command.CreateParameter();

                pChanges.ParameterName = "@Changes";

                pChanges.Value = AuditLog;

                command.Parameters.Add(pChanges);



                command.CommandType = CommandType.StoredProcedure;

                command.CommandText = "Common_AuditLog";

                command.ExecuteNonQuery();

            }

        }
        string GetPageUrl()

        {

            string pageUrl = "";

            if (HttpContext.Current != null && HttpContext.Current.Request != null)

            {

                var httpRequest = HttpContext.Current.Request;

                if (httpRequest.UrlReferrer != null)

                    pageUrl = httpRequest.UrlReferrer.PathAndQuery;

                else if (httpRequest.Url != null)

                    pageUrl = httpRequest.Url.PathAndQuery;

            }

            return pageUrl;

        }

    }
}

create class in database.

CREATE TABLE [dbo].[AuditLog](
 [Id]  [bigint ] IDENTITY (1,1) NOT NULL,
 [UserId]  [int] NOT NULL,
 [UserName]  [varchar] (50) NOT NULL,
 [Action]  [varchar] (50) NOT NULL,
 [ChangedOn]  [datetime] NOT NULL CONSTRAINT  [DF _AuditLog _ChangedOn]  DEFAULT  (getdate()),
 [TableName]  [varchar] (50 ) NOT NULL,
 [RowId]  [int] NOT NULL,
 [Module]  [varchar] (500 ) NULL,
 [Page]  [varchar] (500 ) NULL,
 [Changes]  [varchar] (max ) NULL,
CONSTRAINT [PK_AuditLog] PRIMARY KEY CLUSTERED
(
 [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

create procedure.

CREATE PROCEDURE [dbo].[Common_AuditLog]
 @UserId INT
,@UserName VARCHAR (50 )
,@Action VARCHAR (50 )
,@TableName VARCHAR (50 )
,@RowId INT
,@Module VARCHAR (50 ) = NULL
,@Page VARCHAR (50 ) = NULL
,@Changes VARCHAR (MAX ) = NULL
AS
BEGIN
INSERT INTO [dbo].[AuditLog]
        ([UserId]
       ,[UserName]
       ,[Action]
       ,[ChangedOn]
       ,[TableName]
       ,[RowId]
       ,[Module]
       ,[Page]
       ,[Changes])
 VALUES

        (
        @UserId    
       ,@UserName
       ,@Action
       ,GetDate ( )    
       ,@TableName    
       ,@RowId        
       ,@Module    
       ,@Page        
       ,@Changes    
        )
END

GO

Implement IAuditLog interface on UserRow.cs

namespace Serene.Administration.Entities
{
    using Modules.Common.Audit;
    using Serenity.ComponentModel;
    using Serenity.Data;
    using Serenity.Data.Mapping;
    using System;
    using System.ComponentModel;

    [ConnectionKey("Default"), TableName("Users"), DisplayName("Users"), InstanceName("User"), TwoLevelCached]
    [ReadPermission(PermissionKeys.Security)]
    [ModifyPermission(PermissionKeys.Security)]
    [LookupScript("Administration.User", Permission = PermissionKeys.Security)]
    public sealed class UserRow : LoggingRow, IIdRow, INameRow, IIsActiveRow, Serene.Modules.Common.Audit.IAuditLog
    {
        [DisplayName("User Id"), Identity]
        public Int32? UserId
        {
            get { return Fields.UserId[this]; }
            set { Fields.UserId[this] = value; }
        }

        ...

Reference link

https://sayuga.gitbooks.io/serenitytutorials/content/audit-logging-with-change-tracker.html

results matching ""

    No results matching ""