惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
S
Security @ Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
The Hacker News
The Hacker News
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
博客园 - 司徒正美
雷峰网
雷峰网
L
LINUX DO - 最新话题
博客园 - 叶小钗
云风的 BLOG
云风的 BLOG
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术
S
Security Affairs
有赞技术团队
有赞技术团队
月光博客
月光博客
T
Threatpost
T
Tor Project blog
O
OpenAI News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
Know Your Adversary
Know Your Adversary
Project Zero
Project Zero
博客园 - 三生石上(FineUI控件)
D
Docker
AWS News Blog
AWS News Blog
AI
AI
P
Proofpoint News Feed
K
Kaspersky official blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Securelist
F
Fortinet All Blogs
F
Full Disclosure
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Palo Alto Networks Blog
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
美团技术团队
N
News | PayPal Newsroom
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog

博客园 - 大西瓜3721

SVN分支/合并原理及最佳实践 Web.Config中Runtime节点-DLL版本冲突问题 工作问题 Vue资料 轻松实现WCF服务的构造函数依赖注入 WCF 依赖注入-- Attribute MVC视图分析 C#简单枚举和标志枚举的用法和区别 XDate Admin.NET框架资料 日志管理之log4net+Autofac 关于NopCommerce3.6版用户登录详解 AutoFac注册的动态实例 Named和Keyed NOP源码分析 六 NOP源码分析五---set的存储 NOP源码分析四 NOP源码分析 二 NOP源码分析 一 NopCommerce的资料 IServiceCollection和IServiceProvider 控制反转——Autofac框架 精选10款C#/.NET开发必备类库 11个免费开源后台管理系统模板 H5连接蓝牙打印机打印小票 自定义控件 - 流式布局:TagFlowLayout MVC开源CMS nginx的安装&一个最简单的配置(windows和Centos) DNS解析
Nop源码分析三
大西瓜3721 · 2026-03-15 · via 博客园 - 大西瓜3721

上次卡壳在下面一句,由于有点累了,也没再研究,如下:

//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>();

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