采用Asp.net的定时处理方式,在WEB服务器层处理业务
核心处理就是System.Threading.Timer。这个定时类可以用于在后台定时执行用户提交操作,
它的使用方法:
System.Threading.TimerCallbackt = new System.Threading.TimerCallback(你的处理方法);
System.Threading.Timert = new System.Threading.Timer(t, null , 1000 , 5000 );
这一段说明是在启动1秒后每隔5秒就调用所指定的代理。
在具体实现时我定义了三个类。
1 、BkExecItem用于保存用户提交操作,同时它也可以序列化到磁盘上,以免关键后台任务丢失。
2 、BkExec用于执行。它通过反射来调用BkExecItem中所指定的方法。另外它中间还维护一个先入
先出队列Queue < BkExecItem > ,这个队列记录全部的后台处理项。
3 、BkManager完成定时器的初始化,模块的参数配置等功能。
呵,暂时总结到这里。下次我会将代码也贴上来,供大家参考下。
一个实用ASP.Net后台处理类
呵.这回跟大家讨论下ASP.net后台处理,并会把我们当前项目中应用的一个后台处理类的代码贴上来参考.
后台处理也是现在管理系统设计中需要考虑到的一个问题.
什么是后台处理,可以简单认为不是在用户进程处理中完成用户提交的操作,而是将这一处理放到服务端后台进程来处理.
加入后台处理后,可以提高前台用户的操作速度,改善用户操作体验.
对于一般用户来说他对于一个系统的基本要求就是响应及时,用户很难对一个提交操作后需要等待10秒以后的管理系统产生好感,但在实际系统运行中用户操作是很难在短时间内得到响应,所以这个时候后台处理就可以发挥作用了.
我在后面所帖代码中,将需要后台处理的任务均定义成一个ExecItem对象.用户提交操作后,系统将就操作转成一个ExecItem对象加入到BkExecManager(后台处理管理对象)中的一个先入先出的队列中.
网站在启动时会自动启动BkExecManager,而BkExecManager则启动一个定时器来定时处理后台任务队列.
在处理完成时BkExecManager就队列中移去任务对象,如果操作失败将以邮件方式通知管理员来完成问题处理.
呵.现在贴代码 !
1 ,后台处理管理对象
public class BkExecManager
{
// 定时回调。
private static TimerCallbacktimerDelegate;
private static TimerstateTimer;
private static BkExecerm_Execer;
public static string DataPath;
public static string BkManager = " XXXX " ;
public static int BkBufSize = 100 ;
private static int Interval = 10000 ;
public static BkExecerExecer
{
get { return m_Execer;}
}
static BkExecManager()
{
DataPath = System.AppDomain.CurrentDomain.BaseDirectory + " BkItem/ " ;
if (System.Configuration.ConfigurationManager.AppSettings[ " Interval " ] != null )
Interval = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings[ " Interval " ]);
if (System.Configuration.ConfigurationManager.AppSettings[ " BkBufSize " ] != null )
BkBufSize = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings[ " BkBufSize " ]);
if (System.Configuration.ConfigurationManager.AppSettings[ " BkManager " ] != null )
BkManager = System.Configuration.ConfigurationManager.AppSettings[ " BkManager " ];
m_Execer = new BkExecer();
// 初始化回调
timerDelegate = new TimerCallback(m_Execer.DoBkExec);
// 初始化定时器
stateTimer = new Timer(timerDelegate, null , 5000 ,Interval);
}
/**/ /// <summary>
/// 停止定时器.
/// </summary>
static void BkExecQuit()
{
stateTimer.Dispose();
}
}
2 ,后台处理执行
public class BkExecer
{
// 维护一个前进前出的队列。
private Queue < ExecItem > m_BkExecItemList;
private static object lockHelper = new object ();
private static bool m_IsBusy = false ;
public static bool IsBusy
{
get { return m_IsBusy;}
}
public BkExecer()
{
m_BkExecItemList = new Queue < ExecItem > (BkExecManager.BkBufSize);
/**/ /// /读入待处理事项
InitData();
}
private void InitData()
{
lock (lockHelper)
{
string []fnl = Directory.GetFiles(BkExecManager.DataPath);
foreach ( string s in fnl)
{
if ( ! s.Contains(BKExecItemState.出错.ToString()))
{
ExecItemei = ExecItem.GetObject(s);
m_BkExecItemList.Enqueue(ei);
}
}
}
}
public void AddBkExecItem(ExecItemei)
{
lock (lockHelper)
{
// 锁定资源。
m_BkExecItemList.Enqueue(ei);
}
}
public void DoBkExec( object Msg)
{
ExecItemei;
while (m_BkExecItemList.Count > 0 )
{
lock (lockHelper)
{
ei = m_BkExecItemList.Dequeue();
}
int rv = - 1 ;
try
{
BindingFlagsflags = BindingFlags.InvokeMethod | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.Static;
object t = ei.ExecItemClass.InvokeMember(ei.ExecItemMethed,flags,
null , null ,ei.ExecItemParamList);
if (t != null )
rv = Convert.ToInt32(t);
else
rv = 0 ; // 如果是无返回则直接设置零.
}
catch (Exceptione)
{
// 更新Ei的状态,保存到磁盘。
ei.FinishBkExec( false ,e.Message);
}
finally
{
// 更新Ei的状态,删除存件
// 保存到磁盘。
if (rv >= 0 )
ei.FinishBkExec( true , "" );
else
ei.FinishBkExec( false ,rv.ToString());
}
}
}
}
3 ,任务对象
public enum BKExecItemState {待执行,完成,出错} ;
[Serializable]
/**/ /// <summary>
/// 后台命令集合
/// 直接将这些后台命令二进制序列化到WEb服务器上保存。
/// 如果完成后则从Web服务器上删除。
/// 如果异常则发邮件通知管理员。
/// </summary>
public class ExecItem
{
/**/ /// <summary>
/// 磁盘文档名称 。
/// </summary>
private string BKStoreFileName = "" ;
private string ErrMsg = "" ;
private BKExecItemStatem_ItemState;
public BKExecItemStateItemState
{
get { return m_ItemState;}
}
private DateTimem_ExecItemExecTime;
public DateTimeExecItemExecTime
{
get { return m_ExecItemExecTime;}
}
private DateTimem_ExecItemCreateTime;
public DateTimeExecItemCreateTime
{
get { return m_ExecItemCreateTime;}
}
private string m_ExecItemName;
public string ExecItemName
{
get { return m_ExecItemName;}
}
private Typem_ExecItemClass;
public TypeExecItemClass
{
get { return m_ExecItemClass;}
}
private string m_ExecItemMethed;
public string ExecItemMethed
{
get { return m_ExecItemMethed;}
}
private object []m_ExecItemParamList;
public object []ExecItemParamList
{
get { return m_ExecItemParamList;}
}
private string m_Op;
/**/ /// <summary>
/// 后台任务对象
/// </summary>
/// <paramname="objtype"> 对象类型 </param>
/// <paramname="ExecMethod"> 调用方法 </param>
/// <paramname="param"> 调用参数 </param>
/// <paramname="ExecName"> 任务名 </param>
/// <paramname="Op"> 提交人 </param>
/// <paramname="SavetoDisk"> 是否保存到磁盘 </param>
public ExecItem(Typeobjtype, string ExecMethod, object []param, string ExecName, string Op, bool SavetoDisk)
{
this .BKStoreFileName = String.Format( " {0}{1}{2}.bin " ,
DateTime.Now.ToString( " yyyy-MM-ddHH-mm-ss " ),ExecMethod,Op);
this .m_ExecItemClass = objtype;
this .m_ExecItemCreateTime = DateTime.Now;
this .m_ExecItemExecTime = DateTime.Now;
this .m_ExecItemMethed = ExecMethod;
this .m_ExecItemName = ExecName;
this .m_ExecItemParamList = param;
this .m_ItemState = BKExecItemState.待执行;
this .m_Op = Op;
if (SavetoDisk)
SaveToDisk();
}
private void SaveToDisk()
{
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(BkExecManager.DataPath + BKStoreFileName,
FileMode.Create,FileAccess.Write,FileShare.None);
formatter.Serialize(stream, this );
stream.Close();
}
private void SaveToDisk2()
{
//
string basedir = System.AppDomain.CurrentDomain.BaseDirectory;
this .BKStoreFileName = String.Format( " {0}{1}{2}{3}.bin " ,
m_ExecItemCreateTime.ToString( " yyyy-MM-ddHH-mm-ss " ),
this .m_ExecItemMethed,
m_Op,
m_ItemState.ToString());
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(BkExecManager.DataPath + BKStoreFileName,
FileMode.Create,FileAccess.Write,FileShare.None);
formatter.Serialize(stream, this );
stream.Close();
}
public static ExecItemGetObject( string s)
{
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(s,FileMode.Open,FileAccess.Read,FileShare.None);
ExecIteme = (ExecItem)formatter.Deserialize(stream);
stream.Close();
return e;
}
public void FinishBkExec( bool DoneOk, string Msg)
{
string FileName = BkExecManager.DataPath + BKStoreFileName;
m_ExecItemExecTime = DateTime.Now;
if (File.Exists(FileName))
File.Delete(FileName);
if ( ! DoneOk)
{
m_ItemState = BKExecItemState.出错;
ErrMsg = Msg;
SaveToDisk2();
MakeMail();
}
}
private void MakeMail()
{
StringBuildersb = new StringBuilder();
sb.Append( " 提交人: " ).Append( this .m_Op).Append( " <BR> " );
sb.Append( " 提交时间: " ).Append( this .ExecItemCreateTime).Append( " <BR> " );
sb.Append( " 对象: " ).Append( this .m_ExecItemClass.Name).Append( " <BR> " );
sb.Append( " 方法: " ).Append( this .m_ExecItemMethed).Append( " <BR> " );
sb.Append( " 参数: " );
foreach ( object o in this .m_ExecItemParamList)
sb.Append(o.ToString()).Append( " , " );
sb.Append( " <BR> " );
sb.Append( " 执行时间: " ).Append( this .m_ExecItemExecTime).Append( " <BR> " );
sb.Append( " 错误信息: " ).Append( this .ErrMsg).Append( " <BR> " );
string mb = sb.ToString();
// APP.Mail.Send(m_Op+":"+m_ExecItemClass.Name+"后台处理错",mb,"",BkExecManager.BkManager,"");
}
}
具体调用方法为
1 ,首先新调一个后台任务对象.
2 ,将之加入到任务队列中.
ExecItemei = new ExecItem( typeof (CacheManager),
" RefreshObject " ,
new object [] {Objtype,Params,ct} ,
" 缓存刷新 " ,
"" ,
false ); // 注意以后可以设置为false,即刷新任务不保存到磁盘,以免影响磁盘性能.
BkExecManager.Execer.AddBkExecItem(ei);
核心处理就是System.Threading.Timer。这个定时类可以用于在后台定时执行用户提交操作,
它的使用方法:
System.Threading.TimerCallbackt = new System.Threading.TimerCallback(你的处理方法);
System.Threading.Timert = new System.Threading.Timer(t, null , 1000 , 5000 );
这一段说明是在启动1秒后每隔5秒就调用所指定的代理。
在具体实现时我定义了三个类。
1 、BkExecItem用于保存用户提交操作,同时它也可以序列化到磁盘上,以免关键后台任务丢失。
2 、BkExec用于执行。它通过反射来调用BkExecItem中所指定的方法。另外它中间还维护一个先入
先出队列Queue < BkExecItem > ,这个队列记录全部的后台处理项。
3 、BkManager完成定时器的初始化,模块的参数配置等功能。
呵,暂时总结到这里。下次我会将代码也贴上来,供大家参考下。
一个实用ASP.Net后台处理类
呵.这回跟大家讨论下ASP.net后台处理,并会把我们当前项目中应用的一个后台处理类的代码贴上来参考.
后台处理也是现在管理系统设计中需要考虑到的一个问题.
什么是后台处理,可以简单认为不是在用户进程处理中完成用户提交的操作,而是将这一处理放到服务端后台进程来处理.
加入后台处理后,可以提高前台用户的操作速度,改善用户操作体验.
对于一般用户来说他对于一个系统的基本要求就是响应及时,用户很难对一个提交操作后需要等待10秒以后的管理系统产生好感,但在实际系统运行中用户操作是很难在短时间内得到响应,所以这个时候后台处理就可以发挥作用了.
我在后面所帖代码中,将需要后台处理的任务均定义成一个ExecItem对象.用户提交操作后,系统将就操作转成一个ExecItem对象加入到BkExecManager(后台处理管理对象)中的一个先入先出的队列中.
网站在启动时会自动启动BkExecManager,而BkExecManager则启动一个定时器来定时处理后台任务队列.
在处理完成时BkExecManager就队列中移去任务对象,如果操作失败将以邮件方式通知管理员来完成问题处理.
呵.现在贴代码 !
1 ,后台处理管理对象
public class BkExecManager
{
// 定时回调。
private static TimerCallbacktimerDelegate;
private static TimerstateTimer;
private static BkExecerm_Execer;
public static string DataPath;
public static string BkManager = " XXXX " ;
public static int BkBufSize = 100 ;
private static int Interval = 10000 ;
public static BkExecerExecer
{
get { return m_Execer;}
}
static BkExecManager()
{
DataPath = System.AppDomain.CurrentDomain.BaseDirectory + " BkItem/ " ;
if (System.Configuration.ConfigurationManager.AppSettings[ " Interval " ] != null )
Interval = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings[ " Interval " ]);
if (System.Configuration.ConfigurationManager.AppSettings[ " BkBufSize " ] != null )
BkBufSize = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings[ " BkBufSize " ]);
if (System.Configuration.ConfigurationManager.AppSettings[ " BkManager " ] != null )
BkManager = System.Configuration.ConfigurationManager.AppSettings[ " BkManager " ];
m_Execer = new BkExecer();
// 初始化回调
timerDelegate = new TimerCallback(m_Execer.DoBkExec);
// 初始化定时器
stateTimer = new Timer(timerDelegate, null , 5000 ,Interval);
}
/**/ /// <summary>
/// 停止定时器.
/// </summary>
static void BkExecQuit()
{
stateTimer.Dispose();
}
}
2 ,后台处理执行
public class BkExecer
{
// 维护一个前进前出的队列。
private Queue < ExecItem > m_BkExecItemList;
private static object lockHelper = new object ();
private static bool m_IsBusy = false ;
public static bool IsBusy
{
get { return m_IsBusy;}
}
public BkExecer()
{
m_BkExecItemList = new Queue < ExecItem > (BkExecManager.BkBufSize);
/**/ /// /读入待处理事项
InitData();
}
private void InitData()
{
lock (lockHelper)
{
string []fnl = Directory.GetFiles(BkExecManager.DataPath);
foreach ( string s in fnl)
{
if ( ! s.Contains(BKExecItemState.出错.ToString()))
{
ExecItemei = ExecItem.GetObject(s);
m_BkExecItemList.Enqueue(ei);
}
}
}
}
public void AddBkExecItem(ExecItemei)
{
lock (lockHelper)
{
// 锁定资源。
m_BkExecItemList.Enqueue(ei);
}
}
public void DoBkExec( object Msg)
{
ExecItemei;
while (m_BkExecItemList.Count > 0 )
{
lock (lockHelper)
{
ei = m_BkExecItemList.Dequeue();
}
int rv = - 1 ;
try
{
BindingFlagsflags = BindingFlags.InvokeMethod | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.Static;
object t = ei.ExecItemClass.InvokeMember(ei.ExecItemMethed,flags,
null , null ,ei.ExecItemParamList);
if (t != null )
rv = Convert.ToInt32(t);
else
rv = 0 ; // 如果是无返回则直接设置零.
}
catch (Exceptione)
{
// 更新Ei的状态,保存到磁盘。
ei.FinishBkExec( false ,e.Message);
}
finally
{
// 更新Ei的状态,删除存件
// 保存到磁盘。
if (rv >= 0 )
ei.FinishBkExec( true , "" );
else
ei.FinishBkExec( false ,rv.ToString());
}
}
}
}
3 ,任务对象
public enum BKExecItemState {待执行,完成,出错} ;
[Serializable]
/**/ /// <summary>
/// 后台命令集合
/// 直接将这些后台命令二进制序列化到WEb服务器上保存。
/// 如果完成后则从Web服务器上删除。
/// 如果异常则发邮件通知管理员。
/// </summary>
public class ExecItem
{
/**/ /// <summary>
/// 磁盘文档名称 。
/// </summary>
private string BKStoreFileName = "" ;
private string ErrMsg = "" ;
private BKExecItemStatem_ItemState;
public BKExecItemStateItemState
{
get { return m_ItemState;}
}
private DateTimem_ExecItemExecTime;
public DateTimeExecItemExecTime
{
get { return m_ExecItemExecTime;}
}
private DateTimem_ExecItemCreateTime;
public DateTimeExecItemCreateTime
{
get { return m_ExecItemCreateTime;}
}
private string m_ExecItemName;
public string ExecItemName
{
get { return m_ExecItemName;}
}
private Typem_ExecItemClass;
public TypeExecItemClass
{
get { return m_ExecItemClass;}
}
private string m_ExecItemMethed;
public string ExecItemMethed
{
get { return m_ExecItemMethed;}
}
private object []m_ExecItemParamList;
public object []ExecItemParamList
{
get { return m_ExecItemParamList;}
}
private string m_Op;
/**/ /// <summary>
/// 后台任务对象
/// </summary>
/// <paramname="objtype"> 对象类型 </param>
/// <paramname="ExecMethod"> 调用方法 </param>
/// <paramname="param"> 调用参数 </param>
/// <paramname="ExecName"> 任务名 </param>
/// <paramname="Op"> 提交人 </param>
/// <paramname="SavetoDisk"> 是否保存到磁盘 </param>
public ExecItem(Typeobjtype, string ExecMethod, object []param, string ExecName, string Op, bool SavetoDisk)
{
this .BKStoreFileName = String.Format( " {0}{1}{2}.bin " ,
DateTime.Now.ToString( " yyyy-MM-ddHH-mm-ss " ),ExecMethod,Op);
this .m_ExecItemClass = objtype;
this .m_ExecItemCreateTime = DateTime.Now;
this .m_ExecItemExecTime = DateTime.Now;
this .m_ExecItemMethed = ExecMethod;
this .m_ExecItemName = ExecName;
this .m_ExecItemParamList = param;
this .m_ItemState = BKExecItemState.待执行;
this .m_Op = Op;
if (SavetoDisk)
SaveToDisk();
}
private void SaveToDisk()
{
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(BkExecManager.DataPath + BKStoreFileName,
FileMode.Create,FileAccess.Write,FileShare.None);
formatter.Serialize(stream, this );
stream.Close();
}
private void SaveToDisk2()
{
//
string basedir = System.AppDomain.CurrentDomain.BaseDirectory;
this .BKStoreFileName = String.Format( " {0}{1}{2}{3}.bin " ,
m_ExecItemCreateTime.ToString( " yyyy-MM-ddHH-mm-ss " ),
this .m_ExecItemMethed,
m_Op,
m_ItemState.ToString());
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(BkExecManager.DataPath + BKStoreFileName,
FileMode.Create,FileAccess.Write,FileShare.None);
formatter.Serialize(stream, this );
stream.Close();
}
public static ExecItemGetObject( string s)
{
IFormatterformatter = new BinaryFormatter();
Streamstream = new FileStream(s,FileMode.Open,FileAccess.Read,FileShare.None);
ExecIteme = (ExecItem)formatter.Deserialize(stream);
stream.Close();
return e;
}
public void FinishBkExec( bool DoneOk, string Msg)
{
string FileName = BkExecManager.DataPath + BKStoreFileName;
m_ExecItemExecTime = DateTime.Now;
if (File.Exists(FileName))
File.Delete(FileName);
if ( ! DoneOk)
{
m_ItemState = BKExecItemState.出错;
ErrMsg = Msg;
SaveToDisk2();
MakeMail();
}
}
private void MakeMail()
{
StringBuildersb = new StringBuilder();
sb.Append( " 提交人: " ).Append( this .m_Op).Append( " <BR> " );
sb.Append( " 提交时间: " ).Append( this .ExecItemCreateTime).Append( " <BR> " );
sb.Append( " 对象: " ).Append( this .m_ExecItemClass.Name).Append( " <BR> " );
sb.Append( " 方法: " ).Append( this .m_ExecItemMethed).Append( " <BR> " );
sb.Append( " 参数: " );
foreach ( object o in this .m_ExecItemParamList)
sb.Append(o.ToString()).Append( " , " );
sb.Append( " <BR> " );
sb.Append( " 执行时间: " ).Append( this .m_ExecItemExecTime).Append( " <BR> " );
sb.Append( " 错误信息: " ).Append( this .ErrMsg).Append( " <BR> " );
string mb = sb.ToString();
// APP.Mail.Send(m_Op+":"+m_ExecItemClass.Name+"后台处理错",mb,"",BkExecManager.BkManager,"");
}
}
具体调用方法为
1 ,首先新调一个后台任务对象.
2 ,将之加入到任务队列中.
ExecItemei = new ExecItem( typeof (CacheManager),
" RefreshObject " ,
new object [] {Objtype,Params,ct} ,
" 缓存刷新 " ,
"" ,
false ); // 注意以后可以设置为false,即刷新任务不保存到磁盘,以免影响磁盘性能.
BkExecManager.Execer.AddBkExecItem(ei);