Jelajahi Sumber

Logging gestartet!

Arne Diekmann 8 tahun lalu
induk
melakukan
cd7509b770

+ 81 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Logging/Log.cs

@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Core.Domain.Logging
+{
+    public class Log : BaseEntity
+    {
+        /// <summary>
+        /// The log level identifier
+        /// </summary>
+        public int LogLevelId { get; set; }
+
+        /// <summary>
+        /// The short message
+        /// </summary>
+        public string ShortMessage { get; set; }
+
+        /// <summary>
+        /// The full exception
+        /// </summary>
+        public string FullMessage { get; set; }
+
+        /// <summary>
+        /// The IP address
+        /// </summary>
+        public string IpAddress { get; set; }
+
+        /// <summary>
+        /// The user identifier
+        /// </summary>
+        public int? UserId { get; set; }
+
+        /// <summary>
+        /// The user
+        /// </summary>
+        public virtual User.User User { get; set; }
+
+        /// <summary>
+        /// The entity identifier
+        /// </summary>
+        public int? EntityId { get; set; }
+
+        /// <summary>
+        /// The entity type
+        /// </summary>
+        public string EntityType { get; set; }
+
+        /// <summary>
+        /// The page URL
+        /// </summary>
+        public string PageUrl { get; set; }
+
+        /// <summary>
+        /// Referrer URL
+        /// </summary>
+        public string ReferrerUrl { get; set; }
+
+        /// <summary>
+        /// The date and time of instance creation
+        /// </summary>
+        public DateTime CreatedOnUtc { get; set; }
+
+        /// <summary>
+        /// The log level
+        /// </summary>
+        public LogLevel LogLevel
+        {
+            get
+            {
+                return (LogLevel)this.LogLevelId;
+            }
+            set
+            {
+                this.LogLevelId = (int)value;
+            }
+        }
+    }
+}

+ 18 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Logging/LogEntityActivity.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Core.Domain.Logging
+{
+    /// <summary>
+    /// Represents a log activity for an entity
+    /// </summary>
+    public enum LogEntityActivity
+    {
+        Insert = 1,
+        Update = 2,
+        Delete = 3
+    }
+}

+ 20 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Logging/LogLevel.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Core.Domain.Logging
+{
+    /// <summary>
+    /// Represents a log level
+    /// </summary>
+    public enum LogLevel
+    {
+        Debug = 10,
+        Information = 20,
+        Warning = 30,
+        Error = 40,
+        Fatal = 50
+    }
+}

+ 3 - 0
GreenTree.Nachtragsmanagement.Core/GreenTree.Nachtragsmanagement.Core.csproj

@@ -98,6 +98,9 @@
     <Compile Include="Domain\Deviation\Kind.cs" />
     <Compile Include="Domain\Deviation\Kind.cs" />
     <Compile Include="Domain\Deviation\Status.cs" />
     <Compile Include="Domain\Deviation\Status.cs" />
     <Compile Include="Domain\Invoice\Invoice.cs" />
     <Compile Include="Domain\Invoice\Invoice.cs" />
+    <Compile Include="Domain\Logging\Log.cs" />
+    <Compile Include="Domain\Logging\LogEntityActivity.cs" />
+    <Compile Include="Domain\Logging\LogLevel.cs" />
     <Compile Include="Domain\Misc\DbContextSpec.cs" />
     <Compile Include="Domain\Misc\DbContextSpec.cs" />
     <Compile Include="Domain\Misc\MailNotification.cs" />
     <Compile Include="Domain\Misc\MailNotification.cs" />
     <Compile Include="Domain\Site\Site.cs" />
     <Compile Include="Domain\Site\Site.cs" />

+ 15 - 0
GreenTree.Nachtragsmanagement.Core/IWebHelper.cs

@@ -23,6 +23,21 @@ namespace GreenTree.Nachtragsmanagement.Core
         /// <returns>URL referrer</returns>
         /// <returns>URL referrer</returns>
         string GetCurrentIpAddress();
         string GetCurrentIpAddress();
 
 
