Ensure a windows service is started from Visual Basic .Net - vb.net

I have a WCF service being hosted in a Windows Service (using techniques discussed here) and it works great. I'm now writing a (VB.Net) frontend app that needs to call that service, but I don't want my users having to fiddle around with the services snap-in and starting the service manually.
Can I write some code to ensure the Windows Service is started, or start it if it isn't?
Edit: OF course, I can ensure the Service startup is set to automatic, but it doesn't need to be running all the time, and even then the frontend app still needs to be sure the service is running and start it if it isn't.

You can use the ServiceController class to manipulate a service as needed.
Example from MSDN using the Status property to check if a service needs to be started:
' Toggle the Telnet service -
' If it is started (running, paused, etc), stop the service.
' If it is stopped, start the service.
Dim sc As New ServiceController("Telnet")
Console.WriteLine("The Telnet service status is currently set to {0}", sc.Status)
If sc.Status.Equals(ServiceControllerStatus.Stopped) Or sc.Status.Equals(ServiceControllerStatus.StopPending) Then
' Start the service if the current status is stopped.
Console.WriteLine("Starting the Telnet service...")
sc.Start()
Else
' Stop the service if its status is not set to "Stopped".
Console.WriteLine("Stopping the Telnet service...")
sc.Stop()
End If
' Refresh and display the current service status.
sc.Refresh()
Console.WriteLine("The Telnet service status is now set to {0}.", sc.Status)

You can do something like
Dim controller As New ServiceController("ServiceNameHere")
If controller.Status = ServiceControllerStatus.Stopped Then
controller.Start()
End If
Remember to add reference to and import System.ServiceProcess

Related

Windows Service will not start as Local User

EDIT 2: I now believe this is an issue with the machine I'm attempting to run the service on. I tried moving the service to a different machine that is setup similarly and the service was able to start successfully even as a Local User. Now I just need to figure out what's different between the two machines...
I have a Windows Service project (written in VB.net) that is installed and configured with a Startup Type of Automatic and the Log On As set to a Local User account. This service will start when the computer first starts up. However, if I stop the service and try to start it again, I get "Error 1053: The service did not respond to the start or control request in a timely fashion." immediately. However, if I change the Log On As to "Local System account" then the service will start.
Summary:
Service will run as Local User when computer first starts
Service will not run as Local User if started manually
Service will run as Local System when computer first starts
Service will run as Local System if started manually
I have read that Error 1053 is caused by the OnStart method not returning quickly enough. The fact that the service has started previously, and that I get the error message immediately, leads me to believe a timeout is not what's going on. To verify this, I created a completely new Windows Service Project and without changing anything I built and installed it. I get the same behavior.
I am at a loss as to what's happening. As far as I can tell, the Local User has all of the correct privileges to run a service (as is evident by the fact that it will start with those credentials when it the computer is first starting up), and the OnStart method isn't actually timing out (as is evident by the completely blank dumb service exhibiting the same behavior).
Any ideas as to what's preventing the service from starting, or where I can look for better error messages (I have looked in the Application Event Log, but nothing shows up there)?
EDIT:
Here is the code from the dumb service I created (using the EventLogger from here as a module).
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
EventLogger.WriteToEventLog("On Start")
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
EventLogger.WriteToEventLog("On Stop")
End Sub
And the Main method of the same project.
' The main entry point for the process
<MTAThread()> _
<System.Diagnostics.DebuggerNonUserCode()> _
Shared Sub Main()
EventLogger.WriteToEventLog("Starting Main Method")
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New Service1}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
EventLogger.WriteToEventLog("Leaving Main Method")
End Sub
When I try to run the Service as the Local User, none of the messages show in the Event Log and I get Error 1053. When I run the Service as the Local System, the messages show in the Event Log.
The reason I need to run the actual service as the Local User is so that it can access a network share. I am currently looking into using Windows User Impersonation, but I still think I should be able to start a simple service as a Local User.
Use this resource to create an event logger. Then wrap your code in each sub in a try/catch b/c most likely something is happening in your OnStart sub that is preventing the service from starting. Post some sample code of your onstart, onstop, and/or your service main subs and clarify why you need to use the local user vs the local system.

