Quartz.net 2.x 学习笔记02-Quartz.net 2.x在MVC站点中结合Log4net的使用
Quartz.net 2.x在MVC站点中结合Log4net的使用
首先新建一个MVC的空站点:
第二步,添加Quartz.net的引用
在搜索处输入quartz.net搜索安装即可(目前是2.3)
从上图可以看到它有个依赖项Common.Logging,安装时会自动将Common.Logging也安装上
同时安装上Common.Logging.Log4net(我这里选择的是新的Common.Logging.Log4Net1213)
同Quartz.net的安装,你会发现Common.Logging.Log4Net1213会依赖Log4Net,所以Log4Net也将会被自动安装上
之所以上面这样用是因为Common.Logging是一个日志容器,假如以后你不想用Log4Net记录日志,改用NLog或者其它的日志记录组件,会很方便,只需更改配置,代码不会变
现在先把配置文件准备好,打开站点的Web.Config文件做好如下配置
<configSections> <!--配置Common.Logging节点--> <sectionGroup name="common"> <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /> </sectionGroup> <!--Log4net--> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <common> <logging> <!--1.此Adapter只输出到控制台,如果是用的控制台,用这个输出--> <!-- <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging"> <arg key="level" value="INFO" /> <arg key="showLogName" value="true" /> <arg key="showDataTime" value="true" /> <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" /> </factoryAdapter>--> <!--2.此Adapter只输出到Log4.net的配置文件所指定的地方--> <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net1213"> <!--FILE,FILE-WATCH,INLINE,EXTERNAL--> <arg key="configType" value="FILE" /> <arg key="configFile" value="~/log4net.config" /> <!-- 指定log4net的配置文件名称 --> <arg key="level" value="Warn" /> </factoryAdapter> </logging> </common>
此配置在Configuration节点下,当然里面使用的是Log4Net记录日志,将log4net.config文件放到应用程序中。
log4net.config配置文件信息:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <appSettings> </appSettings> <log4net> <!--定义输出到文件中--> <appender name="JobLogAppender" type="log4net.Appender.RollingFileAppender"> <!--输出日志文件的路径--> <file value="Log\XXLog.log" /> <!--输出日志时自动向后追加--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全,但实际使用时,本地测试正常,部署后有不能写日志的情况--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="false" /> <!--日志以大小作为备份样式,还有一种方式是Date(日期)--> <rollingStyle value="size" /> <countDirection value="-1" /> <!--单个日志的最大容量,(可用的单位:KB|MB|GB)不要使用小数,否则会一直写入当前日志--> <maximumFileSize value="1MB" /> <!--日志最大个数,都是最新的--> <maxSizeRollBackups value="10" /> <datePattern value='"."yyyy-MM-dd".log"' /> <layout type="log4net.Layout.PatternLayout"> <!--每条日志末尾的文字说明--> <footer value="**************************************************************" /> <!--输出格式--> <!--样例:2008-03-26 13:42:32,111 [10] INFO Log4NetDemo.MainClass - info--> <conversionPattern value="%newline%d{yyyy/MM/dd,HH:mm:ss.fff},[%-5level]%newline Message:%message%newline" /> </layout> </appender> <root> <!--文件形式记录日志--> <appender-ref ref="JobLogAppender" /> </root> </log4net> </configuration>
做好准备工作后,现在写执行任务的代码:
在解决方案下新建一个JobLibrary类库,在类库中同上也用Nuget添加Quartz.net
新建一个基类(方便写日志)JobBase.cs
using Common.Logging; namespace JobLibrary { public class JobBase { /// <summary> /// JOB状态日志 /// </summary> protected internal static readonly ILog jobStatus = LogManager.GetLogger("JobLogAppender"); /// <summary> /// 服务错误日志 /// </summary> protected internal static readonly ILog serviceErrorLog = LogManager.GetLogger("JobLogAppender"); } }
代码中JobLogAppender的来源:
新建一个HelloJob.cs任务,该任务继承JobBase基类和IJob接口
using Quartz; namespace JobLibrary { public class HelloJob:JobBase,IJob { public void Execute(IJobExecutionContext context) { jobStatus.Info("-----------------------------------HelloJob开始执行----------------------------------"); try { MyExecMethod(); } catch (Exception ex) { serviceErrorLog.Info(string.Concat("HelloJob执行出错:", ex.StackTrace)); } jobStatus.Info("-----------------------------------HelloJob执行完成----------------------------------"); } public void MyExecMethod() { jobStatus.Info("我正在执行HelloJob的代码,此为测试,只是写日志"); } } }
为了方便对任务的操作(启动、添加、修改、删除等),再建一个JobManage.cs类
using Common.Logging; using Quartz; using Quartz.Impl; namespace JobLibrary { public class JobManage { private static ISchedulerFactory sf = new StdSchedulerFactory(); private static IScheduler Instance; static readonly ILog log = LogManager.GetLogger("JobLogAppender"); /// <summary> /// 开启定时任务 /// </summary> public static void Start() { try { Instance = sf.GetScheduler(); IJobDetail jobDetail = JobBuilder.Create<HelloJob>() .WithIdentity("HelloKey", "JobGroup") .Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("TriggerKey", "TriggerGroup") .ForJob(jobDetail.Key) .WithCronSchedule("/10 * * * * ?") //10秒钟执行一次 .Build(); //告诉Quartz 用trigger这个触发器去执行HelloJob Instance.ScheduleJob(jobDetail, trigger); //开始定时任务 Instance.Start(); } catch (Exception e) { log.Error(e.StackTrace); } } /// <summary> /// 关闭定时任务 /// </summary> public static void ShutDown() { if (Instance != null && !Instance.IsShutdown) { Instance.Shutdown(); } } } }
基础工作准备好了,现在做定时任务的辅助工作,
首先,MVC Web应用程序添加对JobLibrary类型的引用
为了使MVC Web应用程序的运行起来,添加一个HomeController
另外给HomeController的Index方法添加视图页面
接下来打开Global.asax,写入如下代码,让程序一启动就去执行定时任务:
using JobLibrary; namespace Quartz002 { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); //启动定时任务 JobManage.Start(); } protected void Application_End(object sender, EventArgs e) { //关闭定时任务 JobManage.ShutDown(); } } }
好了,代码已经完成,按F5运行应用程序
程序会报出如下错误信息:
以上错误信息的来源是因为我们用NuGet添加Common.Logging.Log4Net1213时自动添加的log4net的版本号和它本身需要的不一致造成的,
打开NuGet控制台,将log4net进行更新
输入命令:update-package log4net
再次按F5运行应用程序,会弹出正确的页面
现在打开应用程序的目录,找到Log文件夹,可以看到里面会有个日志文件XXLog.log
(这个文件名是配置在log4net.config中的)
查看定时任务的执行时间,执行间隔正是上面的HelloJob的执行周期,10秒钟执行一次
HelloJob只是一个Demo任务,使用Quartz.net还可以动态添加、暂停、删除、修改任务执行周期等操作
另外Quartz.net还可以做成服务端和客户端模式,客户端只负责对任务的管理