How to coordinate 3 threads executing (UI done with DevExpress) - c#

Here is my problem:
I have a Wcf service on a server that has two methods:
Synchronize() and GetExecutionState().
I also have a client that is to call those operations.
The Synchronize() executes lots of things and in several steps so at each step i update a local (inside the wcf) variable and i publish this variable via the GetExecutionState() operation The operation can fail, can take eons to execute and so on.
So, when i consume this service on the client, say on somebutton_click() event,
what i want to happen is this:
show infinite progressbar (main thread, UI);
start a thread to run Synchronize();
start another thread to keep reading GetExecutionState() every x minutes and in the event of a connection failure (which is the main reason i need this last thread) cancel the whole thing.
I dont know lot about threading, but so far i have implemented 1 and 2. Can someone help me with 3?
I am using devExpress and here is my relevant code.
SERVER PART:
public class SyncServerService :ISyncServer {
protected CsNo Node;
protected SyncState State;
public SyncServerService() {
State = SyncState.None;
Node = null;
}
public SyncState OperationState() {
return State;
}
public void PutComputerName(string value) {
var man = new CsNoManager();
Node = man.GetByMachineName(value);
}
public bool CanSync() {
var man = new ViewSyncLogManager();
var log = man.GetByMachineName(Node.MachineName);
return !log[0].IsInSync;
}
public CommandExecutionResponse Synchronize() {
CommandExecutionResponse res = null;
var logManager = new CsLogSyncManager();
var log = logManager.GetByNode(Node.IDNo);
State=SyncState.Syncing;
//step 1
State = SyncState.State2;
//...step n
State = SyncState.SomeOtherState;
//somewhere along the path create the res object
return res;
}
}
I read somewhere that with WCF, i can call operations both sync and async, so i dont think i have to mess with the server part regarding my requirements.
Client part:
On the button click that starts the process:
private void cmdSync_Click(object sender, EventArgs e) {
pgbSync.Properties.Stopped = false;
backgroundWorker1.RunWorkerAsync();
}
pgbSync is of type MarqueeProgressBar, a DevExpress progressbar that has infinite loop
backgroundWorker1 is of type System.ComponentModel.BackgroundWorker...supposedly runs tasks on the background.
It's start and finish methods are:
START:
private void StartSync(object sender, DoWorkEventArgs e) {
try {
//setting up wcf link properties
var manager = new CsConfiguracaoManager();
var address = manager.SyncAppServiceAddress();
var binding = new NetTcpBinding {
Security = new NetTcpSecurity() { Mode = SecurityMode.None },
CloseTimeout = new TimeSpan(0, 0, 30, 0, 0),
OpenTimeout = new TimeSpan(0, 0, 30, 0, 0),
ReceiveTimeout = new TimeSpan(0, 0, 30, 0, 0),
SendTimeout = new TimeSpan(0, 0, 30, 0, 0)
};
var factory = new ChannelFactory<ISyncServer>(binding, new EndpointAddress(address));
var proxy = factory.CreateChannel();
proxy.PutComputerName(PcName);
//checking if i can sync first
if (proxy.CanSync() == true) {
ExecutionResponse = proxy.Sync();
}
else {
//set up messages to show errors
}
}
catch (DataException dataErr) {
//set up appropriate messages
}
catch (EndpointNotFoundException err) {
//set up appropriate messages
}
catch (Exception masterErr) {
//set up appropriate messages
}
}
FINISH:
private void FinishSync(object sender, RunWorkerCompletedEventArgs e) {
pgbSync.Properties.Stopped = true;
//process ExecutionResponse object from FinishSync
}
This all runs, but if i disconnect the network after the process has started (we are anticipating lots of communication issues) the process will only throw an exception after the 30 minutes set in the service have passed.
Thats why i want to introduce a 3rd step where i check every x minutes for the output of OperationState.
If i cannot read it, i abort the operation, if it has a null or err state i also stop.
Any ideas?

I am note sure if you need a 3rd thread for this.
Have you tried System.Timers.Timer to have an event generated every x seconds and doing your checks?
If that event does not occur you can go with a BackgroundWorker which will have a loop with Thread.Sleep(250) and cancelation checks.

Related

How to asynchronously write CD/DVD using IMAPI?