WCF NetNamedPipeBinding TimeoutException on Windows Server 2008

I have a problem with WCF NetNamedPipeBinding. When I run my server and client code through Visual Studio 2008 on a Windows XP machine everything works fine. But as soon as I deploy my server as a Windows Service and install my client app in Windows Server 2008 I get a TimeoutException on the client end whenever I try to use any of the contract methods. It seems that I can successfully create the client and open it, but can't call any of the methods.
Service initialisation code:
Uri baseAddress = new Uri("http://localhost:8500/xNet/xNetService");
string address = "net.pipe://localhost/xNet/xNetService";
_xNetAPIServiceHost = new ServiceHost(typeof(xNetService), baseAddress);
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
_xNetAPIServiceHost.AddServiceEndpoint(typeof(IServiceAPI), binding, address);
// Add a mex endpoint
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri("http://localhost:8501/xNet/xNetService/mex");
_xNetAPIServiceHost.Description.Behaviors.Add(smb);
_xNetAPIServiceHost.Open();
Client initialisation code:
string address = "net.pipe://localhost/xNet/xNetService";
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
_serviceClient = new ServiceAPIClient(binding, new EndpointAddress(address));
_serviceClient.Open();
The Windows service runs as "Local System Account". I'm at a loss as to what the problem is. I don't know if it's a security account problem, or if the named pipe is even open? I would assume since I can successfully create and open the client side it would appear it at least found the named pipe. I just can't call any of the service methods without a TimeoutException.
After trying out various bindings and going back to basics I noticed that the sample programs worked, but mine didn't work unless I was using Visual Studio to debug. I decided at that point that it must be something going on with my own code. To simplify debugging I turned off all security in the binding.
I started commenting out most of the statements in my service's OnStart method in order to determine what could be going on. I commented out everything except for the code that initialises the ServiceHost. Magically, my client could now successfully communicate with the service. I then started uncommenting each line of code in the OnStart method until my client suddenly started giving me a TimeoutException again.
My service class, say "MyAPI", implements the contract "IMyAPI". As well as using "MyAPI" class as the WCF service, I was also using an instance of the "MyAPI" class internally in my service to do various things ("internal" methods). In my OnStart method I first created an instance of the "MyAPI" class and then created the ServiceHost:
MyAPI API = new MyAPI();
ServiceHost service = new ServiceHost(typeof(MyAPI));
I was not getting any errors or exceptions, so it appeared everything is fine, but really I couldn't connect to the service using a client. As soon as I changed the order of the above statements, the client started working again:
ServiceHost service = new ServiceHost(typeof(MyAPI));
MyAPI API = new MyAPI();
I'm not sure WHY this is occuring, all I know is that I can use my API internally and as a service without any client connection issues. Maybe someone out there will provide some light on the reasons behind this, or maybe my code is not properly designed.

vb.net console / service app

I'd like to enable my console app. to be installed also as a service using command prompt arguments, handling the following commands
d\:>myapp -console
d\:>myapp -install
d\:>myapp -uninstall
My vb.net service template is as follows,
Public Class MyService
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
End Sub
End Class
How I should proceed to run it as console and/or console.
Thanks in advance,
m0dest0
Ps. using vb.net and Vs 2008
Ps2. The kind of taks to be performed is suitable to be implemented either in console or service. Basically it will monitor files in a specific folder and the process the info.
This is doable, I have a service that does this very thing.
The main business logic should be encapsulated such that it can be run (launched as a thread) from within the Service or from a shared sub Main.
You will need to add a service installer if there is not one already, but the VS template adds that for you so you should be all set.
In your Main, you have to parse the command line (obviously) and execute the appropriate action. I would recommend, for one-stop-shopping, adding a -start and -stop command line option as well to stop and start the service.

