技术总奸

Run Tasks in an ASP.NET Application Domain

 

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;
        }


    }
}

 

posted on 2010-01-01 00:00  阿福  阅读(210)  评论(0编辑  收藏  举报