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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 阿福

TypeScript forms authentication failed the ticket supplied was invalid错误 (Windows Server 2008 + IIS 7.5) jQuery Mobile 1.1.1 RC1发布 HashSet<T> vs List<T> 不要用把无序GUID既作为主键又作为聚集索引 WCF Data Services 5.0 RTM发布 EF Power Tools Beta 2发布 Entity Framework 5性能方面的注意事项 jQuery Mobile 1.1.0 RC2发布 源码+幻灯片:学习HTML5/jQuery/ASP.NET MVC/EF Code First的绝佳资源Account at a Glance项目 使用Autofac在ASP.NET Web API上实现依赖注入 在Windows Azure上开发ASP.NET程序与在Windows Sever上有何不同 充分利用缓存来提高网站性能 ASP.NET MVC 4, ASP.NET Web API, ASP.NET Web Pages v2 (Razor)全部开源,并接受来自社区的贡献(contributions) EF5 beta2通过NuGet发布 Getting Started with HTML5 开发HTML5应用你需要了解的 WCF入门资源 jquery history plugin, url hash ASP.NET 2.0: 生成Excel报表 VS 2008 hot-fix终于出来了 Images; How to create an HTTP handler to dynamically resize images and change quality. ASP.NET 2.0: Add build-in paging feature to repeater/为repeater添加内置分页功能 Tip/Trick ASP.NET 2.0: DropDownList DataBind ASP.NET 2.0: Forms Authentication Across domains Ajax类库、框架、工具包完全列表
Run Tasks in an ASP.NET Application Domain
阿福 · 2010-01-01 · via 博客园 - 阿福

Keywords: Task implement, ASP.NET 2.0 Provider Model

Web应用中有很多耗时的操作比如发送email、生成报表、处理上传图片等等,这些操作是不适合放到页面中的。比如回复一个帖子后email通知所有订阅了该帖子更新的用户,如果在回复操作中处理,那么用户回复帖子时大部分的时间就会浪费在发送email上了。在CommunityServer里,类似的耗时的操作都被独立出来,作为独立的任务运行于服务端同一程序域中的一个或多个线程中。本文通过email notification的实现,来具体了解一下这种实现模式。涉及的知识点包括:.NET configuration API, Provider Model,  ASP.NET 多线程, 抽象工厂模式等。

描述:CS Email Notifcation 包括两部分生成email和发送email。生成email时,针对每个发送地址生成了一个具体的.NET Mail Mesage对象,序列化后存入数据库。发送时反序列化每个Mail Message对象,调用.NET SMTP API发送。发送email可以作为服务独立出来,而生成email是和具体的业务相关的,不能作为独立的服务。但这也是个耗时的操作,涉及到序列化,有时也会有大量email的生成。CS采用异步事件调用,模仿Http Module,定义全局事件,以plug-in的方式载入module,在module中hook全局事件,在事件中处理具体的操作,如生成email。通过事件,使主程序之外的操作异步的进行。以Provider Model的方式来hook事件,增强了程序的可扩展性,实现了即插即用。

代码:

部分代码下载

先看一下配置文件,CS中并没有使用.net 配置文件(即web.config文件)和标准API,本文将其修改为标准的,并采用ASP.NET 2.0中标准的Provider Model。

  <configSections>
    <section name="poConfiguration" type="PO.Component.Configuration.POConfigurationSection, PO.Component"/>
  </configSections>
  <poConfiguration>
    <modules>
      <add name="EmailNotificationModule" type="PO.Component.Module.EmailNotificationModule, PO.Component" />
    </modules>
    <providers>
      <add name="CommonDataProvider" type="PO.Component.Provider.SqlCommonDataProvider, PO.Component" connectionStringName="ShippingWisePortalConnectionString" />
      <add name="EmailTemplateProvider" type="PO.Component.Provider.XmlEmailTemplateProvider, PO.Component" />
      <add name="NotificationProvider" type="PO.Component.Provider.EmailNotificationProvider, PO.Component" />
    </providers>
    <tasks>
      <modules>
      </modules>
      <threads>
        <thread minutes="1">
          <add name="Emails" type="PO.Component.Task.EmailJob, PO.Component" enabled="true" enableShutDown="false" failureInterval="1" numberOfTries="10" />
        </thread>
      </threads>
    </tasks>
  </poConfiguration>

配置文件的操作:

整个自定义节poConifguration

namespace PO.Component.Configuration
{
    public class POConfigurationSection : ConfigurationSection
    {
        [ConfigurationProperty("modules")]
        public ProviderSettingsCollection Modules
        {
            get { return (ProviderSettingsCollection)base["modules"]; }
        }
        [ConfigurationProperty("providers")]
        public ProviderSettingsCollection Providers
        {
            get { return (ProviderSettingsCollection)base["providers"]; }
        }
        [ConfigurationProperty("tasks")]
        public TasksElement Tasks
        {
            get { return (TasksElement)base["tasks"]; }
        }

       }
}

tasks子节

namespace PO.Component.Configuration
{
    public sealed class TasksElement : ConfigurationElement
    {
        [ConfigurationProperty("modules")]
        public ProviderSettingsCollection Modules
        {
            get { return (ProviderSettingsCollection)base["modules"]; }
        }
        [ConfigurationProperty("threads")]
        public ThreadSettingsCollection Threads
        {
            get { return (ThreadSettingsCollection)base["threads"]; }
        }
    }
}

tasks子节中的threads节

namespace PO.Component.Configuration
{
    [ConfigurationCollection(typeof(TaskSettingsCollection))]
    public sealed class ThreadSettingsCollection : ConfigurationElementCollection
    {
        public TaskSettingsCollection this[int index]
        {
            get
            {
                return (TaskSettingsCollection)base.BaseGet(index);
            }
            set
            {
                if (base.BaseGet(index) != null)
                {
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }

        public new TaskSettingsCollection this[string key]
        {
            get
            {
                return (TaskSettingsCollection)base.BaseGet(key);
            }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new TaskSettingsCollection();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return string.Empty;
        }
        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }
        protected override string ElementName
        {
            get
            {
                return "thread";
            }
        }
    }
}

threads节中的thread节

namespace PO.Component.Configuration
{
    [ConfigurationCollection(typeof(ProviderSettings))]
    public sealed class TaskSettingsCollection : ConfigurationElementCollection
    {
        [ConfigurationProperty("minutes", IsRequired = false, DefaultValue = 15)]
        public int Minutes
        {
            get { return (int)base["minutes"]; }
            set { base["minutes"] = value; }
        }
        public ProviderSettings this[int index]
        {
            get
            {
                return (ProviderSettings)base.BaseGet(index);
            }
            set
            {
                if (base.BaseGet(index) != null)
                {
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }

        public new ProviderSettings this[string key]
        {
            get
            {
                return (ProviderSettings)base.BaseGet(key);
            }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ProviderSettings();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ProviderSettings)element).Name;
        }


    }
}