+        /// <summary>
+        /// Gets this page name
+        /// </summary>
+        /// <param name="includeQueryString">Value indicating whether to include query strings</param>
+        /// <returns>Page name</returns>
+        string GetThisPageUrl(bool includeQueryString);
+
+        /// <summary>
+        /// Gets this page name
+        /// </summary>
+        /// <param name="includeQueryString">Value indicating whether to include query strings</param>
+        /// <param name="useSsl">Value indicating whether to get SSL protected page</param>
+        /// <returns>Page name</returns>
+        string GetThisPageUrl(bool includeQueryString, bool useSsl);
+
         /// <summary>
         /// <summary>
         /// Gets a value indicating whether current connection is secured
         /// Gets a value indicating whether current connection is secured
         /// </summary>
         /// </summary>

+ 68 - 0
GreenTree.Nachtragsmanagement.Core/WebHelper.cs

@@ -158,6 +158,74 @@ namespace GreenTree.Nachtragsmanagement.Core
 
 
         }
         }
 
 
+        /// <summary>
+        /// Gets this page name
+        /// </summary>
+        /// <param name="includeQueryString">Value indicating whether to include query strings</param>
+        /// <returns>Page name</returns>
+        public virtual string GetThisPageUrl(bool includeQueryString)
+        {
+            var useSsl = IsCurrentConnectionSecured();
+
+            return GetThisPageUrl(includeQueryString, useSsl);
+        }
+
+        /// <summary>
+        /// Gets this page name
+        /// </summary>
+        /// <param name="includeQueryString">Value indicating whether to include query strings</param>
+        /// <param name="useSsl">Value indicating whether to get SSL protected page</param>
+        /// <returns>Page name</returns>
+        public virtual string GetThisPageUrl(bool includeQueryString, bool useSsl)
+        {
+            var url = String.Empty;
+
+            if (!IsRequestAvailable(_httpContext))
+                return url;
+
+            if (includeQueryString)
+            {
+                var storeHost = GetStoreHost(useSsl);
+
+                if (storeHost.EndsWith("/"))
+                    storeHost = storeHost.Substring(0, storeHost.Length - 1);
+
+                url = storeHost + _httpContext.Request.RawUrl;
+            }
+            else
+            {
+                if (_httpContext.Request.Url != null)
+                    url = _httpContext.Request.Url.GetLeftPart(UriPartial.Path);
+            }
+
+            url = url.ToLowerInvariant();
+
+            return url;
+        }
+
+        /// <summary>
+        /// Gets store host location
+        /// </summary>
+        /// <param name="useSsl">Use SSL</param>
+        /// <returns>Store host location</returns>
+        public virtual string GetStoreHost(bool useSsl)
+        {
+            var result = "";
+            var httpHost = ServerVariables("HTTP_HOST");
+
+            if (!String.IsNullOrEmpty(httpHost))
+            {
+                result = "http://" + httpHost;
+                if (!result.EndsWith("/"))
+                    result += "/";
+            }
+
+            if (!result.EndsWith("/"))
+                result += "/";
+
+            return result.ToLowerInvariant();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets a value indicating whether current connection is secured
         /// Gets a value indicating whether current connection is secured
         /// </summary>
         /// </summary>

+ 6 - 1
GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs

@@ -22,6 +22,8 @@ using GreenTree.Nachtragsmanagement.Data.Mapping.User;
 using System.Data.Entity.Migrations;
 using System.Data.Entity.Migrations;
 using GreenTree.Nachtragsmanagement.Core.Domain.Config;
 using GreenTree.Nachtragsmanagement.Core.Domain.Config;
 using GreenTree.Nachtragsmanagement.Data.Mapping.Config;
 using GreenTree.Nachtragsmanagement.Data.Mapping.Config;
+using GreenTree.Nachtragsmanagement.Core.Domain.Logging;
+using GreenTree.Nachtragsmanagement.Data.Mapping.Logging;
 
 
 namespace GreenTree.Nachtragsmanagement.Data
 namespace GreenTree.Nachtragsmanagement.Data
 {
 {
@@ -57,6 +59,7 @@ namespace GreenTree.Nachtragsmanagement.Data
             var mailNotificationSet = Set<MailNotification>();
             var mailNotificationSet = Set<MailNotification>();
             var dbContextSpecSet = Set<DbContextSpec>();
             var dbContextSpecSet = Set<DbContextSpec>();
             var configItemSet = Set<ConfigItem>();
             var configItemSet = Set<ConfigItem>();
+            var loggingSet = Set<Log>();
 
 
             _dbSets.AddRange(
             _dbSets.AddRange(
                 new object[] 
                 new object[] 
@@ -75,7 +78,8 @@ namespace GreenTree.Nachtragsmanagement.Data
                     appendixSet,
                     appendixSet,
                     mailNotificationSet,
                     mailNotificationSet,
                     dbContextSpecSet,
                     dbContextSpecSet,
-                    configItemSet
+                    configItemSet,
+                    loggingSet
                 }
                 }
             );
             );
 
 
@@ -111,6 +115,7 @@ namespace GreenTree.Nachtragsmanagement.Data
             modelBuilder.Configurations.Add(new MailNotificationMap());
             modelBuilder.Configurations.Add(new MailNotificationMap());
             modelBuilder.Configurations.Add(new DbContextSpecMap());
             modelBuilder.Configurations.Add(new DbContextSpecMap());
             modelBuilder.Configurations.Add(new ConfigItemMap());
             modelBuilder.Configurations.Add(new ConfigItemMap());
+            modelBuilder.Configurations.Add(new LogMap());
 
 
             base.OnModelCreating(modelBuilder);
             base.OnModelCreating(modelBuilder);
         }
         }

