我的NopCommerce之旅(2): 定时任务之邮件
一、功能简介
用户购买物品生成订单后,系统将发送邮件提醒给用户
二、操作步骤
- 后台配置一个系统的默认发送邮箱
![]()
- 启动定时任务,这里包括多个任务,只需要启动邮件任务
![]()
- 查看邮件发送情况
![]()
三、数据库分析
- [dbo].[Log] 系统日志表,可查看邮件发送失败的异常信息
- [dbo].[EmailAccount] 系统发送邮件配置表
- [dbo].[QueuedEmail] 订单邮件序列表,[SentTries]为重试次数,默认尝试3次失败后不再发送。
- [dbo].[ScheduleTask] 定时任务信息表,存储定时任务信息。
四、源码解析
- 根据MVC命名规则,可定位到Nop.Admin.Controllers命名空间,
- 查看ScheduleTaskController的RunNow方法,可跟踪查看到任务调用机制。
- 通过反射类型,采用autofac实例化对象,然后执行。
- 任务实现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 }
五、技术解析
- Autofac的依赖注入
- 反射
我的NopCommerce之旅(5): 缓存
一、基础介绍
1.什么是cache
Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。
2.为什么要用cache
即cache的作用,有以下几点:
2.1.减少网络带宽消耗;
2.2.降低服务器压力;
2.3.减少网络延迟、加快页面打开速度。
3.cache的分类
常见分类如下:
3.1.数据库数据缓存;
3.2.服务器端缓存;
a.代理服务器缓存
b.CDN缓存
3.3.浏览器缓存;
3.4.Web应用缓存
二、NopCommerce的缓存分析
1.UML
接口ICacheManager;
实现MemoryCacheManager(HTTP请求缓存,生命周期长),NopNullCache(仅实现接口,不提供缓存机制),PerRequestCacheManager(HTTP请求缓存,生命周期短),RedisCacheManager(Redis缓存);
扩展CacheExtensions;
2.代码分析
2.1.Nop.Web.Framework.DependencyRegistrar类,配置依赖注入的ICacheManager。
1 //cache managers
2 if (config.RedisCachingEnabled)
3 {
4 builder.RegisterType<RedisCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").InstancePerLifetimeScope();
5 }
6 else
7 {
8 builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
9 }
2.2.RedisCachingEnabled通过读取配置文件,见Nop.Core.Configuration.NopConfig
1 var redisCachingNode = section.SelectSingleNode("RedisCaching");
2 if (redisCachingNode != null && redisCachingNode.Attributes != null)
3 {
4 var enabledAttribute = redisCachingNode.Attributes["Enabled"];
5 if (enabledAttribute != null)
6 config.RedisCachingEnabled = Convert.ToBoolean(enabledAttribute.Value);
7
8 var connectionStringAttribute = redisCachingNode.Attributes["ConnectionString"];
9 if (connectionStringAttribute != null)
10 config.RedisCachingConnectionString = connectionStringAttribute.Value;
11 }
3.应用
通过依赖注入,生成缓存管理类实例,通过方法读取、设置缓存。
[NonAction]
protected virtual List<int> GetChildCategoryIds(int parentCategoryId)
{
string cacheKey = string.Format(ModelCacheEventConsumer.CATEGORY_CHILD_IDENTIFIERS_MODEL_KEY,
parentCategoryId,
string.Join(",", _workContext.CurrentCustomer.GetCustomerRoleIds()),
_storeContext.CurrentStore.Id);
return _cacheManager.Get(cacheKey, () =>
{
var categoriesIds = new List<int>();
var categories = _categoryService.GetAllCategoriesByParentCategoryId(parentCategoryId);
foreach (var category in categories)
{
categoriesIds.Add(category.Id);
categoriesIds.AddRange(GetChildCategoryIds(category.Id));
}
return categoriesIds;
});
}




浙公网安备 33010602011771号