using System;
using System.Collections;
using System.Security.Principal;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using CMS.ExtendedControls;
using CMS.GlobalHelper;
using CMS.SettingsProvider;
using CMS.UIControls;
public partial class CMSAdminControls_AsyncControl : CMSUserControl, ICallbackEventHandler, IPostBackEventHandler
{
#region "Private variables & constants"
///
/// Table of the worker processes.
///
private static readonly Hashtable mWorkers = new Hashtable();
private AsyncWorker mWorker = null;
private string mCallbackResult = null;
private bool mPostbackOnError = true;
private string mLog = null;
// Constants
private const string RESULT_FINISHED = "finished";
private const string RESULT_RUNNING = "running";
private const string RESULT_ERROR = "error";
private const string RESULT_STOPPED = "stopped";
private const string RESULT_THREADLOST = "threadlost";
#endregion
#region "Properties"
///
/// Gets the current log.
///
public string Log
{
get
{
if ((mLog == null) && (OnRequestLog != null))
{
OnRequestLog(this, new EventArgs());
}
return mLog;
}
set
{
mLog = value;
}
}
///
/// Process GUID.
///
public Guid ProcessGUID
{
get
{
if (ViewState["ProcessGUID"] == null)
{
ViewState["ProcessGUID"] = Guid.NewGuid();
}
return ValidationHelper.GetGuid(ViewState["ProcessGUID"], Guid.NewGuid());
}
set
{
ViewState["ProcessGUID"] = value;
}
}
///
/// Asynchronous worker.
///
public AsyncWorker Worker
{
get
{
if (mWorker == null)
{
string key = "AsyncWorker_" + ProcessGUID;
mWorker = (AsyncWorker)mWorkers[key];
if (mWorker == null)
{
mWorker = new AsyncWorker
{
// Ensure process guid
ProcessGUID = ProcessGUID
};
mWorkers[key] = mWorker;
}
}
return mWorker;
}
}
///
/// True if the postback should occure after error.
///
public bool PostbackOnError
{
get
{
return mPostbackOnError;
}
set
{
mPostbackOnError = value;
}
}
///
/// Process parameter.
///
public new object Parameter
{
get
{
return Worker.Parameter;
}
set
{
Worker.Parameter = value;
}
}
///
/// Indicates if the logging is ascendant.
///
public bool AscendantLog
{
get;
set;
}
///
/// Indicates if the control should use the string from resource file.
///
public bool UseFileStrings
{
get;
set;
}
///
/// Gets the worker status.
///
public AsyncWorkerStatusEnum Status
{
get
{
return Worker.Status;
}
}
///
/// Maximum log length. (0 = unlimited)
///
public int MaxLogLines
{
get;
set;
}
///
/// Message panel where log is being displayed.
///
public Panel LogPanel
{
get
{
return pnlAsync;
}
}
///
/// Returns unique name of the instance, i.e. ServerName for multi-instance environments or MachineName in other cases.
///
private string InstanceName
{
get
{
string serverName = WebSyncHelperClass.ServerName;
return !String.IsNullOrEmpty(serverName) ? serverName : SqlHelperClass.MachineName;
}
}
#endregion
#region "Page events"
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Register full postbacks
btnCancel.Attributes.Add("style", "display: none;");
// Register full postbacks
ControlsHelper.RegisterPostbackControl(this);
ControlsHelper.RegisterPostbackControl(btnCancel);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
RenderScripts(false);
}
#endregion
#region "Methods"
///
/// Returns localized string.
///
/// String to localize
public override string GetString(string stringName)
{
if (UseFileStrings)
{
return ResHelper.GetFileString(stringName);
}
else
{
return base.GetString(stringName);
}
}
///
/// Returns true if the worker for current control exists.
///
protected bool WorkerExists()
{
if (ProcessGUID != Guid.Empty)
{
string key = "AsyncWorker_" + ProcessGUID;
return (mWorkers[key] != null);
}
return false;
}
///
/// Runs the asynchronous process without any thread.
///
public void RunAsync()
{
RenderScripts(false);
}
///
/// Runs the asynchronous action.
///
/// Action to run
/// Windows identity (windows user)
public void RunAsync(AsyncAction action, WindowsIdentity wi)
{
RenderScripts(true);
Worker.Stop();
Worker.Reset();
Worker.RunAsync(action, wi);
}
///
/// Stops the worker.
///
public void Stop()
{
Worker.Stop();
}
///
/// Registers scripts necessary.
///
/// Determines whether to register scrips in any case
protected void RenderScripts(bool force)
{
if (!RequestHelper.IsCallback() || force)
{
if (((Worker.Status == AsyncWorkerStatusEnum.Running) || (Worker.Status == AsyncWorkerStatusEnum.WaitForFinish)) || force)
{
string machineName = InstanceName;
const int TIMEOUT = 200;
// Prepare the scripts
StringBuilder script = new StringBuilder();
// Initialize variables
script.Append(
@"
var logText_", ClientID, @" = '';
var callBackParam_", ClientID, @" = '';
var machineName_", ClientID, " = '", machineName.ToLowerCSafe(), @"';
var asyncProcessFinished_", ClientID, @" = false;
var timeout_", ClientID, @" = null;
var asyncBusy = false;");
// Register function that repeatedly gets content
script.Append(@"
function AC_GetAsyncStatus_", ClientID, @"() {
if (!asyncBusy) {
asyncBusy = true;
setTimeout('asyncBusy = false;', 2000);
callBackParam_", ClientID, " = logText_", ClientID, ".length + '|' + machineName_", ClientID, @";
", Page.ClientScript.GetCallbackEventReference(this, "callBackParam_" + ClientID, "AC_ReceiveAsyncStatus_" + ClientID, "logText_" + ClientID + ".length", false), @";
}
if (asyncProcessFinished_", ClientID, @") {
CancelAction_", ClientID, @"(false);
return;
}
else
{
timeout = setTimeout(function() { AC_GetAsyncStatus_", ClientID, "(); }, ", TIMEOUT, @");
}
}");
// Register closing script
script.Append(@"
function AC_SetClose_", ClientID, @"() {
var cancelElem = document.getElementById('", btnCancel.ClientID, @"');
if (cancelElem != null) {
cancelElem.value = '", GetString("General.Close"), @"';
}
}");
// Register function that parses callback
script.Append(@"
function AC_ReceiveAsyncStatus_", ClientID, @"(rvalue, context) {
asyncBusy = false;
if (asyncProcessFinished_", ClientID, @") {
return;
}
values = rvalue.split('|');
code = values[0];
var i = 1;
var resultValue = '';
for (i = 1; i logText_", ClientID, @".length) {
logText_", ClientID, @" = elem.innerHTML = messageText;
}
}");
}
else
{
script.Append(@"
elem.innerHTML = text;
}");
}
// Set timeout for getting content
script.Append(@"
timeout_", ClientID, " = setTimeout(function() {AC_GetAsyncStatus_", ClientID, "();}, ", TIMEOUT, ");");
ScriptHelper.RegisterStartupScript(this, typeof(string), "asyncScript" + ClientID, ScriptHelper.GetScript(script.ToString()));
}
// Register cancel script
StringBuilder cancelScript = new StringBuilder();
cancelScript.Append(
@"function CancelAction_", ClientID, @"(withPostback) {
asyncProcessFinished_", ClientID, @" = true;
if (withPostback) {
", Page.ClientScript.GetPostBackEventReference(btnCancel, null), @";
}
else
{
var t = timeout_", ClientID, @";
if((t != 'undefined') && (t != null)) {
clearTimeout(timeout_", ClientID, @");
}
}
}");
ScriptHelper.RegisterStartupScript(this, typeof(string), "cancelScript" + ClientID, ScriptHelper.GetScript(cancelScript.ToString()));
}
}
public string GetCancelScript(bool withPostback)
{
return "CancelAction_" + ClientID + "(" + withPostback.ToString().ToLowerCSafe() + ");";
}
#endregion
#region "Callback handling"
///
/// Raises the callback event.
///
/// Event argument
public void RaiseCallbackEvent(string eventArgument)
{
string[] args = eventArgument.Split('|');
int requestedLength = ValidationHelper.GetInteger(args[0], 0);
mCallbackResult = string.Empty;
if (InstanceName.EqualsCSafe(args[1], StringComparison.InvariantCultureIgnoreCase))
{
if (WorkerExists())
{
switch (Worker.Status)
{
case AsyncWorkerStatusEnum.Finished:
case AsyncWorkerStatusEnum.WaitForFinish:
// Allow worker to finish
mCallbackResult = RESULT_FINISHED;
break;
case AsyncWorkerStatusEnum.Running:
mCallbackResult = RESULT_RUNNING;
break;
case AsyncWorkerStatusEnum.Error:
// Allow worker to finish
mCallbackResult = RESULT_ERROR;
break;
case AsyncWorkerStatusEnum.Stopped:
mCallbackResult = RESULT_STOPPED;
break;
}
// Log only when worker is running
if ((Worker.Status == AsyncWorkerStatusEnum.Running) && (!String.IsNullOrEmpty(Log)))
{
string log = Log;
int logLength = log.Length;
int trimStart = 0;
int trimLength = 0;
if (MaxLogLines > 0)
{
// Get position of the specified occurrence of new line tag
int index = log.NthIndexOf("
", MaxLogLines, !AscendantLog);
bool indexExists = (index > -1);
if (AscendantLog)
{
// Select max. number of lines from the end of the log
trimStart = indexExists ? index : 0;
trimLength = indexExists ? (logLength - index) : logLength;
}
else
{
// Select max. number of lines from the begining of the log
trimStart = 0;
trimLength = indexExists ? index : logLength;
}
}
else
{
// Correct the length in case of invalid value
if (requestedLength > logLength)
{
requestedLength = logLength;
}
// Send only the part that is not present on the client machine
trimStart = AscendantLog ? requestedLength : 0;
trimLength = (logLength - requestedLength);
}
// Get the message within the specified bounds
log = log.Substring(trimStart, trimLength);
// Send the message to client
mCallbackResult += "|" + log;
}
}
else
{
mCallbackResult = RESULT_THREADLOST + "|" + GetString("AsyncControl.ThreadLost");
}
}
else
{
mCallbackResult = RESULT_RUNNING + "|";
}
}
///
/// Returns the result of a callback.
///
public string GetCallbackResult()
{
return mCallbackResult;
}
#endregion
#region "Events"
///
/// Finished event handler.
///
public event EventHandler OnFinished;
///
/// Error event handler.
///
public new event EventHandler OnError;
///
/// Cancel event handler.
///
public event EventHandler OnCancel;
///
/// Error event handler.
///
public event EventHandler OnRequestLog;
///
/// Raises the finished event.
///
/// Sender
/// Event args
public void RaiseFinished(object sender, EventArgs e)
{
if (OnFinished != null)
{
OnFinished(this, e);
}
}
///
/// Raises the Error event.
///
/// Sender
/// Event args
public void RaiseError(object sender, EventArgs e)
{
if (OnError != null)
{
OnError(this, e);
}
}
///
/// Raises the Cancel event.
///
/// Sender
/// Event args
public void RaiseCancel(object sender, EventArgs e)
{
if (OnCancel != null)
{
OnCancel(this, e);
}
}
protected void btnCancel_Click(object sender, EventArgs e)
{
if (WorkerExists())
{
if (Worker.Status == AsyncWorkerStatusEnum.Running)
{
// Stop worker
Worker.Stop();
}
}
RaiseCancel(this, e);
}
#endregion
#region "IPostbackEventHandler"
///
/// Processes the postback event
///
/// Event argument
public void RaisePostBackEvent(string eventArgument)
{
var e = new EventArgs();
switch (eventArgument)
{
case "finished":
RaiseFinished(this, e);
break;
case "error":
RaiseError(this, e);
break;
}
}
#endregion
}