+ 1 - 0
GreenTree.Nachtragsmanagement.Data/GreenTree.Nachtragsmanagement.Data.csproj

@@ -61,6 +61,7 @@
     <Compile Include="Mapping\Deviation\KindMap.cs" />
     <Compile Include="Mapping\Deviation\KindMap.cs" />
     <Compile Include="Mapping\Deviation\StatusMap.cs" />
     <Compile Include="Mapping\Deviation\StatusMap.cs" />
     <Compile Include="Mapping\Invoice\InvoiceMap.cs" />
     <Compile Include="Mapping\Invoice\InvoiceMap.cs" />
+    <Compile Include="Mapping\Logging\LogMap.cs" />
     <Compile Include="Mapping\Misc\DbContextSpecMap.cs" />
     <Compile Include="Mapping\Misc\DbContextSpecMap.cs" />
     <Compile Include="Mapping\Misc\MailNotificationMap.cs" />
     <Compile Include="Mapping\Misc\MailNotificationMap.cs" />
     <Compile Include="Mapping\Site\SiteMap.cs" />
     <Compile Include="Mapping\Site\SiteMap.cs" />

+ 37 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/Logging/LogMap.cs

@@ -0,0 +1,37 @@
+using GreenTree.Nachtragsmanagement.Core.Domain.Logging;
+using System;
+using System.Collections.Generic;
+using System.Data.Entity.ModelConfiguration;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Data.Mapping.Logging
+{
+    public class LogMap : EntityTypeConfiguration<Log>
+    {
+        public LogMap()
+        {
+            ToTable("Log");
+
+            HasKey(l => l.Id);
+
+            Property(l => l.CreatedOnUtc);
+            Property(l => l.FullMessage);
+            Property(l => l.LogLevelId);
+            Property(l => l.EntityId);
+            Property(l => l.EntityType);
+            Property(l => l.ShortMessage);
+            Property(l => l.IpAddress);
+            Property(l => l.PageUrl);
+            Property(l => l.ReferrerUrl);
+
+            Ignore(l => l.LogLevel);
+
+            HasOptional(l => l.User)
+                .WithMany()
+                .HasForeignKey(l => l.UserId)
+                .WillCascadeOnDelete(true);
+        }
+    }
+}

+ 3 - 0
GreenTree.Nachtragsmanagement.Services/GreenTree.Nachtragsmanagement.Services.csproj

@@ -63,6 +63,9 @@
     <Compile Include="DbContext\IDbContextService.cs" />
     <Compile Include="DbContext\IDbContextService.cs" />
     <Compile Include="Deviation\DeviationService.cs" />
     <Compile Include="Deviation\DeviationService.cs" />
     <Compile Include="Deviation\IDeviationService.cs" />
     <Compile Include="Deviation\IDeviationService.cs" />
