I want to write error log from windows service. I know to call a customcommand from windows service, but it will not allow any parameters. I want to pass my error message to service and the customcommand will write the log. How can I do it. I tried something
I have created a static string variable in my library class.
Whenever an error occurs I am calling the function like
ATELib.AteBAC.getErrorMessage = "error message from client";
ServiceController Controller = new ServiceController("ATELogsService");
if (Controller.Status == ServiceControllerStatus.Running)
{
Controller.ExecuteCommand(128);
}
and the code in my service is
protected override void OnCustomCommand(int command)
{
if (command == 128)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(Application.StartupPath + #"\ATELogCheck.txt", true))
{
file.WriteLine(ATELib.AteBAC.getErrorMessage);
ATELib.AteBAC.getErrorMessage = null;
}
}
}
it is creating the errorlog file(ATELogCheck.txt) but the error message(string value) is not there in the file, creating an empty txt file. It is a static variable even why it is writterning empty. I am using tcp protocol and calling the service object as
baCls = (ATELib.AteBAC)Activator.GetObject(typeof(ATELib.AteBAC), "tcp://localhost:9090/ATE");
How can I pass the string value to the service?
Because your service runs in different domain from your application. So the ATELib.AteBAC.getErrorMessage in your application is different from ATELib.AteBAC.getErrorMessage in your service.
I honestly think, if you have to do something like this, you have issues in the design of your application. The service is really there to do something continuously. Or, it can "sleep" and listen to TCP port. Once signal received, it can find work and execute. Definitely, look into design first, before going into unneeded complexities.
Related
I just started to learn C# for a school project but I'm stuck on something.
I have a solution with 2 projects (and each project has a class), something like this:
Solution:
Server (project) (...) MyServerClass.cs, Program.cs
App (project) (...) MyAppClass.cs, Program.cs
In my "MyServerClass.cs", I have this:
class MyServerClass
{
...
public void SomeMethod()
{
Process.Start("App.exe", "MyAppClass");
}
}
How can I properly send, for example, an IP address and port? Would something like this work?
class MyServerClass
{
....
public void SomeMethod()
{
string ip = "127.0.0.1";
int port = 8888;
Process.Start("App.exe", "MyAppClass " + ip + " " + port);
}
}
Then in my "MyAppClass.cs", how can I receive that IP address and port?
EDIT:
The objective of this work is to practice processes/threads/sockets. The idea is having a server that receives emails and filter them, to know if they're spam or not. We got to have 4 or 5 filters. The idea was having them as separated projects (ex: Filter1.exe, Filter2.exe, ...), but I was trying to have only 1 project (ex: Filters.exe) and have the filters as classes (Filter1.cs, Filter2.cs, ...), and then create a new process for each different filter.
I guess I'll stick to a project for each filter!
Thanks!
There are a number of ways to achieve this, each with their own pros/cons.
Some possible solutions:
Pass the values in on the command line. Pros: Easy. Cons: Can only be passed in once on launch. Unidirectional (child process can't send info back). Doesn't scale well for complex structured data.
Create a webservice (either in the server or client). Connect to it and either pull/push the appropriate settings. Pros: Flexible, ongoing, potentially bi-directional with some form of polling and works if client/server are on different hosts. Cons: A little bit more complex, requires one app to be able to locate the web address of the other which is trivial locally and more involved over a network.
Use shared memory via a memory mapped file. This approach allows multiple processes to access the same chunk of memory. One process can write the required data and the others can read it. Pros: Efficient, bi-directional, can be disk-backed to persist state through restarts. Cons: Requires pointers and an understanding of how they work. Requires a little more manipulation of data to perform a read/write.
There are dozens more ways. Without knowing your situation in detail, it's hard to recommend one over another.
Edit Re: Updated requirements
Ok, command line is definitely a good choice here. A quick detour into some architecture...
There's no reason you can't do this with a single project.
First up, use an interface to make sure all your filters are interchangeable. Something like this...
public interface IFilter {
FilterResult Filter(string email);
void SetConfig(string config);
}
SetConfig() is optional but potentially useful to reconfigure a filter without a recompile.
You also need to decide what your IFilter's FilterResult is going to be. Is it a pass/fail? Or a score? Maybe some flags and other metrics.
If you wanted to do multiple projects, you'd put that interface in a "shared" or "common" project on its own and reference it from every other project. This also makes it easy for third parties to develop a filter.
Anyway, next up. Let's look at how the filter is hosted. You want something that's going to listen on the network but that's not the responsibility of the filter itself, so we need a network client. What you use here is up to you. WCF in one flavour or another seems to be a prime candidate. Your network client class should take in its constructor a network port to listen on and an instance of the filter...
public class NetworkClient {
private string endpoint;
private IFilter filter;
public NetworkClient(string Endpoint, IFilter Filter) {
this.filter = Filter;
this.endpoint = Endpoint;
this.Setup();
}
void Setup() {
// Set up your network client to listen on endpoint.
// When it receives a message, pass it to filter.Filter(msg);
}
}
Finally, we need an application to host everything. It's up to you whether you go for a console app or winforms/wpf. Depends if you want the process to have a GUI. If it's running as a service, the UI won't be visible on a user desktop anyway.
So, we'll have a process that takes the endpoint for the NetworkClient to listen on, a class name for the filter to use, and (optionally) a configuration string to be passed in to the filter before first use.
So, in your app's Main(), do something like this...
static void Main() {
try {
const string usage = "Usage: Filter.exe Endpoint FilterType [Config]";
var args = Environment.GetCommandLineArgs();
Type filterType;
IFilter filter;
string endpoint;
string config = null;
NetworkClient networkClient;
switch (args.Length) {
case 0:
throw new InvalidOperationException(String.Format("{0}. An endpoint and filter type are required", usage));
case 1:
throw new InvalidOperationException(String.Format("{0}. A filter type is required", usage));
case 2:
// We've been given an endpoint and type
break;
case 3:
// We've been given an endpoint, type and config.
config = args[3];
break;
default:
throw new InvalidOperationException(String.Format("{0}. Max three parameters supported. If your config contains spaces, ensure you are quoting/escaping as required.", usage));
}
endpoint = args[1];
filterType = Type.GetType(args[2]); //Look at the overloads here to control where you're searching
// Now actually create an instance of the filter
filter = (IFilter)Activator.CreateInstance(filterType);
if (config != null) {
// If required, set config
filter.SetConfig(config);
}
// Make a new NetworkClient and tell it where to listen and what to host.
networkClient = new NetworkClient(endpoint, filter);
// In a console, loop here until shutdown is requested, however you've implemented that.
// In winforms, the main UI loop will keep you alive.
} catch (Exception e) {
Console.WriteLine(e.ToString()); // Or display a dialog
}
}
You should then be able to invoke your process like this...
Filter.exe "127.0.0.1:8000" MyNamespace.MyFilterClass
or
Filter.exe "127.0.0.1:8000" MyNamespace.MyFilterClass "dictionary=en-gb;cutoff=0.5"
Of course, you can use a helper class to convert the config string into something your filter can use (like a dictionary).
When the network client gets a FilterResult back from the filter, it can pass the data back to the server / act accordingly.
I'd also suggest a little reading on Dependency Injection / Inversion of control and Unity. It makes a pluggable architecture much, much simpler. Instead of instantiating everything manually and tracking concrete instances, you can just do something like...
container.Resolve<IFilter>(filterType);
And the container will make sure that you get the appropriate instance for your thread/context.
Hope that helps
I am completely new to WCF and multithreading. So, I followed this tutorial to set up a selfhosted WCF service. After I right-clicked on the Interface "INews_Service", I clicked on "implement Interface". Then, VS creates a method named DoWork().
In the tutorial above, the DoWork() method is not needed (-> it is deleted). However, in my project, I would like to use this method to run a background worker thread/task.
In my project, the background worker is supposed to permanently load data from an external device and store it in the DataContract-class. The WCF Service, in turn, is supposed to simultaneously provide the instance of that DataContract-class to external WCF consumers.
In reference to the tutorial above, what is the best way to add a background worker method, which constantly changes the variables within an instance of the DataContract-class?
EDIT:
#Brian: Thank you very much! The following example shows the selfhosted service program from the tutuorial above. After I start the host, I would like to run an endless loop that constantly updates my DataContract-class. Can you make an example, how this can be done? I do not need any synchronization, such as SpinLock or Monitor?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCF_NewsService
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(News_Service));
host.Open();
Console.WriteLine("Host Open Sucessfully ...");
while (true)
{
//here I want to constantly update my DataContract-class TOInews
}
}
}
}
EDIT2:
Actually, my problem is that I don't know how to access my DataContract-object objtoinews, which is defined in another file (i.e. in NewsService, as in the tutorial). When I run something like objtoinews.ID = 1;, VS complains that objtoinews is not defined in the current context.
while (true)
{
if (host.State != CommunicationState.Opened)
{
throw new Exception("SynchronizationWS Service Host failed.");
break;
}
else
{
objtoinews.ID = 1;
objtoinews.Header = "blabla";
objtoinews.Body = "huhu";
}
}
You don't need to use DoWork in a WCF solution. Basically, the console program described in that tutoral will perform DoWork() when the Host.Open() is called. In other words, Host.Open() will do what you expect DoWork() will do.
The console acts as the executable, but all the work is done asynchronously/multi-threaded in the background by WCF service.
Booz, I'm not sure why you think you need to continously update your DataContract. I don't think you can, actually, while the program's running. If you're worried about people sending different data constructs to your WS host, maybe you need to abstract the structure so that (basically) your clients can send virtually anything.
In any event, here's the code I'm use to loop and check the status of my web service:
while (true) {
//broken connection case
if (wshost.State != CommunicationState.Opened) {
throw new Exception("Service Host failed.");
//dump from loop and throw error
break;
}
Threading.Thread.Sleep(1000); //sleep 1 second
}
I'm new in WCF. I am currently working on a project where I explained in my last question posted here --> How can I implement callbacks to another server in c#
I am trying to study callback with an example. It uses Console Application for hosting the service and Windows Forms for client. I must run my server B with Console application instead of Windows Form. Everything was fine when I run the service alone. But when I run my server B(client), an error was displayed:
"The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error."
It was pointing on this code in my serverB(client) code:
public void NotifySubscribe(string subscriberName)
{
SendOrPostCallback callback =
delegate (object state)
{
Console.WriteLine(String.Format("{0} has subscribe to service", state.ToString()));
Console.WriteLine(subscriberName);
Console.Read();
};
_uiSyncContext.Post(callback, subscriberName);
}
The almost imitated everything from an example that I have.
This was the original code of that code above:
public void NotifyGuestJoinedParty(string guestName)
{
// The UI thread won't be handling the callback, but it is the only one allowed to update the controls.
// So, we will dispatch the UI update back to the UI sync context.
SendOrPostCallback callback =
delegate (object state)
{ this.WritePartyLogMessage(String.Format("{0} has joined the party.", state.ToString())); };
_uiSyncContext.Post(callback, guestName);
}
private void WritePartyLogMessage(string message)
{
string format = this.txtPartyLog.Text.Length > 0 ? "{0}\r\n{1} {2}" : "{0}{1} {2}";
this.txtPartyLog.Text = String.Format(format, this.txtPartyLog.Text, DateTime.Now.ToShortTimeString(), message);
this.txtPartyLog.SelectionStart = this.txtPartyLog.Text.Length - 1;
this.txtPartyLog.ScrollToCaret();
}
Because I'm using Console Application in my project, instead of having it in a textbox, I write it using Console.writeline();
I don't know if it is about the delegate(object state) there in the code.
Please response. I don't know how to fix the bug. Thank you.
I am new with WCF as well.
I believe you cannot perform such action in a console application using a duplex service.
This question was asked 5 months ago, so I suppose you have found the answer you desire.
Please correct me if I am wrong. I'd appreciate it.
Usually, I get this error:
(The "service name" service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other service or programs) when there's something wrong with my code, like non-existing drive paths, etc. The windows service will not start.
I have a windows service that backs up folder/files, to a location if it reached the size limit. Details are all provide by an XML Configuration that the windows service reads on start. I have a separate windows forms that has a button that does exactly what my windows service's onstart is doing. I use my windows forms for debugging the code before I put it in my windows service.
When I start my windows forms. It does what it suppose to do. When I put my code in the windows service OnStart() method the error showed up.
Here's my code:
protected override void OnStart(string[] args)
{
private static string backupConfig = #"D:\LogBackupConfig\backupconfig.xml";
private static string serviceStat = #"D:\LogBackupConfig\Status.txt";
private static string fileFolderStat = #"D:\LogBackupConfig\FileFolderStat.txt";
protected override void OnStart(string[] args)
{
if (File.Exists(backupConfig))
{
FileSystemWatcher watcher = new FileSystemWatcher();
XmlTextReader reader = new XmlTextReader(backupConfig);
XmlNodeType type;
List<string> listFile = new List<string>();
string fileWatch = "";
//this loop is for reading XML elements and assigning to variables
while (reader.Read())
{
type = reader.NodeType;
if (type == XmlNodeType.Element)
{
if (reader.Name == "File")
{
reader.Read();
fileWatch = reader.Value;
}
else if (reader.Name == "Folder")
{
reader.Read();
fileWatch = reader.Value;
}
}
}
reader.Close();
watcher.Path = fileWatch;
watcher.Filter = "*.*";
//this loop reads whether the service will watch a file/folder
XmlTextReader reader1 = new XmlTextReader(backupConfig);
while (reader1.Read())
{
type = reader1.NodeType;
if (type == XmlNodeType.Element)
{
if (reader1.Name == "File")
{
watcher.IncludeSubdirectories = false;
watcher.Changed += new FileSystemEventHandler(OnChangedFile);
}
else if (reader1.Name == "Folder")
{
watcher.IncludeSubdirectories = true;
watcher.Changed += new FileSystemEventHandler(OnChangedFolder);
}
}
}
reader1.Close();
watcher.EnableRaisingEvents = true;
}
else
{
StreamWriter sw = new StreamWriter(serviceStat, true);
sw.WriteLine("File not found. Please start the Log Backup UI first.");
sw.Close();
}
}
I don't know what keeps the windows service not starting, the windows form simulator worked fine. What seems to be the problem?
UPDATE:
After many trials I've noticed that using only a folder directory (w/out file), the windows service doesn't work. When I replaced the fileWatch variable with a specific file (including its directory), the windows service started. When I changed it back to a folder location, it didn't work. What I think is that folder locations doesn't work in a filewatcher.
When I tried creating a new windows service that watches a folder location, it worked.. However, when I tried the same location in my original windows service, it didn't work! I was mindf$#*ed! It seems that I have to create a new windows service and build the installer everytime I place a new code/function.. This way I can keep track where I get an error.
If the service starts and stops like that, it means your code is throwing an unhandled exception. This is pretty difficult to debug, but there are a few options.
Consult the Windows Event Viewer. Normally you can get to this by going to the computer/server manager, then clicking Event Viewer -> Windows Logs -> Application. You can see what threw the exception here, which may help, but you don't get the stack trace.
Extract your program logic into a library class project. Now create two different versions of the program: a console app (for debugging), and the windows service. (This is a bit of initial effort, but saves a lot of angst in the long run.)
Add more try/catch blocks and logging to the app to get a better picture of what's going on.
Not sure this will be helpful, but for debugging a service you could always use the following in the OnStart method:
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
...
}
than you could attach your visual studio to the process and have better debug abilities.
hope this was helpful,
good luck
I have found it very handy to convert your existing windows service to a console by simply changing your program with the following. With this change you can run the program by debugging in visual studio or running the executable normally. But it will also work as a windows service. I also made a blog post about it
program.cs
class Program
{
static void Main()
{
var program = new YOUR_PROGRAM();
if (Environment.UserInteractive)
{
program.Start();
}
else
{
ServiceBase.Run(new ServiceBase[]
{
program
});
}
}
}
YOUR_PROGRAM.cs
[RunInstallerAttribute(true)]
public class YOUR_PROGRAM : ServiceBase
{
public YOUR_PROGRAM()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Start();
}
protected override void OnStop()
{
//Stop Logic Here
}
public void Start()
{
//Start Logic here
}
}
Please check that you have registered all HTTP endpoints in the local mahcine's Access Control List (ACL)
http://just2thepoint.blogspot.fr/2013/10/windows-service-on-local-computer.html
EventLog.Log should be set as "Application"
Meanwhile, another reason : accidentally deleted the .config file caused the same error message appears:
"Service on local computer started and then stopped. some services stop automatically..."
Use Timer and tick event to copy your files.
On start the service, start the time and specify the interval in the time.
So the service is keep running and copy the files ontick.
Hope it help.
You may want to unit test the initialization - but because it's in the OnStart method this is near to impossible. I would suggest moving the initialization code out into a separate class so that it can be tested or at least re-used in a form tester.
Secondly to add some logging (using Log4Net or similar) and add some verbose logging so that you can see details about runtime errors. Examples of runtime errors would be AccessViolation etc. especially if your service is running without enough privileges to access the config files.
The account which is running the service might not have mapped the D:-drive (they are user-specific). Try sharing the directory, and use full UNC-path in your backupConfig.
Your watcher of type FileSystemWatcher is a local variable, and is out of scope when the OnStart method is done. You probably need it as an instance or class variable.
I came across the same issue. My service is uploading/receiving XMLS and write the errors to the Event Log.
When I went to the Event Log, I tried to filter it. It prompt me that the Event Log was corrupted.
I cleared the Event Log and all OK.
In our case, nothing was added in the Windows Event Logs except logs that the problematic service has been started and then stopped.
It turns out that the service's CONFIG file was invalid. Correcting the invalid CONFIG file fixed the issue.
I'm in the process of designing the architecture of an application I’m planning on building and need some advice on the best way to implement a specific windows service component described below. I'll be building the service using .net 4.0 so I can take advantage of the new parallel and task APIs, I’ve also looked at using the MSMQ service however I’m not sure this is appropriate for what I hope to achieve.
The simplest way of explaining my use case is that users can create a number of reminders of different types for a task that they need to complete, which they create using a web-based application built in ASP.NET MVC 2. These reminders can be of various types for example email and SMS, which of cause must be sent at the specified due time. The reminders can be changed up until the point they have been sent to the user, paused and cancelled all together, which I guess makes a queuing based service such as MSMQ not appropriate?
I plan to host a windows service that will periodically (unless there is a more appropriate way?) check to see if there are any reminders due, determine their type and pass them to the specific component to deal with them and send them off. If an exception occurs the reminder will be queued up at a set interval and tried again, this will continue to happen with the interval increasing until they meet a set threshold at which point they are discarded and logged as a failure. To add a final layer of complexity to the service, I hope to specify in a configuration file the concrete implementation of each type (This means I can say change the SMS service due to cost or whatever), which are loaded at service start-up dynamically. Any reminders of an unknown or unavailable type will of cause automatically fail and be logged as before.
Once a reminder has been successfully sent it simply discards it, however with the SMS gateway I’m planning to use, it requires me to call its API to find out whether the message was successfully delivered or not, which means an additional timer is required at a set interval to check for this. It would also be nice to be able to add additional reminder type services that conform to a unified interface at service start-up without the need to change its code.
Finally, I don't know whether this should be posted as a separate question or not but I wondered would it be possible to say build a console application that could be started/stopped at anytime and when running can see what the windows service is currently doing?
This is my first ever question on Stackoverflow, even though I’ve been using the community for a while so I apologise if I’ve done some incorrectly.
Thanks in advance,
Wayne
For the second part of your question, I have been thinking about this and here is a class I put together that helps to create a service which can be run both as a Console application as well as a Windows Service. This is fresh off the press, so there might be some issues to resolve, and some refactoring required esp. around the reflection code.
NB: You should set the Service project Output type to Console Application, this will still work fine as a normal service.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;
namespace DotNetWarrior.ServiceProcess
{
public class ServiceManager
{
private List<ServiceBase> _services = new List<ServiceBase>();
public void RegisterService(ServiceBase service)
{
if (service == null) throw new ArgumentNullException("service");
_services.Add(service);
}
public void Start(string[] args)
{
if (Environment.UserInteractive)
{
foreach (ServiceBase service in _services)
{
Start(service, args);
}
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(_services.ToArray());
}
}
public void Stop()
{
foreach (ServiceBase service in _services)
{
Stop(service);
}
}
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Stop();
Environment.Exit(0);
}
private void Start(ServiceBase service, string[] args)
{
try
{
Type serviceType = typeof(ServiceBase);
MethodInfo onStartMethod = serviceType.GetMethod(
"OnStart",
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(string[]) },
null);
if (onStartMethod == null)
{
throw new Exception("Could not locate OnStart");
}
Console.WriteLine("Starting Service: {0}", service.ServiceName);
onStartMethod.Invoke(service, new object[] { args });
Console.WriteLine("Started Service: {0}", service.ServiceName);
}
catch (Exception ex)
{
Console.WriteLine("Start Service Failed: {0} - {1}", service.ServiceName, ex.Message);
}
}
private void Stop(ServiceBase service)
{
try
{
Type serviceType = typeof(ServiceBase);
MethodInfo onStopMethod = serviceType.GetMethod(
"OnStop",
BindingFlags.NonPublic | BindingFlags.Instance);
if (onStopMethod == null)
{
throw new Exception("Could not locate OnStart");
}
Console.WriteLine("Stoping Service: {0}", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped Service: {0}", service.ServiceName);
}
catch (Exception ex)
{
Console.WriteLine("Stop Service Failed: {0} - {1}", service.ServiceName, ex.Message);
}
}
}
}
To use this, you can rip the standard code out of the Main entry point of the service and replace it with the following.
static void Main(string[] args)
{
ServiceManager services = new ServiceManager();
services.RegisterService(new Service1());
services.Start(args);
}
The services.Start() method will detect that the service is being run as an interactive application and manually invoke the OnStart method of all the registered services, once started the main thread goes to sleep. To stop the services, just press 'Ctrl+C` which will result in the Services being stopped by calling the OnStop method of the service.
Of course is the application is run as a Service by the SCM then everyhing works as a normal service. The only caveat is that the service should not require to be run with 'Allow service to interact with desktop' since this will make the service run in interactively even though it is run as a service. This can be worked around if required, but hey I only just wrote the code.
Monitoring and Starting/Stopping a Service
From the command line you can use the NET.EXE to Start/Stop a service
Start a service
net start <service name>
Stop a service
net stop <service name>
For managing a service from .NET you can use System.ServiceProcess.ServiceController
// Stop a service
System.ServiceProcess.ServiceController sc = new
System.ServiceProcess.ServiceController("<service name>");
sc.Stop();
For general communication with the service other than what is provided through ServiceController I would suggest that you host a WCF service as part of your service, which you can then use to communicate with the service to query internal details specific to your service.
Handling the Scheduling
To be honest, I was hesitant to answer this aspect of the question since there are so many approaches each with there Pros/Cons. So I will just give some high level options for you to consider. You have probably thought this through already, but here are a few things off the top of my head
If you are using SQL Server to store the notifications.
Have an SP that you can call to retrieve the reminders that are due, then process the result to raise the reminders approriately.
With this SP you have some options
Call the SP periodically from your service and process the reminders
Have a SQL Job that periodically runs the SP and adds a reminder to a Service Broker Queue. Your Service can then subscribe to the Queue and process reminders as they appear on the Queue. The advantage of this approach is that you can scale out with multiple servers processing the reminder notification generation without any special coding, just add another server that runs your service and the messages will automatically be distributed between the two servers.
If you are not using SQL Server to store the reminders
You can still use a similar approach as for SQL Server. Of course the Windows Service can query the data store using what ever is approapriate and process the reminders. Getting this to scale is a little harder since you will need to ensure that multiple servers do not process the same reminder etc. but not a train smash.
I think that covers the gist of it, everything else is some variation on the above. Ultimately your decision would depend on the target volumes, reliability requirements etc..