Getting a Topshelf service to run once on boot, then stop - windows-services

I have written a TopShelf service / console app, which appears to be running as intended, except I would like it to run once on boot, then disable itself until the next boot/reboot.
I was hoping this would work:
class MyServiceClass
{
public void Start()
{
// do the things that need doing
this.Stop();
}
public void Stop()
{
}
But that doesn't work, presumably because the this.Stop() command is there for cleanup, not for causing the service to stop.
My Program.cs looks like this:
// Uses Topshelf: http://topshelf-project.com/
// Guided by: http://www.ordina.nl/nl-nl/blogs/2013/maart/building-windows-services-with-c-and-topshelf/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Topshelf;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
HostFactory.Run(hostConfigurator =>
{
hostConfigurator.Service<MyServiceClass>(serviceConfigurator =>
{
serviceConfigurator.ConstructUsing(() => new MyServiceClass());
serviceConfigurator.WhenStarted(myServiceClass => myServiceClass.Start());
serviceConfigurator.WhenStopped(myServiceClass => myServiceClass.Stop());
});
hostConfigurator.RunAsLocalSystem();
hostConfigurator.SetDisplayName("MyService");
hostConfigurator.SetDescription("Does stuff.");
hostConfigurator.SetServiceName("MyService");
hostConfigurator.StartAutomatically();
hostConfigurator.EnableShutdown();
});
}
};
}
How do I go about stopping the service at the end of execution?
UPDATE: Based on Damien's input, I now have:
public class MyServiceClass
{
private readonly Task task;
private HostControl hostControl;
public MyServiceClass()
{
task = new Task(DoWork);
}
private void DoWork()
{
Console.WriteLine("Listen very carefully, I shall say this only once");
hostControl.Stop();
}
public void Start(HostControl hostControl)
{
// so we can stop the service at the end of the check
this.hostControl = hostControl;
// start the DoWork thread
task.Start();
}
public void Stop()
{
}
};
and an updated Program.cs
class Program
{
static void Main(string[] args)
{
HostFactory.Run(hostConfigurator =>
{
hostConfigurator.Service<MyServiceClass>((serviceConfigurator =>
{
serviceConfigurator.ConstructUsing(() => new MyServiceClass());
serviceConfigurator.WhenStarted((myServiceClass, hostControl) => myServiceClass.Start(hostControl));
serviceConfigurator.WhenStopped(myServiceClass => myServiceClass.Stop());
}); /* compiler thinks there's a ")" missing from this line */
hostConfigurator.RunAsLocalSystem();
hostConfigurator.SetDisplayName("MyService");
hostConfigurator.SetDescription("Does stuff.");
hostConfigurator.SetServiceName("MyService");
hostConfigurator.StartAutomatically();
hostConfigurator.EnableShutdown();
});
}
};
However, this will not compile. My compiler suggests that a ")" is missing on (or around) my comment (shown in the code above), but any addition of a close parenthesis just adds to the error list.
I feel like I'm close... any ideas?

Got this working eventually:
public class MyServiceClass : ServiceControl
{
private readonly Task task;
private HostControl hostControl;
public MyServiceClass()
{
task = new Task(DoWork);
}
private void DoWork()
{
Console.WriteLine("Listen very carefully, I shall say this only once");
//hostControl.Stop();
}
public bool Start(HostControl hostControl)
{
// so we can stop the service at the end of the check
this.hostControl = hostControl;
// start the DoWork thread
task.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
return true;
}
};
and
class Program
{
static void Main(string[] args)
{
HostFactory.Run(hostConfigurator =>
{
hostConfigurator.Service<MyServiceClass>(serviceConfigurator =>
{
serviceConfigurator.ConstructUsing(() => new MyServiceClass());
serviceConfigurator.WhenStarted((myServiceClass, hostControl) => myServiceClass.Start(hostControl));
serviceConfigurator.WhenStopped((myServiceClass, hostControl) => myServiceClass.Stop(hostControl));
});
hostConfigurator.RunAsLocalSystem();
hostConfigurator.SetDisplayName("MyService");
hostConfigurator.SetDescription("Does stuff.");
hostConfigurator.SetServiceName("MyService");
hostConfigurator.StartAutomatically();
hostConfigurator.EnableShutdown();
});
}
};
My 2nd attempt had a spare "(" at the first mention of serviceConfigurator, then I needed to turn my void Start and Stop functions into bool functions. Hope this helps someone.

Related

Check for service registration using IsRegistered(), or use the ResolveOptional() method

The requested service 'Volo.Abp.PermissionManagement.PermissionManagementProvider' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
namespace SecurityDomainModule
{
[DependsOn(
typeof(AbpDddDomainModule),
typeof(SecurityDomainSharedModule),
typeof(AbpUsersDomainModule),
typeof(AbpUsersDomainSharedModule),
typeof(AbpPermissionManagementApplicationContractsModule),
typeof(AbpPermissionManagementDomainModule),
typeof(AbpPermissionManagementDomainSharedModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpPermissionManagementApplicationContractsModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule)
)]
public class SecurityDomainModule : AbpModule
{
public SecurityDomainModule()
{
}
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// ...
AutoAddPermissionManagementProviders(context.Services);
// ...
}
private static void AutoAddPermissionManagementProviders(IServiceCollection services)
{
services.Configure<PermissionManagementOptions>(options =>
{
options.ManagementProviders.Add<BusinessSegmentPermissionManagementProvider>();
options.ManagementProviders.Add<CustomPartnerPermissionmanagementProvider>();
options.ManagementProviders.Add<CustomTeamPermissionmanagementProvider>();
options.ManagementProviders.Add<PermissionManagementProvider>();
//options.ManagementProviders.Add<RolePermissionManagementProvider>();
// Role and User providers are already added by default. So not adding them here.
});
}
// ...
}
}
To reproduce the bug, I am trying below test case:
public async Task<List<PermissionWithGrantedProviders>> GetAllForRoleAsync(string roleName)
{
try
{
Check.NotNullOrEmpty(roleName, nameof(roleName));
var result = await RolePermissionManagerExtensions.GetAllForRoleAsync(_permissionManager, roleName);
return result;
}
catch (Exception ex)
{
//TODO log exception return null;
}
}
Calling RolePermissionManagerExtensions method, however it gives an error saying PermissionManagementProvider is not registered.
PermissionManagementProvider is an abstract class, so don't add it to options.ManagementProviders.
private static void AutoAddPermissionManagementProviders(IServiceCollection services)
{
services.Configure<PermissionManagementOptions>(options =>
{
options.ManagementProviders.Add<BusinessSegmentPermissionManagementProvider>();
options.ManagementProviders.Add<CustomPartnerPermissionmanagementProvider>();
options.ManagementProviders.Add<CustomTeamPermissionmanagementProvider>();
options.ManagementProviders.Add<PermissionManagementProvider>(); // Remove this
// ...
});
}

