C# 使用MVC和lo4net记录发生异常,并显示自定义错误页面

  使用日志组件log4net记录异常日志

到达效果:

在控制器层自动捕获错误,并把错误保存到数据库,之后显示希望用户看到的错误页面

1 首先安装log4net

(1)“程序包管理器控制台”用命令安装:先要打开控制台,在“工具”“NuGet程序包管理器”“程序包管理器控制台”这样就可以打开程序包管理器控制台。

(2)也可以在项目中添加对log4net.dll的引用

2   配置日志文件

1 。

 如果是CS程序,则在默认的App.config文件(没有新建一个)中添加内容;如果是BS程序,则添加到Web.config文件中

<section name="log4net"

type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

  </configSections>
<log4net>
</log4net>

再按照以下添加文件方式配置

2 添加日志的配置文件Log4net.xml,再从后面通过Log4netHelper帮助类实例化

日志类型

Appenders

Appenders用来定义日志的输出方式,

经常使用的输出方式有:

AdoNetAppender 将日志记录到数据库中。可以采用SQL和存储过程两种方式。

FileAppender 将日志输出到文件。

 代码如下:

  <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
  </appender>

定义日志的类型

可以按照本地文件的日志记录,比如

<log4net>
  <!--错误日志类-->
  <logger name="logerror"><!--日志类的名字-->
    <level value="ALL" /><!--定义记录的日志级别-->
    <appender-ref ref="ErrorAppender" /><!--记录到哪个介质中去-->
  </logger>
  <!--信息日志类-->
  <logger name="loginfo">
    <level value="ALL" />
    <appender-ref ref="InfoAppender" />
  </logger>
  <!--错误日志附加介质-->
  <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"><!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
    <param name="File" value="Log\\LogError\\" /><!--日志输出到exe程序这个相对目录下-->
    <param name="AppendToFile" value="true" /><!--输出的日志不会覆盖以前的信息-->
    <param name="MaxSizeRollBackups" value="100" /><!--备份文件的个数-->
    <param name="MaxFileSize" value="10240" /><!--当个日志文件的最大大小-->
    <param name="StaticLogFileName" value="false" /><!--是否使用静态文件名-->
    <param name="DatePattern" value="yyyyMMdd&quot;.htm&quot;" /><!--日志文件名-->
    <param name="RollingStyle" value="Date" /><!--文件创建的方式,这里是以Date方式创建-->
    <!--错误日志布局-->
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="&lt;HR COLOR=red&gt;%n异常时间:%d [%t] &lt;BR&gt;%n异常级别:%-5p &lt;BR&gt;%n异 常 类:%c [%x] &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
    </layout>
  </appender>
  <!--信息日志附加介质-->
  <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
    <param name="File" value="Log\\LogInfo\\" />
    <param name="AppendToFile" value="true" />
    <param name="MaxFileSize" value="10240" />
    <param name="MaxSizeRollBackups" value="100" />
    <param name="StaticLogFileName" value="false" />
    <param name="DatePattern" value="yyyyMMdd&quot;.htm&quot;" />
    <param name="RollingStyle" value="Date" />
    <!--信息日志布局-->
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="&lt;HR COLOR=blue&gt;%n日志时间:%d [%t] &lt;BR&gt;%n日志级别:%-5p &lt;BR&gt;%n日 志 类:%c [%x] &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
    </layout>
  </appender>
</log4net>

 使用C#代码初始化lo4net

  log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Server.MapPath("~/Web.config")));

3,而我使用的是数据库的方式,文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>

  <logger name="WebExceptionLog">
    <level value="ALL" />
    <appender-ref ref="AdoNetAppender" />
  </logger>

  <logger name="ServiceExceptionLog">
    <level value="ALL" />
    <appender-ref ref="AdoNetAppender" />
  </logger>

  <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
    <bufferSize value="1" />
    <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <connectionString value="{connectionString}" />
    <commandText value="INSERT INTO [Log4Net] ([Date],[Host],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @host, @thread, @log_level, @logger, @message, @exception)" />
    <parameter>
      <parameterName value="@log_date" />
      <dbType value="DateTime" />
      <layout type="log4net.Layout.RawTimeStampLayout" />
    </parameter>
    <parameter>
      <parameterName value="@thread" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%thread" />
      </layout>
    </parameter>

    <parameter>
      <parameterName value="@host" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%property{log4net:HostName}" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@log_level" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@logger" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@message" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%message" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@exception" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.ExceptionLayout" />
    </parameter>
  </appender>

</log4net>