+    <Compile Include="Logging\DefaultLogger.cs" />
+    <Compile Include="Logging\ILogger.cs" />
+    <Compile Include="Logging\LoggingExtensions.cs" />
     <Compile Include="Misc\INotificationService.cs" />
     <Compile Include="Misc\INotificationService.cs" />
     <Compile Include="Misc\MiscService.cs" />
     <Compile Include="Misc\MiscService.cs" />
     <Compile Include="Misc\IMiscService.cs" />
     <Compile Include="Misc\IMiscService.cs" />

+ 171 - 0
GreenTree.Nachtragsmanagement.Services/Logging/DefaultLogger.cs

@@ -0,0 +1,171 @@
+using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Data;
+using GreenTree.Nachtragsmanagement.Core.Domain.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Services.Logging
+{
+    /// <summary>
+    /// Default logger
+    /// </summary>
+    public partial class DefaultLogger : ILogger
+    {
+        #region Fields
+
+        private readonly IRepository<Log> _logRepository;
+        private readonly IWebHelper _webHelper;
+
+        #endregion
+
+        #region Ctor
+
+        /// <summary>
+        /// Initializes a new instance of the DefaultLogger class
+        /// </summary>
+        public DefaultLogger(
+            IRepository<Log> logRepository,
+            IWebHelper webHelper)
+        {
+            this._logRepository = logRepository;
+            this._webHelper = webHelper;
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        /// Determines whether a log level is enabled
+        /// </summary>
+        /// <param name="level">Log level</param>
+        /// <returns>Result</returns>
+        public virtual bool IsEnabled(LogLevel level)
+        {
+            switch (level)
+            {
+                case LogLevel.Debug:
+                    return false;
+                default:
+                    return true;
+            }
+        }
+
+        /// <summary>
+        /// Deletes a log item
+        /// </summary>
+        /// <param name="log">Log item</param>
+        public virtual void DeleteLog(Log log)
+        {
+            if (log == null)
+                throw new ArgumentNullException("log");
+
+            _logRepository.Delete(log);
+        }
+
+        /// <summary>
+        /// Clears a log
+        /// </summary>
+        public virtual void ClearLog()
+        {
+            var logs = _logRepository.Table.ToList();
+
+            foreach (var logItem in logs)
+                _logRepository.Delete(logItem);
+        }
+
+        /// <summary>
+        /// Gets all log items
+        /// </summary>
+        /// <param name="fromUtc">Log item creation from; null to load all records</param>
+        /// <param name="toUtc">Log item creation to; null to load all records</param>
+        /// <param name="message">Message</param>
+        /// <param name="logLevel">Log level; null to load all records</param>
+        /// <param name="pageIndex">Page index</param>
+        /// <param name="pageSize">Page size</param>
+        /// <returns>Log item collection</returns>
+        public IList<Log> GetAllLogs(DateTime? fromUtc, DateTime? toUtc,
+            string message, LogLevel? logLevel, int pageIndex, int pageSize)
+        {
+            return _logRepository.Table.ToList();
+        }
+
+        /// <summary>
+        /// Gets a log item
+        /// </summary>
+        /// <param name="logId">Log item identifier</param>
+        /// <returns>Log item</returns>
+        public virtual Log GetLogById(int logId)
+        {
+            if (logId == 0)
+                return null;
+
+            return _logRepository.GetById(logId);
+        }
+
+        /// <summary>
+        /// Get log items by identifiers
+        /// </summary>
+        /// <param name="logIds">Log item identifiers</param>
+        /// <returns>Log items</returns>
+        public virtual IList<Log> GetLogByIds(int[] logIds)
+        {
+            if (logIds == null || logIds.Length == 0)
+                return new List<Log>();
+
+            var query = from l in _logRepository.Table
+                        where logIds.Contains(l.Id)
+                        select l;
+            var logItems = query.ToList();
+            //sort by passed identifiers
+            var sortedLogItems = new List<Log>();
+            foreach (int id in logIds)
+            {
+                var log = logItems.Find(x => x.Id == id);
+                if (log != null)
+                    sortedLogItems.Add(log);
+            }
+            return sortedLogItems;
+        }
+
+        /// <summary>
+        /// Inserts a log item
+        /// </summary>
+        /// <param name="logLevel">Log level</param>
+        /// <param name="entity"></param>
+        /// <param name="shortMessage">The short message</param>
+        /// <param name="fullMessage">The full message</param>
+        /// <param name="user">The user to associate log record with</param>
+        /// <returns>A log item</returns>
+        public virtual Log InsertLog(LogLevel logLevel, string shortMessage, BaseEntity entity = null, string fullMessage = "", 
+            Core.Domain.User.User user = null)
+        {
+            var log = new Log
+            {
+                LogLevel = logLevel,
+                ShortMessage = shortMessage,
+                FullMessage = fullMessage,
+                IpAddress = _webHelper.GetCurrentIpAddress(),
+                User = user,
+                EntityId = entity == null 
+                    ? null
+                    : (int?)entity.Id,
+                EntityType = entity == null
+                    ? null
+                    : entity.GetType().Name,
+                PageUrl = _webHelper.GetThisPageUrl(true),
+                ReferrerUrl = _webHelper.GetUrlReferrer(),
+                CreatedOnUtc = DateTime.UtcNow
+            };
+
+            _logRepository.Insert(log);
+
+            return log;
+        }
+
+        #endregion
+    }
+}

+ 68 - 0
GreenTree.Nachtragsmanagement.Services/Logging/ILogger.cs

@@ -0,0 +1,68 @@
+using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Domain.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Services.Logging
+{
+    public interface ILogger
+    {
+        /// <summary>
+        /// Determines whether a log level is enabled
+        /// </summary>
+        /// <param name="level">Log level</param>
+        bool IsEnabled(LogLevel level);
+
+        /// <summary>
+        /// Deletes a log item
+        /// </summary>
+        /// <param name="log">Log item</param>
+        void DeleteLog(Log log);
+
+        /// <summary>
+        /// Clears a log
+        /// </summary>
+        void ClearLog();
+
+        /// <summary>
+        /// Gets all log items
+        /// </summary>
+        /// <param name="fromUtc">Log item creation from; null to load all records</param>
+        /// <param name="toUtc">Log item creation to; null to load all records</param>
+        /// <param name="message">Message</param>
+        /// <param name="logLevel">Log level; null to load all records</param>
+        /// <param name="pageIndex">Page index</param>
+        /// <param name="pageSize">Page size</param>
+        /// <returns>Log item collection</returns>
+        IList<Log> GetAllLogs(DateTime? fromUtc, DateTime? toUtc,
+            string message, LogLevel? logLevel, int pageIndex, int pageSize);
+
+        /// <summary>
+        /// Gets a log item
+        /// </summary>
+        /// <param name="logId">Log item identifier</param>
+        /// <returns>Log item</returns>
+        Log GetLogById(int logId);
+
+        /// <summary>
+        /// Get log items by identifiers
+        /// </summary>
+        /// <param name="logIds">Log item identifiers</param>
+        /// <returns>Log items</returns>
+        IList<Log> GetLogByIds(int[] logIds);
+
+        /// <summary>
+        /// Inserts a log item
+        /// </summary>
+        /// <param name="logLevel">Log level</param>
+        /// <param name="shortMessage">The short message</param>
+        /// <param name="fullMessage">The full message</param>
+        /// <param name="user">The user to associate log record with</param>
+        /// <returns>A log item</returns>
+        Log InsertLog(LogLevel logLevel, string shortMessage, BaseEntity entity = null, string fullMessage = "", 
+            Core.Domain.User.User user = null);
+    }
+}

+ 108 - 0
GreenTree.Nachtragsmanagement.Services/Logging/LoggingExtensions.cs

@@ -0,0 +1,108 @@
+using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Domain.Logging;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Services.Logging
+{
+    public static class LoggingExtensions
+    {
+        public static void Debug(this ILogger logger, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            FilteredLog(logger, LogLevel.Debug, message, exception, user);
+        }
+
+        public static void Information(this ILogger logger, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            FilteredLog(logger, LogLevel.Information, message, exception, user);
+        }
+
+        public static void Warning(this ILogger logger, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            FilteredLog(logger, LogLevel.Warning, message, exception, user);
+        }
+
+        public static void Error(this ILogger logger, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            FilteredLog(logger, LogLevel.Error, message, exception, user);
+        }
+
+        public static void Fatal(this ILogger logger, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            FilteredLog(logger, LogLevel.Fatal, message, exception, user);
+        }
+
+        private static void FilteredLog(ILogger logger, LogLevel level, string message, Exception exception = null,
+            Core.Domain.User.User user = null)
+        {
+            //don't log thread abort exception
+            if (exception is System.Threading.ThreadAbortException)
+                return;
+
+            if (logger.IsEnabled(level))
+            {
+                var fullMessage = exception == null 
+                    ? string.Empty 
+                    : exception.ToString();
+
+                logger.InsertLog(level, message, null, fullMessage, user);
+            }
+        }
+
+        public static void Entity(this ILogger logger, BaseEntity entity, LogEntityActivity activity, Core.Domain.User.User user = null)
+        {
+            if (entity == null)
+                return;
+
+            var header = String.Empty;
+            var body = String.Empty;
+
+            switch (activity)
+            {
+                case LogEntityActivity.Insert:
+                    header = String.Format("Entität \"{0}\" wurde hinzugefügt", entity.GetType().Name);
+                    break;
+                case LogEntityActivity.Update:
+                    header = String.Format("Entität \"{0}\" mit der ID \"{1}\" wurde geändert", entity.GetType().Name, entity.Id);
+                    break;
+                case LogEntityActivity.Delete:
+                    header = String.Format("Entität \"{0}\" mit der ID \"{1}\" wurde gelöscht", entity.GetType().Name, entity.Id);
+                    break;
+            }
+
+            if (activity == LogEntityActivity.Delete)
+                logger.InsertLog(LogLevel.Information, header, entity, String.Empty, user);
+            else
+            {
+                var properties = entity.GetType().GetProperties(System.Reflection.BindingFlags.GetProperty);
+
+                foreach (var property in properties)
+                {
+                    if (!property.PropertyType.Namespace.StartsWith("System")) continue;
+
+                    if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string))
+                    {
+                        var collection = property.GetValue(entity, null) as IEnumerable;
+
+                        body += String.Format("\t{0} = {1}\n", property.Name, String.Join(", ", collection));
+                    }
+                    else
+                        body += String.Format("\t{0} = {1}\n", property.Name, property.GetValue(entity));
+                }
+
+                var fullMessage = String.Format("{0}:\n{1}", header, body);
+
+                logger.InsertLog(LogLevel.Information, header, entity, String.Empty, user);
+            }
+        }
+    }
+}

