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

推荐订阅源

Forbes - Security
Forbes - Security
A
Arctic Wolf
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
A
About on SuperTechFans
P
Palo Alto Networks Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
大猫的无限游戏
大猫的无限游戏
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
T
Tor Project blog
IT之家
IT之家
P
Proofpoint News Feed
Help Net Security
Help Net Security
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
Microsoft Azure Blog
Microsoft Azure Blog
V2EX - 技术
V2EX - 技术
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
B
Blog
N
News and Events Feed by Topic
The Cloudflare Blog
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LangChain Blog
I
InfoQ
F
Full Disclosure
The Register - Security
The Register - Security
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
V
V2EX

博客园 - 阿福

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类库、框架、工具包完全列表 怀旧啊 Search Box ASP.NET 2.0: Site Maps Checking All CheckBoxes in a GridView Efficient Data Paging and Sorting with ASP.NET 2.0 and SQL 2005 JavaScript Calendar Cool MSDN ASP.NET 2.0 GridView Control Article Do I have to cry for you Google无法访问 扯淡 狗*! Atlas Control Toolkit and Source Code for the Build-in Asp.Net 2.0 Providers Great New Advanced Article on ASP.NET 2.0 Master Pages ASP.NET 2.0:通过SqlDataSource绑定数据到普通控件 通过客户端扩展实现固定GridView表头功能 不使用ISAPI或IIS wildcard实现不带扩展名URL的转向 VS 2005 Web Application Project & Atlas Control Toolkit & CSS Control Adapter ASP.NET 2.0 Language Swithcer and Theme Swicher 多语言转换和多样式主题转换 How to use virtual path providers to dynamically load and compile content from virtual paths in 
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;
        }


    }
}