Nop源码分析三
上次卡壳在下面一句,由于有点累了,也没再研究,如下:
//Add some functionality on top of the default ModelMetadataProvider
ModelMetadataProviders.Current = new NopMetadataProvider();
翻译是 加上默认的ModelMetadataProvider的一些功能,我们看到就是设置元数据提供者为NopMetadataProvider.
而NopMetadataProvider是继承自DataAnnotationsModelMetadataProvider。关于DataAnnotationsModelMetadataProvider的详细内容可以参考http://www.cnblogs.com/artech/archive/2012/05/09/model-metadata-provision.html。
上面有是这样说的:通过前面的介绍我们知道Model元数据是通过定义在System.ComponentModel.DataAnnotations命名空间下的标注特性来定义的,Model元数据解析系统通过对应用在表示Model的数据类型及其属性成员的标注特性进行解析从而对创建的Model元数据进行对应的初始化,而这个工作是通过DataAnnotationsModelMetadataProvider来实现的。一下是一张类关系图:
很简单,ModelMetadataProviders通过Current获取和设置当前使用的ModelMetadataProvider,而真正用到的是DataAnnotationsModelMetadataProvider,他是一个子类,前面都是继承关系。
AssociatedMetadataProvider:它并紧紧是通过反射将应用在Model类型和对应属性上的所有特性,并将这个特性列表作为参数(attributes)传入抽象方法 CreateMetadata完成Model元数据的创建。值得一提的是,当通过调用CreateMetadata创建出ModelMetadata之后,会从特性列表中筛选出实现了IMetadataAware接口的特性,并将该ModelMetadata对象作为参数调用它们的 OnMetadataCreated方法。(它的CreateMetadata方法是抽象的)。
DataAnnotationsModelMetadataProvider 实现了这个方法。而NopMetadataProvider就是覆盖了这个方法,代码如下:
namespace Nop.Web.Framework.Mvc
{
/// <summary>
/// This MetadataProvider adds some functionality on top of the default DataAnnotationsModelMetadataProvider.
/// It adds custom attributes (implementing IModelAttribute) to the AdditionalValues property of the model's metadata
/// so that it can be retrieved later.
/// </summary>
public class NopMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var additionalValues = attributes.OfType<IModelAttribute>().ToList();
foreach (var additionalValue in additionalValues)
{
if (metadata.AdditionalValues.ContainsKey(additionalValue.Name))
throw new NopException("There is already an attribute with the name of \"" + additionalValue.Name +
"\" on this model.");
metadata.AdditionalValues.Add(additionalValue.Name, additionalValue);
}
return metadata;
}
}
}
开始是调用父类的方法,然后通过所有的属性获得继承自IModelAttribute的属性集合,并把他添加到元数据的附加值集合中。
AdditionalValues 参考:http://www.cnblogs.com/artech/archive/2012/04/11/2441696.html,最后竟然才提到一点,后面也没怎么提 只是提了附加属性。
本端代码大概意思是: 遍历所有类型为IModelAttribute的属性,并添加他们为元数据的附加属性,以后可以取回这些值。IModelAttribute是很简单的类,如下:
namespace Nop.Web.Framework.Mvc
{
public interface IModelAttribute
{
string Name { get; }
}
}
注册一些正规的MVC东西。
//Registering some regular mvc stuff
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
下面2句就是fluent validation的设置。 可以参考http://jishu.admin5.com/biancheng/141202/4224.html、http://www.cnblogs.com/libingql/p/3801704.html、http://www.cnblogs.com/artech/archive/2012/06/08/data-annotations-model-validation-03.html,我是没怎么深入,因为目前不需要。
//fluent validation
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new NopValidatorFactory()));
后面的都是第一次不执行,以后都执行。
//start scheduled tasks
if (databaseInstalled)
{
TaskManager.Instance.Initialize();
TaskManager.Instance.Start();
}
下面是TaskManager的代码:
namespace Nop.Services.Tasks
{
/// <summary>
/// Represents task manager
/// </summary>
public partial class TaskManager
{
private static readonly TaskManager _taskManager = new TaskManager();
private readonly List<TaskThread> _taskThreads = new List<TaskThread>();
private int _notRunTasksInterval = 60 * 30; //30 minutes
private TaskManager()
{
}
/// <summary>
/// Initializes the task manager with the property values specified in the configuration file.
/// </summary>
public void Initialize()
{
this._taskThreads.Clear();
var taskService = EngineContext.Current.Resolve<IScheduleTaskService>();
var scheduleTasks = taskService
.GetAllTasks()
.OrderBy(x => x.Seconds)
.ToList();
//group by threads with the same seconds
foreach (var scheduleTaskGrouped in scheduleTasks.GroupBy(x => x.Seconds))
{
//create a thread
var taskThread = new TaskThread
{
Seconds = scheduleTaskGrouped.Key
};
foreach (var scheduleTask in scheduleTaskGrouped)
{
var task = new Task(scheduleTask);
taskThread.AddTask(task);
}
this._taskThreads.Add(taskThread);
}
//sometimes a task period could be set to several hours (or even days).
//in this case a probability that it'll be run is quite small (an application could be restarted)
//we should manually run the tasks which weren't run for a long time
var notRunTasks = scheduleTasks
.Where(x => x.Seconds >= _notRunTasksInterval)
.Where(x => !x.LastStartUtc.HasValue || x.LastStartUtc.Value.AddSeconds(_notRunTasksInterval) < DateTime.UtcNow)
.ToList();
//create a thread for the tasks which weren't run for a long time
if (notRunTasks.Count > 0)
{
var taskThread = new TaskThread
{
RunOnlyOnce = true,
Seconds = 60 * 5 //let's run such tasks in 5 minutes after application start
};
foreach (var scheduleTask in notRunTasks)
{
var task = new Task(scheduleTask);
taskThread.AddTask(task);
}
this._taskThreads.Add(taskThread);
}
}
/// <summary>
/// Starts the task manager
/// </summary>
public void Start()
{
foreach (var taskThread in this._taskThreads)
{
taskThread.InitTimer();
}
}
/// <summary>
/// Stops the task manager
/// </summary>
public void Stop()
{
foreach (var taskThread in this._taskThreads)
{
taskThread.Dispose();
}
}
/// <summary>
/// Gets the task mamanger instance
/// </summary>
public static TaskManager Instance
{
get
{
return _taskManager;
}
}
/// <summary>
/// Gets a list of task threads of this task manager
/// </summary>
public IList<TaskThread> TaskThreads
{
get
{
return new ReadOnlyCollection<TaskThread>(this._taskThreads);
}
}
}
}
TaskManager.Instance 就是他自己的一个静态只读对象,通过代码可知:
private static readonly TaskManager _taskManager = new TaskManager();
.
.
public static TaskManager Instance
{
get
{
return _taskManager;
}
}
我们看它的Initialize方法:
/// <summary>
/// Initializes the task manager with the property values specified in the configuration file.
/// </summary>
public void Initialize()
{
this._taskThreads.Clear();
var taskService = EngineContext.Current.Resolve<IScheduleTaskService>();
var scheduleTasks = taskService
.GetAllTasks()
.OrderBy(x => x.Seconds)
.ToList();
//group by threads with the same seconds
foreach (var scheduleTaskGrouped in scheduleTasks.GroupBy(x => x.Seconds))
{
//create a thread
var taskThread = new TaskThread
{
Seconds = scheduleTaskGrouped.Key
};
foreach (var scheduleTask in scheduleTaskGrouped)
{
var task = new Task(scheduleTask);
taskThread.AddTask(task);
}
this._taskThreads.Add(taskThread);
}
//sometimes a task period could be set to several hours (or even days).
//in this case a probability that it'll be run is quite small (an application could be restarted)
//we should manually run the tasks which weren't run for a long time
var notRunTasks = scheduleTasks
.Where(x => x.Seconds >= _notRunTasksInterval)
.Where(x => !x.LastStartUtc.HasValue || x.LastStartUtc.Value.AddSeconds(_notRunTasksInterval) < DateTime.UtcNow)
.ToList();
//create a thread for the tasks which weren't run for a long time
if (notRunTasks.Count > 0)
{
var taskThread = new TaskThread
{
RunOnlyOnce = true,
Seconds = 60 * 5 //let's run such tasks in 5 minutes after application start
};
foreach (var scheduleTask in notRunTasks)
{
var task = new Task(scheduleTask);
taskThread.AddTask(task);
}
this._taskThreads.Add(taskThread);
}
}
this._taskThreads.Clear(); 清除list所有项。taskThreads是:
private readonly List<TaskThread> _taskThreads = new List<TaskThread>();
今天研究的不多,这个任务系统也需要深入研究啊,明天再说吧,不想搞了,搞点别的。

浙公网安备 33010602011771号