+ 3 - 1
GreenTree.Nachtragsmanagement.Web.Framework/ApplicationContext.cs

@@ -26,6 +26,7 @@ using GreenTree.Nachtragsmanagement.Web.Framework.Mvc.Routes;
 using System.Web.Routing;
 using System.Web.Routing;
 using GreenTree.Nachtragsmanagement.Core.Authentication;
 using GreenTree.Nachtragsmanagement.Core.Authentication;
 using GreenTree.Nachtragsmanagement.Services.Appendix;
 using GreenTree.Nachtragsmanagement.Services.Appendix;
+using GreenTree.Nachtragsmanagement.Services.Logging;
 
 
 namespace GreenTree.Nachtragsmanagement.Web.Framework
 namespace GreenTree.Nachtragsmanagement.Web.Framework
 {
 {
@@ -106,14 +107,15 @@ namespace GreenTree.Nachtragsmanagement.Web.Framework
             builder.RegisterType<DbRelationService>().As<IDbRelationService>();
             builder.RegisterType<DbRelationService>().As<IDbRelationService>();
             builder.RegisterType<UserService>().As<IUserService>();
             builder.RegisterType<UserService>().As<IUserService>();
             builder.RegisterType<UserHelper>().As<IUserHelper>();
             builder.RegisterType<UserHelper>().As<IUserHelper>();
+            builder.RegisterType<WebHelper>().As<IWebHelper>();
             builder.RegisterType<AuthenticationService>().As<IAuthenticationService>();
             builder.RegisterType<AuthenticationService>().As<IAuthenticationService>();
             builder.RegisterType<SiteService>().As<ISiteService>();
             builder.RegisterType<SiteService>().As<ISiteService>();
             builder.RegisterType<DeviationService>().As<IDeviationService>();
             builder.RegisterType<DeviationService>().As<IDeviationService>();
             builder.RegisterType<AppendixService>().As<IAppendixService>();
             builder.RegisterType<AppendixService>().As<IAppendixService>();
             builder.RegisterType<MiscService>().As<IMiscService>();
             builder.RegisterType<MiscService>().As<IMiscService>();
+            builder.RegisterType<DefaultLogger>().As<ILogger>();
             builder.RegisterType<NotificationService>().As<INotificationService>();
             builder.RegisterType<NotificationService>().As<INotificationService>();
             builder.RegisterType<PluginFinder>().As<IPluginFinder>();
             builder.RegisterType<PluginFinder>().As<IPluginFinder>();
-            builder.RegisterType<WebHelper>().As<IWebHelper>();
             builder.RegisterType<WebAppTypeFinder>().As<ITypeFinder>();
             builder.RegisterType<WebAppTypeFinder>().As<ITypeFinder>();
             builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
             builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
 
 

+ 13 - 1
GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs

@@ -1,7 +1,9 @@
 using DevExpress.Web.Mvc;
 using DevExpress.Web.Mvc;
 using GreenTree.Nachtragsmanagement.Core;
 using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Authentication;
 using GreenTree.Nachtragsmanagement.Services.Appendix;
 using GreenTree.Nachtragsmanagement.Services.Appendix;
 using GreenTree.Nachtragsmanagement.Services.Deviation;
 using GreenTree.Nachtragsmanagement.Services.Deviation;
+using GreenTree.Nachtragsmanagement.Services.Logging;
 using GreenTree.Nachtragsmanagement.Services.Site;
 using GreenTree.Nachtragsmanagement.Services.Site;
 using GreenTree.Nachtragsmanagement.Web.Framework.Authorization;
 using GreenTree.Nachtragsmanagement.Web.Framework.Authorization;
 using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
 using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
@@ -21,15 +23,21 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         private readonly IDeviationService _deviationSerivce;
         private readonly IDeviationService _deviationSerivce;
         private readonly IAppendixService _appendixService;
         private readonly IAppendixService _appendixService;
         private readonly ISiteService _siteService;
         private readonly ISiteService _siteService;
+        private readonly IUserHelper _userHelper;
+        private readonly ILogger _logger;
 
 
         public AppendixController(
         public AppendixController(
             IDeviationService deviationService,
             IDeviationService deviationService,
             IAppendixService appendixService,
             IAppendixService appendixService,
-            ISiteService siteService)
+            ISiteService siteService,
+            IUserHelper userHelper,
+            ILogger logger)
         {
         {
             _deviationSerivce = deviationService;
             _deviationSerivce = deviationService;
             _appendixService = appendixService;
             _appendixService = appendixService;
             _siteService = siteService;
             _siteService = siteService;
+            _userHelper = userHelper;
+            _logger = logger;
 
 
             ViewData["AllCategories"] = _appendixService.GetAllCategories();
             ViewData["AllCategories"] = _appendixService.GetAllCategories();
             ViewData["AllStates"] = _appendixService.GetAllStates();
             ViewData["AllStates"] = _appendixService.GetAllStates();
@@ -200,6 +208,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 appendix.SetCategoryValues(categoryValues);
                 appendix.SetCategoryValues(categoryValues);
 
 
                 _appendixService.InsertAppendix(appendix);
                 _appendixService.InsertAppendix(appendix);
+
+                _logger.Entity(appendix, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookies());
             }
             }
             else
             else
             {
             {
@@ -223,6 +233,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 appendix.SetCategoryValues(categoryValues);
                 appendix.SetCategoryValues(categoryValues);
 
 
                 _appendixService.UpdateAppendix(appendix);
                 _appendixService.UpdateAppendix(appendix);
+
+                _logger.Entity(appendix, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookies());
             }
             }
 
 
             return new JsonResult
             return new JsonResult