I have been told to write a software to burn a CD synchronously/asynchronously as per user choice. I am using IMAPIv2 with C# for the project, and it does not provide the functionality explicitly to write the data asynchronously.
In order to design the functionality, I have researched online resources, but in vain.
Can someone explain what Synchronous/Asynchronous I/O is, in terms of burning an image on a disc?
Any help is appreciated.
IMAPI does not provide in-build class/method to write data asynchronously. But it is designed a way that it is possible with any technology that supports asynchronous programming. The one you are using (C# as you mentioned in comments) does support it.
IMAPI exposes interfaces those report status for progress and actions. All you need to do is use the threading to run the activity asynchronously; this will free up your UI and you can perform other activities. Then, you may subscribe for the events those will report the status to you.
Refer this project on CodeProject which uses BackgroundWorker for the same:
Multithreading
Burning or formatting media can take some time, so we do not want to perform these actions on the main UI thread. I use the BackgroundWorker class to handle the multithreading of these lengthy tasks. The BackgroundWorker class allows you to set values within the thread and then call the ReportProgress method which fires a ProgressChanged event in the calling thread. When you are finished with your worker thread, it fires the RunWorkerCompleted event to notify the calling thread that it is finished.
Following are DoWork and Update events:
private void backgroundBurnWorker_DoWork(object sender, DoWorkEventArgs e)
{
MsftDiscRecorder2 discRecorder = null;
MsftDiscFormat2Data discFormatData = null;
try
{
//
// Create and initialize the IDiscRecorder2 object
//
discRecorder = new MsftDiscRecorder2();
var burnData = (BurnData)e.Argument;
discRecorder.InitializeDiscRecorder(burnData.uniqueRecorderId);
//
// Create and initialize the IDiscFormat2Data
//
discFormatData = new MsftDiscFormat2Data
{
Recorder = discRecorder,
ClientName = ClientName,
ForceMediaToBeClosed = _closeMedia
};
//
// Set the verification level
//
var burnVerification = (IBurnVerification)discFormatData;
burnVerification.BurnVerificationLevel = _verificationLevel;
//
// Check if media is blank, (for RW media)
//
object[] multisessionInterfaces = null;
if (!discFormatData.MediaHeuristicallyBlank)
{
multisessionInterfaces = discFormatData.MultisessionInterfaces;
}
//
// Create the file system
//
IStream fileSystem;
if (!CreateMediaFileSystem(discRecorder, multisessionInterfaces, out fileSystem))
{
e.Result = -1;
return;
}
//
// add the Update event handler
//
discFormatData.Update += discFormatData_Update;
//
// Write the data here
//
try
{
discFormatData.Write(fileSystem);
e.Result = 0;
}
catch (COMException ex)
{
e.Result = ex.ErrorCode;
MessageBox.Show(ex.Message, "IDiscFormat2Data.Write failed",
MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
if (fileSystem != null)
{
Marshal.FinalReleaseComObject(fileSystem);
}
}
//
// remove the Update event handler
//
discFormatData.Update -= discFormatData_Update;
if (_ejectMedia)
{
discRecorder.EjectMedia();
}
}
catch (COMException exception)
{
//
// If anything happens during the format, show the message
//
MessageBox.Show(exception.Message);
e.Result = exception.ErrorCode;
}
finally
{
if (discRecorder != null)
{
Marshal.ReleaseComObject(discRecorder);
}
if (discFormatData != null)
{
Marshal.ReleaseComObject(discFormatData);
}
}
}
void discFormatData_Update([In, MarshalAs(UnmanagedType.IDispatch)] object sender,
[In, MarshalAs(UnmanagedType.IDispatch)] objectprogress)
{
//
// Check if we've cancelled
//
if (backgroundBurnWorker.CancellationPending)
{
var format2Data = (IDiscFormat2Data)sender;
format2Data.CancelWrite();
return;
}
var eventArgs = (IDiscFormat2DataEventArgs)progress;
_burnData.task = BURN_MEDIA_TASK.BURN_MEDIA_TASK_WRITING;
// IDiscFormat2DataEventArgs Interface
_burnData.elapsedTime = eventArgs.ElapsedTime;
_burnData.remainingTime = eventArgs.RemainingTime;
_burnData.totalTime = eventArgs.TotalTime;
// IWriteEngine2EventArgs Interface
_burnData.currentAction = eventArgs.CurrentAction;
_burnData.startLba = eventArgs.StartLba;
_burnData.sectorCount = eventArgs.SectorCount;
_burnData.lastReadLba = eventArgs.LastReadLba;
_burnData.lastWrittenLba = eventArgs.LastWrittenLba;
_burnData.totalSystemBuffer = eventArgs.TotalSystemBuffer;
_burnData.usedSystemBuffer = eventArgs.UsedSystemBuffer;
_burnData.freeSystemBuffer = eventArgs.FreeSystemBuffer;
//
// Report back to the UI
//
backgroundBurnWorker.ReportProgress(0, _burnData);
}

Call Web API for 30K times within one hour of time period

I need to call Web API(Hosted on different network) from windows application from users machine for 30,000 times within one hour of time span.
I tried Multithreading to achieve the same but it is not working(giving system out of memory exceprion).
I used TreadPool as below
private static object threadLock = new object();
public delegate void BarDelegate();
int ThreadCount = dtExcel.Rows.Count;
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < ThreadCount - 1; i++)
{
ThreadPool.QueueUserWorkItem(output => CallAPI());
}
}
public void CallAPI()
{
string branchCode = "",
para1 = dtExcel.Rows[progressBar.Value]["para1"].ToString(),
para2 = "324",
para3 = "Test",
para4 = dtExcel.Rows[progressBar.Value]["para4"].ToString();
//Console.WriteLine(Thread.CurrentThread.Name + ": " + progressBar.Value);
var service = new APIService();
var resp = service.CallAPIService(para1, para2, para3, para4, para5);
if (resp.IsSuccess == true)
{
DataGridViewRow dtGrdVwR = dataGrid.Rows[progressBar.Value];
dtGrdVwR.Cells[3].Value = "Success";
}
else
{
DataGridViewRow dtGrdVwR = dataGrid.Rows[progressBar.Value];
dtGrdVwR.Cells[3].Value = "Failed: "+ resp.Message;
}
try
{
this.Invoke(new BarDelegate(UpdateBar));
}
catch
{
}
}
private void UpdateBar()
{
lblEndTime.Text = DateTime.Now.ToString();
progressBar.Value++;
if (progressBar.Value == progressBar.Maximum)
{
// We are finished and the progress bar is full.
}
}
Here dtExcel has 30,000 records(Uploaded by user from excel) which needs to processed within one hour and update the status of executed record in respective row in dataGrid.
The API call is made over network where single call takes approximate 1 to 2 seconds to execute.
service.CallAPIService(para1, para2, para3, para4, para5);
The above method internally performs heavy task like request encryption and digital signature and response decryption and digital signature verification.
Please help me with the best way possible where i can perform the task within time period and without getting SystemOutOfmemoryException.
Thanks in Advance.
Right now your code is horribly broken because of the race condition accessing progressBar.Value. It's pointless to discuss any other issues, because you are going to totally reorganize your code to fix the race condition, rendering other comments obsolete.
Fix it so that you don't have N threads all trying to process item #1, and then ask a new question with your new code.

