zoukankan      html  css  js  c++  java
  • 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来实现的。一下是一张类关系图:

    http://images.cnblogs.com/cnblogs_com/artech/201205/20120509075211275.png很简单,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.htmlhttp://www.cnblogs.com/libingql/p/3801704.htmlhttp://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>();

    今天研究的不多,这个任务系统也需要深入研究啊,明天再说吧,不想搞了,搞点别的。

  • 相关阅读:
    解决php中Cannot send session cache limiter 的问题的方法 (转载)
    手机网页学习(转载)
    在PC上测试移动端网站和模拟手机浏览器的5大方法 (转载)
    php 中使用json(转载)
    String.format("%0"+length+"d", long)说明
    php查询一条数据 while少一条查询数据不显示
    mysql数据安装(装载)
    mysql File '/var/lib/mysql/txtdata/yz2014_1.txt' not found (Errcode: 13 "Permission denied")
    VS2015+Qt新建项目后出现红波浪线
    VS2015报错:无法打开头文件"windows.h"
  • 原文地址:https://www.cnblogs.com/runit/p/4169556.html
Copyright © 2011-2022 走看看