Good morning every body.
I have developing a C# WinForms simple aplication to manage "Apache" windows service, i can start, stop and other operations.
My Scenario:
I open the apache config file and change any line, i made it to causes error configuration (i know it).
When i try start Apache service, this cant start, because the config file syntax is incorrect (i know it).
The message error from the services is registered in Windows Events Viewer (i know it).
I want get this message in my C# WinForms Application, it is posible?
My code:
public void ManageService(string serviceName, int Operation)
{
ServiceController sc = new ServiceController();
sc.ServiceName = serviceName;
try
{
switch (Operation)
{
case 1: sc.Stop(); ; break;
case 2: sc.Start(); break;
}
}
catch (InvalidOperationException e)
{
}
}
How to modify this code to catch messages from the apache service.
PD. Sorry if my english is bery bad ;).
Okay, not a answer per-say but don't know how to place this into a comment. Note the use of WaitForStatus and also a property for error messages. This is fairly bare-bones.
using System;
using System.Linq;
using System.ServiceProcess;
namespace Revenue.Common.Utility
{
public class WindowsServices
{
private string _ErrorMessage;
public string ErrorMessage { get { return _ErrorMessage; } }
/// <summary>
/// Stop a Windows service service name
/// </summary>
/// <param name="ServiceName"></param>
/// <remarks>
/// A service does not stop instantly, so WaitForStatus method
/// is used to 'wait' until the service has stopped. If the
/// caller becomes unresponsive then there may be issues with
/// the service stopping outside of code.
/// </remarks>
public void StopService(string ServiceName)
{
ServiceController sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName == ServiceName);
if (sc == null)
return;
if (sc.Status == ServiceControllerStatus.Running)
{
try
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
catch (InvalidOperationException e)
{
_ErrorMessage = e.Message;
}
}
}
/// <summary>
/// Start a Windows service by service name
/// </summary>
/// <param name="ServiceName"></param>
public void StartService(string ServiceName)
{
ServiceController sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName == ServiceName);
if (sc == null)
return;
sc.ServiceName = ServiceName;
if (sc.Status == ServiceControllerStatus.Stopped)
{
try
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (InvalidOperationException)
{
_ErrorMessage = e.Message;
}
}
}
}
}
Related
I am writing unit tests for my SignalR hubs and using the SignalR .NET client (version 2.3.0) to carry out the tests, but I am not able to get other connections to receive a broadcast when the current connection is excluded from the broadcast.
The hub method is making a broadcast as such:
Clients.Group(groupName, Context.ConnectionId).sendMessage("A message");
My test is configured to have 2 connections to the hub and each connection will call a hub method that will put the connection into groupName. I then have a HubConnection.On event to handle the broadcast the hub method makes, the result of which is then used to assert the test. This might be clearer explained in code (I have removed some AddBroadcast overloads for brevity):
/// <summary>
/// Class to handle the connection, calling of methods and broadcast for a SignalR hub
/// </summary>
public class HubManager
{
public enum Froms
{
Other1,
Other2
}
private HubConnection hubConnection = null;
private IHubProxy hub = null;
/// <summary>
/// The outcome of the broadcast that is made
/// </summary>
public object Result { get; private set; } = null;
/// <summary>
/// The connection ID of this hub connection
/// </summary>
public string ConnectionID { get { return this.hubConnection.ConnectionId; } }
public HubManager(string h)
{
//Create the SignalR connection
this.hubConnection = new HubConnection("http://mywebsite.com");
//Gain access to the hub
this.hub = hubConnection.CreateHubProxy(h);
//Start the connection up and wait for it to complete
this.hubConnection.Start()
.ContinueWith(task =>
{
if (task.IsFaulted)
{
throw new Exception($"Error opening the hub connection ({h}): {task.Exception.GetBaseException()}");
}
})
.Wait();
}
/// <summary>
/// Broadcast a message to clients
/// </summary>
/// <param name="methodName">The name of broadcast message</param>
public void AddBroadcast(string methodName)
{
this.hub.On(methodName, () => {
this.Result = methodName;
});
}
/// <summary>
/// Broadcast a message to clients
/// </summary>
/// <param name="methodName">The name of broadcast message</param>
public void AddBroadcast<T>(string methodName)
{
this.hub.On<T>(methodName, _1 => {
this.Result = _1;
});
}
/// <summary>
/// Invokes a specific hub method
/// </summary>
/// <param name="methodName">The name of the hub method to invoke</param>
/// <param name="args">The parameters for the method</param>
public void CallMethod(string methodName, params object[] args)
{
this.hub.Invoke(methodName, args)
.ContinueWith(task =>
{
if (task.IsFaulted)
{
throw new Exception($"Error calling hub method {methodName}: {task.Exception.GetBaseException()}");
}
})
.Wait();
}
}
Usage case:
//Create a dictionary to hold the connections
var hubManagers = new Dictionary<HubManager.Froms, HubManager>();
hubManagers.Add(HubManager.Froms.Other1, new HubManager(hubName));
hubManagers.Add(HubManager.Froms.Other2, new HubManager(hubName));
//Call HubMethod1 which will add the connection to the same group
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod1", user1ID);
hubManagers[HubManager.Froms.Other2].CallMethod("HubMethod1", user2ID);
//Set a broadcast handle for the second connection (Other2)
hubManagers[HubManager.Froms.Other2].AddBroadcast<string, string>("callbackMethod");
//Make a hub method call (from Other1) to cause the callbackMethod to run
//As from above, the Other1 connection should not receive it but Other2 should
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod2", user1ID);
//Get the broadcast result for the second connection (Other2)
var result = hubManagers[HubManager.Froms.Other2].Result;
//result == null
I have tried using the AdddBroadcast on the following combinations and each case results in result being null: Other1, Other2 and Other1 & Other2.
If I change Clients.Group(groupName, Context.ConnectionId).sendMessage("A message"); to not exclude the current connection (Clients.Group(groupName).sendMessage("A message");) and I use AddBroadcast on Other2, result contains the expected value.
The process works as expected on the live system (using ASP.NET and JavaScript) where the calling connection does not get sent the sendMessage but the other members of the group do.
Any ideas on how I make the second SignalR .NET client connection receive the broadcast when the first connection is excluded from the broadcast are very much welcomed!
After some time, I realised that the this.hub.On event was firing, but after the call to get the result (var result = hubManagers[HubManager.Froms.Other2].Result;). I therefore added a crude wait method (which I am not massively proud of!) and that has done the trick.
New method:
/// <summary>
/// Wait for up to 5 seconds for the broadcast to complete
/// </summary>
public void WaitForBroadcastResult()
{
bool stop = false;
const double WAIT_FOR = 5D;
DateTime started = DateTime.Now;
while (!stop)
{
if (this.Result != null || (DateTime.Now - started).TotalSeconds >= WAIT_FOR)
{
stop = true;
}
else
{
System.Threading.Thread.Sleep(100);
}
}
}
Use:
...
//Set a broadcast handle for the second connection (Other2)
hubManagers[HubManager.Froms.Other2].AddBroadcast<string, string>("callbackMethod");
//Make a hub method call (from Other1) to cause the callbackMethod to run
//As from above, the Other1 connection should not receive it but Other2 should
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod2", user1ID);
//Wait for the broadcast to complete
this.HubManagers[_HubManager.Froms.Other2].WaitForBroadcastResult();
//Get the broadcast result for the second connection (Other2)
var result = hubManagers[HubManager.Froms.Other2].Result;
If anybody has a better idea, then I'm all ears!
I'm trying to write a log class to log to a file, however I keep getting issues with the logging due to different threads trying to log at the same time.
A first chance exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Log.Diag.<DebugPrint>d__0.MoveNext()
Here is my code:
public static async void DebugPrint(string msg, LogLevel level)
{
if (ShouldLog(level))
{
#if DEBUG
// Only do this in debug
Debug.WriteLine(msg);
#endif
#if !DEBUG // Never crash in release build
try
{
#endif
if (sFile == null && !(await GetLogFile()))
{
throw new FileNotFoundException("Cannot create ms-appdata:///local/log.txt");
}
try
{
await Windows.Storage.FileIO.AppendTextAsync(sFile, ComposeMessage(msg, level));
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
#if !DEBUG
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
#endif
}
}
/// <summary>
/// Initialise the log file.
/// </summary>
/// <returns></returns>
private async static Task<bool> GetLogFile()
{
try
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
sFile = await localFolder.CreateFileAsync("log.txt", CreationCollisionOption.OpenIfExists);
return true;
}
catch (Exception)
{
return false;
}
}
What can I do to ensure that all threads can log to the file?
Here is how I did it using event tracing.
Task.cs
sealed class LogEventSource : EventSource
{
public static LogEventSource Log = new LogEventSource();
[Event(1, Level = EventLevel.LogAlways)]
public void Debug(string message)
{
this.WriteEvent(1, message);
}
}
/// <summary>
/// Storage event listner to do thread safe logging to a file.
/// </summary>
sealed class StorageFileEventListener : EventListener
{
private object syncObj = new object();
private List<string> logLines;
private StorageFile logFile;
private ThreadPoolTimer periodicTimer;
public StorageFileEventListener()
{
Debug.WriteLine("StorageFileEventListener for {0}", GetHashCode());
logLines = new List<string>();
}
// Should be called right after the constructor (since constructors can't have async calls)
public async Task InitializeAsync()
{
logFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("logs.txt", CreationCollisionOption.OpenIfExists);
// We don't want to write to disk every single time a log event occurs, so let's schedule a
// thread pool task
periodicTimer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
{
// We have to lock when writing to disk as well, otherwise the in memory cache could change
// or we might try to write lines to disk more than once
lock (syncObj)
{
if (logLines.Count > 0)
{
// Write synchronously here. We'll never be called on a UI thread and you
// cannot make an async call within a lock statement
FileIO.AppendLinesAsync(logFile, logLines).AsTask().Wait();
logLines = new List<string>();
}
}
CheckLogFile();
}, TimeSpan.FromSeconds(5));
}
private async void CheckLogFile()
{
BasicProperties p = await logFile.GetBasicPropertiesAsync();
if(p.Size > (1024 * 1024))
{
// TODO: Create new log file and compress old.
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
// This could be called from any thread, and we want our logs in order, so lock here
lock (syncObj)
{
logLines.Add((string)eventData.Payload[0]);
}
}
}
Wrapped in a logging class.
/// <summary>
/// A static class for help with debugging and logging.
/// </summary>
public static class Log
{
public enum LogLevel {
NONE = 0,
FATAL,
ERROR,
INFO,
DEBUG,
VERBOSE,
TRACE
};
private static StorageFileEventListener eventListener;
#if DEBUG
public static LogLevel logLevel = LogLevel.DEBUG;
#else
public static LogLevel logLevel = LogLevel.NONE;
#endif
/// <summary>
/// Print out the debug message.
/// </summary>
/// <param name="msg">Message to print</param>
/// <param name="level">Debug level of message</param>
public async static void DebugPrint(string msg, LogLevel level)
{
if (ShouldLog(level))
{
msg = ComposeMessage(msg, level);
#if DEBUG
// Only do this in debug
Debug.WriteLine(msg);
#endif
#if !DEBUG // Never crash in release build
try
{
#endif
if (eventListener == null)
{
eventListener = new StorageFileEventListener();
eventListener.EnableEvents(LogEventSource.Log, EventLevel.LogAlways);
await eventListener.InitializeAsync();
}
LogEventSource.Log.Debug(msg);
#if !DEBUG
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
#endif
}
}
/// <summary>
/// Construc the formatted log message
/// </summary>
/// <param name="msg">Main message</param>
/// <param name="level">Log level</param>
/// <returns>Formated message</returns>
private static string ComposeMessage(string msg, LogLevel level)
{
return DateTime.Now.ToString(#"M/d/yyyy hh:mm:ss.fff tt") + " [" + Environment.CurrentManagedThreadId.ToString("X4") + "] " + LevelToString(level) + " " + msg;
}
/// <summary>
/// Get the string alias for a log level.
/// </summary>
/// <param name="level">The log level</param>
/// <returns>String representation of the log level.</returns>
private static string LevelToString(LogLevel level)
{
string res = "NOT FOUND";
switch (level)
{
case LogLevel.NONE:
throw new Exception("You should not log at this level (NONE)");
case LogLevel.FATAL: res = "FATAL"; break;
case LogLevel.ERROR: res = "ERROR"; break;
case LogLevel.INFO: res = "INFO"; break;
case LogLevel.DEBUG: res = "DEBUG"; break;
case LogLevel.VERBOSE: res = "VERBOSE"; break;
case LogLevel.TRACE: res = "TRACE"; break;
}
return res;
}
/// <summary>
/// Check the passed log level against the current log level
/// to see if the message should be logged.
/// </summary>
/// <param name="level">Log level to check against</param>
/// <returns>True is should be logeed otherwise false.</returns>
private static bool ShouldLog(LogLevel level)
{
if (level <= logLevel)
return true;
else
return false;
}
}
Usage:
Log.DebugPrint("Hello, Thread safe logger!", Log.LogLevel.DEBUG);
In order to avoid concurrency issues you need to use locks.
It would be better to write all the messages into a queue and use a background thread to write the queue into the file. This has many advantages:
easy to make it multithreading saving. Just lock every access to the queue
only 1 thread writing to the file => no more multi threading problems
Adding to the queue is very fast (microseconds) and will hardly lock, while writing to the file does not just create multi threading problems, but might create milliseconds delays or even exceptions.
The logging can start right from the first line of code. Messages are written into the queue, which will only get emptied once file system is ready
About programming Windows services: how to stop my windows service?
Here is a very simplified example code(C#):
// Here is my service class (MyTestService.cs).
public class MyTestService:ServiceBase{
// Constructor.
public MyTestService(){
this.ServiceName = "My Test Service";
return;
}
};
// My application class (ApplicationClass.cs).
public static class ApplicationClass{
// Here is main Main() method.
public static void Main(){
// 1. Creating a service instance
// and running it using ServiceBase.
MyTestService service = new MyTestService();
ServiceBase.Run(service);
// 2. Performing a test shutdown of a service.
service.Stop();
Environment.Exit(0);
return;
};
};
So: I've just created "My Test Service" started it and stopped. But when I'm looking into my Services.msc - "My Test Service" is continues to running and stops ONLY when I click a "Stop" link. Why? - why service.Stop() command does nothing?
ServiceController.Stop() also does nothing!
How can I stop my service from Main() method?
The Stop-function sends a stop-signal. It does not wait till the signal is received and processed.
You will have to wait till the Stop-signal has done it's work. You can do that by calling WaitForStatus:
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped);
See for more info: http://msdn.microsoft.com/nl-nl/library/system.serviceprocess.servicecontroller.waitforstatus(v=vs.71).aspx
Environment.Exit is a nasty one. DO NOT USE IT! It aborts your application the hard way, without performing any cleanup in finally blocks, without calling finalizer methods by the GC, it terminates all other forground threads, etc. I can imagine that your application is aborted before the stop-signal even left your application.
I am using following functions in my project
public static ServiceController GetService(string serviceName)
{
ServiceController[] services = ServiceController.GetServices();
return services.FirstOrDefault(_ => Contracts.Extensions.CompareStrings(_.ServiceName, serviceName));
}
public static bool IsServiceRunning(string serviceName)
{
ServiceControllerStatus status;
uint counter = 0;
do
{
ServiceController service = GetService(serviceName);
if (service == null)
{
return false;
}
Thread.Sleep(100);
status = service.Status;
} while (!(status == ServiceControllerStatus.Stopped ||
status == ServiceControllerStatus.Running) &&
(++counter < 30));
return status == ServiceControllerStatus.Running;
}
public static bool IsServiceInstalled(string serviceName)
{
return GetService(serviceName) != null;
}
public static void StartService(string serviceName)
{
ServiceController controller = GetService(serviceName);
if (controller == null)
{
return;
}
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running);
}
public static void StopService(string serviceName)
{
ServiceController controller = GetService(serviceName);
if (controller == null)
{
return;
}
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped);
}
In your code example service.Stop() and ServiceController.Stop() commands does nothing because they are not called while service is running since ServiceBase.Run(service) is blocking operation and it returns only on stop of the service.
I am handling errors in my controller and I have [CustomErrorHandleAttribute] which I have written what to do when there is an exception in my actions. Even there is no error in my code it is redirecting to customerrorhandle and throwing error. I am not able to find the error why it is doing this.
Here is my code:
namespace ExceptionHandlingInMVC.Controllers
{
[CustomHandleError]
public class HomeController : Controller
{
//
// GET: /Home/
public object Index()
{
try
{
ViewData["Title"] = "Home Page";
ViewData["Message"] = "Current time is:" + DateTime.Now.ToLongTimeString();
var x = 10;
var y = 10;
var result = x / y;
ViewData["Result"] = result;
return View();
}
catch (Exception e)
{
throw e;
}
}
[CustomHandleError]
public object About()
{
ViewData["Title"] = "About Page";
return View();
}
}
public class ErrorPresentation
{
public String ErrorMessage { get; set; }
public Exception TheException { get; set; }
public Boolean ShowMessage { get; set; }
public Boolean ShowLink { get; set; }
}
}
CustomHandleErrorAttribute that i've wrote:
namespace ExceptionHandlingInMVC
{
/// <summary>
/// This attribute (AOP) filter is used to override the Error handling and make sure that all erros are recorded in the event logs, so that they can in turn be picked up by
/// our SIEM tool so that we a) stop customers seing a bad error message and b) we are capturing all the events that happen and c) improives security for
/// by preventing a hacker from seing s=details of how our application is put together
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class CustomHandleErrorAttribute : ActionFilterAttribute
{
/// <summary>
/// This event is called when the action is called i.e. an error has just occured
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
try
{
// Bail if we can't do anything; app will crash.
if (filterContext == null)
return;
// since we're handling this, log to ELMAH(Error logging modules and handler)
var ex = filterContext.Exception ?? new Exception("No further information exists.");
WriteToEventLog(ex);
filterContext.ExceptionHandled = true;
var data = new ErrorPresentation
{
ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
TheException = ex,
ShowMessage = filterContext.Exception != null,
ShowLink = false
};
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Home/ErrorPage.aspx"
};
}
catch (Exception exception)
{
throw;
}
}
/// <summary>
/// This method writes the exception to the event log we have specified in the web.config or the app.config
/// </summary>
/// <param name="exception"></param>
public void WriteToEventLog(Exception exception)
{
// pick up which machine we are on, this will already be set for all websites
var machineName = ConfigurationManager.AppSettings["MachineName"];
// PIck up the eventlog we are going to write to
var eventLogName = ConfigurationManager.AppSettings["EventLogName"];
EventLog.WriteEntry("abc", exception.Message, EventLogEntryType.Error);
}
}
}
You should really be performing your error handling by overriding Application_Error in global.asax. That way you can be sure that your code will only execute when an error occurs. Using OnActionExecuted means that your code will execute regardless or whether or not an error is thrown.
Here's the function:
void Application_Error(object sender, EventArgs e)
{
//do your stuff here
}
Try this:
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
try
{
// Bail if we can't do anything; app will crash.
if (filterContext == null)
return;
// since we're handling this, log to ELMAH(Error logging modules and handler)
if (filterContext.Exception == null || filterContext.ExceptionHandled)
{
var ex = filterContext.Exception ?? new Exception("No further information exists.");
this.WriteToEventLog(ex);
return;
};
filterContext.ExceptionHandled = true;
var data = new ErrorPresentation
{
ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
TheException = ex,
ShowMessage = filterContext.Exception != null,
ShowLink = false
};
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Home/ErrorPage.aspx"
};
}
catch (Exception exception)
{
throw;
}
}
if there is no exeption you need to return, because this attribute fires every time, not only when you have an error.
update:
I suggest to you write code below in global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomErrorHandle());
}
to fire this attibute to all actions. So you don't need to write attribute to any action.
Event should be fired when there is error only and I am writing to eventlog:
In my global.asax I added the following code:
/// <summary>
/// Managing errors from a single location
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Application_Error(object sender, EventArgs e)
{
// 1. Get the last error raised
var error = Server.GetLastError();
//2. Get the error code to respond with
var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;
//3.. Log the error ( I am ignoring 404 error)
if (code != 404)
{
// Write error details to eventlog
WriteToEventLog(error);
}
//4. Clear the response stream
Response.Clear();
//5. Clear the server error
Server.ClearError();
//6. Render the Error handling controller without a redirect
string path = Request.Path;
Context.RewritePath(string.Format("~/Home/Error",code),false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(Context);
Context.RewritePath(path,false);
}
/// <summary>
/// This method writes the exception to the event log we have specified in the web.config or the app.config
/// </summary>
/// <param name="exception"></param>
public void WriteToEventLog(Exception exception)
{
EventLog.WriteEntry("abc", exception.Message, EventLogEntryType.Error);
}
How can I restart a windows service programmatically in .NET?
Also, I need to do an operation when the service restart is completed.
This article uses the ServiceController class to write methods for Starting, Stopping, and Restarting Windows services; it might be worth taking a look at.
Snippet from the article (the "Restart Service" method):
public static void RestartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
// count the rest of the timeout
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2-millisec1));
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
// ...
}
}
Take a look at the ServiceController class.
To perform the operation that needs to be done when the service is restarted, I guess you should do that in the Service yourself (if it is your own service).
If you do not have access to the source of the service, then perhaps you can use the WaitForStatus method of the ServiceController.
An example using by ServiceController Class
private void RestartWindowsService(string serviceName)
{
ServiceController serviceController = new ServiceController(serviceName);
try
{
if ((serviceController.Status.Equals(ServiceControllerStatus.Running)) || (serviceController.Status.Equals(ServiceControllerStatus.StartPending)))
{
serviceController.Stop();
}
serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running);
}
catch
{
ShowMsg(AppTexts.Information, AppTexts.SystematicError, MessageBox.Icon.WARNING);
}
}
You could also call the net command to do this. Example:
System.Diagnostics.Process.Start("net", "stop IISAdmin");
System.Diagnostics.Process.Start("net", "start IISAdmin");
This answer is based on #Donut Answer (the most up-voted answer of this question), but with some modifications.
Disposing of ServiceController class after each use, because it implements IDisposable interface.
Reduce the parameters of the method: there is no need to the serviceName parameter being passed for each method, we can set it in the constructor, and each other method will use that service name.
This is also more OOP-friendly.
Handle the catch exception in a way that this class could be used as a component.
Remove the timeoutMilliseconds parameter from each method.
Add two new methods StartOrRestart and StopServiceIfRunning, which could be considered as a wrapper for other basic methods, The purpose of those methods are only to avoid exceptions, as described in the comment.
Here is the class
public class WindowsServiceController
{
private readonly string serviceName;
public WindowsServiceController(string serviceName)
{
this.serviceName = serviceName;
}
// this method will throw an exception if the service is NOT in Running status.
public void RestartService()
{
using (ServiceController service = new ServiceController(serviceName))
{
try
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
throw new Exception($"Can not restart the Windows Service {serviceName}", ex);
}
}
}
// this method will throw an exception if the service is NOT in Running status.
public void StopService()
{
using (ServiceController service = new ServiceController(serviceName))
{
try
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped);
}
catch (Exception ex)
{
throw new Exception($"Can not Stop the Windows Service [{serviceName}]", ex);
}
}
}
// this method will throw an exception if the service is NOT in Stopped status.
public void StartService()
{
using (ServiceController service = new ServiceController(serviceName))
{
try
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
throw new Exception($"Can not Start the Windows Service [{serviceName}]", ex);
}
}
}
// if service running then restart the service if the service is stopped then start it.
// this method will not throw an exception.
public void StartOrRestart()
{
if (IsRunningStatus)
RestartService();
else if (IsStoppedStatus)
StartService();
}
// stop the service if it is running. if it is already stopped then do nothing.
// this method will not throw an exception if the service is in Stopped status.
public void StopServiceIfRunning()
{
using (ServiceController service = new ServiceController(serviceName))
{
try
{
if (!IsRunningStatus)
return;
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped);
}
catch (Exception ex)
{
throw new Exception($"Can not Stop the Windows Service [{serviceName}]", ex);
}
}
}
public bool IsRunningStatus => Status == ServiceControllerStatus.Running;
public bool IsStoppedStatus => Status == ServiceControllerStatus.Stopped;
public ServiceControllerStatus Status
{
get
{
using (ServiceController service = new ServiceController(serviceName))
{
return service.Status;
}
}
}
}
If you are using .NET Core you have to download System.ServiceProcess package
And this will work only on WINDOWS
How about
var theController = new System.ServiceProcess.ServiceController("IISAdmin");
theController.Stop();
theController.Start();
Don't forget to add the System.ServiceProcess.dll to your project for this to work.
See this article.
Here is a snippet from the article.
//[QUICK CODE] FOR THE IMPATIENT
using System;
using System.Collections.Generic;
using System.Text;
// ADD "using System.ServiceProcess;" after you add the
// Reference to the System.ServiceProcess in the solution Explorer
using System.ServiceProcess;
namespace Using_ServiceController{
class Program{
static void Main(string[] args){
ServiceController myService = new ServiceController();
myService.ServiceName = "ImapiService";
string svcStatus = myService.Status.ToString();
if (svcStatus == "Running"){
myService.Stop();
}else if(svcStatus == "Stopped"){
myService.Start();
}else{
myService.Stop();
}
}
}
}
I needed somethin more complex, because sometimes services with depencies couldnt be restarted and just throw exception or service could be set to "disabled" and so on.
So this is what i did:
(It checks if service does exist, if its "Disabled" it will set service to "Auto" and when it couldnt restart service it will use taskkill command to kill service through PID and then start it again (You need to be carefull with dependent services with this cause you will need to start/restart them too).
And it just returns true/false if restart was sucessfull
Tested on WIN10 only.
PS: working on version which detect dependent services when using taskkill and restart them too
//Get windows service status
public static string GetServiceStatus(string NameOfService)
{
ServiceController sc = new ServiceController(NameOfService);
switch (sc.Status)
{
case ServiceControllerStatus.Running:
return "Running";
case ServiceControllerStatus.Stopped:
return "Stopped";
case ServiceControllerStatus.Paused:
return "Paused";
case ServiceControllerStatus.StopPending:
return "Stopping";
case ServiceControllerStatus.StartPending:
return "Starting";
default:
return "Status Changing";
}
}
//finds if service exists in OS
public static bool DoesServiceExist(string serviceName)
{
return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals(serviceName));
}
//finds startup type of service
public static string GetStartupType(string serviceName)
{
ManagementObject objManage = new ManagementObject("Win32_Service.Name='"+serviceName+"'");
objManage.Get();
string status1 = objManage["StartMode"].ToString();
return status1;
}
//restart service through PID
public static bool RestartServiceByPID(string NameOfService)
{
LogWriter log = new LogWriter("TaskKilling: " + NameOfService);
string strCmdText = "/C taskkill /f /fi \"SERVICES eq " + NameOfService + "\"";
Process.Start("CMD.exe", strCmdText);
using(ServiceController ScvController = new ServiceController(NameOfService))
{
ScvController.WaitForStatus(ServiceControllerStatus.Stopped);
if (GetServiceStatus(NameOfService) == "Stopped")
{
ScvController.Start();
ScvController.WaitForStatus(ServiceControllerStatus.Running);
if (GetServiceStatus(NameOfService) == "Running")
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
//Restart windows service
public static bool RestartWindowsService(string NameOfService)
{
try
{
//check if service exists
if(DoesServiceExist(NameOfService) == false)
{
MessageBox.Show("Service " + NameOfService + " was not found.");
return false;
}
else
{
//if it does it check startup type and if it is disabled it will set it to "Auto"
if (GetStartupType(NameOfService) == "Disabled")
{
using (var svc = new ServiceController(NameOfService))
{
ServiceHelper.ChangeStartMode(svc, ServiceStartMode.Automatic);
if (svc.Status != ServiceControllerStatus.Running)
{
svc.Start();
svc.WaitForStatus(ServiceControllerStatus.Running);
if(GetServiceStatus(NameOfService) == "Running")
{
return true;
}
else
{
return false;
}
}
else
{
svc.Stop();
svc.WaitForStatus(ServiceControllerStatus.Stopped);
if(GetServiceStatus(NameOfService) == "Stopped")
{
svc.Start();
svc.WaitForStatus(ServiceControllerStatus.Running);
if(GetServiceStatus(NameOfService) == "Running")
{
return true;
}
else
{
return false;
}
}
//restart through PID
else
{
return RestartServiceByPID(NameOfService);
}
}
}
}
//If service is not disabled it will restart it
else
{
using(ServiceController ScvController = new ServiceController(NameOfService))
{
if(GetServiceStatus(NameOfService) == "Running")
{
ScvController.Stop();
ScvController.WaitForStatus(ServiceControllerStatus.Stopped);
if(GetServiceStatus(NameOfService) == "Stopped")
{
ScvController.Start();
ScvController.WaitForStatus(ServiceControllerStatus.Running);
if(GetServiceStatus(NameOfService) == "Running")
{
return true;
}
else
{
return false;
}
}
//if stopping service fails, it uses taskkill
else
{
return RestartServiceByPID(NameOfService);
}
}
else
{
ScvController.Start();
ScvController.WaitForStatus(ServiceControllerStatus.Running);
if(GetServiceStatus(NameOfService) == "Running")
{
return true;
}
else
{
return false;
}
}
}
}
}
}
catch(Exception ex)
{
return RestartServiceByPID(NameOfService);
}
}
You can set a service to restart after failure. So a restart can be forced by throwing an exception.
Use recovery tab on service properties.
Be sure to use reset fail count property to prevent service stopping altogether.
Call Environment.Exit with an error code greater than 0, which seems appropriate, then on install we configure the service to restart on error.
Environment.Exit(1);
I have done same thing in my Service. It is working fine.