4 添加本地配置文件读取类,通过这个公共类很方便读取本地配置XML文件

 public class ConfigContext
    {
        public IConfigService ConfigService { get; set; }

        /// <summary>
        /// 默认以文件形式存取配置
        /// </summary>
        public ConfigContext() : this(new FileConfigService())
        {
        }
        
        public ConfigContext(IConfigService pageContentConfigService)
        {
            this.ConfigService = pageContentConfigService;
        }

        public virtual T Get<T>(string index = null) where T : ConfigFileBase, new()
        {
            var result = new T();
            this.VilidateClusteredByIndex(result, index);
            result = this.GetConfigFile<T>(index);

            return result;
        }

        public void Save<T>(T configFile, string index = null) where T : ConfigFileBase
        {
            this.VilidateClusteredByIndex(configFile, index);

            configFile.Save();

            var fileName = this.GetConfigFileName<T>(index);
            this.ConfigService.SaveConfig(fileName, SerializationHelper.XmlSerialize(configFile));
        }

        private T GetConfigFile<T>(string index = null) where T : ConfigFileBase, new()
        {
            var result = new T();

            var fileName = this.GetConfigFileName<T>(index);
            var content = this.ConfigService.GetConfig(fileName);
            if (content == null)
            {
                this.ConfigService.SaveConfig(fileName, string.Empty);
            }
            else if (!string.IsNullOrEmpty(content))
            {
                try
                {
                    result = (T)SerializationHelper.XmlDeserialize(typeof(T), content);
                }
                catch
                {
                    result = new T();
                }
            }

            return result;
        }

        public virtual void VilidateClusteredByIndex<T>(T configFile, string index) where T : ConfigFileBase
        {
            //if (configFile.ClusteredByIndex && string.IsNullOrEmpty(index))
            //    throw new Exception("调用时没有提供配置文件的分区索引");
        }

        public virtual string GetConfigFileName<T>(string index = null)
        {
            var fileName = typeof(T).Name;
            if (!string.IsNullOrEmpty(index))
                fileName = string.Format("{0}_{1}", fileName, index);
            return fileName;
        }
    }

添加log.xml

<?xml version="1.0" encoding="utf-16"?>
  <Log xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Log>Data Source=Data Source;Initial Catalog=Catalog;uid=uid;pwd=pwd;MAX Pool Size=512;Min Pool Size=50;Connection Lifetime=30</Log>
 
  </Log>

5.添加Log4netHelper类实列化配置文件

    public static class Log4NetHelper
    {
        static Log4NetHelper()
        {
            //初始化log4net配置
            var config = CachedConfigContext.Current.ConfigService.GetConfig("log4net");
            //重写log4net配置里的连接字符串
            config = config.Replace("{connectionString}", CachedConfigContext.Current.Log);
            var ms = new MemoryStream(Encoding.Default.GetBytes(config));
            log4net.Config.XmlConfigurator.Configure(ms);
        }

        public static void Debug(LoggerType loggerType, object message, Exception e)
        {
            var logger = LogManager.GetLogger(loggerType.ToString());
            logger.Debug(SerializeObject(message), e);
        }

        public static void Error(LoggerType loggerType, object message, Exception e)
        {
            var logger = LogManager.GetLogger(loggerType.ToString());
            logger.Error(SerializeObject(message), e);
        }

        public static void Info(LoggerType loggerType, object message, Exception e)
        {
            var logger = LogManager.GetLogger(loggerType.ToString());
            logger.Info(SerializeObject(message), e);
        }

        public static void Fatal(LoggerType loggerType, object message, Exception e)
        {
            var logger = LogManager.GetLogger(loggerType.ToString());
            logger.Fatal(SerializeObject(message), e);
        }

        public static void Warn(LoggerType loggerType, object message, Exception e)
        {
            var logger = LogManager.GetLogger(loggerType.ToString());
            logger.Warn(SerializeObject(message), e);
        }

        private static object SerializeObject(object message)
        {
            if (message is string || message == null)
                return message;
            else
                return JsonConvert.SerializeObject(message, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
        }
    }

    public enum LoggerType
    {
        WebExceptionLog,
        ServiceExceptionLog
    }

6写一个所有controllb继承的controllbase父类,所有访问的controller发生的异常在这里处理并记录

    public class ControllerBase : Controller
    {
        /// <summary>
        /// 发生异常写Log
        /// </summary>
        /// <param name="filterContext"></param>
          protected override void OnException(ExceptionContext filterContext)
        {
            base.OnException(filterContext);
            var e = filterContext.Exception;

            var str = "错误记录";
            Log4NetHelper.Error(LoggerType.WebExceptionLog, str, e);
        }
    }

7、在WebConfig中把过滤器配置启动

 <customErrors mode="On">
    </customErrors>

8控制器的代码报错时,会跳转到~/Views/Shared/Error.cshtml页面。mode="Off"页面不会跳转直接显示错误信息。

9绑定异常过滤器(过滤范围是在controller的action方法中。)

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
   }

猜你喜欢

转载自blog.csdn.net/qq_25744257/article/details/81122148