/// <summary> /// /// </summary> /// <param name="cancelRunner"></param> /// <param name="companyConfig"></param> /// <param name="runnerProgress"></param> /// <returns></returns> private ServiceTaskResult RunWindowsService(CancellationToken cancelRunner, CompanyConfig companyConfig, ServiceProgressInfo runnerProgress) { // NOTE: In order to get the initial code delivered, I am reusing the code, or parts of it at least, // from the original MakoRunner project that uses the Topshelf library. This is not ideal since // we lose a great deal of control over our services. However, we know the code works for one // company ID at a time, which is why I'm reusing here, in the Sequential portion of the IF clause. // TopshelfExitCode retCode = HostFactory.Run(x => { x.Service <TopshelfWindowsService>(sc => { sc.ConstructUsing(name => new TopshelfWindowsService(companyConfig, runnerProgress)); sc.WhenStarted((s, hostControl) => s.Start(hostControl)); sc.WhenShutdown(s => s.Shutdown()); sc.WhenStopped((s, hostControl) => s.Stop(hostControl)); }); // x.SetServiceName($"CommRunner {companyConfig.CompanyName + companyConfig.CompanyId}"); x.SetDescription($"Mako Commission Runner for CompanyID ({companyConfig.CompanyId})"); x.SetDisplayName($"Mako Commission Runner {companyConfig.CompanyId}"); // //x.StartAutomaticallyDelayed(); }); // int exitCode = (int)Convert.ChangeType(retCode, retCode.GetTypeCode()); // Create and return a ServiceTaskResult. // TODO: Add properties to the ServiceTaskResult and populate based on service exit code, etc. return(new ServiceTaskResult() { ServiceReturnCode = exitCode }); }
/// <summary> /// /// </summary> /// <param name="companyConfig"></param> /// <param name="serviceProgressInfo"></param> protected BaseTopshelfWindowsService(CompanyConfig companyConfig, ServiceProgressInfo serviceProgressInfo) { // MakoSocket = new ServicesWebSocket(); // Create the log provider to log progress. if (MakoLogger == null) { MakoLogger = new DelegateLogProvider(); } // Set the event handler for change events. MakoLogger._onProgressUpdate += MakoLogger__onProgressUpdate; // ServiceProgressInfo = serviceProgressInfo; // Config = companyConfig; }
/// <summary> /// /// </summary> /// <param name="companyConfig"></param> /// <param name="serviceProgressInfo"></param> public TopshelfWindowsService(CompanyConfig companyConfig, ServiceProgressInfo serviceProgressInfo) : base(companyConfig, serviceProgressInfo) { }
/// <inheritdoc /> /// <summary> /// The Start method will create and start the task(s). /// </summary> public override void Start() { // Make sure that the RunnerInfo object is non-null. if (Info == null) { throw new ApplicationException($"RunnerInfo has not been allocated for Runner with ID: {MyRunnerId}"); } // We will create and start Tasks based on the values in the RunnerInfo object. if ((Info.SequentialOrParallel == ProcessingOrder.Sequential || Info.SequentialOrParallel == ProcessingOrder.Undefined) && !CanRunInParallel) { // All company IDs will be processed sequentially. foreach (var infoCompanyId in Info.CompanyIds) { try { // Retrieve the encoded Company Configuration data from the Settings. var encodedCompanyConfig = Settings.Default["CompanyId" + infoCompanyId].ToString(); // Convert the encoded company configuration value to a byte array. var data = Convert.FromBase64String(encodedCompanyConfig); // Decode the byte array to a string. var decodedString = Encoding.UTF8.GetString(data); // Deserialize the decoded string to a CompanyConfig object. var config = JsonConvert.DeserializeObject <CompanyConfig>(decodedString); // Create a ProgressInfo object. var runnerProgress = new ServiceProgressInfo(); // Create a new CancellationTokenSource. var tokenSource = new CancellationTokenSource(); // Create a Cancellation Token. var cancelRunner = tokenSource.Token; // Create and start a Task using the Windows service library currently being used. Task <ServiceTaskResult> newTask = new Task <ServiceTaskResult>(() => RunWindowsService(cancelRunner, config, runnerProgress), cancelRunner, TaskCreationOptions.LongRunning); // Store the Task in the RunerInfo for this Mako Runner. if (Info.RunnerTaskWithResult != null) { // Add the Task to the List of this type of Task. Info.RunnerTaskWithResult.Add(newTask); // Save the Task and associated CancellationTokenSource. Info.TaskTokenSources.Add(newTask, tokenSource); // Start the Task. newTask.Start(); } else { throw new ApplicationException($"The RunnerInfo object's RunnerTaskWithResult property has not been initialized."); } } catch (Exception e) { // TODO: Instead of throwing an exception and breaking the loop, log the error and continue. throw new ApplicationException("Error starting Windows Service for company ID" + infoCompanyId, e); } } } else if (Info.SequentialOrParallel == ProcessingOrder.Parallel && CanRunInParallel) { // All company IDs will be processed in parallel, up to a predefined maximum number of parallel tasks. // TODO: Define maximum number of parallel tasks and add to read that value. } else { throw new ApplicationException("Error in ServerMakoRunner.Start(). Invalid processing order."); } }