can't enable net.tcp port sharing

I'm doing my dev work on a Window 7 x64 machine, deploying to a Windows 2008 x32 server. At the moment I'm adding WCF services to some internal apps so that we can build smaller clients using net.tcp bindings that report to the user what the server is doing without running multiple instances of the server. To cut back on how much administration the apps will require, I tried enabling port sharing on my first server app. I'm using the app to self-host the WCF service so they can be easily moved from one server to another if necessary. Here's the code starting the server:
Dim _service_host As ServiceHost
Dim active_server_address As Uri = New UriBuilder("net.tcp", "localhost", CInt(My.Settings.ServerPort)).Uri
_service_host = New ServiceHost(GetType(UpdateServiceOps), active_server_address)
_service_host.AddServiceEndpoint(GetType(IUpdateService), New NetTcpBinding With {.Name = "endpoint_tcp"}, "MiddlewareEndpoint")
_service_host.Description.Behaviors.Add(New ServiceMetadataBehavior)
_service_host.AddServiceEndpoint(GetType(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding, "mex")
_service_host.Open()
That works great. When I change it to what's below, however, I get an error. Here's the code:
Dim _service_host As ServiceHost
Dim active_server_address As Uri = New UriBuilder("net.tcp", "localhost", CInt(My.Settings.ServerPort)).Uri
_service_host = New ServiceHost(GetType(UpdateServiceOps), active_server_address)
_service_host.AddServiceEndpoint(GetType(IUpdateService), New NetTcpBinding With {.Name = "endpoint_tcp", .PortSharingEnabled = True}, "MiddlewareEndpoint")
_service_host.Description.Behaviors.Add(New ServiceMetadataBehavior)
_service_host.AddServiceEndpoint(GetType(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding, "mex")
_service_host.Open()
I get the following error when I put a breakpoint at the last line: Unable to automatically step into the server. Connecting to the server machine 'nettcpportsharing' failed. The requested name is valid, but no data of the requested type was found. The Try...Catch block housing that code says the exception type is AddressAlreadyInUseException...but when I run netstat I don't see anything else listening on that address. There's no occurrence of 'nettcpportsharing' anywhere in my solution. I've checked to make sure that the Net.Tcp Port Sharing service is started. Any ideas?
I think this may be a permissions issue. Please see the associated article which explains how to configure the port sharing service to support self-hosted services.
(For production purposes I would strongly recommend using IIS Hosting with WAS anyway - it makes management of the services much cleaner and you get dynamic startup/shutdown for free.)

How can I write to a custom event log from my ASMX web service running as network service?

I have a ASMX web services running as 'network service'. I want to be able to write to a custom event log every time a web service is called (and when errors happen).
I have created a new event log (MyLog) using the following code running as admin on a Windows server 2008 machine:
if (!EventLog.SourceExists(APPLICATIONNAME))
{
EventLog.CreateEventSource(APPLICATIONNAME, EVENTLOGNAME);
}
EventLog.WriteEntry(APPLICATIONNAME, "Service started", EventLogEntryType.Information);
where APPLICATIONAME is "MyApp" and EVENTLOGNAME is "MyLog" (names changed to protect the innocents).
Firstly, it creates a new "MyLog" event log (verified with eventvwr), but its contents are the same as the Application event log. I was expecting to get an empty, non-connected event log.
Secondly, when I try to write to the newly created event log from within the Application_Start method using the following code:
EventLog.WriteEntry(APPLICATIONNAME, "Service started", EventLogEntryType.Information);
I get a SecurityException of type System.Diagnostics.EventLogPermission.
I have tried to change the ACLs of the "MyLog" hive in the registry (as suggested on MSDN) but to no avail.
I'd rather not change the identity of the web service nor change the ACLs on the Application event log which is used by other applications on the system.
Since my web service is running in the context of SharePoint, I simply wrapped the call to EventLog.WriteEntry with SPSecurity.RunWithElevatedPrivileges.