public override void OnScopeSaving(AuditScope auditScope)
 {
     if (!Singleton.Instance.Audit)
     {
         auditScope.Discard();
     }
     auditScope.SetCustomField("Ip", Singleton.Instance.Ip);
 }
        /// <inheritdoc />
        public virtual async Task <TEntity> RetrieveAsync(
            TKey id,
            CancellationToken cancellationToken = default,
            params Expression <Func <TEntity, object> >[] includes)
        {
            TEntity    retrieved          = default;
            AuditScope auditScope         = null;
            var        isServiceException = false;

            try
            {
                auditScope = await AuditScope.CreateAsync($"{EntityName}:Retrieve", () => retrieved);

                auditScope.Event.Environment.UserName = UserContext.CurrentUser;
                auditScope.Event.Target.Type          = $"{EntityFullName}";

                try
                {
                    retrieved = await DecoratedService.RetrieveAsync(id, cancellationToken, includes);
                }
                catch
                {
                    isServiceException = true;
                    auditScope.Discard();
                    throw;
                }
            }
            catch (Exception e)
            {
                if (isServiceException)
                {
                    throw;
                }

                Logger.Warning(e, "Auditing failed for RetrieveAsync of type {Entity} with ID {Id}.", EntityName, id);
            }
            finally
            {
                if (auditScope != null)
                {
                    await auditScope.DisposeAsync();
                }
            }

            return(retrieved);
        }
        /// <inheritdoc />
        public virtual async Task UpdateAsync(TEntity item, CancellationToken cancellationToken = default)
        {
            AuditScope auditScope         = null;
            var        isServiceException = false;
            TKey       id       = item.Id;
            TEntity    original = await ReadOnlyRepository.RetrieveAsync(id, cancellationToken);

            try
            {
                auditScope = await AuditScope.CreateAsync($"{EntityName}:Update", () => original);

                auditScope.Event.Environment.UserName = UserContext.CurrentUser;
                auditScope.Event.Target.Type          = $"{EntityFullName}";

                try
                {
                    await DecoratedService.UpdateAsync(item, cancellationToken);
                }
                catch
                {
                    isServiceException = true;
                    auditScope.Discard();
                    throw;
                }

                // Assign the updated item back to the original. This allows Audit.NET to determine what was changed.
                // ReSharper disable once RedundantAssignment
                original = item;
            }
            catch (Exception e)
            {
                if (isServiceException)
                {
                    throw;
                }

                Logger.Warning(e, "Auditing failed for UpdateAsync of type {Entity} with ID {Id}.", EntityName, id);
            }
            finally
            {
                if (auditScope != null)
                {
                    await auditScope.DisposeAsync();
                }
            }
        }
        /// <inheritdoc />
        public virtual async Task <TEntity> CreateAsync(
            TEntity item,
            CancellationToken cancellationToken = default)
        {
            TEntity    created            = default;
            AuditScope auditScope         = null;
            var        isServiceException = false;

            try
            {
                auditScope = await AuditScope.CreateAsync($"{EntityName}:Create", () => created);

                auditScope.Event.Environment.UserName = UserContext.CurrentUser;
                auditScope.Event.Target.Type          = $"{EntityFullName}";

                try
                {
                    created = await DecoratedService.CreateAsync(item, cancellationToken);
                }
                catch
                {
                    isServiceException = true;
                    auditScope.Discard();
                    throw;
                }
            }
            catch (Exception e)
            {
                if (isServiceException)
                {
                    throw;
                }

                Logger.Warning(e, "Auditing failed for CreateAsync of type {Entity}.", EntityName);
            }
            finally
            {
                if (auditScope != null)
                {
                    await auditScope.DisposeAsync();
                }
            }

            return(created);
        }