windows service: Read from different servers with different settings - c#

Scenario:
Read files from different servers. Each server provide files with different format, extension and data.
The reading process is periodically different for each server (per minute, hour, weekly, monthly).
There should be config file (or whatever) to set the configuration related to "File format", "File extension", "Server credentials".
My Implementation:
I wrote an application to read these different files depending on configuration set as follow:
interface IServer
{
// Common implementation
}
[ServerPath("anyLocation")]
[FileDelimiter(",")]
[FileSearchPattern("*.txt")]
class Server2 : IServer
{
// Specific implementation
}
[ServerPath("anyLocation")]
[FileDelimiter("|")]
[FileSearchPattern("*.csv")]
class Server1 : IServer
{
// Specific implementation
}
Questions:
Should I use a windows service to run this app?
The settings I set as attributes should exists as settings accessible to the user, How to do?
Most importantly, I don't know if I should use a separate service for each server, taking into consideration that reading time may interfere (what happen in that case?). I still prefer to have a single service.

I wouldn't create a windows service for this kind of problem.
Create a simple console application that accepts a commend line parameter to specify the desired target (server) and read the according configuration from a simple App.config instead of hardcoding it into your app.
Run your console app useing Scheduled Tasks - this will give you fine grained scheduling control, built in monitoring and error tracking without any additional code.

Related

Process not functioning on cloud after started by Windows Service

We have a Windows Service that checks a configuration file, and based on those settings, starts a new Process (let's call this ClusterProcess) which connects to a database and does the actual functionality.
There is a test project, that cuts out the Windows Service's part in the play, and just provides ClusterProcess with the necessary settings.
For our current test environment, we have the database on a cloud and I would say, rather restricted permissions.
My problem is this: when I run the test project, ClusterProcess gets its settings and things happen on the database. However, when I run the Windows Service, nothing gets changed on the database.
I've been using log4net to try and see where things fall over, but it seems to fail silently.
So the Windows Service calls this:
_ClusterRunnner.StartAllClusters();
In this method mentioned above, this is (amongst other things) what happens, and I get both log statements:
_ClusterProcesses = new List<Process>();
log.Debug("Cluster Name: " + cluster.Name + " ConfigPath: " + _ConfigPath);
_ClusterProcesses.Add(Process.Start(startInfo));
log.Debug("After process spawn.");
Okay, so the Process that it should start is ClusterProcess.exe, and in the Main method of that project I don't get any of the log statements that should be given, for instance:
log.Debug("Going to Start Processing");
_ClusterProcessor = new ClusterProcessor(config);
_ClusterProcessor.StartProcessing();
log.Debug("Finished Processing");
With log4net I have a special logger for ClusterProcess.exe (two appenders, a RollingFileAppender and an AdoNetAppender) and similar appenders for the Windows Service. (The Windows Service process holds a lock to its RollingFileAppender, so I had to create a special one for ClusterProcess.exe. The AdoNetAppenders are for nicely formatted logs after the connection to the database has been made.)
But now, the test project just calls this directly:
ClusterProcessor x = new ClusterProcessor(config);
x.StartProcessing();
and it works! I get the log statements in StartProcessing() and the database is changed.
So any ideas?
From my experience with services they run with very limited rights.
So if your Test(possible windows application) runs perfectly then I guess it has something to do with user rights.
I guess you can't realy access the filesystem so if your logger writes to a place on the harddrive you should think about the windows event log --> Write to Windows Application Event Log without registering an Event Source
To try if it has something to do with user rights just open your service in the windows service settings and let it log on as your administrator account and see if it has something to do with this.

Restart a WCF service hosted by a C# console application

I have a WCF service that is hosted on a c# console application. Is there a way to restart this service, preferably by calling an endpoint in the service itself (ex. myService.Restart()).
Thanks
I have to do something similar when I perform an automatic update of a remote WCF service. In your Restart() method, close the host:
try
{
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Closing {0}", endpoint.Address));
host.Close(TimeSpan.FromSeconds(5));
}
catch (Exception)
{
host.Abort();
}
I wait for my update to apply, and then after a success or failure, I re-open the host using the same code I used to start it in the first place.
If you just wanted to restart immediately, you could just call host.Open(), or you could set up a timer to call it, etc.
try
{
host.Open();
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Host opened at: {0}", endpoint.Address));
}
catch (Exception ex)
{
_log.Error("Unable to open host.", ex);
}
To answer my question, I have solved the problem by doing the following:
Separating the code that loads the DLL files from the WCF service code into another class library project
Create an interface with the same method signatures as the ones that load DLL files in the new project (this interface is used by both projects now)
In the web service, load the other project in a new application domain. This way the DLL files are locked by the new application domain not the default.
If I want to update my nunit DLL files now, all I have to do is unload the application domain from the web service, update the files and finally create a new application domain.
AppDomain remoteDomain = AppDomain.CreateDomain("New Domain");
IClass1 class1 = (IClass1)remoteDomain.CreateInstanceFromAndUnwrap(
"Test1.dll", "Test1.Class1");
Note: IClass1 is the common interface between the projects.
you definitely are not going to be able to 'restart' a faulted service from calling that same service itself. In theory you could host 2 services in the same process. put the one you want to be 'restartable' in a public static variable and restart it within the other service. The problem would be restarting the restarter service if it faults... :) and you definitely want 'administrator-like' restrictions on your restarter service so unauthorized users can't do it.
It's a bit kludgy, but I suppose you could expose a callback on your service that the host could attach to and take appropriate action when it's triggered. That would give your host the ability to decide what a "restart" really means and how it needs to be executed. More importantly, it lets your decide whether it should do something extreme like spawn off a watcher process and then off itself or gracefully trash and reinstantiate your service (preferable).
Mmmmmm... kludge....
You cannot ask a service to restart itself. Consider a windows service (a service hosted in windows provided container) which has a RESTART functionality. Here RESTART functionality is provided not by the service but by the container. The container controls how to stop the service and start it.
Similarly in your case, you should try to look out for options if your container can provide the functionality you need. Since you want to control it remotely, the container should also be available remotely, which cannot be possible if the container is a console application. Instead it has to be another web service or web application.