Automapper AddAfterMapAction not calling method

I am using global configuration for Automapper profile mapping.
public class StudentProfile : Profile
{
public StudentProfile()
{
CreateMap<Student, StudentVM>()
.ForMember(dest => dest.school, src => src.Ignore());
}
}
Mapper Configuration
public static class Configuration
{
public static IMapper InitializeAutoMapper()
{
MapperConfiguration config = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new StudentProfile());
});
config.AssertConfigurationIsValid();
return config.CreateMapper();
}
}
Now I am adding .AddAfterMapAction using Expression.
static void Main(string[] args)
{
try
{
var mapper = Configuration.InitializeAutoMapper();
foreach (var item in mapper.ConfigurationProvider.GetAllTypeMaps())
{
Expression<Action<int>> beforeMapAction = (x) => Test(x);
item.AddAfterMapAction(beforeMapAction);
}
var dest = mapper.Map<Student, StudentVM>(StudentService.GetStudent());
Console.ReadLine();
}
catch (Exception ex)
{
}
}
public static void Test(int x)
{
Console.WriteLine("X = {0}", x);
}
It is not invoking the Test method when I am mapping using this line: var dest = mapper.Map<Student, StudentVM>(StudentService.GetStudent());
Am I doing anything wrong here. As it should call the Test method while mapping.
You can't modify maps after MappingConfiguration is instantiated. Once a TypeMap is built, the execution plan is created and can't change.
You need to move that AfterMap configuration into where you're configuring.