Windows Service is Running but not executing code

We have windows service which is running fine untill any exceptions occured in the process.
It contains two Threads (GenerateInvoice and GenerateReport).
These threads are getting blocked and results in DeadLock like situation mostly when there is high CPU usage on our DataBase server.
We have done some changes in code to handle such situations like added while condition below code but still it is not working.
Below is the OnStart() method of service:
protected override void OnStart(string[] args)
{
try
{
log.Debug("Starting Invoice Generation Service");
_thread = new Thread(new ThreadStart((new GenerateInvoice()).Process));
_thread.IsBackground = true;
_thread.Start();
_reportThread = new Thread(new ThreadStart((new GenerateReport()).Process));
_reportThread.IsBackground = true;
_reportThread.Start();
}
catch (Exception ex)
{
log.Error("Error in Invoice Generation Service:", ex);
}
}
Here is the processing code of first thread: GenerateInvoice
public void Process()
{
while (isProcessActive)
{
try
{
DBBilling obj = new DBBilling();
DataTable dtInvoiceID = obj.readData(#"SELECT * FROM (SELECT ird.BillByType, ird.InvoiceID, ir.BeginDate, ir.EndDate, ir.SendToQB, ir.SendEmail,
i.ARAccountID, i.ARAccountHotelID, i.invoiceNumber,i.[STATUS],UPDATETIME,row_number() over (PARTITION BY ird.INVOICEID ORDER BY UPDATETIME DESC) AS row_number
FROM Invoices i JOIN InvoicesRunRequestDetails ird ON ird.InvoiceID=i.InvoiceID
JOIN InvoicesRunRequest ir ON ird.RequestID = ir.RequestID
Where i.[STATUS] = 'PENDING') AS rows
WHERE ROW_NUMBER=1 ORDER BY UPDATETIME");
processCounter = 0;
#region process
if (dtInvoiceID != null && dtInvoiceID.Rows.Count > 0)
{
//some code here..
}
#endregion
}
catch (Exception ex) //Mantis 1486 : WEBPMS1 Disk Space : 10 Aug 2016
{
log.ErrorFormat("Generate Invoice -> Process -> InnLink Billing Execute Query Exception. Error={0}", ex);
if(DBBilling.dbConnTimeoutErrorMessage.Any(ex.Message.Contains))
{
processCounter++;
if (processCounter >= 1) //Need to change to 25 after Problem Solve
{
isProcessActive = false;
log.ErrorFormat("Generate Invoice -> Process -> RunInvoice Service exiting loop"); //From here control is not going back
}
else
System.Threading.Thread.Sleep(5000); //Sleep for 5 Sec
}
}
}
}
Processing of Second Thread i.e. GenerateReport code:
public void Process()
{
AppSettingsReader ar = new AppSettingsReader();
string constr = (string)ar.GetValue("BillingDB", typeof(string));
SqlConnection con = new SqlConnection(constr);
while (isProcessActive)
{
try
{
DBBilling obj = new DBBilling();
DataTable dtReportRunID = obj.readData(#"SELECT ReportRunID,MonYear, BeginDate, EndDate FROM ReportRunRequest
Where [STATUS] = 'PENDING' ORDER BY ReportRunID");
processCounter = 0;
if (dtReportRunID != null && dtReportRunID.Rows.Count > 0)
{
//some code here..
}
}
catch (Exception ex) //Mantis 1486 : WEBPMS1 Disk Space : 10 Aug 2016
{
log.ErrorFormat("Generate Report -> Process -> InnLink Billing Execute Query Exception. Error={0}", ex);
if (DBBilling.dbConnTimeoutErrorMessage.Any(ex.Message.Contains))
{
processCounter++;
if (processCounter >= 1) //Need to change to 25 after Problem Solve
{
isProcessActive = false;
log.ErrorFormat("Generate Report -> Process -> RunInvoice Service Exiting loop"); //From here control is not going back
}
else
System.Threading.Thread.Sleep(5000); //Sleep for 5 Sec
}
}
}
}
What possible solution to avoid such conditions?
The way to avoid it is to either lock every access to a global variable, or not to use global variables.
here is one obvious example
DBBilling.dbConnTimeoutErrorMessage.Any(ex.Message.Contains)
dbConnTimeoutErrorMessage is a static field that is being used from two different threads and I assume is not thread safe, surround access to it with a
lock(locObj)
{
// access to dbConnTimeoutErrorMessage
}
I am gonna go ahead and guess that log is also a global variable. Perhaps maybe even isProcessActive or processCounter.
I am guessing there is more in those comments - make sure your code is threadsafe before using it with two different threads.
I doubt locking access to what I said will fix your problem, but I guess your lack of threadsafe programming in these is a symptom to not using lock when it is needed. The secret is to lock every access to a global context, and just that.
What i suggest is to use Timer instead of infinite loop and as mentioned earlier in other answere you need some kind of synchronization. First of all, you need to implement your variables which used in different threads as follows (i don't know exactly definitions of your variables, but main idea is to use volatile keyword in your case):
public static volatile bool isProcessActive;
public static volatile int proccessCounter;
volatile keyword switches off the compiler optimizations for using variable in one thread. It means that your variables now are thread safe.
Next you need to use neither System.Threading.Timer or System.Timers.Timer. I will use in my example second one.
public sealed class GenerateInvoice :
{
protected const int timerInterval = 1000; // define here interval between ticks
protected Timer timer = new Timer(timerInterval); // creating timer
public GenerateInvoice()
{
timer.Elapsed += Timer_Elapsed;
}
public void Start()
{
timer.Start();
}
public void Stop()
{
timer.Stop();
}
public void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
DBBilling obj = new DBBilling();
DataTable dtInvoiceID = obj.readData(#"SELECT * FROM (SELECT ird.BillByType, ird.InvoiceID, ir.BeginDate, ir.EndDate, ir.SendToQB, ir.SendEmail,
i.ARAccountID, i.ARAccountHotelID, i.invoiceNumber,i.[STATUS],UPDATETIME,row_number() over (PARTITION BY ird.INVOICEID ORDER BY UPDATETIME DESC) AS row_number
FROM Invoices i JOIN InvoicesRunRequestDetails ird ON ird.InvoiceID=i.InvoiceID
JOIN InvoicesRunRequest ir ON ird.RequestID = ir.RequestID
Where i.[STATUS] = 'PENDING') AS rows
WHERE ROW_NUMBER=1 ORDER BY UPDATETIME");
processCounter = 0;
#region process
if (dtInvoiceID != null && dtInvoiceID.Rows.Count > 0)
{
//some code here..
}
#endregion
}
catch (Exception ex) //Mantis 1486 : WEBPMS1 Disk Space : 10 Aug 2016
{
log.ErrorFormat("Generate Invoice -> Process -> InnLink Billing Execute Query Exception. Error={0}", ex);
if(DBBilling.dbConnTimeoutErrorMessage.Any(ex.Message.Contains))
{
processCounter++;
if (processCounter >= 1) //Need to change to 25 after Problem Solve
{
isProcessActive = false;
// supposing that log is a reference type and one of the solutions can be using lock
// in that case only one thread at the moment will call log.ErrorFormat
// but better to make synchronization stuff unside logger
lock (log)
log.ErrorFormat("Generate Invoice -> Process -> RunInvoice Service exiting loop"); //From here control is not going back
}
else
// if you need here some kind of execution sleep
// here you can stop timer, change it interval and run again
// it's better than use Thread.Sleep
// System.Threading.Thread.Sleep(5000); //Sleep for 5 Sec
}
}
}
}
Use the same approach for the GenerateReport to make Timer-based.
And, finally, you need to change your OnStart and OnStop methods something like so:
protected GenerateInvoice generateInvoice;
protected GenerateReport generateReport;
protected override void OnStart(string[] args)
{
// all exception handling should be inside class
log.Debug("Starting Invoice Generation Service");
generateInvoice = new GenerateInvoice();
generateInvoice.Start();
generateReport = new GenerateReport();
generateReport.Start();
}
protected override void OnStop()
{
generateInvoice.Stop();
generateReport.Stop();
}

