Ah. This time I will discuss with you about Asp.net background processing and refer to the background processing class code applied in our current project.
Background processing is also a problem that needs to be considered in the current management system design.
What is background processing? You can simply think that this process is not completed in user process processing, but is put into the server background process for processing.
After being added to the background processing, the operation speed of foreground users can be improved and the user operation experience can be improved.
Generally, a user's basic requirement for a system is to respond in a timely manner. It is difficult for the user to have a liking for a management system that needs to wait 10 seconds after the operation is submitted, however, in actual system running, user operations are difficult to get response in a short time, So background processing can play a role at this time.
In the subsequent post code, I define all tasks to be processed in the background as an execitem object. after the user submits the operation, the system will convert the operation into an execitem object and add it to a first-in-first-out queue in bkexecmanager (background processing management object.
When the website is started, bkexecmanager is automatically started, while bkexecmanager starts a timer to regularly process backend task queues.
Bkexecmanager removes the task object in the queue when the processing is completed. If the operation fails, the Administrator will be notified by email to complete the troubleshooting.
Oh. paste the code now!
1. Manage objects in the background
Public class bkexecmanager
{// Timed callback.
Private Static timercallback timerdelegate;
Private Static timer statetimer;
Private Static bkexecer m_execer;
Public static string datapath;
Public static string bkmanager = "XXXX ";
Public static int bkbufsize = 100;
Private Static int interval = 10000;
Public static bkexecer execer
{
Get {return m_execer ;}
}
Static bkexecmanager ()
{
Datapath = system. appdomain. currentdomain. basedirectory + "bkitem //";
If (system. configuration. configurationmanager. receivettings ["interval"]! = NULL)
Interval = convert. toint32 (system. configuration. configurationmanager. deleettings ["interval"]);
If (system. configuration. configurationmanager. receivettings ["bkbufsize"]! = NULL)
Bkbufsize = convert. toint32 (system. configuration. configurationmanager. deleettings ["bkbufsize"]);
If (system. configuration. configurationmanager. deleetmanager ["bkmanager"]! = NULL)
Bkmanager = system. configuration. configurationmanager. deleetmanager ["bkmanager"];
M_execer = new bkexecer ();
// Initialization callback
Timerdelegate = new timercallback (m_execer.dobkexec );
// Initialize the timer
Statetimer = new timer (timerdelegate, null, 5000, interval );
}
/// <Summary>
/// Stop the timer.
/// </Summary>
Static void bkexecquit ()
{
Statetimer. Dispose ();
}
}
2. background processing and execution
Public class bkexecer
{
// Maintenance 1
Forward and forward queues.
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 );
//// Read the pending items
Initdata ();
}
Private void initdata ()
{
Lock (lockhelper)
{
String [] FNL = directory. getfiles (bkexecmanager. datapath );
Foreach (string s in FNL)
{
If (! S. Contains (bkexecitemstate. Error. tostring ()))
{
Execitem Ei = execitem. GetObject (s );
M_bkexecitemlist.enqueue (EI );
}
}
}
}
Public void addbkexecitem (execitem EI)
{
Lock (lockhelper)
{
// Lock the resource.
M_bkexecitemlist.enqueue (EI );
}
}
Public void dobkexec (Object MSG)
{
Execitem EI;
While (m_bkexecitemlist.count> 0)
{
Lock (lockhelper)
{
Ei = m_bkexecitemlist.dequeue ();
}
Int Rv =-1;
Try
{
Bindingflags flags = 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; // if no return is returned, set zero directly.
}
Catch (exception E)
{
// Update the EI status and save it to the disk.
EI. finishbkexec (false, E. Message );
}
Finally
{
// Update the EI status and delete the storage.
// Save it to the disk.
If (RV> = 0)
EI. finishbkexec (true ,"");
Else
EI. finishbkexec (false, RV. tostring ());
}
}
}
}
3. task object
Public Enum bkexecitemstate {waiting for execution, complete, error };
[Serializable]
/// <Summary>
/// Background command set
/// Directly serialize these background commands to the Web server for storage.
/// If it is complete, it will be deleted from the web server.
/// Send an email to the administrator if an exception occurs.
/// </Summary>
Public class execitem
{
/// <Summary>
/// Disk document name.
/// </Summary>
Private string bkstorefilename = "";
Private string errmsg = "";
Private bkexecitemstate m_itemstate;
Public bkexecitemstate itemstate
{
Get {return m_itemstate ;}
}
Private datetime m_execitemexectime;
Public datetime execitemexectime
{
Get {return m_execitemexectime ;}
}
Private datetime m_execitemcreatetime;
Public datetime execitemcreatetime
{
Get {return m_execitemcreatetime ;}
}
Private string m_execitemname;
Public String execitemname
{
Get {return m_execitemname ;}
}
Private type m_execitemclass;
Public type execitemclass
{
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>
/// Background task object
/// </Summary>
/// <Param name = "objtype"> Object Type </param>
/// <Param name = "execmethod"> call method </param>
/// <Param name = "Param"> call parameters </param>
/// <Param name = "execname"> Task Name </param>
/// <Param name = "op"> submitted by </param>
/// <Param name = "savetodisk"> whether to save to disk </param>
Public execitem (type objtype, string execmethod, object [] Param, string execname, string op, bool savetodisk)
{
This. bkstorefilename = string. format ("{0} {1} {2 }. bin ", datetime. now. tostring ("yyyy-mm-dd hh-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. To be executed;
This. m_op = op;
If (savetodisk)
Savetodisk ();
}
Private void savetodisk ()
{
Iformatter formatter = new binaryformatter ();
Stream stream = 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-dd hh-mm-SS "), this. m_execitemmethed, m_op, m_itemstate.tostring ());
Iformatter formatter = new binaryformatter ();
Stream stream = new filestream (bkexecmanager. datapath + bkstorefilename, filemode. Create, fileaccess. Write, fileshare. None );
Formatter. serialize (stream, this );
Stream. Close ();
}
Public static execitem GetObject (string S)
{
Iformatter formatter = new binaryformatter ();
Stream stream = new filestream (S, filemode. Open, fileaccess. Read, fileshare. None );
Execitem E = (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. error;
Errmsg = MSG;
Savetodisk2 ();
Makemail ();
}
}
Private void makemail ()
{
Stringbuilder sb = new stringbuilder ();
SB. append ("submitted by:"). append (this. m_op). append ("<br> ");
SB. append ("submission time:"). append (this. execitemcreatetime). append ("<br> ");
SB. append ("Object:"). append (this. m_execitemclass.name). append ("<br> ");
SB. append ("method:"). append (this. m_execitemmethed). append ("<br> ");
SB. append ("parameter :");
Foreach (Object o in this. m_execitemparamlist)
SB. append (O. tostring (). append (",");
SB. append ("<br> ");
SB. append ("execution time:"). append (this. m_execitemexectime). append ("<br> ");
SB. append ("error message:"). append (this. errmsg). append ("<br> ");
String MB = sb. tostring ();
// App. Mail. Send (m_op + ":" + m_execitemclass.name + "background processing error", MB, "", bkexecmanager. bkmanager ,"");
}
}
The specific call method is
1. First, call a new background task object.
2. Add it to the task queue.
Execitem Ei = new execitem (typeof (cachemanager), "refreshobject", new object [] {objtype, Params, CT}, "cache refresh", "", false ); // you can set it to false in the future, that is, the refresh task is not saved to the disk to avoid affecting disk performance.
Bkexecmanager. execer. addbkexecitem (EI );
Now this object works well in our project.
In the future, I want to continue to improve this object. Its shortcomings include: the user is not informed of the progress and result of the Operation submitted by the user.