I have made a WCF Service and it contains a method string SaveVideoInformation()
The purpose of this method is to run a process if it is not running.
Following is the code of that method.
public string SaveVideoInformation(string ID, string videoName)
{
string Result = null;
try
{
Result = Insert(ID, videoName);
Process[] pname = Process.GetProcessesByName("AutoRunVideoWaterMarkingTook");
if (pname.Length == 0)
{
Result += " | Trying to run Process";
try
{
Process process = Process.Start(#"~\Debug\AutoRunVideoWaterMarkingTook.exe");
Result += " | Process Ran Successfully";
}
catch (Exception ex)
{
Result += " | Exception While Running the process";
throw new Exception("Unable to start Process);
}
}
else
{
Result += "|Process Already Running";
}
}
catch (Exception ex)
{
Result = "Not Done," + ex.Message;
}
return Result;
}
The problem I am facing is when i call this method from Windows Form Tool Application, it run successfully and i can see the UI.
but when i call this method from Windows Service, Process Starts but its UI is not visible.
That is most likely because your Windows Service is not in user interactive mode.
You have to enable this from the Services panel, as described in this blog: Check the Allow service to interact with desktop in the service properties Log On page.
Also read Microsofts recommendations on user interactive services.
Related
I have this strange situation where I have an Outlook VSTO add-in written in c# targeting Outlook 2007 and 2010. The add-in works fine in 2007 environment. It also works fine in debug mode with Outlook 2010 in Visual Studio (2010) when I press start. However, once I deploy to UAT one of the functions doesn't get evaluated at all.
One of the functions is
private static bool HTTPTransmitEmailItem(string username, string email_file_name)
{
// DEBUG
Utils.LogDebug("Got into HTTPTransmitEmailItem");
try
{
Stopwatch timer = new Stopwatch();
timer.Start();
try
{
Utils.LogDebug("Msg saved as : " + full_file_name_and_path);
if (HTTPPostDataToEP(username, temp_path, email_file_name))
{
File.Delete(full_file_name_and_path);
return true;
}
else
{
Utils.LogWarn("Trans Fail, Storing for later sending. " + email_file_name);
//if need start resend timer
TransmitFailed();
}
}
catch (Exception ex)
{
Utils.HandleException("OFE HHTP Ex", ex);
TransmitFailed();
}
timer.Stop();
Utils.LogDebug("Email File Thread took " + timer.ElapsedMilliseconds.ToString() + "(ms)");
}
catch (Exception ex)
{
}
return false;
}
The culprit is the part:
if (HTTPPostDataToEP(username, temp_path, email_file_name))
{
File.Delete(full_file_name_and_path);
return true;
}
else
{
Utils.LogWarn("Trans Fail, Storing for later sending. " + email_file_name);
//if need start resend timer
TransmitFailed();
}
The application never enters the method HTTPPostDataToEP... The method definition is
private static bool HTTPPostDataToEP(string username, string path, string name)
{
// DEBUG
Utils.LogDebug("Got into HTTPPostDataToEP");
try
{
var content = new MultipartFormDataContent();
content.Add(new StringContent(username), "userAddress");
content.Add(new StreamContent(File.Open(path + name, FileMode.Open)), "msg", name);
// DEBUG
Utils.LogDebug("In Line 174 in OutlookTransmitRaw");
var client = new HttpClient();
HttpResponseMessage result = client.PostAsync(Utils.configEndPoint, content).Result;
// DEBUG
Utils.LogDebug("In Line 178 in OutlookTransmitRaw. Result is " + result);
if (result.IsSuccessStatusCode)
Utils.LogDebug("Msg Transmit Response : " + result.ToString());
else
Utils.LogInfo("Msg Fail Transmit Response: " + result.ToString());
return result.IsSuccessStatusCode;
}
catch (Exception ex)
{
throw new Exception("Failed to dispatch email to API. Caused by ", ex);
}
}
The application doesn't raise any exception. It simply walks pass that if block and executes Utils.LogDebug("Email File Thread took " + timer.ElapsedMilliseconds.ToString() + "(ms)"); This only happens when I publish the project and install it using set.exe file. In debug mode it works as expected...
The empty catch block would explain your problem: an exception is raised and you simply ignore that and happily carry on.
I could imaging something going wrong with file permissions after you deploy your solution, for instance. But whatever goes wrong gets swallowed up and you'll never hear about it...
Either throw from that catch block, or log something before you throw, but blindly ignoring exceptions like this is never a good idea. Something goes wrong, you get an exception with information, and you refuse to look at it.
Wrong:
catch (Exception ex)
{
}
Weird and useless:
catch (Exception ex)
{
throw;
}
Often useful:
catch (Exception ex)
{
Logger.Log(ex);
throw;
}
Needless to say I'm new to C# and doing some basic things to learn along the way. I'm trying to understand async/await feature. I have a form with 2 textboxes and a button. When I click the button, it checks a remote computer's service status (in this case remote registry. While it checks, it writes that it is checking the registry and tells the user to wait. Then starts if the state is stopped and gets some values I look for and writes those to the second textbox.
My code works, and I'm able to get my values. But the GUI freezes during this time. I tried to implement backgroundworker, thread and Async/Wait with no success. I tried doing Task and couldn't get that to work.
All the examples shown here or on other sites simply return int while I'm trying to return a string that writes the status and the values I want to textboxes. I tried to convert it to string with no success.
Long story short, for this type of processes, what would be a better approach? Can someone show me how and comment what does what along the way just so I understand better? I want to learn how to do it but at the same time learn why and learn to write cleaner code.
Thank you everyone for taking their time in advance.
string ComputerName = "Lab01";
public frmRegChecker()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
Check_Status();
}
private void Check_Status()
{
TxtBoxstatus.AppendText("Checking Remote Registry service status on computer : " + ComputerName);
TxtBoxstatus.AppendText(Environment.NewLine);
TxtBoxstatus.AppendText("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
try
{
TxtBoxstatus.AppendText("The Remote Registry service status is currently set to : " + sc.Status.ToString());
TxtBoxstatus.AppendText(Environment.NewLine);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
TxtBoxstatus.AppendText("Starting Remote Registry service...");
TxtBoxstatus.AppendText(Environment.NewLine);
try
{
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
// Display the current service status.
TxtBoxstatus.AppendText("The Remote Registry status is now set to:" + sc.Status.ToString());
richTextBox1.AppendText(Environment.NewLine);
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Could not start the Remote Registry service.");
richTextBox1.AppendText(Environment.NewLine);
}
}
else if (sc.Status == ServiceControllerStatus.Running)
{
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
}
}
catch
{
richTextBox1.AppendText("Error getting registry value from " + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
Unfortunately, ServiceController is a rather outdated class and doesn't natively support async/await. That would be the cleanest solution if it were possible.
So, what you can do is use async/await with Task.Run. Task.Run executes code on a background thread, and you can use async/await from the UI to consume that background operation. This approach allows exceptions to be propagated and handled in a natural fashion, and it allows return values to also be handled naturally. Strip out the textbox updates for now for simplicity, and the first step looks like this:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var osVersion = await Task.Run(() => CheckStatus());
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus()
{
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
Next, add the progress updates. There's a built-in mechanism for that - IProgress<T>/Progress<T>, and it works like this:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var progress = new Progress<string>(update =>
{
TxtBoxstatus.AppendText(update);
TxtBoxstatus.AppendText(Environment.NewLine);
});
var osVersion = await Task.Run(() => CheckStatus(progress));
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus(IProgres<string> progress)
{
progress?.Report("Checking Remote Registry service status on computer : " + ComputerName);
progress?.Report("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
progress?.Report("The Remote Registry service status is currently set to : " + sc.Status.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
progress?.Report("Starting Remote Registry service...");
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
progress?.Report("The Remote Registry status is now set to:" + sc.Status.ToString());
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
Note the separation of concerns: the only code that touches UI objects is a UI event handler. The CheckStatus method that contains the actual program logic is separated from the UI - all it knows is that it can report progress strings and return a string result.
This can easily be accomplished using async/await. An Example:
A simple WPF form:
<Window x:Class="WpfApp1.MainWindow"
...>
<Grid>
<Button Name="button" Content="Start" Click="Button_Click"/>
<TextBox Name="textButton" />
</Grid>
</Window>
and the associated code-behind:
public partial class MainWindow:Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
textButton.Text = "Running...";
string result = await DoIt();
textButton.Text = result;
}
private async Task<string> DoIt()
{
await Task.Delay(3000);
return "Finished...";
}
}
When clicking the button, the long-running 'calculation' in 'DoIt' is started'asynchrounously. While it is running, the UI remains responsive.
When DoIt returns returns its result (in this example after a dummy delay of 3 seconds) the 'click' eventhandler continues...
Remarks:
this example uses code behind for simplicity. The technique works as well using the MVVM-pattern (where the async operation is started from a command).
'async void' is an anti pattern, but is used to comply withe the auto generated eventhandler in code behind.
in a real world application the async 'DoIt' method would propably be situated in a backend 'model class'.
the example assumes you only want to update the UI once the long-running operation has finished. If you want intermediate updates, there are several options (unfortunately a bit more complex).
I think you can still use the backgroundworker to make your textboxes display messages without freezing the GUI. Take reference from this question Here on how to return an object from backgroundworker.
I have a WCF service that must be always up, and is therefore hosted by a Windows Service. My Windows Service model has simple startup code:
HostService:
public void StartService()
{
if (_hostController.Status != ServiceControllerStatus.Stopped && _hostController.Status != ServiceControllerStatus.StopPending)
{
var msg = string.Format("Service '{0}' must be in status '{1}' or '{2}' to accept a 'Start' command.",
HostResources.ServiceName, ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceStatusControl);
}
try
{
_hostController.Start();
}
catch (Exception ex)
{
if (ex is Win32Exception || ex is InvalidOperationException)
{
throw new HostServiceException(string.Format("'{0}' failed to respond properly to a 'StartService` command: '{1}'", _hostController.ServiceName, ex.Message), ex);
}
throw;
}
try
{
_hostController.WaitForStatus(ServiceControllerStatus.Running, _waitForStatusTimeout);
}
catch (TimeoutException tx)
{
throw new HostServiceException(string.Format("{0} did not start respond after {1} seconds and the 'Start' command timed out.", _hostController.ServiceName, _waitForStatusTimeout.TotalSeconds), tx);
}
if (ServiceControllerStatus.Running != _hostController.Status)
{
throw new HostServiceException(string.Format("The 'StartService' command for '{0}' failed. The Service has a status of '{1}'.", _hostController.ServiceName, _hostController.Status));
}
}
My WCF service has even simpler startup code:
SchedulerService:
public void Start()
{
_isBusy = false;
var interval = _config.Settings.ServicePollingInterval * 1000;
_pollTimer = new Timer(interval);
_pollTimer.Enabled = true;
_pollTimer.Elapsed += PollTimerElapsed;
_pollTimer.Start();
Status = SchedulerServiceStatus.Running;
var msg = string.Format("'{0}' started with the timer set for {1} second{2} intervals.", SchedulerResources.ServiceName, _pollTimer.Interval / 1000, _pollTimer.Interval / 1000 > 1 ? "s" : "");
_logger.Info(msg);
StatusChanged(this, new SchedulerStatusChangeEventArgs(Status, msg));
}
It is the code in my view model in question here, because only if it can start the Windows Service, will it start the WCF service:
SchedulerViewModel:
private void ExecuteStart()
{
if (_hostModel.ServiceStatus != ServiceControllerStatus.Running)
{
_logger.Warn("The '" + _hostModel.ServiceName + "' host service is not running. The '" + GetType().Name + "' will attempt to start it.");
try
{
_hostModel.StartService();
}
catch (Exception ex)
{
var msg = string.Format("The '{0}' could not start the '{1}' host service: {2}", GetType().Name, _hostModel.ServiceName, ex.Message);
_logger.Error(msg, ex);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceController, ex);
}
}
try
{
_scheduler.Start();
}
catch (Exception ex)
{
throw new SchedulerServiceException(ex.Message, SchedulerServiceException.SchedulerServiceExceptionCategory.SchedulerControl, ex);
}
SchedulerStatus = _scheduler.Status;
CommandsCanExecuteChanged();
}
Now this is indeed not view logic, but it is hardly business logic either; more like housekeeping: I can only use the washing machine if the water supply is switched on. Now I don't really see the need for a whole new model with just an instance of HostModel and SchedulerService, just for this decision. What say the jury on my current setup?
I would push all the code behind another service and inject this via an interface into the VM, I'd do this becuase I presume the WCF expose state via events and you want to display this in the UI. If you push this behind another service allows to 'shape' the exposed state into a more UI centric model suited for use in the VM.
If you did this, from the view point of the VM all it would then know about is 'start\stop' methods and an event handler - the implementation is then abstracted away and makes testing the VM very easy via mocking.
To take this further I would consider using Reactive extensions instead of CLR events for communicating state changes in the service.
Im working in windows service syncmysqldb.exe i need the service to run a process ie syncing of two mysql databases in n intervals of time given in setting.xml file
When i install this service service manager i see the service not in started state and when i try to run in manually by right clicking it gives following error
When i install service it gives following error
The description for Event ID ( 11001 ) in Source ( MsiInstaller ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Product: SetupSynMysqldb -- Error 1001. Error 1001. An exception occurred during the Commit phase of the installation. This exception will be ignored and installation will continue. However, the application might not function correctly after installation is complete. --> The savedState dictionary contains inconsistent data and might have been corrupted., (NULL), (NULL), (NULL), (NULL), , .
When i run service in service manager it gives following error
The SyncMysqlDb service failed to start due to the following error:
The system cannot find the file specified.
C# code
protected override void OnStart(string[] args)
{
try
{
//add this line to text file during start of service
EventLog.WriteEntry("SyncMysqlDb in OnStart. at " + DateTime.Now);
//handle Elapsed event
tmrSync.Elapsed += new ElapsedEventHandler(OnElapsedTime);
tmrSync.Interval = GetIntervals();
//enabling the timer
tmrSync.Enabled = true;
//TraceService(" tmrSync.Interval =" + tmrSync.Interval + " at " + DateTime.Now);
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceWorkerThread));
}
catch (Exception ex)
{
EventLog.WriteEntry("Service failed to start.", EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
}
}
private void ServiceWorkerThread(object state)
{
// Periodically check if the service is stopping.
while (!this.stopping)
{
// Perform main service function here...
Thread.Sleep(2000); // Simulate some lengthy operations.
}
// Signal the stopped event.
this.stoppedEvent.Set();
}
protected override void OnStop()
{
tmrSync.Enabled = false;
//TraceService("stopping service" + DateTime.Now);
EventLog.WriteEntry("SyncMysqlDb in OnStop. at " + DateTime.Now);
this.stopping = true;
this.stoppedEvent.WaitOne();
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
EventLog.WriteEntry(#"Executing C:\SyncMysqlDbRepository\task.bat at " + DateTime.Now);
Process.Start(#"C:\SyncMysqlDbRepository\task.bat");
}
catch (Exception ex)
{
EventLog.WriteEntry("Service failed to start.at " + DateTime.Now, EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
}
// TraceService("syncing db at " + DateTime.Now);
}
protected int GetIntervals()
{
var dt = new DataTable();
try
{
dt.ReadXmlSchema(#"C:\SyncMysqlDbRepository\SettingsDs.xml");
dt.ReadXml(#"C:\SyncMysqlDbRepository\Settings.xml");
}
catch (Exception ex)
{
EventLog.WriteEntry("GetIntervals failed at " + DateTime.Now, EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
return 0;
}
return Convert.ToInt16(dt.Rows[0].ItemArray[2]); //Intervals from settings.xml
}
I'm fairly new at working with Windows services but I found a peculiar incident and I would like some clarification. I have a Windows service written in C# which I install and start using the command line (great instructions found on stackoverflow). The main method of my service looks like this:
static void Main(string[] args)
{
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
else if (args.Length == 1)
{
const string name = "MyServiceName";
Type type = typeof(MyAssembly);
switch (args[0])
{
case "-install":
ServiceUtils.InstallService(name, type);
ServiceUtils.StartService(args, name);
break;
case "-uninstall":
ServiceUtils.StopService(name);
ServiceUtils.UninstallService(name, type);
break;
default:
throw new NotImplementedException();
}
}
}
When I debug, I ALWAYS send one parameter (-install) to the application. Because of this, the first if statement (if (args.Length == 0) is NEVER executed. This is expected and my service is installed and started just fine. However, if I remove that if statement and just leave the if (args.Length == 1) statement, my service installs correctly but it does not start and I get the following error:
Cannot start MyServiceName on computer '.'
My question is: Why is the code in the first if statement needed when it is NEVER executed in my application?
Here is the supporting code for the InstallService and StartService methods (which I got from stackoverflow also):
public static void InstallService(string serviceName, Type t)
{
if (IsInstalled(serviceName)) return;
try
{
Assembly a = t.Assembly;
using (AssemblyInstaller installer = GetInstaller(a))
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(state);
}
catch
{ }
throw;
}
}
}
catch
{
throw;
}
}
public static void StartService(string[] args, string serviceName)
{
if (!IsInstalled(serviceName)) return;
Console.WriteLine("Service is installed. Attempting to start service.");
ServiceController sc = new ServiceController();
sc.ServiceName = serviceName;
if (sc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine("Starting {0}: ", sc.ServiceName);
try
{
sc.Start(args);
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
the first if statement (if (args.Length == 0) is NEVER executed
That's not correct, it is executed. By ServiceController.Start(). You cannot see this because the service controller starts your EXE again, creating another process. A service process this time, not a console process. One that you don't have a debugger attached to. If you remove that if statement then the service immediately exits after getting started. And the service controller correctly complains about that with the "Cannot start MyServiceName" exception message.
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
is run when the service is started by the Service Controller, as the Service Controller doesn't pass any arguments in to Main().
If you don't do ServiceBase.Run(new MyServiceName()), then your service will not respond to any commands from the Service Controller, and you get errors as the ones you see.
Main() is still the entry point of the application. The process is started as a separate step from starting the service(s) within.
It's actually possible to have multiple services running in the same process, and this way of handling things enables that. That is... not just the same exe program, but actually in the same running process.