1.项目概述
这是一个基于 C# 的 WPF 项目 WpfApp12log4net
,它综合运用了依赖注入、日志记录和接口实现等多种技术,同时使用了 Autofac
、Castle.Core
和 log4net
等第三方库。
2.配置log4net
新建一个Log4Net.config,配置需要记录的日志信息,主要该文件在编译后要生成到debug或者release文件夹下。
配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!--错误日志类-->
<logger name="logerror">
<!--日志类的名字-->
<level value="ALL" />
<!--定义记录的日志级别-->
<appender-ref ref="ErrorAppender" />
<!--记录到哪个介质中去-->
</logger>
<!--信息日志类-->
<logger name="loginfo">
<level value="ALL" />
<appender-ref ref="InfoAppender" />
</logger>
<!--MES日志类-->
<logger name="Mesinfo">
<level value="ALL" />
<appender-ref ref="MesAppender" />
</logger>
<!--错误日志附加介质-->
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
<!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
<param name="File" value="Log\\LogError2\\" />
<!--日志输出到exe程序这个相对目录下-->
<param name="AppendToFile" value="true" />
<!--输出的日志不会覆盖以前的信息-->
<param name="MaxSizeRollBackups" value="100" />
<!--备份文件的个数-->
<param name="MaxFileSize" value="1024" />
<!--当个日志文件的最大大小-->
<param name="StaticLogFileName" value="false" />
<!--是否使用静态文件名-->
<param name="DatePattern" value="yyyyMMdd".txt"" />
<!--日志文件名-->
<param name="RollingStyle" value="Date" />
<!--文件创建的方式,这里是以Date方式创建-->
<!--错误日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%n异常时间:%d [%t] %n异常级别:%-5p %n异 常 类:%c [%x] %n%m %n " />
</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".txt"" />
<param name="RollingStyle" value="Date" />
<!--信息日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="[时间] %d [%t] [信息] %m%n" />
</layout>
</appender>
<!--信息日志附加介质-->
<appender name="MesAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\MesInfo\\"/>
<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".txt"" />
<param name="RollingStyle" value="Date" />
<!--信息日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="[时间] %d [%t] [信息] %m%n" />
</layout>
</appender>
</log4net>
3.加载配置文件
要在代码启动的时候加载,以下是涉及到其他配置,所以是动态路径的案例。
string configFilePath = "Log4Net.config";
var fileInfo = new FileInfo(configFilePath);
if (!fileInfo.Exists)
{
throw new FileNotFoundException($"配置文件 {configFilePath} 不存在!");
}
XmlConfigurator.Configure(fileInfo);
string path = @"C:\\Log4NetTestFile\\";
string[] fileName = { "InfoAppender", "ErrorAppender", "MesAppender" };
ILoggerRepository repository = LogManager.GetRepository(Assembly.GetEntryAssembly());
for (int i = 0; i < fileName.Length; i++)
{
log4net.Appender.RollingFileAppender appender = repository.GetAppenders().OfType<log4net.Appender.RollingFileAppender>().FirstOrDefault(a => a.Name == fileName[i]);
if (appender != null)
{
appender.File = path + fileName[i] + "\\";
appender.ActivateOptions();
}
}
4.搭建日志方法类LogHelp
日志存储的方法写在里面。
using log4net;
using log4net.Config;
using System;
using System.IO;
namespace WpfApp12log4net
{
public class LogHelp
{
private readonly ILog log_info = LogManager.GetLogger("loginfo");
private readonly ILog log_error = LogManager.GetLogger("logerror");
private readonly ILog mes_info = LogManager.GetLogger("Mesinfo");
public void Info(string info)
{
if (log_info.IsInfoEnabled)
{
log_info.Info(info);
}
}
public void mesinfo(string info)
{
if (mes_info.IsInfoEnabled)
{
mes_info.Info(info);
}
}
public void Error(string error, Exception ex)
{
if (log_error.IsErrorEnabled)
{
log_error.Error(error, ex);
}
}
public void Error(string error)
{
if (log_error.IsErrorEnabled)
{
log_error.Error(error);
}
}
}
}
4.拦截器搭建LoggingInterceptor
using Castle.DynamicProxy;
using log4net;
using System;
using System.Reflection;
namespace WpfApp12log4net
{
public class LoggingInterceptor : IInterceptor
{
private readonly LogHelp logHelp;
public LoggingInterceptor(LogHelp logHelp)
{
this.logHelp = logHelp;
}
public void Intercept(IInvocation invocation)
{
try
{
logHelp.Info($"开始执行方法: {invocation.Method.Name}");
logHelp.Info($"参数: {string.Join(", ", invocation.Arguments)}");
// 执行方法并获取返回值
invocation.Proceed();
object result = invocation.ReturnValue;
// 记录返回值(如果方法不是 void)s
if (invocation.Method.ReturnType != typeof(void))
{
logHelp.Info($"方法 {invocation.Method.Name} 返回值: {result ?? "null"}");
}
logHelp.Info($"方法 {invocation.Method.Name} 执行完毕");
}
catch (Exception ex)
{
// 记录完整的异常信息(包括堆栈跟踪)
logHelp.Error($"方法 {invocation.Method.Name} 执行出错: {ex.ToString()}", ex);
throw; // 重新抛出异常,确保调用方能够捕获
}
}
}
}
5.创建服务类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApp12log4net
{
public class Service : IService
{
public string methodservice11(string ttt)
{
try
{
string[] str = null;
if (str[1] == "1")
{
// 此部分代码会触发异常
}
else
{
// 此部分代码会触发异常
}
}
catch (Exception ex)
{
//LogHelp.Error(ex.Message);
//LogHelp.Error("异常", ex);
}
return "这是参数返回........的内容";
}
public string methodservice12(string ttt)
{
try
{
//string[] str = null;
//if (str[1] == "1")
//{
// // 此部分代码会触发异常
//}
//else
//{
// // 此部分代码会触发异常
//}
}
catch (Exception ex)
{
//LogHelp.Error(ex.Message);
//LogHelp.Error("异常", ex);
}
return "这是参数返回........的内容";
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApp12log4net
{
public class Service2 : IService2
{
public string methodservice21(string ttt)
{
try
{
string[] str = null;
if (str[1] == "1")
{
// 此部分代码会触发异常
}
else
{
// 此部分代码会触发异常
}
}
catch (Exception ex)
{
//LogHelp.Error(ex.Message);
//LogHelp.Error("异常", ex);
}
return "这是参数返回........的内容";
}
}
}
6.创建服务接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApp12log4net
{
public interface IService
{
string methodservice11(string ttt);
string methodservice12(string ttt);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApp12log4net
{
public interface IService2
{
string methodservice21(string ttt);
}
}
7.依赖注入
var builder = new ContainerBuilder();
var proxyGenerator = new ProxyGenerator();
// 先注册 LogHelp
builder.RegisterType<LogHelp>().AsSelf();
// 注册 LoggingInterceptor
builder.RegisterType<LoggingInterceptor>().AsSelf();
// 注册 IService 接口及其实现类 Service
builder.Register(c =>
{
var service = new Service();
var interceptor = c.Resolve<LoggingInterceptor>();
return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(IService), service, interceptor) as IService;
}).As<IService>();
// 注册 IService2 接口及其实现类 Service2
builder.Register(c =>
{
var service = new Service2();
var interceptor = c.Resolve<LoggingInterceptor>();
return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(IService2), service, interceptor) as IService2;
}).As<IService2>();
// 注册 MainWindow
builder.RegisterType<MainWindow>().AsSelf();
Container = builder.Build();
8.总结
1. 依赖注入(Dependency Injection,DI)
使用 Autofac
库实现依赖注入。通过 ContainerBuilder
构建容器,注册接口及其实现类(如 IService
与 Service
、IService2
与 Service2
)以及窗口类(MainWindow
)等,在程序运行时由容器负责创建对象并注入依赖关系,降低组件间耦合度。
2. 动态代理(Dynamic Proxy)
借助 Castle.DynamicProxy
库实现动态代理。定义了 LoggingInterceptor
类实现 IInterceptor
接口,在方法执行前后进行日志记录等操作。在注册服务时,利用 ProxyGenerator
创建代理对象,将拦截器应用到目标服务(Service
、Service2
)上,实现对服务方法调用的拦截和增强 。
3. 日志记录
运用 log4net
日志框架进行日志记录。通过配置文件(log4net.config
)设置不同类型日志(错误日志、信息日志、MES 日志 )的记录方式,包括日志级别、日志存储路径、文件滚动策略、日志格式等。在代码中通过 LogHelp
类封装的方法,在不同业务场景(方法执行、异常处理等 )下记录日志。
4. WPF(Windows Presentation Foundation)
这是一个 WPF 项目,使用 WPF 技术构建桌面应用程序界面。定义了 MainWindow
类继承自 Window
,实现窗口相关功能,如按钮点击事件处理等,利用 WPF 的特性来呈现用户界面和交互逻辑。