I have .net core console application, which is hosted as windows service.
I want to catch an event if the user logs off/shutdown the computer.
I have found ways to catch this event in .net framework (here & here).
But I cant figure out how to achieve this in .net core.
To create service I am using "ServiceBase" class. Sample code is as given below:
public class MyService : ServiceBase
{
readonly string LogPath = "D:\\TestAppService.txt";
#region Constructors
public MyService()
{
this.CanShutdown = true;
}
#endregion
#region Protected Functions
protected override void OnStart(string[] args)
{
//your code here
// call the base class so it has a chance
// to perform any work it needs to
base.OnStart(args);
}
protected override void OnStop()
{
//your code here
// Call the base class
base.OnStop();
}
protected override void OnShutdown()
{
using (StreamWriter sw = File.AppendText(LogPath))
{
sw.WriteLine("shutdown == true");
}
//your code here
base.OnShutdown();
}
#endregion
}
The OnStop and OnStart methods are being called.
but when I shutdown the computer my OnShutdown method is not called.
According to aspisof.net, you should be able to use the SessionEnding API. This is because it is listed as being exposed in the windows Compatibility Pack - available on NuGet here.
This article on learn.microsoft.com shows how you can include it in a .NET Core application.
tl;dr
Add the NuGet package
Target Windows only
One thing to note: this was originally designed to be a temporary fix for porting Windows specific .NET code over to .NET Core.
The more accepted way to implement Windows only features is to move as much code to .NET Standard libraries as possible, and to use conditional compilation directives to include platform specific code when building for that platform.
By design dotnet core is not "friendly" with platform specific stuff
(like listening to log off event seems to me).
The solution I use in one of Windows-hosted services is described here.
When application domain is forced to close by operating system on shutdown - there is a room for using AppDomain event handlers.
Related
I would like to reuse a library class that I made for some projects in Asp .Net Framework within an Asp .Net Core project on which I am now working.
For that project I have to use a MySQL database so I added the MySqlConnector NuGet package to my library class.
As the registered .NET Data Providers are not automatically added to the Global Assembly Cache I must register it manually thanks the call of that method DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance) during application startup as mentionned here.
It's my first .Net core project so I don't know if that's how I should do it but I called that method in the Startup.cs file like this :
It is working but I am wondering if it's the right way to do it. Would you advise me another proper way to do it?
Thanks
There is nothing fundamentally wrong with your approach, IMO.
One problem I see is the task you're trying to run takes too long, in which case you're better off spawning a task.
The other is reusability, your code is coupled together. You could solve that by wrapping it in a class and injecting it into a middleware component by interface, and then calling a method. For example:
public interface ITask { void Run(); }
class RegisterMySqlTask : ITask { public void Run() { DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance); } }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITask, RegisterMySqlTask>();
//rest goes here
}
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.RequestServices.GetRequiredService<ITask>().Run();
await next(context);
});
//rest goes here
}
Note, however, that this may be overcomplicating things. As I said, I believe that you are not doing anything wrong.
I'm creating a way to publish integration events via NServiceBus that are published from within an operation executed in a handler. The path I've chosen is bridge the IIntegrationEventProvider with IEventCollectionPublisher to get the published events from domain layer.
public sealed class Bridge : IIntegrationEventProvider /* Infrastructure */,
IEventCollectionPublisher /* Domain */
{
private readonly List<object> _events = new List<object>();
void IEventCollectionPublisher.Publish(object domainEvent) { _events.Add(domainEvent): }
IReadOnlyCollection IIntegrationEventProvider.GetEvents() => _events;
}
Since NServiceBus has its own service provider (IBuilder) I need to resolve the class doing the application operation from the IServiceProvider that is made available to pipeline in ServiceScopedBehavior. Doing this I can get the bridge instance that contains the events published from domain layer and publish them as integration events using NServiceBus.
I published a Gist with (hopefully) the code pieces needed to grasp what I'm trying to achieve.
The question is: can I instruct NServiceBus to just delegate calls to the application service provider instead of building it and copy all instructions in endpoint.UserContainer<ServiceBuilder>()? Below is an example
internal sealed class Handler : IHandleMessages<Command>
{
public async Task Handle(Command message, IMessageHandlerContext context)
{
// Resolved from ASPNET DI
var useCase = context.GetService<CommandUseCase>();
// _useCase is resolved NSB DI since injected from constructor
Debug.Assert(ReferenceEquals(useCase, _useCase), "");
await useCase.Execute().ConfigureAwait(false);
}
}
This way I could inject to correct scoped application class in the handler constructor instead of resolving it from the scope provided by IServiceProvider that is made available from context.Extensions.Get<IServiceScope>().ServiceProvider.
Thanks for help
Regards
I think ASP.NET Core integration sample could be useful. Starting from version 7.2 sharing of the DI infrastructure between ASP.NET and NServiceBus is much simpler. There is also a specialized NServiceBus.Extensions.Hosting adapter package that adds UseNServiceBus API.
I followed : this article and implemented it in a WCF Service.
It allows us to create a instance of a Service that doesn't have a parameterless constructor, by implementing a custom IServiceBehavior, and then decorating the service with that Service Behavior, so instead of having for example:
[ServiceBehavior]
public class MyService : IMyService
I would have
[InstanceProviderBehavior]
public class MyService : IMyService
I then implement the ApplyDispatchBehavior like this:
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers) {
foreach (EndpointDispatcher ed in cd.Endpoints) {
if (!ed.IsSystemEndpoint) {
Console.WriteLine("Using InstanceProviderBehaviorAttribute");
ed.DispatchRuntime.InstanceProvider = new ServiceInstanceProvider(Configuration.Instance.Container);
}
}
}
And to provide an instance of the service I just do:
public object GetInstance(InstanceContext instanceContext, Message message)
{
AlertQueryService result = Container.Resolve<AlertQueryService>();
return result;
}
I ran it in windows and it worked as expected. But in linux with mono, it throws the exception
Exception Default constructor not found for type MyService
which indicates that maybe mono is ignoring the InstanceProviderBehaviorAttribute.
Another thing i noticed was that the line:
Console.WriteLine("Using InstanceProviderBehaviorAttribute");
Is executed in windows when the service host is opened. While in linux when the service host is opened, it doesn't write that in the console. Also the exception in linux is not thrown when we open the service host, but when the IsInitiating operation is called in MyService:
[OperationContract(IsInitiating = true)]
void Initialize();
Which indicates that with mono the service instance is only being resolved when we call the IsInitiating operation.
Any idea why this is works in windows and not in linux with mono? And why is the initialization behavior different?
Thanks
Try adding an InstanceContextProvider as well as your InstanceProvider in your EndpointBehavior. It seems the Mono implementation of ChannelDispatcher.ListenerLoopManager.Setup doesn't like the idea of being sans InstanceContextProvider if there is no parameterless constructor.
The InstanceContextProvider can be essentially a no-op implementation. So long as there is an instance, it will pass that check in ListenerLoopManagerSetup and happily proceed to utilize your InstanceProvider.
Re: why the different implementation... Mono is a re-implementation rather than a cross-compilation or even port. Consider the Important Rules section of their Contribution Guidelines. It wasn't until very recently that developers could contribute to the project if they had so much as looked at MS source code.
I am trying to create an IOC container in Castle Windsor that's configuration is shared across assemblies.
(What follows is an example of how this works in Unity. What I want to do is to make it work the same way using Castle Windsor)
I have the following project configuration...
TestCompany.Services.Host
(Web project hosting a number of .svc files)
PrintService.svc
Web.Config
Unity.Config
TestCompany.Services.PrintService
IPrintService.cs
PrintService.cs
The actual implementation of my "PrintService" is not implemented inside my Services.Host but in the TestCompany.Services.PrintService assembly.
As part of my shared project code (not shown) I have a container helper which is responsible for loading the unity configuration...
public static IUnityContainer GetContainer()
{
// Checks for existance of container (_container == null) ommitted.
var section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(_container, name);
...
...
}
This method loads the unity configuration section from the Unity.Config and uses it to configure the container.
The advantage of this method is that one Unity.Config loaded inside (I presume) the AppDomain can service a number of assemblies. Simply calling GetContainer() from any of the assemblies consumed by my service host will return a container populated with the same type resolution's etc.
I really want to use the fluent configuration in Castle Windsor but I dont see how without this "shared" configuration file that can be acheived. PrintService and any future services will all need to resolve the same dependencies and I dont want to have to repeat my fluent configuration between these services.
Ideally I need some sort of container configured in the service host app that can "flow" into all of the assemblies that it makes use of.
Thanks.
I think I may not be understanding your question but I think I understand your scenario and here is how I do something similar, if it helps at all...
My Philosophy:
Each part of the application should be in charge of registering what
it knows about and nothing more, so there is no need for a single
central configuration file and things that are shared between
components are registered in one place and their interfaces are
available everywhere via a common library.
So let's take an example...
First of all, let us just say (for the purposes of my example) that IPrintService is something that you want to register an implementation of once and use throughout the application and that we have some other component that needs to be implemented by some external module from the main application. We, therefore, create an assembly called Common like so:
Common
public interface IPrintService
{
void Print();
}
public interface IMyService
{
void DoSomething();
}
Now let us think about the main part of the application (maybe it is an ASP .NET application, maybe justa console application, does not really matter). Here we construct the container and ask it to find all the possible components. We can do that like so:
Main Application
// Could be the Global.asax code behind but for simplicity this is
// just a console application
class Program
{
private static readonly IWindsorContainer Mycontainer
= BootstrapContainer();
// Allow access to the raw container - this is probably a bad idea but
// in the rare case that you need it you can get it from here
public static IWindsorContainer Container { get { return Mycontainer; } }
private static IWindsorContainer BootstrapContainer()
{
// Here we will just install every IWindsorInstaller found in any
// assembly in the same folder as the application (so no need for
// references or anything).
var c = new WindsorContainer();
string folder = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location);
c.Install(FromAssembly.InDirectory(new AssemblyFilter(folder)));
return c;
}
}
// Here is the print service implementation
public class MyPrintService : IPrintService
{
public void Print()
{
// Print!
}
}
// This is the installer for the main module - here we are saying exactly
// what is implementing the interface
public class MainApplicationInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container,
IConfigurationStore store)
{
container
.Register(Component
.For<IPrintService>()
.ImplementedBy<MyPrintService>());
}
}
So now we have a common library with our shared inetrfaces and a main application that will register an implementation for our shared interface and also load up any other modules in the system.
The only thing, therefore, left to do is to consume that print service and use it. We can do this anywhere that is using the container so let's create a third assembly that references only Common (we will call it test module.
Test Module
// This installer installs just the things inside this module since that
// is all it knows about but those things can use things that are
// registered in the container by anybody.
public class TestModuleInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container,
IConfigurationStore store)
{
container
.Register(Component
.For<IMyService>()
.ImplementedBy<MyServiceThatDoesSomething>());
}
}
public class MyServiceThatDoesSomething : IMyService
{
private readonly IPrintService _printService;
public MyServiceThatDoesSomething(IPrintService printService)
{
_printService = printService;
}
public void DoSomething()
{
// Use the print service!
_printService.Print();
}
}
Finally compile everything and copy the test module to the same folder as the main application and then from the main you can do this:
Container.Resolve<IMyService>().DoSomething();
And then the magic happens! Well, some code runs and you find that the print service is called by the class from the module even though it knows nothing about it.
Anyway, maybe that helps a little bit, maybe not, good luck!
What is the preferable way to manage configuration file changes in WCF webservices? I know usually in desktop applications people use a FileSystemWatcher to watch for changes in App.config, but how exactly does one go about configuring one in WCF? I tried using something like the following code:
public class Service : IService
{
private static readonly FileSystemWatcher ConfigurationWatcher = new FileSystemWatcher(PathToRootDirectory);
private void ReloadConfiguration(object sender, FileSystemEventArgs e)
{
ConfigurationManager.RefreshSection("appSettings");
ConfigurationManager.RefreshSection("connectionStrings");
}
// IService implementation goes here.
static Service()
{
ConfigurationWatcher.Filter = "web.config";
ConfigurationWatcher.NotifyFilter = NotifyFilter.LastWrite;
ConfigurationWatcher.Change += ReloadConfiguration;
}
}
However, that didn't seem to work since ConfigurationWatcher seemed to being initialized upon every call to the service... How does one go about accomplishing this?
This happens automatically for a service hosted in IIS.
Any change to the web.config or any assembly in the bin folder will cause the current AppDomain to shut down and a new AppDomain to be started for subsequent requests - just like with ASP.NET.