I am creating a simple ASP.NET solution that is based on the ABP and as a part of this solution I use a standard Windows service that is supposed to do small background operations (so far only ICMP ping, but later probably more).
Is it possible to use the ABP application services inside of this Windows service (ideally using IoC)?
Thanks for any suggestion.
ofcourse you can use your AppServices in a Windows Service project. Also you can write background jobs in the windows service. You need to reference to your Application project from Windows Service. As each project behaves as module. Your new Windows Service needs to be registered as module. so you can use dependency services and other useful ABP libraries.
I'll show you some sample codes about moduling. But i recommend you to read the module doc : https://aspnetboilerplate.com/Pages/Documents/Module-System
MyWindowsServiceManagementModule.cs
[DependsOn(typeof(MySampleProjectApplicationModule))]
public class MyWindowsServiceManagementModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
MyWindowsServiceWinService.cs
public partial class MyWindowsServiceWinService : ServiceBase
{
private MyWindowsServiceManagementBootstrapper _bootstrapper;
public MyWindowsServiceWinService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
_bootstrapper = new MyWindowsServiceManagementBootstrapper();
_bootstrapper.Initialize();
}
catch (Exception ex)
{
//EventLog.WriteEntry("MyWindowsService can not be started. Exception message = " + ex.GetType().Name + ": " + ex.Message + " | " + ex.StackTrace, EventLogEntryType.Error);
}
}
protected override void OnStop()
{
try
{
_bootstrapper.Dispose();
}
catch (Exception ex)
{
//log...
}
}
}
MyWindowsServiceManagementBootstrapper.cs
public class MyWindowsServiceManagementBootstrapper : AbpBootstrapper
{
public override void Initialize()
{
base.Initialize();
}
public override void Dispose()
{
//release your resources...
base.Dispose();
}
}
Ps: As I wrote the codes on the top off my head, it might throw errors but basically this should guide you.
Related
So I am just messing around here nothing production just proof of concept with my first ever Windows Service.
I am trying to essentially create a windows service that sits as the listener for a signalr connection. In essence, I will have a windows application and a windows service. The win service will handle connecting to the signalr hub and on signalr calls fire an event. The windows application will listen for these events and perform actions based on them.
Currently I cannot get this to work. I have never worked with events, or windows services before. In my windows application my events never hit their break points, as well I log an error of null reference exception from the
ConnectToHub()
Alright if I comment out the OnConnected() method call I log a successful connection to the hub. I have never worked with events before so is my mistake with the events?
I debated that this approach was a bit overkill. However, for me it was a proof of concept that I could find a use for a long running windows service, and adding some events into the mix.
Code for service:
public delegate void MessageRecievedEventHanlder(object sender, MessageRecievedArgs e);
public delegate void ConnectedToHubEventHandler(object sender, ConnectedArgs e);
public partial class SignalRService : ServiceBase
{
IHubProxy _hub;
HubConnection connection;
string url = #"http://localhost:8080/";
private Message LastMessage;
public static event MessageRecievedEventHanlder NewMessage;
protected virtual void OnNewMessage(MessageRecievedArgs e)
{
NewMessage(null, e);
}
public static event ConnectedToHubEventHandler Connected;
protected virtual void OnConnected(ConnectedArgs e) {
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Logg.txt", "Hit OnConnected " + e.Success +" " + Connected != null ? "Isn't null" : "Null event");
Connected(null, e);
}
public SignalRService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ConnectToHub().Wait();
}
private async Task ConnectToHub()
{
try
{
//Connecting
if (connection == null)
{
connection = new HubConnection(url);
}
if (_hub == null)
{
_hub = connection.CreateHubProxy("ChatHub");
}
await connection.Start();
//Connected
//Configure all the incoming options
_hub.On<Message>("RecieveMessage", IncomingMessage);
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Succes.txt", "Connected");
OnConnected(new ConnectedArgs(true));
}
catch (Exception ex)
{
//Failed
//OnConnected(new ConnectedArgs(false));
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Fail.txt", "Failed to connect " + ex.Message.ToString());
}
}
private void IncomingMessage(Message state)
{
DateTime? lmt;
//Determine if has lastmessagetime
if (LastMessage == null) {
lmt = null;
}
else {
lmt = LastMessage.RecievedAt;
}
LastMessage = state;
//New Message
//OnNewMessage(new MessageRecievedArgs(state, lmt));
}
protected override void OnStop()
{
}
}
public class MessageRecievedArgs : EventArgs
{
public Message NewMessage { get; }
public DateTime? LastMessageTime { get; }
public MessageRecievedArgs(Message msg, DateTime? lmt) {
this.NewMessage = msg;
this.LastMessageTime = lmt;
}
}
public class ConnectedArgs : EventArgs {
public bool Success { get; }
public ConnectedArgs(bool suc) {
this.Success = suc;
}
}
My windows application as of now:
public MainWindow()
{
InitializeComponent();
SignalRService.SignalRService.NewMessage += SignalRService_NewMessage;
SignalRService.SignalRService.Connected += SignalRService_Connected;
}
private void SignalRService_Connected(object sender, SignalRService.ConnectedArgs e)
{
throw new NotImplementedException();
}
private void SignalRService_NewMessage(object sender, SignalRService.MessageRecievedArgs e)
{
throw new NotImplementedException();
}
Your question is a bit broad- you don't describe exactly what isn't working, so I am guessing that when you start your service, it says "starting..." for a long while and eventually windows service manager gives you an error saying your service didn't start in a timely fashion. The issue is that OnStart() is expected to return- you can't block the thread there with the Wait() call. My suggestion would be to spawn a new background thread here to perform the waiting, then exit. That should get you past the first hurdle.
As another aside... You can add a regular main method to a windows service project, change the project type to Console Application, and run it that way to reduce your debugging cycle time. Then when you are sure it basically works, change the project type back to Windows Service and install it.
EDIT: Now that you have a better error description, I see the real problem. The issue is that you are raising an event without checking for null first. Event fields are null until you attach a listener. So change your code as follows:
protected virtual void OnConnected(ConnectedArgs e) {
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Logg.txt", "Hit OnConnected " + e.Success +" " + Connected != null ? "Isn't null" : "Null event");
ConnectedToHubEventHandler connectedEvent = Connected;
if (connectedEvent != null) // This event might be null, so check first
connectedEvent(null, e);
}
So I am trying to experiment (based on this EasyNetQ toturial: Quick Start - EasyNetQ) with a simple EasyNetQ messaging architecture involving a Publisher and a Subscriber and it doesn't seem to be working quite as expected. Both my Publisher and Subscriber are Windows Service projects in Visual Studio 2015 and the message being sent between them is an instance of a custom type (TextMessage), which is a simple Class Library that looks like this:
namespace Messaging.Messages
{
public class TextMessage
{
public string Text { get; set; }
}
}
My Publisher looks like this:
namespace Messaging.Publisher
{
public partial class ReportService : ServiceBase
{
private Timer timer = null;
public ReportService()
{
this.InitializeComponent();
}
protected override void OnStart(string[] args)
{
Library.WriteErrorLog("Report Publisher Service started");
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Publish(new TextMessage
{
Text = "Hello"
});
}
}
protected override void OnStop()
{
this.timer.Enabled = false;
Library.WriteErrorLog("Test window service has stopped");
}
}
}
So nothing fancy. All it does is publish one message of type TextMessage and logs to a text file "PublisherLogFile.txt":
namespace Messaging.Publisher
{
public static class Library
{
public static void WriteErrorLog(string Message)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\PublisherLogFile.txt", true);
sw.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ": " + Message);
sw.Flush();
sw.Close();
}
catch (Exception)
{
throw;
}
}
}
}
And the Subscriber looks like this:
namespace Messaging.Subscriber
{
public partial class ReportSubscriberService : ServiceBase
{
public ReportSubscriberService()
{
this.InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteErrorLog("Report Subscriber Service started");
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Subscribe<TextMessage>("testId", HandleTextMessage);
}
}
protected override void OnStop()
{
WriteErrorLog("Exiting Report Subscriber Service");
}
private static void HandleTextMessage(TextMessage textMessage)
{
WriteErrorLog("Got message: " + textMessage.Text);
}
private static void WriteErrorLog(string Message)
{
try
{
var sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\SubscriberLogFile.txt", true);
sw.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ": " + Message);
sw.Flush();
sw.Close();
}
catch (Exception)
{
throw;
}
}
}
}
Also very simple. All it does is receive messages of type TextMessage and prints out the value of their Text attribute to a log file "SubscriberLogFile.txt". The problem is that it doesn't seem to be receiving the message because it doesn't log to the text file above. It looks like the HandleTextMessage handler in my Suscriber is never called. This is the content of "SubscriberLogFile.txt":
Also, looking at the RabbitMQ management console, no connections or channels are created, just one queue:
And the RabbitMQ log:
When I first did the same experiment, but with the difference that the Publisher and Subscriber were Console Applications instead of Windows Services, things seemed to work fine. What could be the problem here?
The problem was that I was disposing the bus as soon as I opened it. Instead it has to stay open and only be disposed when the service is stopped, on the OnStop event.
I have 3 projects in my solution:
Scheduler (Windows application)
WCF Service (WCF)
WindowsService (Windows Service)
My Scheduler use WCF Service functions and runs them when Scheduler decide.
All this works fine,and know i add new project Windows Service that his purpose is to launch Scheduler every time when PC is up, and here I fail.
I never worked with Windows Service sow i am new at this.I added the reference of Scheduler to WindowsService and still can't find the way to run it.
I will be very glad for any help.
Here my code that i tried.
My WindowsService project
My namespace WindowsService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// Scheduler myscheduler = new Scheduler();
// Scheduler.SchedulerForm myForm = new Scheduler.SchedulerForm();
}
protected override void OnStop()
{
}
}
}
And my Scheduler Project (Main)
static void Main()
{
string step = "";
try
{
ServiceHost client = new ServiceHost(typeof(WcfService.Service));
try
{
using (client = new ServiceHost(typeof(WcfService.Service)))
{
step = "1";
if (client.State == CommunicationState.Faulted)
{
step = "2";
System.Windows.Forms.MessageBox.Show(step);
System.Windows.Forms.MessageBox.Show("Faulted state. " + step);
client.Abort();
}
client.Open();
SysTrayApp();
Application.Run();
}
}
catch (Exception ex)
{
if (client.State == CommunicationState.Faulted)
{
step = "Faulted";
System.Windows.Forms.MessageBox.Show(step);
client.Abort();
client = new ServiceHost(typeof(WcfService.Service));
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message + " " + ex.Source + " " + ex.StackTrace);
}
}
I'm new to windows service and I'm facing a problem I need to call a function on my services on start method but its not working. When I'm starts the service the following error occures
"The MIM service on local Computer started and then stopped.Some
service stop automatically if they are not in use by other services or
programs"
and my current code is given below
public CHK()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Logger.Message("ChkUser", "Service Start", "");
CheckUser();
}
protected override void OnStop()
{
Logger.Message("MChkUser", "Service Stop", "");
}
public void CheckUser()
{
//actions
}
and If I didnt call the CheckUser() method then the service works without any problem. What will be the reason behind this???
Most likely the reason is that your CheckUser() method throws an uncaught exception ...
To see what the exception is try simply putting the call to the method inside a try-catch block :
protected override void OnStart(string[] args)
{
Logger.Message("ChkUser", "Service Start", "");
try {
CheckUser();
} catch (Exception e) {
Logger.Message("ChkUser", e.Message, "");
}
}
I created a windows service and installer that watches a collection of files for changes and copies any file that changes to a destination directory specified in the WatchlistConfig.xml file.
I have a couple issues with the service:
1. It has stopped running on one occasion. (unacceptable)
2. We sometimes have to attempt to start the service several times before it "takes".
I believe issue #1 is probably due to not handling fatal errors in the application. I found a bit of code that I tried to incorporate into the Main() method, but is written for a console app (Application is not a recognized class) and thus is commented out for now. Any idea which is the right class for implementing this in a service?
Issue #2 is most likely a timeout I'm guessing. The watchlist is currently comprised of 9 different files on different machines on the network. Connecting to these sources is not immediate (not all on a single domain). Is there a way to set a different timeout value for service startup?
Here's the relevant code. Additional classes on request.
Thanks in advance.
Edit: mistakenly posted the Main() from the test harness (console) which I use to debug. I've left it in place and add the Program class from the WinSvc Project
//Console Test harness
class Program
{
[STAThread]
static void Main(string[] args)
{
//AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
//Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
//Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile()));
Console.WriteLine("Press \'q\' to quit the sample.");
while (Console.Read() != 'q') ;
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException((Exception)e.ExceptionObject);
}
static void HandleException(Exception e)
{
//Handle/Log Exception Here
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Logger.Loggit(e.Exception.Message);
}
}
//Actual Service
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Psu()
};
ServiceBase.Run(ServicesToRun);
}
}
public partial class Psu : ServiceBase
{
public Psu()
{
InitializeComponent();
TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile()));
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
public class TimedWatchList
{
public static PSU_Config Config { get; set; }
List<WatchFile> WatchList = new List<WatchFile>();
public TimedWatchList(PSU_Config config)
{
Config = config;
if (Config.PrintDebugMsgs) Logger.Loggit("Attempting to create TimedWatchList object");
WatchList = WatchListFactory.GetWatchList(Helpers.GetWatchListFile());
if (Config.PrintDebugMsgs) Logger.Loggit("TimedWatchList created");
Timer _timer = new Timer();
_timer.Interval += Config.Interval;
_timer.Enabled = true;
// register OnTimedEvent() to fire on each "tick"
_timer.Elapsed += OnTimedEvent;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
foreach (WatchFile file in WatchList)
{
file.PostOnUpdate();
}
}
}//TimedWatchList class
internal class WatchFile
// represents a file that is being watched
{
#region Props
public FileInfo SourceFile { get; set; }
public DirectoryInfo TargetPath { get; set; }
#endregion //Props
#region CTOR
public WatchFile() { }
public WatchFile(string fileName, string sourcePath, string destPath)
{
SourceFile = new FileInfo(Path.Combine(sourcePath, fileName));
TargetPath = new DirectoryInfo(destPath);
}
public WatchFile(FileInfo sourceFile, DirectoryInfo targetDirectory)
{
SourceFile = sourceFile;
TargetPath = targetDirectory;
}
#endregion //CTOR
public void PostOnUpdate()
{
//if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("WatchFile Post Event called for: " + SourceFile.Name);
//if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("Stored LastModified datetime: " + LastModified);
string targetPath = String.Format(#"{0}\{1}", TargetPath.FullName, SourceFile.Name);
{
try
{
//ensure directory exists
if (!Directory.Exists(TargetPath.FullName)) Directory.CreateDirectory(TargetPath.FullName);
//ensure file version is current
if (!File.Exists(targetPath) || (File.GetLastWriteTime(targetPath) != File.GetLastWriteTime(SourceFile.FullName)))
{
Logger.Loggit(String.Empty);
Logger.Loggit("Attempting to copy: " + SourceFile + " (" + File.GetLastWriteTime(SourceFile.FullName) + ")");
SourceFile.CopyTo(targetPath, true);
Logger.Loggit("\tCopy posted.\tLastModified: " + File.GetLastWriteTime(targetPath));
}
}
catch (IOException ioex)
{
Logger.Loggit("Error: " + ioex.Message);
}
catch (Exception ex)
{
Logger.Loggit("Error: " + ex.Message);
}
}
}
}// WatchFile class
There's really no need to guess; as a service you should be logging your errors to the system event log. Set a top level handler (as you've done), but don't expect to be able to handle it.
If the error was unhandled you're not going to be able to do anything about it there. Log it and exit. Catch the errors you can handle as soon as possible, test and design your code to not break otherwise.
You can set your service to restart automatically after a crash, but that should be a last resort. Bust out your debugger and figure out exactly where the errors are occurring and why. I see a lot of "it's probably [something]" and "it may be [something else]" statements here. Again, there is no good reason to guess; you have tools at your disposal which will help you figure out exactly what is going on.
You might want to simply wrap your function in a try / catch block to see what you might find.
try
{
MainAppFunctionality();
}
catch (Exception e)
{
//Not sure what you are going to do here, it's probably too late
}
I suggest you log to the Windows Event Log at various points in your application as a start so you can start to narrow down the location of the error.
I'm also not sure why you are using Console.Read() from a Windows Service context. As of Vista, there isn't a way for the service to interact with the desktop.