Getting the C# BackgroundWorker process to invoke Pings

Read through most (all?) of the answered questions regarding the C# BackgroundWorker but none seemed to apply to this situation. If I missed one, please point me in that direction!
Anyway, I having troubles getting the Ping process to run as a background process. I made a simple form application to send pings and report back. That worked fine but it would only results results to the user after the pings were complete -- thus the need to a background process. I am somewhat new to C# and was unfamiliar with the particulars of BackgroundWorker. However found a helpful walkthrough from Microsoft here: http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx
I am now attempting to get the same process to apply to a System.Net.NetworkInformation object instead of a System.IO.StreamReader object. I think I am really close (read: I can get the app to build and run) but I consistently get an error at runtime (see below).
This is the Microsoft code for their sample app. It works like a champ:
The method in MainForm.cs that calls the Words.cs class referenced in the walkthrough
void backgroundWorker1DoWork(object sender, DoWorkEventArgs e)
{
System.ComponentModel.BackgroundWorker worker;
worker = (System.ComponentModel.BackgroundWorker)sender;
Words WC = (Words)e.Argument;
WC.CountWords(worker, e);
}
The relevant method in the 'Words.cs' class
public void CountWords(
System.ComponentModel.BackgroundWorker worker,
System.ComponentModel.DoWorkEventArgs e)
{
// Initialize the variables.
CurrentState state = new CurrentState();
string line = "";
int elapsedTime = 20;
DateTime lastReportDateTime = DateTime.Now;
if (CompareString == null ||
CompareString == System.String.Empty)
{
throw new Exception("CompareString not specified.");
}
// Open a new stream.
using (System.IO.StreamReader myStream = new System.IO.StreamReader(SourceFile))
{
// Process lines while there are lines remaining in the file.
while (!myStream.EndOfStream)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
line = myStream.ReadLine();
WordCount += CountInString(line, CompareString);
LinesCounted += 1;
// Raise an event so the form can monitor progress.
int compare = DateTime.Compare(
DateTime.Now, lastReportDateTime.AddMilliseconds(elapsedTime));
if (compare > 0)
{
state.LinesCounted = LinesCounted;
state.WordsMatched = WordCount;
worker.ReportProgress(0, state);
lastReportDateTime = DateTime.Now;
}
}
// Uncomment for testing.
System.Threading.Thread.Sleep(5);
}
// Report the final count values.
state.LinesCounted = LinesCounted;
state.WordsMatched = WordCount;
worker.ReportProgress(0, state);
}
}
When I try a similar process (sending a Ping instead of a reading a file) I get this error:
Error: Object reference not set to an instance of an object.
Details: System.Collections.ListDictionaryInternal //This is defined in the MyApp namespace as: using System.Collections
Source: MyApp
StackTrack: at MyApp.MainForm.Bw01DoWork(Object sender, DoWorkEventArgs e) in
[path]\MainForm.cs:line 152
at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
Target: Void Bw01DoWork(System.Object, System.ComponentModel.DoWorkEventArgs)
Here is my method. Line 152 referenced in the error is the very last line of the last method in MainForm.cs (the var names are different, but you get the idea):
void Bw01DoWork(object sender, DoWorkEventArgs e)
{
System.ComponentModel.BackgroundWorker worker;
worker = (System.ComponentModel.BackgroundWorker)sender;
PTResults PR = (PTResults)e.Argument;
PR.SendPings(worker, e); // Line 152
}
And the relevant portion of the PTResults.cs class:
using (Ping newPing = new Ping())
{
PingReply reply = newPing.Send([Target Site],[Timeout]);
if(reply.Status == IPStatus.Success)
{
state.PingOK = true;
}
else if(reply.Status == IPStatus.TimedOut)
{
state.PingOK = false;
state.PingUpdateState = " Timed Out";
}
else if(reply.Status != IPStatus.Success)
{
state.PingOK = false;
state.PingUpdateState = " FAILED";
}
else
{
state.PingOK = false;
state.PingUpdateState = " UNKNOWN";
}
worker.ReportProgress(0, state.PingOK);
}
I am thinking the System.Net.NetworkInformation.Ping component cannot be invoked the same way System.IO.StreamReader is. Thoughts?
I doubt it makes a difference but FWIW I am coding in SharpDevelop on a Windows 8.1 system.
Take a look at the Ping SendAsync, you may be able to eliminate most of your code - just call PingAsync, and handle the result being sure to dispatch it to the UI thread and then re-queue another call.
http://msdn.microsoft.com/en-us/library/ms144961(v=vs.110).aspx

