How to trigger a Service in a Network Service Account on a server when a client logs in?

436 Views Asked by At

We have an existing system in which a windows service, which is network service enabled, is hosted on a network service account on the server. There are windows services installed on every client which start automatically once a user logs in through each client and these services on client trigger the service on the server telling it that for e.g client A has logged in.

What i want to do is create a network service and host it on the server, and trigger it directly without installing a separate windows service on each client. Is it possible? I want each client to use the existing network service and inform it upon log-in that it is online. Sort of maintaining a user log-in log at the server with time.

1

There are 1 best solutions below

6
taquion On

I have made this using Simple Impersonation Library. Here is the snippet that I use on my WPF client.

public static async Task ToggleServiceStatus(this EdiServiceInfo serviceInfo)
        {
            await Task.Factory.StartNew(() =>
            {
                using (
                    Impersonation.LogonUser(serviceInfo.Domain, serviceInfo.User, serviceInfo.Pswd,
                        Environment.MachineName.Equals(serviceInfo.ComputerName,
                            StringComparison.InvariantCultureIgnoreCase)
                            ? LogonType.Network
                            : LogonType.Interactive))
                {
                    var service = new ServiceController(serviceInfo.ServiceName, serviceInfo.ComputerName);
                    if (service.Status == ServiceControllerStatus.Stopped)
                    {
                        service.Start();
                        service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60));
                    }
                    else
                    {
                        service.Stop();
                        service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60));
                    }
                }
            });
        }

This is useful if you want to trigger the service from your client. But if the service is already working and just want to respond to log in, then you could maintain a table of clients with a flag DidLoggedIn, and your windows service should have a long running task monitoring this flags. The idea here is that whenever the client logs in you will set the flag to true, and on your server side the windows service's long running task will detect this and well do whatever you want it to do.

Hope it helps

EDIT>>> I have an application that does so. Let me share some snippets.

public virtual async Task InitAsync()
        {
            EdiDataAccess.ResetServiceFlags();
            EdiDataAccess.SetServiceAsWorking();
            var startMonitorTask = new Func<Task>(StartAllWorkersAsync)
                .CyclicalTask(TimeSpan.FromSeconds(MonitorSeconds), MonitorCancellationToken);
            var stopMonitorTask = new Func<Task>(StopRequestsMonitor)
                .CyclicalTask(TimeSpan.FromSeconds(MonitorSeconds), MonitorCancellationToken);
            await TaskEx.WhenAll(startMonitorTask, stopMonitorTask);
        }

startMonitorTask is the long running task to monitor the flags. CyclicalTask is just an extension method of my own:

public static Task CyclicalTask(this Func<Task> task, TimeSpan waitTimeSpan,
            CancellationToken token = default(CancellationToken))
        {
            return TaskEx.Run(async () =>
            {
                while (true)
                {
                    token.ThrowIfCancellationRequested();
                    await task();
                    token.WaitHandle.WaitOne(waitTimeSpan);
                }
            }, token);
        }

StartAllWorkersAsync is the method than has the monitoring funcionality.

protected virtual async Task StartAllWorkersAsync()
        {
            var ediCustomersToStart = EdiDataAccess.GetEdiCostumersToStart();
            var ediTasks = ediCustomersToStart
                .Select(StartWorkerAsync)
                .ToList();
            await TaskEx.WhenAll(ediTasks);
        }

Where EdiDataAccess.GetEdiCostumersToStart(); retrieves all those customers that have requested to log in

This my window service can detect when a customer has requested to begin a session.