Implement dependency injection in background services in Xamarin Forms using Prism

I am making use of Prism in my xamarin forms project.I was able to use dependency injection(constructor injection) in my View Model without any problems.I am also making use of background services to push long running tasks in the background.How do I inject dependency in my Background services?When I try to pass the interface object as a paramater to the constructor(SyncingBackgroundingCode) ,the object(SqliteService) is null.I have registered and resolved the objects in the dependency injection container.
How to handle this case?Can anybody provide an example or link to implement this scenario?
This is the piece of code where im trying to implement dependency injection.
This is in Droid :-
public class AndroidSyncBackgroundService : Service
{
CancellationTokenSource _cts;
public override IBinder OnBind (Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand (Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource ();
Task.Run (() => {
try {
//INVOKE THE SHARED CODE
var oBackground = new SyncingBackgroundingCode();
oBackground.RunBackgroundingCode(_cts.Token).Wait();
}
catch (OperationCanceledException)
{
}
finally {
if (_cts.IsCancellationRequested)
{
var message = new CancelledTask();
Device.BeginInvokeOnMainThread (
() => MessagingCenter.Send(message, "CancelledTask")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
if (_cts != null) {
_cts.Token.ThrowIfCancellationRequested ();
_cts.Cancel ();
}
base.OnDestroy ();
}
}
This is in PCL:-
public class SyncingBackgroundingCode
{
public SQLiteConnection _sqlconnection;
SqliteCalls oSQLite = new SqliteCalls();
ISqliteService _SqliteService;
public SyncingBackgroundingCode(ISqliteService SqliteService)
{
//object is null
}
public async Task RunBackgroundingCode(CancellationToken token)
{
DependencyService.Get<ISQLite>().GetConnection();
await Task.Run (async () => {
token.ThrowIfCancellationRequested();
if (App.oSqliteCallsMainLH != null)
{
App.bRunningBackgroundTask = true;
oSQLite = App.oSqliteCallsMainLH;
await Task.Run(async () =>
{
await Task.Delay(1);
oSQLite.ftnSaveOnlineModeXMLFormat("Offline", 0);
oSQLite.SyncEmployeeTableData();
oSQLite.SaveOfflineAppCommentData();
oSQLite.SaveOfflineAdditionToFlowData();
await Task.Delay(500);
var msgStopSyncBackgroundingTask = new StopSyncBackgroundingTask();
MessagingCenter.Send(msgStopSyncBackgroundingTask, "StopSyncBackgroundingTask");
});
}
}, token);
}
}
Unfortunately Xamarin and Xamarin Forms don't give frameworks like Prism anywhere to tie into to handle IoC scenarios. There are a couple of ways you can handle this though.
First the Container is a public property on the PrismApplication in your background service you could do something like:
public class FooBackgroundService
{
private App _app => (App)Xamarin.Forms.Application.Current;
private void DoFoo()
{
var sqlite = _app.Container.Resolve<ISQLite>();
}
}
Another slightly more involved way would be to use the ServiceLocator pattern. You might have something like the following:
public static class Locator
{
private static Func<Type, object> _resolver;
public static T ResolveService<T>() =>
(T)_resolver?.Invoke(typeof(T));
public static void SetResolver(Func<Type, object> resolver) =>
_resolver = resolver;
}
In your app you would then simply set the resolver. Prism actually does something similar to this with the ViewModel locator, which then allows it to inject the correct instance of the NavigationService.
public class App : PrismApplication
{
protected override void OnInitialized()
{
SetServiceLocator();
NavigationService.NavigateAsync("MainPage");
}
protected override void RegisterTypes()
{
// RegisterTypes
}
private void SetServiceLocator()
{
Locator.SetResolver(type => Container.Resolve(type, true));
}
}
Finally your service would simply reference the Service Locator like:
public class BarBackgroundService
{
public void DoBar()
{
var sqlite = Locator.ResolveService<ISQLite>();
// do foo
}
}

Resolve named Dependencies with Dependency Resolver

I've noticed that when I register my dependencies via named overrides Dependency Resolver struggles to resolve components properly. Seems like the first instance is provided. Everything is fine with ctor injection.
Example:
Registration
RegisterProvider<IAccountProvider, AccountProvider>();
RegisterProvider<IAccountProvider, CustomAccountProvider>("customAccountProvider");
Resolution
var instance = DependecyResolver.Current.GetService<IAccountProvider>();
Cannot retrieve customAccountProvider instance.
It always refers to the first registered component ignoring named constraints.
When you have multiple implementations of the same component you have to name them or mark them with marking interface. Here is a code example with naming the instances :
using System;
using System.Linq;
using System.Reflection;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace ResolvingNamedInctances
{
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<AccountProviderTypeSelector>());
container.Register(Component.For<IAccountProviderSelector>().AsFactory(typeof(AccountProviderTypeSelector)));
container.Register(Component.For<IAccountProvider>().ImplementedBy<DefaultAccountProvider>().Named("default"));
container.Register(Component.For<IAccountProvider>().ImplementedBy<CustomAccountProvider>().Named("custom"));
// uncomment this line in MVC app and use DependencyResolver instead of container
//DependencyResolver.SetResolver(new WindsorDependencyResolver(container.Kernel));
var accountProviderSelector = container.Resolve<IAccountProviderSelector>();
var defaultAccountProvider = accountProviderSelector.GetAccountProvider(); // default
defaultAccountProvider.Provide();
var customAccountProvider = accountProviderSelector.GetAccountProvider("custom");
customAccountProvider.Provide();
Console.ReadLine();
}
}
public class AccountProviderTypeSelector : ITypedFactoryComponentSelector
{
public Func<IKernelInternal, IReleasePolicy, object> SelectComponent(MethodInfo method, Type type, object[] arguments)
{
string providerName = arguments.Length > 0 ? (string)arguments[0] : "default";
return (k, r) => k.GetHandlers(typeof(IAccountProvider))
.Where(
h =>
{
return h.ComponentModel.Name == providerName;
})
.Select(h => (IAccountProvider)k.Resolve(
h.ComponentModel.Name,
typeof(IAccountProvider),
new Arguments { },
r))
.FirstOrDefault();
}
}
public interface IAccountProviderSelector
{
IAccountProvider GetAccountProvider();
IAccountProvider GetAccountProvider(string nameIdentifier);
}
public interface IAccountProvider
{
void Provide();
}
public class DefaultAccountProvider : IAccountProvider
{
public void Provide()
{
Console.WriteLine("Working in default AccountProvider");
}
}
public class CustomAccountProvider : IAccountProvider
{
public void Provide()
{
Console.WriteLine("Working in standart CustomAccountProvider");
}
}
}

threading concept

A thread should not start event the start method is called.. is it possible? in c#
As this code demonstrates, the thread automatically is created in a suspended state and will not start until you call start.
class Program
{
static void Main(string[] args)
{
Worker w = new Worker();
Console.ReadKey();
w.Start();
Console.ReadKey();
w.Stop();
Console.ReadKey();
}
}
class Worker
{
System.Threading.Thread workerThread;
bool work;
public Worker()
{
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(DoWork);
workerThread = new System.Threading.Thread(ts);
}
public void Start()
{
work = true;
workerThread.Start();
}
public void Stop()
{
work = false;
}
private void DoWork()
{
while(work)
{
Console.WriteLine(System.DateTime.Now.ToLongTimeString());
System.Threading.Thread.Sleep(1000);
}
}
}
(This was created with C# on .NET 3.5, was threading different for 2.0?)

Resources