Custom API requirement

We are currently working on an API for an existing system.
It basically wraps some web-requests as an easy-to-use library that 3rd party companies should be able to use with our product.
As part of the API, there is an event mechanism where the server can call back to the client via a constantly-running socket connection.
To minimize load on the server, we want to only have one connection per computer. Currently there is a socket open per process, and that could eventually cause load problems if you had multiple applications using the API.
So my question is: if we want to deploy our API as a single standalone assembly, what is the best way to fix our problem?
A couple options we thought of:
Write an out of process COM object (don't know if that works in .Net)
Include a second exe file that would be required for events, it would have to single-instance itself, and open a named pipe or something to communicate through multiple processes
Extract this exe file from an embedded resource and execute it
None of those really seem ideal.
Any better ideas?
Do you mean something like Net.TCP port sharing?
You could fix the client-side port while opening your socket, say 45534. Since one port can be opened by only one process, only one process at a time would be able to open socket connection to the server.
Well, there are many ways to solve this as expressed in all the answers and comments, but may be the simpler way you can use is just have global status store in a place accesible for all the users of the current machine (may be you might have various users logged-in on the machine) where you store WHO has the right to have this open. Something like a "lock" as is used to be called. That store can be a field in a local or intranet database, a simple file, or whatever. That way you don't need to build or distribute extra binaries.
When a client connects to your server you create a new thread to handle him (not a process). You can store his IP address in a static dictionary (shared between all threads).
Something like:
static Dictionary<string, TcpClient> clients = new Dictionary<string, TcpClient>();
//This method is executed in a thread
void ProcessRequest(TcpClient client)
{
string ip = null;
//TODO: get client IP address
lock (clients)
{
...
if (clients.ContainsKey(ip))
{
//TODO: Deny connection
return;
}
else
{
clients.Add(ip, client);
}
}
//TODO: Answer the client
}
//TODO: Delete client from list on disconnection
The best solution we've come up with is to create a windows service that opens up a named pipe to manage multiple client processes through one socket connection to the server.
Then our API will be able to detect if the service is running/installed and fall back to creating it's own connection for the client otherwise.
3rd parties can decide if they want to bundle the service with their product or not, but core applications from our system will have it installed.
I will mark this as the answer in a few days if no one has a better option. I was hoping there was a way to execute our assembly as a new process, but all roads to do this do not seem very reliable.

Set service dependencies after install

I have an application that runs as a Windows service. It stores various things settings in a database that are looked up when the service starts. I built the service to support various types of databases (SQL Server, Oracle, MySQL, etc). Often times end users choose to configure the software to use SQL Server (they can simply modify a config file with the connection string and restart the service). The problem is that when their machine boots up, often times SQL Server is started after my service so my service errors out on start up because it can't connect to the database. I know that I can specify dependencies for my service to help guide the Windows service manager to start the appropriate services before mine. However, I don't know what services to depend upon at install time (when my service is registered) since the user can change databases later on.
So my question is: is there a way for the user to manually indicate the service dependencies based on the database that they are using? If not, what is the proper design approach that I should be taking? I've thought about trying to do something like wait 30 seconds after my service starts up before connecting to the database but this seems really flaky for various reasons. I've also considered trying to "lazily" connect to the database; the problem is that I need a connection immediately upon start up since the database contains various pieces of vital info that my service needs when it first starts. Any ideas?
Dennis
what your looking for is SC.exe. This is a command line tool that users can use to configure services.
sc [Servername] Command Servicename [Optionname= Optionvalue...]
more specificly you would want to use
sc [ServerName] config ServiceName depend=servicetoDependOn
Here is a link on the commandlike options for SC.EXE
http://msdn.microsoft.com/en-us/library/ms810435.aspx
A possible (far from ideal) code solution:
In you startup method code it as a loop that terminates when you've got a connection. Then in that loop trap any database connection errors and keep retrying as the following pseudo code illustrates:
bool connected = false;
while (!connected)
{
try
{
connected = openDatabase(...);
}
catch (connection error)
{
// It might be worth waiting for some time here
}
}
This means that your program doesn't continue until it has a connection. However, it could also mean that your program never gets out of this loop, so you'd need some way of terminating it - either manually or after a certain number of tries.
As you need your service to start in a reasonable time, this code can't go in the main initialisation. You have to arrange for your program to "start" successfully, but not do any processing until this method had returned connected = true. You might achieve this by putting this code in a thread and then starting your actual application code on the "thread completed" event.
Not a direct answer put some points you can look into
Windows service can be started Automatically with a delay. You can check this question in SO for some information about it.
How to make Windows Service start as “Automatic (Delayed Start)”
Check this post How to: Code Service Dependencies

What is the accepted pattern for an application that can be run as a service or as a console application

I have a project that is deployed to production as a windows service. However for local development purposes it would be useful to run it as a console application. At the moment I have a class Called ReportingHost that provides my core functionality, And a class called ReportingServiceHost that inherits from ServiceBase and allows me to run the application as a service. There is also a program class with a main method that calls ServiceBase.Run on my ReportingServiceHost.
I think I need to write a ReportingConsoleHost class that allows me to run the functionality in a console. Then I need to modify my Main to react to a command line switch and choose one or the other. These are the two bits I am having trouble with.
I have had a look at this and attempted to use that code but my app exits immediately, it doesn't show a console window and it doesn't wait for Enter before closing.
Part of the problem is that I dont have a deep understanding of how these things work. a definitive pattern for splitting my functionality, my two different ways of running that functionality, and a main method that chooses one of these ways based on a command line argument is what I am hoping to achieve.
I suspect your test project was configured as a windows exe, not a console exe. With a windows exe Console.ReadLine will return immediately.
To have a console exe that works both as a service and at the command line, start it as a service project (in Visual Studio) - and add a check on Environment.UserInteractive - i.e.
static void Main() {
if(Environment.UserInteractive) {
// code that starts the listener and waits on ReadLine
} else {
// run the service code that the VS template injected
}
}
You can of course also use a command line switch. I have example on microsoft.public.dotnet.languages.csharp that acts as:
an installer / uninstaller
a service
a console-mode app
depending on the switches
I have done this before by implementing a normal Windows Service (by deriving from ServiceBase), but putting a check in the main method to check for a command line argument.
If the args contain /console, start the console version, otherwise start the service.
Something like this:
internal class MyService : ServiceBase
{
internal static void Main(string[] args)
{
if (args.Length == 0)
{
// run as a service....
ServiceBase[] servicesToRun = new ServiceBase[] {new MyService()};
Run(servicesToRun);
}
else
{
// run as a console application....
}
}
}
My advise? Put all your logic for your service in a separate assembly. (A class library or DLL.) Then create one project as service which references your class library and puts the code to use as services. Create a second console project which also references your class library but which will make it available as a console application.
You would end up with three different projects in your solution but it does allow you to keep things separate. Actually, this would make it possible to extend your service in several other shapes too. You could, for example, create a 4th project as a web service and thus call your service from a web browser on a client system. Because the software logic is separated from the usage logic, you gain lots of control over it.
Be aware that a service will possibly run with more limitations than a console application. In general, services don't have network access by default, don't have a monitor assigned to them to display error messages and in general run with a limited user account or system account. Your service might work as a console yet fail as a service because of this.
There are already two good answers above - but I thought I'd post a link to Brian Noyes' Debuggable Self-Host Windows Service Project blog post - it talks about WCF but should apply to any 'Windows Service'.
The best thing is the sample code - if you can't figure out where the above examples 'fit', grab the complete project and see how it works. Thanks Brian!

Categories

Resources