我的NopCommerce之旅(4): 定时任务之邮件

一、功能简介

用户购买物品生成订单后,系统将发送邮件提醒给用户

二、操作步骤

  1. 后台配置一个系统的默认发送邮箱
  2. 启动定时任务,这里包括多个任务,只需要启动邮件任务
  3. 查看邮件发送情况

三、数据库分析

  1. [dbo].[Log] 系统日志表,可查看邮件发送失败的异常信息
  2. [dbo].[EmailAccount] 系统发送邮件配置表
  3. [dbo].[QueuedEmail] 订单邮件序列表,[SentTries]为重试次数,默认尝试3次失败后不再发送。
  4. [dbo].[ScheduleTask] 定时任务信息表,存储定时任务信息。

四、源码解析

  1. 根据MVC命名规则,可定位到Nop.Admin.Controllers命名空间,
  2. 查看ScheduleTaskControllerRunNow方法,可跟踪查看到任务调用机制。
    1. 通过反射类型,采用autofac实例化对象,然后执行。
    2. 任务实现Nop.Services.Tasks.ITask接口的Execute()方法,如Nop.Services.Messages.QueuedMessagesSendTask。
 1         private ITask CreateTask(ILifetimeScope scope)
 2         {
 3             ITask task = null;
 4             if (this.Enabled)
 5             {
 6                 var type2 = System.Type.GetType(this.Type);
 7                 if (type2 != null)
 8                 {
 9                     object instance;
10                     if (!EngineContext.Current.ContainerManager.TryResolve(type2, scope, out instance))
11                     {
12                         //not resolved
13                         instance = EngineContext.Current.ContainerManager.ResolveUnregistered(type2, scope);
14                     }
15                     task = instance as ITask;
16                 }
17             }
18             return task;
19         }
 1         /// <summary>
 2         /// Executes the task
 3         /// </summary>
 4         /// <param name="throwException">A value indicating whether exception should be thrown if some error happens</param>
 5         /// <param name="dispose">A value indicating whether all instances should be disposed after task run</param>
 6         /// <param name="ensureRunOnOneWebFarmInstance">A value indicating whether we should ensure this task is run on one farm node at a time</param>
 7         public void Execute(bool throwException = false, bool dispose = true, bool ensureRunOnOneWebFarmInstance = true)
 8         {
 9             ...
10                 //initialize and execute 初始化成功后执行任务
11                 var task = this.CreateTask(scope);
12                 if (task != null)
13                 {
14                     this.LastStartUtc = DateTime.UtcNow;
15                     if (scheduleTask != null)
16                     {
17                         //update appropriate datetime properties
18                         scheduleTask.LastStartUtc = this.LastStartUtc;
19                         scheduleTaskService.UpdateTask(scheduleTask);
20                     }
21                     task.Execute();
22                     this.LastEndUtc = this.LastSuccessUtc = DateTime.UtcNow;
23                 }
24             }
25             catch (Exception exc)
26             {
27                 this.Enabled = !this.StopOnError;
28                 this.LastEndUtc = DateTime.UtcNow;
29 
30                 //log error
31                 var logger = EngineContext.Current.ContainerManager.Resolve<ILogger>("", scope);
32                 logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this.Name, exc.Message), exc);
33                 if (throwException)
34                     throw;
35             }
36 
37             if (scheduleTask != null)
38             {
39                 //update appropriate datetime properties
40                 scheduleTask.LastEndUtc = this.LastEndUtc;
41                 scheduleTask.LastSuccessUtc = this.LastSuccessUtc;
42                 scheduleTaskService.UpdateTask(scheduleTask);
43             }
44 
45             //dispose all resources
46             if (dispose)
47             {
48                 scope.Dispose();
49             }
50         }

 

五、技术解析

  1. Autofac的依赖注入
  2. 反射
posted @ 2016-03-30 15:11  闲音  阅读(1570)  评论(0编辑  收藏  举报