I am running .net core application as windows services. So my question is how can I use the dbcontext in windows service for database operations?
Below is Service Class
public class SendMailHostService : WebHostService
{
private readonly EventLog _log = new EventLog("Application") { Source = "Application" };
public SendMailHostService(IWebHost host) : base(host)
{
}
protected override void OnStarted()
{
Console.WriteLine("Asp.net service started.");
Console.ReadLine();
}
protected override void OnStarting(string[] args)
{
Console.WriteLine("Asp.net service starting.");
Console.ReadLine();
}
}
and service extension class:
public static class SendMailHostServiceExtensions
{
public static void RunAsSendMailService(this IWebHost host)
{
var webHostService = new SendMailHostService(host);
webHostService.ServiceName = "LMS.WinService.SendEmail";
ServiceBase.Run(webHostService);
}
}
Do I need to inject the dependency in service class?
Edit:1
Initially I need to connect to Client management database in which a table called Clientsconnectionstring will have the connection string of all clients and after that I need to create db context for each of clients and execute windows service logic.
You can create the context on demand in each method you need it.
Related
I am learning the built-in DI of .net core and I am confused why I can use B but not A in the following?
interface IService
{
void Do();
}
class Service : IService
{
public void Do() => Console.WriteLine("Doing...");
}
class Program
{
static void Main()
{
using (ServiceProvider sp = RegisterServices())
{
sp.GetRequiredService<Service>().Do();
}
}
static ServiceProvider RegisterServices()
{
ServiceCollection sc = new ServiceCollection();
//sc.AddTransient<IService, Service>(); // A
sc.AddTransient<Service>(); // B
return sc.BuildServiceProvider();
}
}
If you do this:
sc.AddTransient<Service>();
You're telling the ServiceProvider (container) that it must be able to resolve Service. When I ask for Service, give me Service.
That would work if you had a class that depended directly on Service. For example:
public class DependsOnService
{
private readonly Service _service;
public DependsOnService(Service service)
{
_service = service;
}
}
But in many (perhaps most cases) we're going to write classes to depend on abstractions (like interfaces) instead of directly on concrete classes. So the above would more commonly look like this:
public class DependsOnService
{
private readonly IService _service;
public DependsOnService(IService service)
{
_service = service;
}
}
Now, when DependsOnService is created, the container must resolve IService. It has to know that when it's asked to resolve IService, the implementation it should create is Service. That's what this does:
sc.AddTransient<IService, Service>();
It says, when I ask for IService, give me Service.
How can I restart a ServiceStack self hosted Apphost? Setting my AppHost instance to null and disposing of it does not work correctly, it throws the following Exception:
System.ArgumentException: An entry with the same key already exists.
I need to be able to do this to reload settings and start the AppHost without restarting the Windows Service hosting the AppHost
EDIT:
Scott and Moo-Juice's suggestions to run the AppHost in a different AppDomain is the correct solution. In order to get past the Cross Domain calls to restart the AppHost, I created a second AppHost which runs in the Main AppDomain and calls the Restart method from Scott's solution. Enabling CORS on both AppHost instances allows for a simple $ajax call to restart the service and reload the page once the service is started and the request returns.
Use an AppDomain:
Moo-Juice's suggestion to use an AppDomain is correct. I have included a simple example of how to use an AppDomain to isolate ServiceStack, and allow it to be Started/Restarted/Stopped.
using System;
using ServiceStack;
using System.Runtime.Remoting;
namespace Test
{
public class ServiceStackConsoleHost : MarshalByRefObject
{
public static void Main()
{
Start();
}
static ObjectHandle Handle;
static AppDomain ServiceStackAppDomain;
public static void Start()
{
// Get the assembly of our host
var assemblyName = typeof(ServiceStackConsoleHost).Assembly.FullName;
// Create an AppDomain
ServiceStackAppDomain = AppDomain.CreateDomain("ServiceStackAppDomain");
// Load in our service assembly
ServiceStackAppDomain.Load(assemblyName);
// Create instance of our ServiceStack application
Handle = ServiceStackAppDomain.CreateInstance(assemblyName, "Test.ServiceStackConsoleHost");
// Show that the main application is in a separate AppDomain
Console.WriteLine("Main Application is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);
// Wait for input
Console.ReadLine();
// Restart the application
Restart();
}
public static void Stop()
{
if(ServiceStackAppDomain == null)
return;
// Notify ServiceStack that the AppDomain is going to be unloaded
var host = (ServiceStackConsoleHost)Handle.Unwrap();
host.Shutdown();
// Shutdown the ServiceStack application
AppDomain.Unload(ServiceStackAppDomain);
ServiceStackAppDomain = null;
}
public static void Restart()
{
Stop();
Console.WriteLine("Restarting ...");
Start();
}
readonly AppHost appHost;
public ServiceStackConsoleHost()
{
appHost = new AppHost();
appHost.Init();
appHost.Start("http://*:8090/");
Console.WriteLine("ServiceStack is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);
}
public void Shutdown()
{
if(appHost != null)
{
Console.WriteLine("Shutting down ServiceStack host");
if(appHost.HasStarted)
appHost.Stop();
appHost.Dispose();
}
}
}
public class AppHost : AppSelfHostBase
{
public AppHost(): base("My ServiceStack Service", typeof(AppHost).Assembly)
{
}
public override void Configure(Funq.Container container)
{
}
}
}
Instructions for how to use an AppDomain can be found here.
I have a Windows service that uses net.pipe as a WCF server and a Windows forms client to connect to it. There is a class called ConfigSettings that has values I want the client to query.
I want to have the client read the current values inside the serviceConfig instance that the service uses. Ultimately, I want the client to change values in it, but baby steps first.
The form can talk to the server via named pipes, but 'return serviceConfig is sending a new empty instance back to the client. I want the data that the service is actively using (that is, serviceConfig.Setting1 = x; serviceConfig.Setting2 = "foo"; )
The Windows service and WCF server code is (updated to working version):
using System.IO;
using System.ServiceModel;
using System.ServiceProcess;
namespace WindowsServiceTest
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost myServiceHost = null;
//this is the master config that the service uses
public static ConfigSettings serviceConfig = new ConfigSettings();
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(WCFService1));
myServiceHost.Open();
//set active default settings
serviceConfig.Setting1 = 1;
serviceConfig.Setting2 = "initial.Setting2:" + serviceConfig.Setting1;
}
protected override void OnStop()
{
if (myServiceHost != null)
{
myServiceHost.Close();
myServiceHost = null;
}
}
}
public partial class WCFService1 : IService1
{
public ConfigSettings GetConfig()
{
return Service1.serviceConfig;
}
public void SetConfig(ConfigSettings sentConfig)
{
Service1.serviceConfig = sentConfig;
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ConfigSettings GetConfig();
[OperationContract]
void SetConfig(ConfigSettings sentConfig);
}
public class ConfigSettings
{
public int Setting1 { get; set; }
public string Setting2 { get; set; }
public ConfigSettings() { }
}
}
The client retrieves the config like this (updated with some changes):
using System;
using System.ServiceProcess;
using System.Windows.Forms;
using WindowsServiceTest;
namespace WindowsServiceTestForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ConfigSettings config = new ConfigSettings();
//GetConfig()
private void button1_Click(object sender, EventArgs e)
{
ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
//get the current config and display
config = myService.GetConfig();
MessageBox.Show(config.Setting1 + "\r\n" + config.Setting2, "config");
myService.Close();
}
//SetConfig(ConfigSettings)
private void button2_Click(object sender, EventArgs e)
{ //make changes to values
config.Setting1 += 1;
config.Setting2 = "new.Setting2:" + config.Setting1;
ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
//send the new config
myService.SetConfig(config);
myService.Close();
}
}
}
Update:
Maybe what I'm thinking needs to be done is overkill. It seems that I'm hitting a membrane between WCF and the Windows Service.
How would YOU approach this problem?
Windows Service that needs a Form for configuration.
When service starts, it loads a config.xml file from disk. (a serialized class)
When GUI starts, I want to:
retrieve its current configuration,
make some changes to it,
push it back to the service,
trigger service to re-read and react to the new configuration.
I was trying to avoid statically/writing the config file to disk and telling service to re-read it again. It "seemed" like WCF was the way to go.
Update 2
It seems that by just changing the master config in the service to static, the WCF service can access it directly. I could have sworn I did that originally before I posted, but I guess not.
I also separated the naming of Service1 to WCFService1 above, but it turns out that doesn't matter and works either way.
New complete code has been updated above.
You are getting confused between Windows Service and WCF Service - and have tried to have them both in the same class - while this is possible - it is probably easier to understand if you split them into two classes.
In your example the Windows Service starts, creates a new instance of itself as the WCF service then sets the config elements in the Windows Service instance, meaning the config is empty in the WCF Service instance.
try this instead
using System.ServiceModel;
using System.ServiceProcess;
namespace WindowsServiceTest
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost myServiceHost = null;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(WCFService1 ));
myServiceHost.Open();
}
protected override void OnStop()
{
if (myServiceHost != null)
{
myServiceHost.Close();
myServiceHost = null;
}
}
}
public class WCFService1 : IService1
{
public WCFService1()
{
//change master settings from null
myConfig.Setting1 = "123";
myConfig.Setting2 = "456";
}
//this is the master config that the service uses
public ConfigSettings myConfig = new ConfigSettings();
public ConfigSettings GetConfig()
{
return myConfig;
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ConfigSettings GetConfig();
}
public class ConfigSettings
{
public string Setting1 { get; set; }
public string Setting2 { get; set; }
public ConfigSettings()
{ }
}
}
There are a few ways of doing this (injecting dependencies in the service instance). I'll show two of them.
You have a special case here because the Windows Service is also your WCF service implementation. I think that soon enough you will want to separate them. So, my samples are based on a separate WCF service implementation.
The thing is that WCF has a concept of service instance mode. By default it is PerCall, meaning that a new Service1 instance is created to handle each request. This makes it a bit more difficult to inject something in these instances.
The simplest way is to set the instance mode to Single, meaning there will be only one Service1 instance handling all requests.
The second is easy to implement:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1Implementation : IService1
{
private ConfigSettings _configSettings;
public Service1(ConfigSettings settings)
{
//now you have the settings in the service
_configSettings = setting;
}
...
}
//in the Windows Service
myServiceHost = new ServiceHost(typeof(Service1Implementation), new Service1Implementation(myConfig));
myServiceHost.Open();
The first solution involves you creating and specifying a service instance factory which the infrastructure will use later to create service instances per call.
The factory gives you the possibility to instantiate Service1 yourself and pass the config.
There is quite some code to be written for this, but I'll show the essential. For the complete solution, read this.
For you, it's easier to make the Windows Service just implement IInstanceProvider:
public class Service1 : ServiceBase, IInstanceProvider
{
private ConfigSettings _myConfig; //assign this member later on
...
//IInstanceProvider implementation
public object GetInstance(InstanceContext instanceContext, Message message)
{
//this is how you inject the config
return new Service1Implementation(_myConfig);
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
...
}
I will admit that it's been a while since I've touched WCF, but it looks to me like your ConfigSettings class is missing some attributes required to make it serializable via WCF.
using System.Runtime.Serialization;
[DataContract]
public class ConfigSettings
{
[DataMember]
public string Setting1 { get; set; }
[DataMember]
public string Setting2 { get; set; }
public ConfigSettings()
{ }
}
I don't believe having your Windows service operate as your WCF service, like other answers have suggested, is the problem. But I do agree that it's best to have them be separate classes.
I'm self-hosting WebAPI on a Windows service with the goal of being able to communicate with the Windows service.
However, although I'm able to connect to my web service with no difficulty at a basic level, I'm very unclear on the relationship between the web service and it's host. If my ultimate goal is to expose information from the Windows service through the Web service, how can I share information and communicate between them? What does the web service code have access to that's in the windows service code?
EDIT: Hmmm, too broad... how to narrow this down?
Here is my code. What I want to do is to call "api/strings/0" and have it return "One". However, the List indexOfStrings lives in the Windows Service host. How does the web service controller access the information?
public class StringsController : ApiController
{
/// <summary>
/// Get one entry from indexOfStrings
/// </summary>
public string Get(int listIndex)
{
// How to return indexOfStrings[listIndex]?
return "";
}
}
public class TestWindowsService : ServiceBase
{
public const string ServiceAddress = "Address and port number";
private HttpSelfHostServer _server; // This is the server you're hosting WebAPI on
private HttpSelfHostConfiguration _config; // WebAPI config
private List<string> indexOfStrings = new List<string>();
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
TestWindowsService service = new TestWindowsService() { AutoLog = false };
ServiceBase.Run(service);
}
public TestWindowsService()
{
indexOfStrings.Add("One");
indexOfStrings.Add("Two");
indexOfStrings.Add("Three");
//Create a host configuration
_config = new HttpSelfHostConfiguration(ServiceAddress);
//Setup the routes
_config.Routes.MapHttpRoute(
name: "DefaultGetApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
// Create the server
_server = new HttpSelfHostServer(_config);
}
protected override void OnStart(string[] args)
{
_server.OpenAsync();
}
protected override void OnStop()
{
_server.CloseAsync().Wait();
_server.Dispose();
}
}
You can do this by plugging in a Dependency Injection container framework like Unity, Ninject, Autofac, Structure Map, etc and registering a service in the container and then injecting that service into your controller. There are Nuget packages for most of these DI frameworks to support Web API.
There is an example using Autofac here
However, using the same basic principle you can expose a service level object to controllers methods without using a DI Framework.
The idea is that you use a MessageHandler to insert your object instances to the Request Properties collection and then in the controller method pull it back out.
public class MyServiceHandler : DelegatingHandler
{
private readonly MyService _service;
public MyServiceHandler(MyService service)
{
_service = service;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Properties["MyService_Key"] = _service;
return base.SendAsync(request, cancellationToken);
}
}
In your configuration code you can add your message handler to the pipeline using,
config.MessageHandlers.Add(new MyServiceHandler(new MyService()));
and in your controller you can access the service like this,
public class StringsController : ApiController
{
/// <summary>
/// Get one entry from indexOfStrings
/// </summary>
public string Get(int listIndex)
{
var myService = Request.Properties["MyService_Key"] as MyService;
// How to return indexOfStrings[listIndex]?
var mystring = myService.GetMyString(99);
return "";
}
}
Ideally you should wrap up the access to your service in a helper method or a ApiController extension method, but those are just cosmetic details.
Now, you need to be careful, because MyService can now be called simultaneously on different threads. You need to ensure that you either use Concurrent collections for storing data or you use locks where necessary.
In my project I have different assemblies.
The SignalR hub (and client MVC4 files) live in the Website project.
My hub looks like this:
public class PredictHub : Hub
{
private readonly IChat _chat;
public PredictHub(IChat chat)
{
_chat = chat;
}
public void Chat(String message)
{
_chat.AddMessage(message);
}
}
In my second assembly Business the IChat.cs and Chat.cs live:
public class Chat : IChat
{
public void AddMessage(String message)
{
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
}
}
But because Chat.cs is in the Business assembly the ChatHub directive is not known because it's not referenced.
How could this be solved?
You can only get the context when SignalR and the Chat class are in the same process.