上次卡壳在下面一句,由于有点累了,也没再研究,如下:
//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>();
今天研究的不多,这个任务系统也需要深入研究啊,明天再说吧,不想搞了,搞点别的。