C# Cancelling ServiceController Service State Change Request

I've not been able to find any information on this, so I apologize if this is a duplicate.
I'm using an ASP website to trigger a WebMethod on my code behind that will trigger the service on the computer to change its state to some state specified on the front-end.
However, I want to make it so that when I call ServiceController.WaitForStatus() on Timeout it returns to the default status it started with prior to the call. So, if something doesn't start/pause/stop fast enough it'll revert to its previous state like nothing happened.
Is there a way to do this? I tried calling ServiceController.close() and that did nothing for me.
Is there a way to manage this gracefully so that if the timeout exception occurs it catches the exception gracefully and returns the service back to its original state prior to the service controller call.
This is the web method code I'm using:
[WebMethod]
public static string ToggleService(string serverName, string serviceName, string newServiceState) {
ServiceController serviceToToggle = null;
if (newServiceState.ToLower().Equals("start")
|| newServiceState.ToLower().Equals("pause")
|| newServiceState.ToLower().Equals("stop")) {
serviceToToggle = new ServiceController(serviceName, serverName);
}
if (serviceToToggle != null)
{
try
{
if (serviceToToggle.Status == ServiceControllerStatus.Paused)
{
if (newServiceState.ToLower().Equals("start"))
{
serviceToToggle.Start();
serviceToToggle.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 1));
}
else if (newServiceState.ToLower().Equals("stop"))
{
serviceToToggle.Stop();
serviceToToggle.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 1));
}
}
else if (serviceToToggle.Status == ServiceControllerStatus.Running)
{
if (newServiceState.ToLower().Equals("pause"))
{
serviceToToggle.Pause();
serviceToToggle.WaitForStatus(ServiceControllerStatus.Paused, new TimeSpan(0, 0, 1));
}
else if (newServiceState.ToLower().Equals("stop"))
{
serviceToToggle.Stop();
serviceToToggle.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 1));
}
}
else if (serviceToToggle.Status == ServiceControllerStatus.Stopped)
{
if (newServiceState.ToLower().Equals("start"))
{
serviceToToggle.Start();
serviceToToggle.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 1));
}
}
return "\"OutputStatus\": \"Success\"";
}
catch (Exception e) {
serviceToToggle.Close();
return "\"OutputStatus\": \"Failed\"";
}
}
return "No service to toggle";
}
I would appreciate any help or insight into this.
In short, no - there is no way to revert or cancel a command already sent to a service.
You could write code to remember the previous state, and initiate a controller request to set that state again if something goes awry or times out, but it doesn't sound particularly robust.
If they're your own services, it's better to write them to properly respond to service requests.

Categories