├── .gitignore ├── ConsoleApp ├── ConsoleApp.csproj ├── Program.cs └── TestJob.cs ├── ConsoleAppNET ├── App.config ├── ConsoleAppNET.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── LICENSE ├── QuartzWebApi.Tests ├── Properties │ └── AssemblyInfo.cs ├── QuartzWebApi.Tests.csproj ├── TestJob.cs ├── UnitTest1.cs ├── app.config ├── obj │ └── Debug │ │ ├── .NETFramework,Version=v4.8.AssemblyAttributes.cs │ │ └── DesignTimeResolveAssemblyReferencesInput.cache └── packages.config ├── QuartzWebApi.sln ├── QuartzWebApi.sln.DotSettings ├── QuartzWebApi ├── Controllers │ └── SchedulerController.cs ├── Loggers │ ├── Console.cs │ ├── File.cs │ └── Stream.cs ├── QuartzWebApi.csproj ├── SchedulerConnector.cs ├── SchedulerHost.cs ├── Startup.cs └── Wrappers │ ├── Calendars │ ├── AbstractClassContractResolver.cs │ ├── AnnualCalendar.cs │ ├── BaseCalendar.cs │ ├── BaseConverter.cs │ ├── CalendarType.cs │ ├── CronCalendar.cs │ ├── DailyCalendar.cs │ ├── HolidayCalendar.cs │ ├── MonthlyCalendar.cs │ └── WeeklyCalendar.cs │ ├── GroupMatcher.cs │ ├── GroupMatcherType.cs │ ├── JobDetail.cs │ ├── JobDetailWithTrigger.cs │ ├── JobDetailWithTriggers.cs │ ├── JobExecutionContext.cs │ ├── JobExecutionContexts.cs │ ├── JobKey.cs │ ├── JobKeyWithDataMap.cs │ ├── JobKeys.cs │ ├── Key.cs │ ├── RescheduleJob.cs │ ├── RunningJobs.cs │ ├── ScheduleJobs.cs │ ├── SchedulerContext.cs │ ├── SchedulerMetaData.cs │ ├── Trigger.cs │ ├── TriggerKey.cs │ ├── TriggerKeys.cs │ └── Triggers.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | #packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | packages/ 158 | .vs/ 159 | -------------------------------------------------------------------------------- /ConsoleApp/ConsoleApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | latest 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ConsoleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Specialized; 2 | using System.Net; 3 | using ConsoleApp; 4 | using Quartz; 5 | using Quartz.Impl; 6 | using Quartz.Impl.Calendar; 7 | using QuartzWebApi; 8 | 9 | var properties = new NameValueCollection 10 | { 11 | ["quartz.scheduler.exporter.bindName"] = "Scheduler", 12 | ["quartz.scheduler.exporter.channelName"] = "tcpQuartz", 13 | ["quartz.scheduler.exporter.channelType"] = "tcp", 14 | ["quartz.scheduler.exporter.port"] = "45000", 15 | ["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz", 16 | ["quartz.scheduler.instanceName"] = Dns.GetHostEntry(Environment.MachineName).HostName.Replace(".", "_"), 17 | ["quartz.jobStore.type"] = "Quartz.Simpl.RAMJobStore, Quartz", 18 | ["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz" 19 | }; 20 | 21 | var scheduler = new StdSchedulerFactory(properties).GetScheduler().Result; 22 | 23 | scheduler.Context.Add("key1", "value1"); 24 | scheduler.Context.Add("key2", "value2"); 25 | scheduler.Context.Add("key3", "value3"); 26 | 27 | scheduler.Start(); 28 | 29 | var job = new TestJob(); 30 | var schedulerJob = JobBuilder.Create(job.GetType()) 31 | .WithIdentity(new JobKey("JobKeyName", "JobKeyGroup")) 32 | .WithDescription("Test") 33 | .RequestRecovery() 34 | .Build(); 35 | 36 | var schedulerTrigger = (ISimpleTrigger)TriggerBuilder.Create() 37 | .WithIdentity("triggerKey") 38 | .WithDescription("TestTrigger") 39 | .StartAt(DateTime.Now) 40 | .Build(); 41 | 42 | var mc = new MonthlyCalendar(); 43 | mc.SetDayExcluded(1, true); 44 | mc.SetDayExcluded(12, true); 45 | scheduler.AddCalendar("monthlyCalendar", mc, true, true); 46 | scheduler.ScheduleJob(schedulerJob, schedulerTrigger); 47 | 48 | var host = new SchedulerHost("http://localhost:44344", scheduler, null); 49 | host.Start(); 50 | 51 | var connector = new SchedulerConnector("http://localhost:44344"); 52 | var test = connector.GetMetaData().Result; 53 | 54 | Console.ReadKey(); -------------------------------------------------------------------------------- /ConsoleApp/TestJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | 3 | namespace ConsoleApp; 4 | 5 | public class TestJob : IJob 6 | { 7 | public Task Execute(IJobExecutionContext context) 8 | { 9 | while (true) 10 | { 11 | context.JobDetail.JobDataMap.PutAsString("Timer", DateTime.Now); 12 | Thread.Sleep(10000); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /ConsoleAppNET/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ConsoleAppNET/ConsoleAppNET.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5C27C0B4-2E28-46A5-BD4C-54F51D5041F0} 8 | Exe 9 | ConsoleAppNET 10 | ConsoleAppNET 11 | v4.8 12 | 512 13 | true 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 10 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 10 37 | 38 | 39 | 40 | ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll 41 | 42 | 43 | ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll 44 | 45 | 46 | ..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll 47 | 48 | 49 | ..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll 50 | 51 | 52 | ..\packages\Microsoft.Owin.Host.HttpListener.4.2.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll 53 | 54 | 55 | ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll 56 | 57 | 58 | ..\packages\Owin.1.0\lib\net40\Owin.dll 59 | 60 | 61 | ..\packages\Quartz.3.8.1\lib\net472\Quartz.dll 62 | 63 | 64 | ..\packages\Quartz.Serialization.Json.3.8.1\lib\net472\Quartz.Serialization.Json.dll 65 | 66 | 67 | 68 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll 69 | 70 | 71 | 72 | 73 | ..\packages\System.Diagnostics.DiagnosticSource.8.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll 74 | 75 | 76 | ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll 77 | 78 | 79 | 80 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll 81 | 82 | 83 | ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll 84 | 85 | 86 | 87 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | {d95e8519-ca6c-4e08-bf4c-2f2ee4fff728} 107 | QuartzWebApi 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ConsoleAppNET/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.Net; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Quartz; 7 | using Quartz.Impl; 8 | using Quartz.Impl.Calendar; 9 | using QuartzWebApi; 10 | 11 | namespace ConsoleAppNET; 12 | 13 | internal class Program 14 | { 15 | static void Main(string[] args) 16 | { 17 | var properties = new NameValueCollection 18 | { 19 | ["quartz.scheduler.exporter.bindName"] = "Scheduler", 20 | ["quartz.scheduler.exporter.channelName"] = "tcpQuartz", 21 | ["quartz.scheduler.exporter.channelType"] = "tcp", 22 | ["quartz.scheduler.exporter.port"] = "45000", 23 | ["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz", 24 | ["quartz.scheduler.instanceName"] = Dns.GetHostEntry(Environment.MachineName).HostName.Replace(".", "_"), 25 | ["quartz.jobStore.type"] = "Quartz.Simpl.RAMJobStore, Quartz", 26 | ["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz" 27 | }; 28 | 29 | var scheduler = new StdSchedulerFactory(properties).GetScheduler().Result; 30 | 31 | scheduler.Context.Add("key1", "value1"); 32 | scheduler.Context.Add("key2", "value2"); 33 | scheduler.Context.Add("key3", "value3"); 34 | 35 | scheduler.Start(); 36 | 37 | var job = new TestJob(); 38 | var schedulerJob = JobBuilder.Create(job.GetType()) 39 | .WithIdentity(new JobKey("JobKeyName", "JobKeyGroup")) 40 | .WithDescription("Test") 41 | .RequestRecovery() 42 | .Build(); 43 | 44 | var schedulerTrigger = (ISimpleTrigger)TriggerBuilder.Create() 45 | .WithIdentity("triggerKey") 46 | .WithDescription("TestTrigger") 47 | .StartAt(DateTime.Now) 48 | .Build(); 49 | 50 | var mc = new MonthlyCalendar(); 51 | mc.SetDayExcluded(1, true); 52 | mc.SetDayExcluded(12, true); 53 | scheduler.AddCalendar("monthlyCalendar", mc, true, true); 54 | scheduler.ScheduleJob(schedulerJob, schedulerTrigger); 55 | 56 | var host = new SchedulerHost("http://localhost:44344", scheduler, null); 57 | host.Start(); 58 | 59 | var connector = new SchedulerConnector("http://localhost:44344"); 60 | var paused = connector.IsJobGroupPaused("JobKeyGroup").Result; 61 | 62 | 63 | Console.ReadKey(); 64 | } 65 | } 66 | 67 | public class TestJob : IJob 68 | { 69 | public Task Execute(IJobExecutionContext context) 70 | { 71 | while (true) 72 | { 73 | context.JobDetail.JobDataMap.PutAsString("Timer", DateTime.Now); 74 | Thread.Sleep(10000); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /ConsoleAppNET/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ConsoleAppNET")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ConsoleAppNET")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5c27c0b4-2e28-46a5-bd4c-54f51d5041f0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ConsoleAppNET/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Kees 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QuartzWebApi.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("QuartzWebApi.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("QuartzWebApi.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e99aabc4-f815-487a-8efe-5625e7a07f64")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /QuartzWebApi.Tests/QuartzWebApi.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {E99AABC4-F815-487A-8EFE-5625E7A07F64} 10 | Library 11 | Properties 12 | QuartzWebApi.Tests 13 | QuartzWebApi.Tests 14 | v4.8 15 | 512 16 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | latest 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | latest 40 | 41 | 42 | 43 | ..\packages\Microsoft.ApplicationInsights.2.22.0\lib\net46\Microsoft.ApplicationInsights.dll 44 | 45 | 46 | ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll 47 | 48 | 49 | 50 | ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll 51 | 52 | 53 | ..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll 54 | 55 | 56 | ..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll 57 | 58 | 59 | ..\packages\Microsoft.Owin.Host.HttpListener.4.2.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll 60 | 61 | 62 | ..\packages\Microsoft.Testing.Extensions.Telemetry.1.0.1\lib\netstandard2.0\Microsoft.Testing.Extensions.Telemetry.dll 63 | 64 | 65 | ..\packages\Microsoft.Testing.Extensions.TrxReport.Abstractions.1.0.1\lib\netstandard2.0\Microsoft.Testing.Extensions.TrxReport.Abstractions.dll 66 | 67 | 68 | ..\packages\Microsoft.Testing.Extensions.VSTestBridge.1.0.1\lib\netstandard2.0\Microsoft.Testing.Extensions.VSTestBridge.dll 69 | 70 | 71 | ..\packages\Microsoft.Testing.Platform.MSBuild.1.0.1\lib\netstandard2.0\Microsoft.Testing.Platform.dll 72 | 73 | 74 | ..\packages\Microsoft.Testing.Platform.MSBuild.1.0.1\lib\netstandard2.0\Microsoft.Testing.Platform.MSBuild.dll 75 | 76 | 77 | ..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll 78 | 79 | 80 | ..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll 81 | 82 | 83 | ..\packages\Microsoft.TestPlatform.ObjectModel.17.9.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll 84 | 85 | 86 | ..\packages\MSTest.TestFramework.3.2.1\lib\net462\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 87 | 88 | 89 | ..\packages\MSTest.TestFramework.3.2.1\lib\net462\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 90 | 91 | 92 | ..\packages\NuGet.Frameworks.6.9.1\lib\net472\NuGet.Frameworks.dll 93 | 94 | 95 | ..\packages\Owin.1.0\lib\net40\Owin.dll 96 | 97 | 98 | ..\packages\Quartz.3.8.1\lib\net472\Quartz.dll 99 | 100 | 101 | 102 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll 103 | 104 | 105 | ..\packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll 106 | 107 | 108 | 109 | 110 | 111 | 112 | ..\packages\System.Diagnostics.DiagnosticSource.8.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll 113 | 114 | 115 | ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll 116 | 117 | 118 | 119 | 120 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll 121 | 122 | 123 | ..\packages\System.Reflection.Metadata.8.0.0\lib\net462\System.Reflection.Metadata.dll 124 | 125 | 126 | 127 | ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll 128 | 129 | 130 | 131 | 132 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | {d95e8519-ca6c-4e08-bf4c-2f2ee4fff728} 154 | QuartzWebApi 155 | 156 | 157 | 158 | 159 | 160 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 177 | -------------------------------------------------------------------------------- /QuartzWebApi.Tests/TestJob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Tests; 7 | 8 | public class TestJob : IJob 9 | { 10 | public Task Execute(IJobExecutionContext context) 11 | { 12 | while (true) 13 | { 14 | context.JobDetail.JobDataMap.PutAsString("Timer", DateTime.Now); 15 | Thread.Sleep(10000); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /QuartzWebApi.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.Collections.Specialized; 4 | using Quartz; 5 | using Quartz.Impl; 6 | using Quartz.Impl.Calendar; 7 | 8 | namespace QuartzWebApi.Tests; 9 | 10 | [TestClass] 11 | public class UnitTest1 12 | { 13 | #region Fields 14 | private SchedulerHost _host; 15 | private SchedulerConnector _connector; 16 | #endregion 17 | 18 | #region Initialize 19 | /// 20 | /// Setup testing 21 | /// 22 | [TestInitialize] 23 | public void Initialize() 24 | { 25 | var properties = new NameValueCollection 26 | { 27 | ["quartz.scheduler.exporter.bindName"] = "Scheduler", 28 | ["quartz.scheduler.exporter.channelName"] = "tcpQuartz", 29 | ["quartz.scheduler.exporter.channelType"] = "tcp", 30 | ["quartz.scheduler.exporter.port"] = "45000", 31 | ["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz", 32 | ["quartz.scheduler.instanceName"] = "SchedulerInstance", 33 | ["quartz.jobStore.type"] = "Quartz.Simpl.RAMJobStore, Quartz", 34 | ["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz" 35 | }; 36 | 37 | var scheduler = new StdSchedulerFactory(properties).GetScheduler().Result; 38 | 39 | scheduler.Context.Add("key1", "value1"); 40 | scheduler.Context.Add("key2", "value2"); 41 | scheduler.Context.Add("key3", "value3"); 42 | 43 | scheduler.Start(); 44 | 45 | var job = new TestJob(); 46 | var schedulerJob = JobBuilder.Create(job.GetType()) 47 | .WithIdentity(new JobKey("JobKeyName", "JobKeyGroup")) 48 | .WithDescription("Test") 49 | .RequestRecovery() 50 | .Build(); 51 | 52 | var schedulerTrigger = (ISimpleTrigger)TriggerBuilder.Create() 53 | .WithIdentity("triggerKey") 54 | .WithDescription("TestTrigger") 55 | .StartAt(DateTime.Now) 56 | .Build(); 57 | 58 | var mc = new MonthlyCalendar(); 59 | mc.SetDayExcluded(1, true); 60 | mc.SetDayExcluded(12, true); 61 | scheduler.AddCalendar("monthlyCalendar", mc, true, true); 62 | scheduler.ScheduleJob(schedulerJob, schedulerTrigger); 63 | 64 | _host = new SchedulerHost("http://localhost:44344", scheduler, null); 65 | _host.Start(); 66 | 67 | _connector = new SchedulerConnector("http://localhost:44344"); 68 | } 69 | #endregion 70 | 71 | #region Cleanup 72 | [TestCleanup] 73 | public void Cleanup() 74 | { 75 | _host.Stop(); 76 | } 77 | #endregion 78 | 79 | [TestMethod] 80 | public void IsJobGroupPaused() 81 | { 82 | var paused = _connector.IsJobGroupPaused("JobKeyGroup").Result; 83 | Assert.IsFalse(paused); 84 | } 85 | 86 | [TestMethod] 87 | public void IsTriggerGroupPaused() 88 | { 89 | var paused = _connector.IsTriggerGroupPaused("JobKeyGroup").Result; 90 | Assert.IsFalse(paused); 91 | } 92 | 93 | [TestMethod] 94 | public void SchedulerName() 95 | { 96 | var name = _connector.SchedulerName().Result; 97 | Assert.AreEqual("SchedulerInstance", name); 98 | } 99 | 100 | [TestMethod] 101 | public void SchedulerInstanceId() 102 | { 103 | var id = _connector.SchedulerInstanceId().Result; 104 | Assert.AreEqual("NON_CLUSTERED", id); 105 | } 106 | 107 | [TestMethod] 108 | public void Context() 109 | { 110 | var result = _connector.Context().Result; 111 | Assert.AreEqual("value1", result["key1"]); 112 | Assert.AreEqual("value2", result["key2"]); 113 | Assert.AreEqual("value3", result["key3"]); 114 | } 115 | 116 | [TestMethod] 117 | public void GetMetaData() 118 | { 119 | var result = _connector.GetMetaData().Result; 120 | Assert.IsTrue(result.Summary.Contains("Quartz")); 121 | } 122 | 123 | [TestMethod] 124 | public void Start() 125 | { 126 | _connector.Start().GetAwaiter().GetResult(); 127 | } 128 | } -------------------------------------------------------------------------------- /QuartzWebApi.Tests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /QuartzWebApi.Tests/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] 5 | -------------------------------------------------------------------------------- /QuartzWebApi.Tests/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sicos1977/QuartzWebApi/9b57a913d530824b96b6508394b37f454b2b6427/QuartzWebApi.Tests/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /QuartzWebApi.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /QuartzWebApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32421.90 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuartzWebApi.Tests", "QuartzWebApi.Tests\QuartzWebApi.Tests.csproj", "{E99AABC4-F815-487A-8EFE-5625E7A07F64}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuartzWebApi", "QuartzWebApi\QuartzWebApi.csproj", "{D95E8519-CA6C-4E08-BF4C-2F2EE4FFF728}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E99AABC4-F815-487A-8EFE-5625E7A07F64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {E99AABC4-F815-487A-8EFE-5625E7A07F64}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {E99AABC4-F815-487A-8EFE-5625E7A07F64}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {E99AABC4-F815-487A-8EFE-5625E7A07F64}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {D95E8519-CA6C-4E08-BF4C-2F2EE4FFF728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {D95E8519-CA6C-4E08-BF4C-2F2EE4FFF728}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {D95E8519-CA6C-4E08-BF4C-2F2EE4FFF728}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {D95E8519-CA6C-4E08-BF4C-2F2EE4FFF728}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {AE16B40F-D3D7-4C75-A620-2874AF2D00F7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /QuartzWebApi.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True 10 | True 11 | True 12 | True 13 | True 14 | True 15 | True 16 | True 17 | True 18 | True 19 | True 20 | True 21 | True 22 | True 23 | True 24 | True 25 | True 26 | True 27 | True 28 | True 29 | True 30 | True 31 | True 32 | True 33 | True 34 | True 35 | True 36 | True 37 | True 38 | True 39 | True 40 | True 41 | True 42 | True 43 | True 44 | True 45 | True 46 | True 47 | True 48 | True 49 | True 50 | True 51 | True 52 | True 53 | True 54 | True 55 | True 56 | True 57 | True 58 | True 59 | True 60 | True 61 | True 62 | True 63 | True 64 | True 65 | True 66 | True 67 | True 68 | True 69 | True 70 | True 71 | True 72 | True 73 | True 74 | True 75 | True 76 | True 77 | True 78 | True 79 | True 80 | True 81 | True 82 | True 83 | True -------------------------------------------------------------------------------- /QuartzWebApi/Loggers/Console.cs: -------------------------------------------------------------------------------- 1 | namespace QuartzWebApi.Loggers; 2 | 3 | /// 4 | /// Writes log information to the console 5 | /// 6 | public class Console() : Stream(System.Console.OpenStandardOutput()); -------------------------------------------------------------------------------- /QuartzWebApi/Loggers/File.cs: -------------------------------------------------------------------------------- 1 | namespace QuartzWebApi.Loggers; 2 | 3 | /// 4 | /// Writes log information to a file 5 | /// 6 | public class File : Stream 7 | { 8 | /// 9 | /// Logs information to the given 10 | /// 11 | /// 12 | public File(string fileName) : base(System.IO.File.OpenWrite(fileName)) 13 | { 14 | } 15 | } -------------------------------------------------------------------------------- /QuartzWebApi/Loggers/Stream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace QuartzWebApi.Loggers; 6 | 7 | /// 8 | /// Writes log information to a stream 9 | /// 10 | public class Stream : ILogger, IDisposable 11 | { 12 | #region Fields 13 | private System.IO.Stream _stream; 14 | private string _instanceId; 15 | #endregion 16 | 17 | #region Constructors 18 | /// 19 | /// Logs information to the given 20 | /// 21 | /// 22 | public Stream(System.IO.Stream stream) 23 | { 24 | _stream = stream; 25 | } 26 | #endregion 27 | 28 | #region BeginScope 29 | public IDisposable BeginScope(TState state) 30 | { 31 | _instanceId = state?.ToString(); 32 | return null; 33 | } 34 | #endregion 35 | 36 | #region IsEnabled 37 | /// 38 | /// Will always return true 39 | /// 40 | /// 41 | /// 42 | public bool IsEnabled(LogLevel logLevel) 43 | { 44 | return true; 45 | } 46 | #endregion 47 | 48 | #region Log 49 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, 50 | Func formatter) 51 | { 52 | var message = $"{formatter(state, exception)}"; 53 | 54 | if (_stream == null || !_stream.CanWrite) return; 55 | var line = 56 | $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss.fff}{(_instanceId != null ? $" - {_instanceId}" : string.Empty)} - {message}{Environment.NewLine}"; 57 | var bytes = Encoding.UTF8.GetBytes(line); 58 | _stream.Write(bytes, 0, bytes.Length); 59 | _stream.Flush(); 60 | } 61 | #endregion 62 | 63 | #region Dispose 64 | public void Dispose() 65 | { 66 | if (_stream == null) 67 | return; 68 | 69 | _stream.Dispose(); 70 | _stream = null; 71 | } 72 | #endregion 73 | } -------------------------------------------------------------------------------- /QuartzWebApi/QuartzWebApi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net48;net6 5 | latest 6 | True 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /QuartzWebApi/SchedulerConnector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using QuartzWebApi.Wrappers; 5 | // ReSharper disable UnusedMember.Global 6 | 7 | namespace QuartzWebApi; 8 | 9 | /// 10 | /// Connects to the 11 | /// 12 | public class SchedulerConnector 13 | { 14 | #region Fields 15 | private readonly HttpClient _httpClient; 16 | #endregion 17 | 18 | #region Constructor 19 | /// 20 | /// Create a new instance of the 21 | /// 22 | /// The host address of the scheduler 23 | public SchedulerConnector(string schedulerHostAddress) 24 | { 25 | _httpClient = new HttpClient(); 26 | _httpClient.BaseAddress = new Uri(schedulerHostAddress); 27 | } 28 | #endregion 29 | 30 | #region IsJobGroupPaused 31 | /// 32 | /// Returns true if the given JobGroup is paused 33 | /// 34 | /// The group name 35 | /// 36 | public async Task IsJobGroupPaused(string groupName) 37 | { 38 | var response = await _httpClient.GetAsync($"Scheduler/IsJobGroupPaused/{groupName}").ConfigureAwait(false); 39 | return bool.Parse(await response.Content.ReadAsStringAsync()); 40 | } 41 | #endregion 42 | 43 | #region IsTriggerGroupPaused 44 | /// 45 | /// Returns true if the given TriggerGroup is paused 46 | /// 47 | /// The group name 48 | /// 49 | public async Task IsTriggerGroupPaused(string groupName) 50 | { 51 | var response = await _httpClient.GetAsync($"Scheduler/IsTriggerGroupPaused/{groupName}").ConfigureAwait(false); 52 | return bool.Parse(await response.Content.ReadAsStringAsync()); 53 | } 54 | #endregion 55 | 56 | #region SchedulerName 57 | /// 58 | /// Returns the name of the scheduler 59 | /// 60 | public async Task SchedulerName() 61 | { 62 | var response = await _httpClient.GetAsync("Scheduler/SchedulerName").ConfigureAwait(false); 63 | var result = await response.Content.ReadAsStringAsync(); 64 | return result.Trim('\"'); 65 | } 66 | #endregion 67 | 68 | #region SchedulerInstanceId 69 | /// 70 | /// Returns the instance id of the scheduler 71 | /// 72 | public async Task SchedulerInstanceId() 73 | { 74 | var response = await _httpClient.GetAsync("Scheduler/SchedulerInstanceId").ConfigureAwait(false); 75 | var result = await response.Content.ReadAsStringAsync(); 76 | return result.Trim('\"'); 77 | } 78 | #endregion 79 | 80 | #region Context 81 | /// 82 | /// Returns the of the . 83 | /// 84 | public async Task Context() 85 | { 86 | var response = await _httpClient.GetAsync("Scheduler/SchedulerContext").ConfigureAwait(false); 87 | var result = await response.Content.ReadAsStringAsync(); 88 | return SchedulerContext.FromJsonString(result); 89 | } 90 | #endregion 91 | 92 | #region GetMetaData 93 | /// 94 | /// Get a object describing the settings 95 | /// and capabilities of the scheduler instance. 96 | /// 97 | /// 98 | /// Note that the data returned is an 'instantaneous' snapshot, and that as 99 | /// soon as it's returned, the meta-data values may be different. 100 | /// 101 | public async Task GetMetaData() 102 | { 103 | var response = await _httpClient.GetAsync("Scheduler/GetMetaData").ConfigureAwait(false); 104 | var json = await response.Content.ReadAsStringAsync(); 105 | return SchedulerMetaData.FromJsonString(json); 106 | } 107 | #endregion 108 | 109 | public async Task Start() 110 | { 111 | await _httpClient.PostAsync("Scheduler/Start", null).ConfigureAwait(false); 112 | } 113 | 114 | public async Task StartDelayed(int delay) 115 | { 116 | var response = await _httpClient.PostAsync($"Scheduler/StartDelayed/{delay}", null); 117 | // Handle response if necessary 118 | } 119 | } -------------------------------------------------------------------------------- /QuartzWebApi/SchedulerHost.cs: -------------------------------------------------------------------------------- 1 | #if NET48 2 | //using Microsoft.Owin; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Http; 6 | using System.Net.Http.Headers; 7 | using System.Net.Http.Formatting; 8 | using Microsoft.Owin.Hosting; 9 | using System.Web.Http.Controllers; 10 | using System.Web.Http.Dispatcher; 11 | #endif 12 | 13 | #if NET6_0 14 | using Microsoft.AspNetCore.Hosting; 15 | using Microsoft.Extensions.DependencyInjection; 16 | using Microsoft.Extensions.Logging; 17 | #endif 18 | 19 | using Microsoft.Extensions.Logging; 20 | using Quartz; 21 | 22 | namespace QuartzWebApi; 23 | 24 | /// 25 | /// Acts as a host for the Web API 26 | /// 27 | /// 28 | /// Create a new instance of the class 29 | /// 30 | /// The base address, e.g. http://localhost:45000 31 | /// 32 | /// > 33 | public class SchedulerHost(string baseAddress, IScheduler scheduler, ILogger logger) 34 | { 35 | #region Fields 36 | #if NET48 37 | private IDisposable _webApp; 38 | #endif 39 | #if NET6_0 40 | private IWebHost _webHost; 41 | #endif 42 | #endregion 43 | 44 | #region Start 45 | /// 46 | /// Start the Web API 47 | /// 48 | public void Start() 49 | { 50 | #if NET48 51 | Startup.Scheduler = scheduler; 52 | Startup.Logger = logger; 53 | _webApp = WebApp.Start(baseAddress); 54 | #endif 55 | 56 | #if NET6_0 57 | var builder = new WebHostBuilder() 58 | .UseKestrel() 59 | .ConfigureServices(services => services.AddSingleton(scheduler)) 60 | .UseStartup() 61 | .UseUrls(baseAddress) 62 | .ConfigureLogging(logging => logging.AddConsole()); 63 | 64 | if (logger != null) 65 | builder.ConfigureServices(services => services.AddSingleton(logger)); 66 | 67 | _webHost = builder.Build(); 68 | _webHost.Start(); 69 | #endif 70 | } 71 | #endregion 72 | 73 | #region Stop 74 | /// 75 | /// Stops the Web API 76 | /// 77 | public void Stop() 78 | { 79 | #if NET48 80 | _webApp?.Dispose(); 81 | #endif 82 | #if NET6_0 83 | _webHost?.StopAsync(); 84 | #endif 85 | } 86 | #endregion 87 | } 88 | 89 | #if NET48 90 | internal class JsonContentNegotiator(MediaTypeFormatter formatter) : IContentNegotiator 91 | { 92 | public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable formatters) 93 | { 94 | var result = new ContentNegotiationResult(formatter, new MediaTypeHeaderValue("application/json")); 95 | return result; 96 | } 97 | } 98 | 99 | internal class CustomHttpControllerActivator(Func controllerFactory) : IHttpControllerActivator 100 | { 101 | private readonly Func _controllerFactory = controllerFactory ?? throw new ArgumentNullException(nameof(controllerFactory)); 102 | 103 | public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) 104 | { 105 | return _controllerFactory(request); 106 | } 107 | } 108 | #endif -------------------------------------------------------------------------------- /QuartzWebApi/Startup.cs: -------------------------------------------------------------------------------- 1 |  2 | using Microsoft.Extensions.Logging; 3 | using Quartz; 4 | #if NET48 5 | using Owin; 6 | using System; 7 | using System.Net.Http; 8 | using System.Net.Http.Formatting; 9 | using System.Web.Http; 10 | using System.Web.Http.Controllers; 11 | using System.Web.Http.Dispatcher; 12 | using QuartzWebApi.Controllers; 13 | #endif 14 | 15 | #if NET6_0 16 | using System; 17 | using Microsoft.AspNetCore.Hosting; 18 | using Microsoft.Extensions.DependencyInjection; 19 | using Microsoft.AspNetCore.Builder; 20 | using Microsoft.Extensions.Logging; 21 | using Microsoft.Extensions.Hosting; 22 | #endif 23 | 24 | namespace QuartzWebApi; 25 | 26 | /// 27 | /// The startup class for OWIN or Kestrel 28 | /// 29 | internal class Startup 30 | { 31 | internal static IScheduler Scheduler; 32 | internal static ILogger Logger; 33 | 34 | #if NET48 35 | /// 36 | /// Configure the Web API that is hosted by OWIN 37 | /// 38 | /// 39 | public void Configuration(IAppBuilder app) 40 | { 41 | var config = new HttpConfiguration(); 42 | config.MapHttpAttributeRoutes(); 43 | config.Formatters.Clear(); 44 | config.Formatters.Add(new JsonMediaTypeFormatter()); 45 | var jsonFormatter = new JsonMediaTypeFormatter(); 46 | config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter)); 47 | var controllerFactory = new Func(_ => new SchedulerController(Scheduler, Logger)); 48 | config.Services.Replace(typeof(IHttpControllerActivator), new CustomHttpControllerActivator(controllerFactory)); 49 | 50 | config.Routes.MapHttpRoute( 51 | name: "DefaultApi", 52 | routeTemplate: "api/{controller}/{id}", 53 | defaults: new { id = RouteParameter.Optional } 54 | ); 55 | 56 | app.UseErrorPage(); 57 | app.UseWebApi(config); 58 | } 59 | #endif 60 | 61 | #if NET6_0 62 | /// 63 | /// Configure the service 64 | /// 65 | public IServiceProvider ConfigureServices(IServiceCollection services) 66 | { 67 | services.AddRouting(); 68 | services.AddControllers(); 69 | return services.BuildServiceProvider(); 70 | } 71 | 72 | /// 73 | /// Configure the application 74 | /// 75 | /// 76 | /// 77 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 78 | { 79 | if (env.IsDevelopment()) 80 | app.UseDeveloperExceptionPage(); 81 | 82 | app.UseRouting(); 83 | 84 | app.UseEndpoints(endpoints => 85 | { 86 | endpoints.MapControllers(); // Map controllers for API endpoints 87 | }); 88 | } 89 | #endif 90 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/AbstractClassContractResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace QuartzWebApi.Wrappers.Calendars; 6 | 7 | internal class AbstractClassContractResolver : DefaultContractResolver 8 | { 9 | protected override JsonConverter ResolveContractConverter(Type objectType) 10 | { 11 | if (typeof(BaseCalendar).IsAssignableFrom(objectType) && !objectType.IsAbstract) 12 | return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow) 13 | return base.ResolveContractConverter(objectType); 14 | } 15 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/AnnualCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Wrappers.Calendars; 7 | 8 | /// 9 | /// A json wrapper for the 10 | /// 11 | public class AnnualCalendar : BaseCalendar 12 | { 13 | #region Properties 14 | /// 15 | /// Returns a collection of days of the year that are excluded 16 | /// 17 | [JsonProperty("DaysExcluded")] 18 | public List DaysExcluded { get; internal set; } = []; 19 | #endregion 20 | 21 | #region Constructor 22 | /// 23 | /// Takes a and wraps it in a json object 24 | /// 25 | /// 26 | public AnnualCalendar(Quartz.Impl.Calendar.AnnualCalendar annualCalendar) : base(annualCalendar) 27 | { 28 | foreach(var day in annualCalendar.DaysExcluded) 29 | DaysExcluded.Add(day); 30 | } 31 | #endregion 32 | 33 | #region ToCalendar 34 | /// 35 | /// Returns this object as a Quartz 36 | /// 37 | /// 38 | public override ICalendar ToCalendar() 39 | { 40 | var result = new Quartz.Impl.Calendar.AnnualCalendar 41 | { 42 | Description = Description, 43 | TimeZone = TimeZone 44 | }; 45 | 46 | foreach (var day in DaysExcluded) 47 | result.SetDayExcluded(day, true); 48 | 49 | return result; 50 | } 51 | #endregion 52 | 53 | #region ToJsonString 54 | /// 55 | /// Returns this object as a json string 56 | /// 57 | /// 58 | public new string ToJsonString() 59 | { 60 | return JsonConvert.SerializeObject(this, Formatting.Indented); 61 | } 62 | #endregion 63 | 64 | #region FromJsonString 65 | /// 66 | /// Returns the object from the given string 67 | /// 68 | /// The json string 69 | /// 70 | /// 71 | /// 72 | public new static AnnualCalendar FromJsonString(string json) 73 | { 74 | return JsonConvert.DeserializeObject(json); 75 | } 76 | #endregion 77 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/BaseCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Converters; 5 | using Quartz; 6 | 7 | namespace QuartzWebApi.Wrappers.Calendars; 8 | 9 | /// 10 | /// The base calendar for all calendars 11 | /// 12 | /// 13 | /// Takes a and wraps it in a json object 14 | /// 15 | /// 16 | [JsonConverter(typeof(BaseConverter))] 17 | public abstract class BaseCalendar(ICalendar calendar) 18 | { 19 | #region Properties 20 | /// 21 | /// The name of the calendar 22 | /// 23 | [JsonProperty("Name")] 24 | public string Name { get; internal set; } 25 | 26 | /// 27 | /// The of the calendar 28 | /// 29 | [JsonConverter(typeof(StringEnumConverter))] 30 | [JsonProperty("Type")] 31 | public CalendarType Type { get; internal set; } 32 | 33 | /// 34 | /// The description of the calendar 35 | /// 36 | [JsonProperty("Description", DefaultValueHandling = DefaultValueHandling.Ignore)] 37 | public string Description { get; internal set; } = calendar?.Description; 38 | 39 | /// 40 | /// The time zone of the calendar 41 | /// 42 | [JsonProperty("TimeZone", DefaultValueHandling = DefaultValueHandling.Ignore)] 43 | public TimeZoneInfo TimeZone { get; internal set; } 44 | 45 | /// 46 | /// The base of the calendar 47 | /// 48 | [JsonProperty("CalendarBase", DefaultValueHandling = DefaultValueHandling.Ignore)] 49 | public string CalendarBase { get; internal set; } 50 | 51 | /// 52 | /// If set to true [replace]. 53 | /// 54 | [JsonProperty("Replace", DefaultValueHandling = DefaultValueHandling.Ignore)] 55 | public bool Replace { get; internal set; } 56 | 57 | /// 58 | /// Whether to update existing triggers that 59 | /// referenced the already existing calendar so that they are 'correct' 60 | /// based on the new trigger. 61 | /// 62 | [JsonProperty("UpdateTriggers", DefaultValueHandling = DefaultValueHandling.Ignore)] 63 | public bool UpdateTriggers { get; internal set; } 64 | 65 | #endregion 66 | 67 | #region ToJsonString 68 | /// 69 | /// Returns this object as a json string 70 | /// 71 | /// 72 | public string ToJsonString() 73 | { 74 | return JsonConvert.SerializeObject(this, Formatting.Indented); 75 | } 76 | #endregion 77 | 78 | #region FromJsonString 79 | /// 80 | /// Returns the object from the given string 81 | /// 82 | /// The json string 83 | /// 84 | /// 85 | /// 86 | public static BaseCalendar FromJsonString(string json) 87 | { 88 | return JsonConvert.DeserializeObject(json); 89 | } 90 | #endregion 91 | 92 | public abstract ICalendar ToCalendar(); 93 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/BaseConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | 5 | namespace QuartzWebApi.Wrappers.Calendars; 6 | 7 | /// 8 | /// A json converter for the 9 | /// 10 | internal class BaseConverter : JsonConverter 11 | { 12 | #region Properties 13 | public override bool CanWrite => false; 14 | #endregion 15 | 16 | #region CanConvert 17 | public override bool CanConvert(Type objectType) 18 | { 19 | return objectType == typeof(BaseCalendar); 20 | } 21 | #endregion 22 | 23 | #region ReadJson 24 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 25 | { 26 | var jobObject = JObject.Load(reader); 27 | 28 | if (jobObject["Type"] == null) 29 | throw new ArgumentException("Type is not set"); 30 | 31 | var type = Enum.Parse(typeof(CalendarType), jobObject["Type"].ToString()); 32 | var settings = new JsonSerializerSettings { ContractResolver = new AbstractClassContractResolver() }; 33 | 34 | return type switch 35 | { 36 | CalendarType.Cron => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 37 | CalendarType.Daily => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 38 | CalendarType.Weekly => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 39 | CalendarType.Monthly => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 40 | CalendarType.Annual => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 41 | CalendarType.Holiday => JsonConvert.DeserializeObject(jobObject.ToString(), settings), 42 | _ => throw new ArgumentException("Invalid type") 43 | }; 44 | } 45 | #endregion 46 | 47 | #region WriteJson 48 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 49 | { 50 | throw new NotImplementedException(); 51 | } 52 | #endregion 53 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/CalendarType.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace QuartzWebApi.Wrappers.Calendars; 4 | 5 | public enum CalendarType 6 | { 7 | /// 8 | /// It is a cron calendar 9 | /// 10 | [DataMember(Name = "Cron")] 11 | Cron, 12 | 13 | /// 14 | /// It is a daily calendar 15 | /// 16 | [DataMember(Name = "Daily")] 17 | Daily, 18 | 19 | /// 20 | /// It is a week calendar 21 | /// 22 | [DataMember(Name = "Weekly")] 23 | Weekly, 24 | 25 | /// 26 | /// It is a monthly calendar 27 | /// 28 | [DataMember(Name = "Monthly")] 29 | Monthly, 30 | 31 | /// 32 | /// It is an annual calendar 33 | /// 34 | [DataMember(Name = "Annual")] 35 | Annual, 36 | 37 | /// 38 | /// It is a holiday calendar 39 | /// 40 | [DataMember(Name = "Holiday")] 41 | Holiday 42 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/CronCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Quartz; 4 | 5 | namespace QuartzWebApi.Wrappers.Calendars; 6 | 7 | /// 8 | /// A json wrapper for the 9 | /// 10 | public class CronCalendar : BaseCalendar 11 | { 12 | #region Properties 13 | /// 14 | /// The cron expression 15 | /// 16 | /// 17 | /// Only used when the is 18 | /// 19 | [JsonProperty("CronExpression")] 20 | public string CronExpression { get; internal set; } 21 | #endregion 22 | 23 | #region Constructor 24 | /// 25 | /// Takes a and wraps it in a json object 26 | /// 27 | /// 28 | public CronCalendar(Quartz.Impl.Calendar.CronCalendar cronCalendar) : base(cronCalendar) 29 | { 30 | Type = CalendarType.Cron; 31 | CronExpression = cronCalendar?.CronExpression.CronExpressionString; 32 | TimeZone = cronCalendar?.TimeZone; 33 | } 34 | #endregion 35 | 36 | #region ToCalendar 37 | /// 38 | /// Returns this object as a Quartz 39 | /// 40 | /// 41 | public override ICalendar ToCalendar() 42 | { 43 | var result = new Quartz.Impl.Calendar.CronCalendar(CronExpression) 44 | { 45 | Description = Description, 46 | TimeZone = TimeZone 47 | }; 48 | 49 | return result; 50 | } 51 | #endregion 52 | 53 | #region ToJsonString 54 | /// 55 | /// Returns this object as a json string 56 | /// 57 | /// 58 | public new string ToJsonString() 59 | { 60 | return JsonConvert.SerializeObject(this, Formatting.Indented); 61 | } 62 | #endregion 63 | 64 | #region FromJsonString 65 | /// 66 | /// Returns the object from the given string 67 | /// 68 | /// The json string 69 | /// 70 | /// 71 | /// 72 | public new static CronCalendar FromJsonString(string json) 73 | { 74 | return JsonConvert.DeserializeObject(json); 75 | } 76 | #endregion 77 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/DailyCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Quartz; 4 | 5 | namespace QuartzWebApi.Wrappers.Calendars; 6 | 7 | /// 8 | /// A json wrapper for the 9 | /// 10 | public class DailyCalendar : BaseCalendar 11 | { 12 | #region Properties 13 | /// 14 | /// Must be in the format "HH:MM[:SS[:mmm]]" where: 15 | ///
    16 | ///
  • 17 | /// HH is the hour of the specified time. The hour should be 18 | /// specified using military (24-hour) time and must be in the range 19 | /// 0 to 23. 20 | ///
  • 21 | ///
  • 22 | /// MM is the minute of the specified time and must be in the range 23 | /// 0 to 59. 24 | ///
  • 25 | ///
  • 26 | /// SS is the second of the specified time and must be in the range 27 | /// 0 to 59. 28 | ///
  • 29 | ///
  • 30 | /// mmm is the millisecond of the specified time and must be in the 31 | /// range 0 to 999. 32 | ///
  • 33 | ///
  • items enclosed in brackets ('[', ']') are optional.
  • 34 | ///
  • 35 | /// The time range starting time must be before the time range ending 36 | /// time. Note this means that a time range may not cross daily 37 | /// boundaries (10PM - 2AM) 38 | ///
  • 39 | ///
40 | ///
41 | /// 42 | /// Only used when the is 43 | /// 44 | [JsonProperty("RangeStartingTime")] 45 | public string RangeStartingTime { get; internal set; } 46 | 47 | /// 48 | /// Must be in the format "HH:MM[:SS[:mmm]]" where: 49 | ///
    50 | ///
  • 51 | /// HH is the hour of the specified time. The hour should be 52 | /// specified using military (24-hour) time and must be in the range 53 | /// 0 to 23. 54 | ///
  • 55 | ///
  • 56 | /// MM is the minute of the specified time and must be in the range 57 | /// 0 to 59. 58 | ///
  • 59 | ///
  • 60 | /// SS is the second of the specified time and must be in the range 61 | /// 0 to 59. 62 | ///
  • 63 | ///
  • 64 | /// mmm is the millisecond of the specified time and must be in the 65 | /// range 0 to 999. 66 | ///
  • 67 | ///
  • items enclosed in brackets ('[', ']') are optional.
  • 68 | ///
  • 69 | /// The time range starting time must be before the time range ending 70 | /// time. Note this means that a time range may not cross daily 71 | /// boundaries (10PM - 2AM) 72 | ///
  • 73 | ///
74 | ///
75 | [JsonProperty("RangeEndingTime")] 76 | public string RangeEndingTime { get; internal set; } 77 | 78 | /// 79 | /// Indicates whether the time range represents an inverted time range (see 80 | /// class description). 81 | /// 82 | /// true if invert time range; otherwise, false. 83 | [JsonProperty("InvertTimeRange")] 84 | public bool InvertTimeRange { get; internal set; } 85 | #endregion 86 | 87 | #region Constructor 88 | /// 89 | /// Takes a and wraps it in a json object 90 | /// 91 | /// 92 | public DailyCalendar(Quartz.Impl.Calendar.DailyCalendar dailyCalendar) : base(dailyCalendar) 93 | { 94 | Type = CalendarType.Daily; 95 | RangeStartingTime = dailyCalendar.RangeStartingTime; 96 | RangeEndingTime = dailyCalendar.RangeEndingTime; 97 | InvertTimeRange = dailyCalendar.InvertTimeRange; 98 | TimeZone = dailyCalendar.TimeZone; 99 | } 100 | #endregion 101 | 102 | #region ToCalendar 103 | /// 104 | /// Returns this object as a Quartz 105 | /// 106 | /// 107 | public override ICalendar ToCalendar() 108 | { 109 | var result = new Quartz.Impl.Calendar.DailyCalendar(RangeStartingTime, RangeEndingTime) 110 | { 111 | Description = Description, 112 | TimeZone = TimeZone, 113 | InvertTimeRange = InvertTimeRange 114 | }; 115 | 116 | return result; 117 | } 118 | #endregion 119 | 120 | #region ToJsonString 121 | /// 122 | /// Returns this object as a json string 123 | /// 124 | /// 125 | public new string ToJsonString() 126 | { 127 | return JsonConvert.SerializeObject(this, Formatting.Indented); 128 | } 129 | #endregion 130 | 131 | #region FromJsonString 132 | /// 133 | /// Returns the object from the given string 134 | /// 135 | /// The json string 136 | /// 137 | /// 138 | /// 139 | public new static DailyCalendar FromJsonString(string json) 140 | { 141 | return JsonConvert.DeserializeObject(json); 142 | } 143 | #endregion 144 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/HolidayCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Wrappers.Calendars; 7 | 8 | /// 9 | /// A json wrapper for the 10 | /// 11 | public class HolidayCalendar : BaseCalendar 12 | { 13 | #region Properties 14 | /// 15 | /// Returns a collection of dates representing the excluded 16 | /// days. Only the month, day and year of the returned dates are 17 | /// significant 18 | /// 19 | [JsonProperty("ExcludedDates")] 20 | public List ExcludedDates { get; internal set; } 21 | #endregion 22 | 23 | #region Constructor 24 | /// 25 | /// Takes a and wraps it in a json object 26 | /// 27 | /// 28 | public HolidayCalendar(Quartz.Impl.Calendar.HolidayCalendar holidayCalendar) : base(holidayCalendar) 29 | { 30 | Type = CalendarType.Holiday; 31 | 32 | foreach (var excludedDate in holidayCalendar.ExcludedDates) 33 | ExcludedDates.Add(excludedDate); 34 | 35 | TimeZone = holidayCalendar.TimeZone; 36 | } 37 | #endregion 38 | 39 | #region ToCalendar 40 | /// 41 | /// Returns this object as a Quartz 42 | /// 43 | /// 44 | public override ICalendar ToCalendar() 45 | { 46 | var result = new Quartz.Impl.Calendar.HolidayCalendar 47 | { 48 | Description = Description, 49 | TimeZone = TimeZone 50 | }; 51 | 52 | foreach (var day in ExcludedDates) 53 | result.AddExcludedDate(day); 54 | 55 | return result; 56 | } 57 | #endregion 58 | 59 | #region ToJsonString 60 | /// 61 | /// Returns this object as a json string 62 | /// 63 | /// 64 | public new string ToJsonString() 65 | { 66 | return JsonConvert.SerializeObject(this, Formatting.Indented); 67 | } 68 | #endregion 69 | 70 | #region FromJsonString 71 | /// 72 | /// Returns the object from the given string 73 | /// 74 | /// The json string 75 | /// 76 | /// 77 | /// 78 | public new static HolidayCalendar FromJsonString(string json) 79 | { 80 | return JsonConvert.DeserializeObject(json); 81 | } 82 | #endregion 83 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/MonthlyCalendar.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | using Quartz; 4 | 5 | namespace QuartzWebApi.Wrappers.Calendars; 6 | 7 | /// 8 | /// A json wrapper for the 9 | /// 10 | public class MonthlyCalendar : BaseCalendar 11 | { 12 | #region Properties 13 | /// 14 | /// Returns a collection of days of the month that are excluded 15 | /// 16 | [JsonProperty("DaysExcluded")] 17 | public List DaysExcluded { get; internal set; } = []; 18 | #endregion 19 | 20 | #region Constructor 21 | /// 22 | /// Takes a and wraps it in a json object 23 | /// 24 | /// 25 | public MonthlyCalendar(Quartz.Impl.Calendar.MonthlyCalendar monthlyCalendar) : base(monthlyCalendar) 26 | { 27 | Type = CalendarType.Monthly; 28 | 29 | foreach(var day in monthlyCalendar.DaysExcluded) 30 | DaysExcluded.Add(day); 31 | 32 | TimeZone = monthlyCalendar.TimeZone; 33 | } 34 | #endregion 35 | 36 | #region ToCalendar 37 | /// 38 | /// Returns this object as a Quartz 39 | /// 40 | /// 41 | public override ICalendar ToCalendar() 42 | { 43 | var result = new Quartz.Impl.Calendar.MonthlyCalendar 44 | { 45 | Description = Description, 46 | TimeZone = TimeZone 47 | }; 48 | 49 | for(var i = 0; i < DaysExcluded.Count; i++) 50 | result.SetDayExcluded(i + 1, DaysExcluded[i]); 51 | 52 | return result; 53 | } 54 | #endregion 55 | 56 | #region ToJsonString 57 | /// 58 | /// Returns this object as a json string 59 | /// 60 | /// 61 | public new string ToJsonString() 62 | { 63 | return JsonConvert.SerializeObject(this, Formatting.Indented); 64 | } 65 | #endregion 66 | 67 | #region FromJsonString 68 | /// 69 | /// Returns the object from the given string 70 | /// 71 | /// The json string 72 | /// 73 | /// 74 | /// 75 | public new static MonthlyCalendar FromJsonString(string json) 76 | { 77 | return JsonConvert.DeserializeObject(json); 78 | } 79 | #endregion 80 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Calendars/WeeklyCalendar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Wrappers.Calendars; 7 | 8 | /// 9 | /// A json wrapper for the 10 | /// 11 | public class WeeklyCalendar : BaseCalendar 12 | { 13 | #region Properties 14 | /// 15 | /// Returns a collection of days of the week that are excluded 16 | /// 17 | [JsonProperty("DaysExcluded")] 18 | public List DaysExcluded { get; internal set; } = []; 19 | #endregion 20 | 21 | #region Constructor 22 | /// 23 | /// Takes a and wraps it in a json object 24 | /// 25 | /// 26 | public WeeklyCalendar(Quartz.Impl.Calendar.WeeklyCalendar weeklyCalendar) : base(weeklyCalendar) 27 | { 28 | Type = CalendarType.Weekly; 29 | 30 | foreach(var day in weeklyCalendar.DaysExcluded) 31 | DaysExcluded.Add(day); 32 | 33 | TimeZone = weeklyCalendar.TimeZone; 34 | } 35 | #endregion 36 | 37 | #region ToCalendar 38 | /// 39 | /// Returns this object as a Quartz 40 | /// 41 | /// 42 | public override ICalendar ToCalendar() 43 | { 44 | var result = new Quartz.Impl.Calendar.WeeklyCalendar 45 | { 46 | Description = Description, 47 | TimeZone = TimeZone 48 | }; 49 | 50 | for(var i = 0; i < DaysExcluded.Count; i++) 51 | result.SetDayExcluded((DayOfWeek) i + 1, DaysExcluded[i]); 52 | 53 | return result; 54 | } 55 | #endregion 56 | 57 | #region ToJsonString 58 | /// 59 | /// Returns this object as a json string 60 | /// 61 | /// 62 | public new string ToJsonString() 63 | { 64 | return JsonConvert.SerializeObject(this, Formatting.Indented); 65 | } 66 | #endregion 67 | 68 | #region FromJsonString 69 | /// 70 | /// Returns the object from the given string 71 | /// 72 | /// The json string 73 | /// 74 | /// 75 | /// 76 | public new static WeeklyCalendar FromJsonString(string json) 77 | { 78 | return JsonConvert.DeserializeObject(json); 79 | } 80 | #endregion 81 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/GroupMatcher.cs: -------------------------------------------------------------------------------- 1 | // 2 | // GroupMatcher.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using System; 28 | using Newtonsoft.Json; 29 | using Newtonsoft.Json.Converters; 30 | using Quartz.Util; 31 | 32 | namespace QuartzWebApi.Wrappers; 33 | 34 | /// 35 | /// Json wrapper for the Quartz 36 | /// 37 | /// 38 | public class GroupMatcher where T : Key 39 | { 40 | #region Properties 41 | /// 42 | /// The 43 | /// 44 | [JsonConverter(typeof(StringEnumConverter))] 45 | [JsonProperty("Type")] 46 | public GroupMatcherType Type { get; private set; } 47 | 48 | /// 49 | /// The value to match 50 | /// 51 | [JsonProperty("Value")] 52 | public string Value { get; private set; } 53 | #endregion 54 | 55 | #region Constructor 56 | /// 57 | /// Makes this object and sets it's needed properties 58 | /// 59 | /// The 60 | /// The value to match 61 | public GroupMatcher(GroupMatcherType type, string value) 62 | { 63 | Type = type; 64 | Value = value; 65 | } 66 | #endregion 67 | 68 | #region ToJsonString 69 | /// 70 | /// Returns this object as a json string 71 | /// 72 | /// 73 | public string ToJsonString() 74 | { 75 | return JsonConvert.SerializeObject(this, Formatting.Indented); 76 | } 77 | #endregion 78 | 79 | #region FromJsonString 80 | /// 81 | /// Returns the object from the given string 82 | /// 83 | /// The json string 84 | /// 85 | /// 86 | /// 87 | public static GroupMatcher FromJsonString(string json) 88 | { 89 | return JsonConvert.DeserializeObject>(json); 90 | } 91 | #endregion 92 | 93 | #region ToGroupMatcher 94 | public Quartz.Impl.Matchers.GroupMatcher ToGroupMatcher() 95 | { 96 | switch (Type) 97 | { 98 | case GroupMatcherType.Contains: 99 | return Quartz.Impl.Matchers.GroupMatcher.GroupContains(Value); 100 | 101 | case GroupMatcherType.EndsWith: 102 | return Quartz.Impl.Matchers.GroupMatcher.GroupEndsWith(Value); 103 | 104 | case GroupMatcherType.Equals: 105 | return Quartz.Impl.Matchers.GroupMatcher.GroupEquals(Value); 106 | 107 | case GroupMatcherType.StartsWith: 108 | return Quartz.Impl.Matchers.GroupMatcher.GroupStartsWith(Value); 109 | 110 | default: 111 | throw new ArgumentOutOfRangeException(); 112 | } 113 | } 114 | #endregion 115 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/GroupMatcherType.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace QuartzWebApi.Wrappers; 4 | 5 | /// 6 | /// The matching type 7 | /// 8 | public enum GroupMatcherType 9 | { 10 | /// 11 | /// Should contain 12 | /// 13 | [DataMember(Name = "Contains")] 14 | Contains, 15 | 16 | /// 17 | /// Should end with 18 | /// 19 | [DataMember(Name = "EndsWith")] 20 | EndsWith, 21 | 22 | /// 23 | /// Should equal 24 | /// 25 | [DataMember(Name = "Equals")] 26 | Equals, 27 | 28 | /// 29 | /// Should start with 30 | /// 31 | [DataMember(Name = "StartsWith")] 32 | StartsWith 33 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobDetail.cs: -------------------------------------------------------------------------------- 1 | // 2 | // JobDetail.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using System; 28 | using Newtonsoft.Json; 29 | using Quartz; 30 | 31 | namespace QuartzWebApi.Wrappers; 32 | 33 | /// 34 | /// Json wrapper for the Quartz 35 | /// 36 | public class JobDetail 37 | { 38 | #region Properties 39 | /// 40 | /// The key that identifies this jobs uniquely 41 | /// 42 | [JsonProperty("JobKey")] 43 | public JobKey JobKey { get; private set; } 44 | 45 | /// 46 | /// Get or set the description given to the instance by its 47 | /// creator (if any) 48 | /// 49 | [JsonProperty("Description")] 50 | public string Description { get; private set; } 51 | 52 | /// 53 | /// Get or sets the instance of that will be executed 54 | /// 55 | [JsonProperty("JobType")] 56 | public string JobType { get; private set; } 57 | 58 | /// 59 | /// Get or set the that is associated with the 60 | /// 61 | [JsonProperty("JobDataMap")] 62 | public JobDataMap JobDataMap { get; private set; } 63 | 64 | /// 65 | /// Whether the should remain stored after it is 66 | /// orphaned (no s point to it) 67 | /// 68 | /// 69 | /// If not explicitly set, the default value is 70 | /// 71 | /// 72 | /// if the Job should remain persisted after being orphaned 73 | /// 74 | [JsonProperty("Durable")] 75 | public bool Durable { get; private set; } 76 | 77 | /// 78 | /// Whether the should be replaced 79 | /// 80 | [JsonProperty("Replace")] 81 | public bool Replace { get; private set; } 82 | 83 | /// 84 | /// Whether the should be stored durable while awaiting scheduling 85 | /// 86 | [JsonProperty("StoreNonDurableWhileAwaitingScheduling")] 87 | public bool StoreNonDurableWhileAwaitingScheduling { get; private set; } 88 | #endregion 89 | 90 | #region Constructor 91 | /// 92 | /// Creates this object and sets it's needed properties 93 | /// 94 | /// The key that identifies this jobs uniquely 95 | /// 96 | /// Get or set the description given to the instance by its 97 | /// creator (if any) 98 | /// 99 | /// Get or sets the instance of that will be executed 100 | /// 101 | /// Get or set the that is associated with the 102 | /// 103 | /// 104 | /// Whether the should remain stored after it is 105 | /// orphaned (no s point to it) 106 | /// 107 | /// Whether the should be replaced 108 | /// 109 | /// Whether the should be stored durable 110 | /// while awaiting scheduling 111 | /// 112 | public JobDetail( 113 | JobKey jobKey, 114 | string description, 115 | string jobType, 116 | JobDataMap jobDataMap, 117 | bool durable, 118 | bool replace, 119 | bool storeNonDurableWhileAwaitingScheduling) 120 | { 121 | JobKey = jobKey; 122 | Description = description; 123 | JobType = jobType; 124 | JobDataMap = jobDataMap; 125 | Durable = durable; 126 | Replace = replace; 127 | StoreNonDurableWhileAwaitingScheduling = storeNonDurableWhileAwaitingScheduling; 128 | } 129 | 130 | /// 131 | /// Create this object and sets it's needed properties 132 | /// 133 | /// 134 | /// 135 | /// 136 | public JobDetail(IJobDetail jobDetail) 137 | { 138 | JobKey = new JobKey(jobDetail.Key); 139 | Description = jobDetail.Description; 140 | JobType = jobDetail.JobType.ToString(); 141 | JobDataMap = jobDetail.JobDataMap; 142 | Durable = jobDetail.Durable; 143 | } 144 | #endregion 145 | 146 | #region ToJobDetail 147 | /// 148 | /// Returns this object as a Quartz 149 | /// 150 | /// 151 | public IJobDetail ToJobDetail() 152 | { 153 | var type = Type.GetType(JobType); 154 | 155 | if (type == null) 156 | throw new Exception($"Could not find an IJob class with the type '{JobType}'"); 157 | 158 | var job = JobBuilder.Create(type) 159 | .WithIdentity(JobKey.ToJobKey()) 160 | .WithDescription(Description) 161 | .StoreDurably(Durable) 162 | .RequestRecovery() 163 | .Build(); 164 | 165 | return job; 166 | } 167 | #endregion 168 | 169 | #region ToJsonString 170 | /// 171 | /// Returns this object as a json string 172 | /// 173 | /// 174 | public string ToJsonString() 175 | { 176 | return JsonConvert.SerializeObject(this, Formatting.Indented); 177 | } 178 | #endregion 179 | 180 | #region FromJsonString 181 | /// 182 | /// Returns the object from the given string 183 | /// 184 | /// The json string 185 | /// 186 | /// 187 | /// 188 | public static JobDetail FromJsonString(string json) 189 | { 190 | return JsonConvert.DeserializeObject(json); 191 | } 192 | #endregion 193 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobDetailWithTrigger.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace QuartzWebApi.Wrappers; 4 | 5 | /// 6 | /// Json wrapper to create a with a 7 | /// 8 | public class JobDetailWithTrigger 9 | { 10 | #region Properties 11 | /// 12 | /// 13 | /// 14 | [JsonProperty("JobDetail")] 15 | public JobDetail JobDetail { get; private set; } 16 | 17 | /// 18 | /// A list with related 's 19 | /// 20 | [JsonProperty("Trigger")] 21 | public Trigger Trigger { get; private set; } 22 | #endregion 23 | 24 | #region Constructor 25 | /// 26 | /// Makes this object and sets it's needed properties 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 's 32 | public JobDetailWithTrigger(JobDetail jobDetail, Trigger trigger) 33 | { 34 | JobDetail = jobDetail; 35 | Trigger = trigger; 36 | } 37 | #endregion 38 | 39 | #region ToJsonString 40 | /// 41 | /// Returns this object as a json string 42 | /// 43 | /// 44 | public string ToJsonString() 45 | { 46 | return JsonConvert.SerializeObject(this, Formatting.Indented); 47 | } 48 | #endregion 49 | 50 | #region FromJsonString 51 | /// 52 | /// Returns the object from the given string 53 | /// 54 | /// The json string 55 | /// 56 | /// 57 | /// 58 | public static JobDetailWithTrigger FromJsonString(string json) 59 | { 60 | return JsonConvert.DeserializeObject(json); 61 | } 62 | #endregion 63 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobDetailWithTriggers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Newtonsoft.Json; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Wrappers; 7 | 8 | /// 9 | /// Json wrapper to create a with a list of s 10 | /// 11 | public class JobDetailWithTriggers 12 | { 13 | #region Properties 14 | /// 15 | /// 16 | /// 17 | [JsonProperty("JobDetail")] 18 | public JobDetail JobDetail { get; private set; } 19 | 20 | /// 21 | /// A list with related 's 22 | /// 23 | [JsonProperty("Triggers")] 24 | public List Triggers { get; private set; } 25 | 26 | /// 27 | /// true when the job needs to be replaced 28 | /// 29 | [JsonProperty("Replace")] 30 | public bool Replace { get; private set; } 31 | #endregion 32 | 33 | #region Constructor 34 | /// 35 | /// Makes this object and sets it's needed properties 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// A list with related 's 41 | public JobDetailWithTriggers(JobDetail jobDetail, List triggers) 42 | { 43 | JobDetail = jobDetail; 44 | Triggers = triggers; 45 | } 46 | #endregion 47 | 48 | #region ToReadOnlyTriggerCollection 49 | /// 50 | /// Returns the as a 51 | /// 52 | /// 53 | public IReadOnlyCollection ToReadOnlyTriggerCollection() 54 | { 55 | return Triggers.Select(trigger => trigger.ToTrigger()).ToList(); 56 | } 57 | #endregion 58 | 59 | #region ToJsonString 60 | /// 61 | /// Returns this object as a json string 62 | /// 63 | /// 64 | public string ToJsonString() 65 | { 66 | return JsonConvert.SerializeObject(this, Formatting.Indented); 67 | } 68 | #endregion 69 | 70 | #region FromJsonString 71 | /// 72 | /// Returns the object from the given string 73 | /// 74 | /// The json string 75 | /// 76 | /// 77 | /// 78 | public static JobDetailWithTriggers FromJsonString(string json) 79 | { 80 | return JsonConvert.DeserializeObject(json); 81 | } 82 | #endregion 83 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobExecutionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Quartz; 4 | 5 | namespace QuartzWebApi.Wrappers; 6 | 7 | /// 8 | /// Json wrapper for the Quartz 9 | /// 10 | [JsonObject("JobExecutionContext")] 11 | public class JobExecutionContext(IJobExecutionContext jobExecutionContext) 12 | { 13 | #region Properties 14 | /// 15 | /// Get a handle to the instance that fired the 16 | /// . 17 | /// 18 | [JsonProperty("Scheduler")] 19 | public IScheduler Scheduler { get; private set; } = jobExecutionContext.Scheduler; 20 | 21 | /// 22 | /// Get a handle to the instance that fired the 23 | /// . 24 | /// 25 | [JsonProperty("Trigger")] 26 | public Trigger Trigger { get; private set; } = new(jobExecutionContext.Trigger); 27 | 28 | /// 29 | /// Get a handle to the referenced by the 30 | /// instance that fired the . 31 | /// 32 | [JsonProperty("Calender")] 33 | public ICalendar Calendar { get; private set; } = jobExecutionContext.Calendar; 34 | 35 | /// 36 | /// If the is being re-executed because of a 'recovery' 37 | /// situation, this method will return . 38 | /// 39 | [JsonProperty("Recovering")] 40 | public bool Recovering { get; private set; } = jobExecutionContext.Recovering; 41 | 42 | /// 43 | /// Returns the of the originally scheduled and now recovering job. 44 | /// 45 | /// 46 | /// When recovering a previously failed job execution this property returns the identity 47 | /// of the originally firing trigger. This recovering job will have been scheduled for 48 | /// the same firing time as the original job, and so is available via the 49 | /// property. The original firing time of the job can be 50 | /// accessed via the 51 | /// element of this job's . 52 | /// 53 | [JsonProperty("RecoveringTriggerKey")] 54 | public Quartz.TriggerKey RecoveringTriggerKey { get; private set; } = jobExecutionContext.RecoveringTriggerKey; 55 | 56 | /// 57 | /// Gets the refire count. 58 | /// 59 | /// The refire count. 60 | [JsonProperty("RefireCount")] 61 | public int RefireCount { get; private set; } = jobExecutionContext.RefireCount; 62 | 63 | /// 64 | /// Get the convenience of this execution context. 65 | /// 66 | /// 67 | /// 68 | /// The found on this object serves as a convenience - 69 | /// it is a merge of the found on the 70 | /// and the one found on the , with 71 | /// the value in the latter overriding any same-named values in the former. 72 | /// 73 | /// It is thus considered a 'best practice' that the Execute code of a Job 74 | /// retrieve data from the JobDataMap found on this object. 75 | /// 76 | /// 77 | /// 78 | /// NOTE: Do not expect value 'set' into this JobDataMap to somehow be 79 | /// set back onto a job's own JobDataMap. 80 | /// 81 | /// 82 | /// Attempts to change the contents of this map typically result in an 83 | /// illegal state. 84 | /// 85 | /// 86 | [JsonProperty("MergedJobDataMap")] 87 | public JobDataMap MergedJobDataMap { get; private set; } = jobExecutionContext.MergedJobDataMap; 88 | 89 | /// 90 | /// Get the associated with the . 91 | /// 92 | [JsonProperty("JobDetail")] 93 | public JobDetail JobDetail { get; private set; } = new(jobExecutionContext.JobDetail); 94 | 95 | /// 96 | /// Get the instance of the that was created for this 97 | /// execution. 98 | /// 99 | /// Note: The Job instance is not available through remote scheduler 100 | /// interfaces. 101 | /// 102 | /// 103 | [JsonProperty("JobInstance")] 104 | public string JobInstance { get; private set; } = jobExecutionContext.JobInstance.ToString(); 105 | 106 | /// 107 | /// The actual time the trigger fired. For instance the scheduled time may 108 | /// have been 10:00:00 but the actual fire time may have been 10:00:03 if 109 | /// the scheduler was too busy. 110 | /// 111 | /// Returns the fireTimeUtc. 112 | /// 113 | [JsonProperty("FireTimeUtc")] 114 | public DateTimeOffset FireTimeUtc { get; private set; } = jobExecutionContext.FireTimeUtc; 115 | 116 | /// 117 | /// The scheduled time the trigger fired for. For instance the scheduled 118 | /// time may have been 10:00:00 but the actual fire time may have been 119 | /// 10:00:03 if the scheduler was too busy. 120 | /// 121 | /// Returns the scheduledFireTimeUtc. 122 | /// 123 | [JsonProperty("ScheduledFireTimeUtc")] 124 | public DateTimeOffset? ScheduledFireTimeUtc { get; private set; } = jobExecutionContext.ScheduledFireTimeUtc; 125 | 126 | /// 127 | /// Gets the previous fire time. 128 | /// 129 | /// The previous fire time. 130 | [JsonProperty("PreviousFireTimeUtc")] 131 | public DateTimeOffset? PreviousFireTimeUtc { get; private set; } = jobExecutionContext.PreviousFireTimeUtc; 132 | 133 | /// 134 | /// Gets the next fire time. 135 | /// 136 | /// The next fire time. 137 | [JsonProperty("NextFireTimeUtc")] 138 | public DateTimeOffset? NextFireTimeUtc { get; private set; } = jobExecutionContext.NextFireTimeUtc; 139 | 140 | /// 141 | /// Get the unique id that identifies this particular firing instance of the 142 | /// trigger that triggered this job execution. It is unique to this 143 | /// JobExecutionContext instance as well. 144 | /// 145 | /// the unique fire instance id 146 | /// 147 | [JsonProperty("FireInstanceId")] 148 | public string FireInstanceId { get; private set; } = jobExecutionContext.FireInstanceId; 149 | 150 | ///// 151 | ///// Returns the result (if any) that the set before its 152 | ///// execution completed (the type of object set as the result is entirely up 153 | ///// to the particular job). 154 | ///// 155 | ///// 156 | ///// 157 | ///// The result itself is meaningless to Quartz, but may be informative 158 | ///// to s or 159 | ///// s that are watching the job's 160 | ///// execution. 161 | ///// 162 | ///// Set the result (if any) of the 's execution (the type of 163 | ///// object set as the result is entirely up to the particular job). 164 | ///// 165 | ///// The result itself is meaningless to Quartz, but may be informative 166 | ///// to s or 167 | ///// s that are watching the job's 168 | ///// execution. 169 | ///// 170 | ///// 171 | //[JsonProperty("Result")] 172 | //public object Result { get; private set; } 173 | 174 | /// 175 | /// The amount of time the job ran for. The returned 176 | /// value will be until the job has actually completed (or thrown an 177 | /// exception), and is therefore generally only useful to 178 | /// s and s. 179 | /// 180 | [JsonProperty("JobRunTime")] 181 | public TimeSpan JobRunTime { get; private set; } = jobExecutionContext.JobRunTime; 182 | #endregion 183 | 184 | #region Constructor 185 | //Result = jobExecutionContext.Result; 186 | #endregion 187 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobExecutionContexts.cs: -------------------------------------------------------------------------------- 1 | // 2 | // JobExecutionContexts.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using System.Collections.Generic; 28 | using System.Collections.ObjectModel; 29 | using Newtonsoft.Json; 30 | using Quartz; 31 | 32 | namespace QuartzWebApi.Wrappers; 33 | 34 | /// 35 | /// Json wrapper for a list of Quartz s 36 | /// 37 | [JsonArray] 38 | public class JobExecutionContexts : List 39 | { 40 | #region Constructor 41 | /// 42 | /// Makes this object and sets it's needed properties 43 | /// 44 | /// 45 | /// A of 46 | /// 47 | public JobExecutionContexts(IReadOnlyCollection jobExecutionContexts) 48 | { 49 | foreach (var jobExecutionContext in jobExecutionContexts) 50 | Add(new JobExecutionContext(jobExecutionContext)); 51 | } 52 | #endregion 53 | 54 | #region ToJsonString 55 | /// 56 | /// Returns this object as a json string 57 | /// 58 | /// 59 | public string ToJsonString() 60 | { 61 | return JsonConvert.SerializeObject(this, Formatting.Indented); 62 | } 63 | #endregion 64 | 65 | #region FromJsonString 66 | /// 67 | /// Returns the object from the given string 68 | /// 69 | /// The json string 70 | /// 71 | /// 72 | /// 73 | public static JobExecutionContexts FromJsonString(string json) 74 | { 75 | return JsonConvert.DeserializeObject(json); 76 | } 77 | #endregion 78 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobKey.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace QuartzWebApi.Wrappers; 4 | 5 | /// 6 | /// A json wrapper for the 7 | /// 8 | public class JobKey : Key 9 | { 10 | #region Constructor 11 | /// 12 | /// Makes this object and sets it's needed properties 13 | /// 14 | /// The name of the job 15 | [JsonConstructor] 16 | public JobKey(string name) : base(name) 17 | { 18 | } 19 | 20 | /// 21 | /// Makes this object and sets it's needed properties 22 | /// 23 | /// The name of the trigger 24 | /// The group of the trigger 25 | public JobKey(string name, string group) : base(name, group) 26 | { 27 | } 28 | 29 | /// 30 | /// Makes this object and sets it's needed properties 31 | /// 32 | /// The 33 | public JobKey(Quartz.JobKey key) : base(key.Name, key.Group) 34 | { 35 | } 36 | #endregion 37 | 38 | #region ToJobKey 39 | /// 40 | /// Returns this object as a Quartz 41 | /// 42 | /// 43 | public Quartz.JobKey ToJobKey() 44 | { 45 | return new Quartz.JobKey(Name, Group); 46 | } 47 | #endregion 48 | 49 | #region ToJsonString 50 | /// 51 | /// Returns this object as a json string 52 | /// 53 | /// 54 | public string ToJsonString() 55 | { 56 | return JsonConvert.SerializeObject(this, Formatting.Indented); 57 | } 58 | #endregion 59 | 60 | #region FromJsonString 61 | /// 62 | /// Returns the object from the given string 63 | /// 64 | /// The json string 65 | /// 66 | /// 67 | /// 68 | public static JobKey FromJsonString(string json) 69 | { 70 | return JsonConvert.DeserializeObject(json); 71 | } 72 | #endregion 73 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobKeyWithDataMap.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Quartz; 3 | 4 | namespace QuartzWebApi.Wrappers; 5 | 6 | /// 7 | /// Json wrapper to create a with a 8 | /// 9 | public class JobKeyWithDataMap 10 | { 11 | #region Properties 12 | /// 13 | /// The 14 | /// 15 | [JsonProperty("JobKey")] 16 | public JobKey JobKey { get; private set; } 17 | 18 | /// 19 | /// The 20 | /// 21 | [JsonProperty("JobDataMap")] 22 | public JobDataMap JobDataMap { get; private set; } 23 | #endregion 24 | 25 | #region Constructor 26 | /// 27 | /// Makes this object and sets it's needed properties 28 | /// 29 | /// The 30 | /// The 31 | public JobKeyWithDataMap(JobKey jobKey, JobDataMap jobDataMap) 32 | { 33 | JobKey = jobKey; 34 | JobDataMap = jobDataMap; 35 | } 36 | 37 | /// 38 | /// Makes this object and sets it's needed properties 39 | /// 40 | public JobKeyWithDataMap() 41 | { 42 | } 43 | #endregion 44 | 45 | #region ToJsonString 46 | /// 47 | /// Returns this object as a json string 48 | /// 49 | /// 50 | public string ToJsonString() 51 | { 52 | return JsonConvert.SerializeObject(this, Formatting.Indented); 53 | } 54 | #endregion 55 | 56 | #region FromJsonString 57 | /// 58 | /// Returns the object from the given string 59 | /// 60 | /// The json string 61 | /// 62 | /// 63 | /// 64 | public static JobKeyWithDataMap FromJsonString(string json) 65 | { 66 | return JsonConvert.DeserializeObject(json); 67 | } 68 | #endregion 69 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/JobKeys.cs: -------------------------------------------------------------------------------- 1 | // 2 | // JobKeys.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | using System.Collections.Generic; 27 | using System.Collections.ObjectModel; 28 | using System.Linq; 29 | using Newtonsoft.Json; 30 | 31 | namespace QuartzWebApi.Wrappers; 32 | 33 | /// 34 | /// A list of s 35 | /// 36 | [JsonArray] 37 | public class JobKeys : List 38 | { 39 | #region Constructor 40 | /// 41 | /// Makes this object and sets all it's needed properties 42 | /// 43 | /// A of s 44 | public JobKeys(IEnumerable jobKeys) 45 | { 46 | foreach (var jobKey in jobKeys) 47 | Add(new JobKey(jobKey.Name, jobKey.Group)); 48 | } 49 | #endregion 50 | 51 | #region ToJobKeys 52 | /// 53 | /// Returns a of s 54 | /// 55 | /// 56 | public IReadOnlyCollection ToJobKeys() 57 | { 58 | var result = this.Select(m => m.ToJobKey()).ToList(); 59 | return new ReadOnlyCollection(result); 60 | } 61 | #endregion 62 | 63 | #region ToJsonString 64 | /// 65 | /// Returns this object as a json string 66 | /// 67 | /// 68 | public string ToJsonString() 69 | { 70 | return JsonConvert.SerializeObject(this, Formatting.Indented); 71 | } 72 | #endregion 73 | 74 | #region FromJsonString 75 | /// 76 | /// Returns the object from the given string 77 | /// 78 | /// The json string 79 | /// 80 | /// 81 | /// 82 | public static JobKeys FromJsonString(string json) 83 | { 84 | return JsonConvert.DeserializeObject(json); 85 | } 86 | #endregion 87 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Key.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Key.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | using Newtonsoft.Json; 27 | 28 | namespace QuartzWebApi.Wrappers; 29 | 30 | /// 31 | /// A json wrapper for the or 32 | /// 33 | public class Key 34 | { 35 | #region Fields 36 | /// 37 | /// Returns the name of the trigger 38 | /// 39 | [JsonProperty("Name")] 40 | public string Name { get; internal set; } 41 | 42 | /// 43 | /// Returns the group of the trigger 44 | /// 45 | [JsonProperty("Group")] 46 | public string Group { get; internal set; } 47 | #endregion 48 | 49 | #region Constructor 50 | /// 51 | /// Makes this object and sets it's needed properties 52 | /// 53 | /// The name 54 | public Key(string name) 55 | { 56 | Name = name; 57 | } 58 | 59 | /// 60 | /// Makes this object and sets it's needed properties 61 | /// 62 | /// The name 63 | /// The group 64 | public Key(string name, string group) 65 | { 66 | Name = name; 67 | Group = group; 68 | } 69 | #endregion 70 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/RescheduleJob.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RescheduleJob.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using Newtonsoft.Json; 28 | 29 | namespace QuartzWebApi.Wrappers; 30 | 31 | /// 32 | /// Class used to read or create json to reschedule a job 33 | /// 34 | public class RescheduleJob 35 | { 36 | #region Properties 37 | /// 38 | /// The current trigger key 39 | /// 40 | [JsonProperty("CurrentTriggerKey")] 41 | public TriggerKey CurrentTriggerKey { get; private set; } 42 | 43 | /// 44 | /// The new trigger 45 | /// 46 | [JsonProperty("NewTrigger")] 47 | public Trigger Trigger { get; private set; } 48 | #endregion 49 | 50 | #region ToJsonString 51 | /// 52 | /// Returns this object as a json string 53 | /// 54 | /// 55 | public string ToJsonString() 56 | { 57 | return JsonConvert.SerializeObject(this, Formatting.Indented); 58 | } 59 | #endregion 60 | 61 | #region FromJsonString 62 | /// 63 | /// Returns the object from the given string 64 | /// 65 | /// The json string 66 | /// 67 | /// 68 | /// 69 | public static RescheduleJob FromJsonString(string json) 70 | { 71 | return JsonConvert.DeserializeObject(json); 72 | } 73 | #endregion 74 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/RunningJobs.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RunningJobs.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | namespace QuartzWebApi.Wrappers; 28 | //public class RunningJobs : IJobExecutionContext 29 | //{ 30 | // public void Put(object key, object objectValue) 31 | // { 32 | // throw new NotImplementedException(); 33 | // } 34 | 35 | // public object Get(object key) 36 | // { 37 | // throw new NotImplementedException(); 38 | // } 39 | 40 | // public IScheduler Scheduler { get; } 41 | // public ITrigger Trigger { get; } 42 | // public ICalendar Calendar { get; } 43 | // public bool Recovering { get; } 44 | // public TriggerKey RecoveringTriggerKey { get; } 45 | // public int RefireCount { get; } 46 | // public JobDataMap MergedJobDataMap { get; } 47 | // public IJobDetail JobDetail { get; } 48 | // public IJob JobInstance { get; } 49 | // public DateTimeOffset FireTimeUtc { get; } 50 | // public DateTimeOffset? ScheduledFireTimeUtc { get; } 51 | // public DateTimeOffset? PreviousFireTimeUtc { get; } 52 | // public DateTimeOffset? NextFireTimeUtc { get; } 53 | // public string FireInstanceId { get; } 54 | // public object Result { get; set; } 55 | // public TimeSpan JobRunTime { get; } 56 | // public CancellationToken CancellationToken { get; } 57 | //} -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/ScheduleJobs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace QuartzWebApi.Wrappers; 4 | 5 | public class ScheduleJobs : List 6 | { 7 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/SchedulerContext.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using Newtonsoft.Json; 3 | 4 | namespace QuartzWebApi.Wrappers; 5 | 6 | /// 7 | /// A json wrapper for the 8 | /// 9 | public sealed class SchedulerContext : Quartz.SchedulerContext 10 | { 11 | #region Constructor 12 | /// 13 | /// Needed for json de-serialization 14 | /// 15 | [JsonConstructor] 16 | internal SchedulerContext() 17 | { 18 | 19 | } 20 | 21 | internal SchedulerContext(Quartz.SchedulerContext schedulerContext) 22 | { 23 | foreach (var item in schedulerContext) 24 | Add(item.Key, item.Value); 25 | } 26 | #endregion 27 | 28 | #region ToJsonString 29 | /// 30 | /// Returns this object as a json string 31 | /// 32 | /// 33 | public string ToJsonString() 34 | { 35 | return JsonConvert.SerializeObject(this, Formatting.Indented); 36 | } 37 | #endregion 38 | 39 | #region FromJsonString 40 | /// 41 | /// Returns the object from the given string 42 | /// 43 | /// The json string 44 | /// 45 | /// 46 | /// 47 | public static SchedulerContext FromJsonString(string json) 48 | { 49 | var str = JsonConvert.DeserializeObject(json); 50 | var result = JsonConvert.DeserializeObject(str); 51 | return new SchedulerContext(result); 52 | } 53 | #endregion 54 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/SchedulerMetaData.cs: -------------------------------------------------------------------------------- 1 | // 2 | // SchedulerMetaData.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using System; 28 | using Newtonsoft.Json; 29 | 30 | namespace QuartzWebApi.Wrappers; 31 | 32 | /// 33 | /// Class used to read or create json to get the schedulers meta-data 34 | /// 35 | public class SchedulerMetaData 36 | { 37 | #region Properties 38 | /// 39 | /// Returns true when in standby mode 40 | /// 41 | [JsonProperty("InStandbyMode")] 42 | public bool InStandbyMode { get; private set; } 43 | 44 | /// 45 | /// Returns the job store type 46 | /// 47 | [JsonProperty("JobStoreType")] 48 | public Type JobStoreType { get; private set; } 49 | 50 | /// 51 | /// Returns true when the job store is clustered 52 | /// 53 | [JsonProperty("JobStoreClustered")] 54 | public bool JobStoreClustered { get; private set; } 55 | 56 | /// 57 | /// Returns true when the job store supports persistence 58 | /// 59 | [JsonProperty("JobsStoreSupportsPersistence")] 60 | public bool JobStoreSupportsPersistence { get; private set; } 61 | 62 | /// 63 | /// Returns the numbers of jobs executed 64 | /// 65 | [JsonProperty("NumbersOfJobsExecuted")] 66 | public int NumbersOfJobsExecuted { get; private set; } 67 | 68 | /// 69 | /// Returns the date time since the scheduler is running 70 | /// 71 | [JsonProperty("RunningSince")] 72 | public DateTimeOffset? RunningSince { get; private set; } 73 | 74 | /// 75 | /// Returns the scheduler instance id 76 | /// 77 | [JsonProperty("SchedulerInstanceId")] 78 | public string SchedulerInstanceId { get; private set; } 79 | 80 | /// 81 | /// Returns the scheduler name 82 | /// 83 | [JsonProperty("SchedulerName")] 84 | public string SchedulerName { get; private set; } 85 | 86 | /// 87 | /// Returns true when the scheduler is remote 88 | /// 89 | [JsonProperty("SchedulerRemote")] 90 | public bool SchedulerRemote { get; private set; } 91 | 92 | /// 93 | /// Returns the scheduler type 94 | /// 95 | [JsonProperty("SchedulerType")] 96 | public Type SchedulerType { get; private set; } 97 | 98 | /// 99 | /// Returns true when the scheduler is shutdown 100 | /// 101 | [JsonProperty("Shutdown")] 102 | public bool Shutdown { get; private set; } 103 | 104 | /// 105 | /// Returns true when the scheduler is started 106 | /// 107 | [JsonProperty("Started")] 108 | public bool Started { get; private set; } 109 | 110 | /// 111 | /// Returns the thread pool size 112 | /// 113 | [JsonProperty("ThreadPoolSize")] 114 | public int ThreadPoolSize { get; private set; } 115 | 116 | /// 117 | /// Returns the thread pool type 118 | /// 119 | [JsonProperty("ThreadPoolType")] 120 | public Type ThreadPoolType { get; private set; } 121 | 122 | /// 123 | /// Returns the scheduler version 124 | /// 125 | [JsonProperty("Version")] 126 | public string Version { get; private set; } 127 | 128 | [JsonProperty("Summary")] 129 | public string Summary { get; private set; } 130 | #endregion 131 | 132 | #region Constructor 133 | /// 134 | /// Needed for json de-serialization 135 | /// 136 | [JsonConstructor] 137 | internal SchedulerMetaData() 138 | { 139 | } 140 | 141 | /// 142 | /// Creates this object and sets all it's needed properties 143 | /// 144 | /// 145 | public SchedulerMetaData(Quartz.SchedulerMetaData metaData) 146 | { 147 | InStandbyMode = metaData.InStandbyMode; 148 | JobStoreType = metaData.JobStoreType; 149 | JobStoreClustered = metaData.JobStoreClustered; 150 | JobStoreSupportsPersistence = metaData.JobStoreSupportsPersistence; 151 | NumbersOfJobsExecuted = metaData.NumberOfJobsExecuted; 152 | RunningSince = metaData.RunningSince; 153 | SchedulerInstanceId = metaData.SchedulerInstanceId; 154 | SchedulerName = metaData.SchedulerName; 155 | SchedulerRemote = metaData.SchedulerRemote; 156 | SchedulerType = metaData.SchedulerType; 157 | Shutdown = metaData.Shutdown; 158 | Started = metaData.Started; 159 | ThreadPoolSize = metaData.ThreadPoolSize; 160 | ThreadPoolType = metaData.ThreadPoolType; 161 | Version = metaData.Version; 162 | Summary = metaData.GetSummary(); 163 | } 164 | #endregion 165 | 166 | #region ToJsonString 167 | /// 168 | /// Returns this object as a json string 169 | /// 170 | /// 171 | public string ToJsonString() 172 | { 173 | return JsonConvert.SerializeObject(this, Formatting.Indented); 174 | } 175 | #endregion 176 | 177 | #region FromJsonString 178 | /// 179 | /// Returns the object from the given string 180 | /// 181 | /// The json string 182 | /// 183 | /// 184 | /// 185 | public static SchedulerMetaData FromJsonString(string json) 186 | { 187 | var str = JsonConvert.DeserializeObject(json); 188 | return JsonConvert.DeserializeObject(str); 189 | } 190 | #endregion 191 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Trigger.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Trigger.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | using System; 28 | using Newtonsoft.Json; 29 | using Quartz; 30 | 31 | namespace QuartzWebApi.Wrappers; 32 | 33 | /// 34 | /// Class used to create or read json to get a trigger with a job key and data map 35 | /// 36 | public class Trigger : JobKeyWithDataMap 37 | { 38 | #region Properties 39 | /// 40 | /// The 41 | /// 42 | [JsonProperty("TriggerKey")] 43 | public TriggerKey TriggerKey { get; private set; } 44 | 45 | /// 46 | /// A description for the 47 | /// 48 | [JsonProperty("Description")] 49 | public string Description { get; private set; } 50 | 51 | /// 52 | /// The name of the calendar to use or null when not 53 | /// 54 | [JsonProperty("CalendarName")] 55 | public string CalendarName { get; private set; } 56 | 57 | /// 58 | /// The cron schedule 59 | /// 60 | [JsonProperty("CronSchedule")] 61 | public string CronSchedule { get; private set; } 62 | 63 | /// 64 | /// The next fire time in UTC format 65 | /// 66 | [JsonProperty("NextFireTimeUtc")] 67 | public DateTimeOffset? NextFireTimeUtc { get; private set; } 68 | 69 | /// 70 | /// The previous fire time in UTC format 71 | /// 72 | [JsonProperty("PreviousFireTimeUtc")] 73 | public DateTimeOffset? PreviousFireTimeUtc { get; private set; } 74 | 75 | /// 76 | /// The start time in UTC format 77 | /// 78 | [JsonProperty("StartTimeUtc")] 79 | public DateTimeOffset StartTimeUtc { get; private set; } 80 | 81 | /// 82 | /// The end time in UTC format 83 | /// 84 | [JsonProperty("EndTimeUtc")] 85 | public DateTimeOffset? EndTimeUtc { get; private set; } 86 | 87 | /// 88 | /// The final fire time in UTC format 89 | /// 90 | [JsonProperty("FinalFireTimeUtc")] 91 | public DateTimeOffset? FinalFireTimeUtc { get; private set; } 92 | 93 | /// 94 | /// The priority 95 | /// 96 | [JsonProperty("Priority")] 97 | public int Priority { get; private set; } 98 | 99 | /// 100 | /// Returns true when it has millisecond precision 101 | /// 102 | [JsonProperty("HasMillisecondPrecision")] 103 | public bool HasMillisecondPrecision { get; private set; } 104 | #endregion 105 | 106 | #region Constructor 107 | /// 108 | /// Makes this object and sets all it's needed properties 109 | /// 110 | /// The 111 | /// A description for the 112 | /// The name of the calendar to use or null when not 113 | /// The cron schedule 114 | /// The next fire time in UTC format 115 | /// The previous fire time in UTC format 116 | /// The start time in UTC format 117 | /// The end time in UTC format 118 | /// The final fire time in UTC format 119 | /// The priority 120 | /// The 121 | /// The 122 | public Trigger( 123 | TriggerKey triggerKey, 124 | string description, 125 | string calendarName, 126 | string cronSchedule, 127 | DateTimeOffset? nextFireTimeUtc, 128 | DateTimeOffset? previousFireTimeUtc, 129 | DateTimeOffset startTimeUtc, 130 | DateTimeOffset? endTimeUtc, 131 | DateTimeOffset? finalFireTimeUtc, 132 | int priority, 133 | JobKey jobKey, 134 | JobDataMap jobDataMap) : base(jobKey, jobDataMap) 135 | { 136 | TriggerKey = triggerKey; 137 | Description = description; 138 | CalendarName = calendarName; 139 | CronSchedule = cronSchedule; 140 | NextFireTimeUtc = nextFireTimeUtc; 141 | PreviousFireTimeUtc = previousFireTimeUtc; 142 | StartTimeUtc = startTimeUtc; 143 | EndTimeUtc = endTimeUtc; 144 | FinalFireTimeUtc = finalFireTimeUtc; 145 | Priority = priority; 146 | } 147 | 148 | /// 149 | /// Makes this object and sets all it's needed properties 150 | /// 151 | /// 152 | public Trigger(ITrigger trigger) 153 | { 154 | TriggerKey = new TriggerKey(trigger.Key); 155 | Description = trigger.Description; 156 | CalendarName = trigger.CalendarName; 157 | //CronSchedule = trigger; 158 | NextFireTimeUtc = trigger.GetNextFireTimeUtc(); 159 | PreviousFireTimeUtc = trigger.GetPreviousFireTimeUtc(); 160 | StartTimeUtc = trigger.StartTimeUtc; 161 | EndTimeUtc = trigger.EndTimeUtc; 162 | FinalFireTimeUtc = trigger.FinalFireTimeUtc; 163 | Priority = trigger.Priority; 164 | HasMillisecondPrecision = trigger.HasMillisecondPrecision; 165 | } 166 | #endregion 167 | 168 | #region ToTrigger 169 | /// 170 | /// Returns this object as a Quartz 171 | /// 172 | /// 173 | public ITrigger ToTrigger() 174 | { 175 | var trigger = TriggerBuilder 176 | .Create() 177 | .ForJob(JobKey.ToJobKey()) 178 | .WithIdentity(TriggerKey.ToTriggerKey()) 179 | .WithPriority(Priority) 180 | .StartAt(StartTimeUtc); 181 | 182 | if (EndTimeUtc.HasValue) 183 | trigger = trigger.EndAt(EndTimeUtc.Value); 184 | 185 | if (!string.IsNullOrWhiteSpace(CronSchedule)) 186 | trigger = trigger.WithCronSchedule(CronSchedule); 187 | 188 | if (!string.IsNullOrWhiteSpace(CalendarName)) 189 | trigger = trigger.ModifiedByCalendar(CalendarName); 190 | 191 | if (!string.IsNullOrWhiteSpace(Description)) 192 | trigger = trigger.WithDescription(Description); 193 | 194 | if (JobDataMap != null) 195 | trigger = trigger.UsingJobData(JobDataMap); 196 | 197 | return trigger.Build(); 198 | } 199 | #endregion 200 | 201 | #region ToJsonString 202 | /// 203 | /// Returns this object as a json string 204 | /// 205 | /// 206 | public new string ToJsonString() 207 | { 208 | return JsonConvert.SerializeObject(this, Formatting.Indented); 209 | } 210 | #endregion 211 | 212 | #region FromJsonString 213 | /// 214 | /// Returns the object from the given string 215 | /// 216 | /// The json string 217 | /// 218 | /// 219 | /// 220 | public new static Trigger FromJsonString(string json) 221 | { 222 | return JsonConvert.DeserializeObject(json); 223 | } 224 | #endregion 225 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/TriggerKey.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace QuartzWebApi.Wrappers; 4 | 5 | /// 6 | /// A json wrapper for the 7 | /// 8 | public class TriggerKey : Key 9 | { 10 | #region Constructor 11 | /// 12 | /// Makes this object and sets it's needed properties 13 | /// 14 | /// The name of the trigger 15 | [JsonConstructor] 16 | public TriggerKey(string name) : base(name) 17 | { 18 | } 19 | 20 | /// 21 | /// Makes this object and sets it's needed properties 22 | /// 23 | /// The name of the trigger 24 | /// The group of the trigger 25 | public TriggerKey(string name, string group) : base(name, group) 26 | { 27 | } 28 | 29 | /// 30 | /// Makes this object and sets it's needed properties 31 | /// 32 | /// The 33 | public TriggerKey(Quartz.TriggerKey key) : base(key.Name, key.Group) 34 | { 35 | } 36 | #endregion 37 | 38 | #region ToTriggerKey 39 | /// 40 | /// Returns this object as a Quartz 41 | /// 42 | /// 43 | public Quartz.TriggerKey ToTriggerKey() 44 | { 45 | return new Quartz.TriggerKey(Name, Group); 46 | } 47 | #endregion 48 | 49 | #region ToJsonString 50 | /// 51 | /// Returns this object as a json string 52 | /// 53 | /// 54 | public string ToJsonString() 55 | { 56 | return JsonConvert.SerializeObject(this, Formatting.Indented); 57 | } 58 | #endregion 59 | 60 | #region FromJsonString 61 | /// 62 | /// Returns the object from the given string 63 | /// 64 | /// The json string 65 | /// 66 | /// 67 | /// 68 | public static TriggerKey FromJsonString(string json) 69 | { 70 | return JsonConvert.DeserializeObject(json); 71 | } 72 | #endregion 73 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/TriggerKeys.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TriggerKeys.cs 3 | // 4 | // Author: Kees van Spelde 5 | // 6 | // Copyright (c) 2022 - 2024 Magic-Sessions. (www.magic-sessions.com) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | using System.Collections.Generic; 27 | using System.Collections.ObjectModel; 28 | using System.Linq; 29 | using Newtonsoft.Json; 30 | 31 | namespace QuartzWebApi.Wrappers; 32 | 33 | [JsonArray] 34 | public class TriggerKeys : List 35 | { 36 | #region Constructor 37 | /// 38 | /// Makes this object and sets all it's needed properties 39 | /// 40 | /// A of s 41 | public TriggerKeys(IEnumerable triggerKeys) 42 | { 43 | foreach (var triggerKey in triggerKeys) 44 | Add(new TriggerKey(triggerKey.Name, triggerKey.Group)); 45 | } 46 | #endregion 47 | 48 | #region ToTriggerKeys 49 | /// 50 | /// Returns a of s 51 | /// 52 | /// 53 | public IReadOnlyCollection ToTriggerKeys() 54 | { 55 | var result = this.Select(m => m.ToTriggerKey()).ToList(); 56 | return new ReadOnlyCollection(result); 57 | } 58 | #endregion 59 | 60 | #region ToJsonString 61 | /// 62 | /// Returns this object as a json string 63 | /// 64 | /// 65 | public string ToJsonString() 66 | { 67 | return JsonConvert.SerializeObject(this, Formatting.Indented); 68 | } 69 | #endregion 70 | 71 | #region FromJsonString 72 | /// 73 | /// Returns the object from the given string 74 | /// 75 | /// The json string 76 | /// 77 | /// 78 | /// 79 | public static TriggerKeys FromJsonString(string json) 80 | { 81 | return JsonConvert.DeserializeObject(json); 82 | } 83 | #endregion 84 | } -------------------------------------------------------------------------------- /QuartzWebApi/Wrappers/Triggers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using Newtonsoft.Json; 4 | using Quartz; 5 | 6 | namespace QuartzWebApi.Wrappers; 7 | 8 | /// 9 | /// A list of s 10 | /// 11 | [JsonArray] 12 | public class Triggers : List 13 | { 14 | #region Constructor 15 | /// 16 | /// Makes this object and sets all it's needed properties 17 | /// 18 | /// A of s 19 | public Triggers(IEnumerable triggers) 20 | { 21 | foreach (var trigger in triggers) 22 | Add(new Trigger(trigger)); 23 | } 24 | #endregion 25 | 26 | #region ToJsonString 27 | /// 28 | /// Returns this object as a json string 29 | /// 30 | /// 31 | public string ToJsonString() 32 | { 33 | return JsonConvert.SerializeObject(this, Formatting.Indented); 34 | } 35 | #endregion 36 | 37 | #region FromJsonString 38 | /// 39 | /// Returns the object from the given string 40 | /// 41 | /// The json string 42 | /// 43 | /// 44 | /// 45 | public static Triggers FromJsonString(string json) 46 | { 47 | return JsonConvert.DeserializeObject(json); 48 | } 49 | #endregion 50 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuartzWebApi 2 | A self hosted Web API for Quartz.Net, hosting on .net 4.8 is done with OWIN and on .net6 and higher with Kestrel 3 | 4 | ## Installing via NuGet (not yet done) 5 | 6 | [![NuGet](https://img.shields.io/nuget/v/QuartzWebApi.svg?style=flat-square)](https://www.nuget.org/packages/QuartzWebApi) 7 | 8 | # How to host Quartz.Net 9 | 10 | ```c# 11 | var host = new SchedulerHost("http://localhost:44344", , ); 12 | host.Start(); 13 | ``` 14 | 15 | Where `IScheduler` is your Quartz.Net scheduler and `ILogger` any logger that implements the Microsoft ILogger interface (or null if you don't want any logging) 16 | 17 | # How to connect to the host 18 | 19 | ```c# 20 | var connector = new SchedulerConnector("http://localhost:44344"); 21 | ``` 22 | 23 | ## License Information 24 | 25 | QuartzWebApi is Copyright (C) 2022 - 2024 Magic-Sessions and is licensed under the MIT license: 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining a copy 28 | of this software and associated documentation files (the "Software"), to deal 29 | in the Software without restriction, including without limitation the rights 30 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31 | copies of the Software, and to permit persons to whom the Software is 32 | furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in 35 | all copies or substantial portions of the Software. 36 | 37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 | FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE 40 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 43 | THE SOFTWARE. 44 | 45 | Core Team 46 | ========= 47 | Sicos1977 (Kees van Spelde) 48 | 49 | Logging 50 | ======= 51 | 52 | QuartzWebApi uses the Microsoft ILogger interface (https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger?view=dotnet-plat-ext-5.0). You can use any logging library that uses this interface. 53 | 54 | QuartzWebApi has some build in loggers that can be found in the ```QuartzWebApi.Logger``` namespace. 55 | 56 | For example 57 | 58 | ```csharp 59 | var logger = !string.IsNullOrWhiteSpace() 60 | ? new ChromeHtmlToPdfLib.Loggers.Stream(File.OpenWrite()) 61 | : new ChromeHtmlToPdfLib.Loggers.Console(); 62 | ``` 63 | 64 | Most of the log informartion is logged at the `information` level, small answers like `booleans`, `DateTimeOffsets` and small `strings` (like the schedulers name) are also logged at this level. All the json that is received and sent back is logged at the `debug` level. 65 | 66 | How to use the API directly 67 | ========== 68 | 69 | ### Check if a job group is paused 70 | 71 | Do a `POST` request to `Scheduler/IsJobGroupPaused/{groupName}`, where `{groupName}` is the name of the group this will return `true` or `false` 72 | 73 | ### Check if a trigger group is paused 74 | 75 | Do a `POST` request to `Scheduler/IsTriggerGroupPaused/{groupName}`, where `{groupName}` is the name of the group this will return `true` or `false` 76 | 77 | ### Get the schedulers name 78 | 79 | Do a `GET` request to `Scheduler/SchedulerName`, this will return the name of the scheduler 80 | 81 | ### Get the schedulers instance id 82 | 83 | Do a `GET` request to `Scheduler/SchedulerInstanceId`, this will return the schedulers instance id 84 | 85 | ### Get the schedulers context 86 | 87 | Do a `GET` request to `Scheduler/SchedulerContext` 88 | 89 | When the context is; 90 | 91 | - key1 - value1 92 | - key2 - value2 93 | - key3 - value3 94 | 95 | it will return 96 | 97 | ```json 98 | { 99 | "key1": "value1", 100 | "key2": "value2", 101 | "key3": "value3" 102 | } 103 | ``` 104 | 105 | ### Check if a scheduler is in standby mode 106 | 107 | Do a `GET` request to `Scheduler/InStandbyMode` , this will return `true` or `false` 108 | 109 | ### Check if a scheduler is in shutdown 110 | 111 | Do a `GET` request to `Scheduler/Isshutdown` , this will return `true` or `false` 112 | 113 | ### Get the schedulers meta-data 114 | 115 | Do a `GET` request to `Scheduler/GetMetaData` , this will return the meta-data that will look something like this 116 | 117 | ```json 118 | { 119 | "InStandbyMode": false, 120 | "JobStoreType": "Quartz.Simpl.RAMJobStore, Quartz, Version=3.4.0.0, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4", 121 | "JobStoreClustered": false, 122 | "JobsStoreSupportsPersistence": false, 123 | "NumbersOfJobsExecuted": 0, 124 | "RunningSince": "2022-05-11T16:30:06.5957565+00:00", 125 | "SchedulerInstanceId": "NON_CLUSTERED", 126 | "SchedulerName": "The name of the scheduler", 127 | "SchedulerRemote": false, 128 | "SchedulerType": "Quartz.Impl.StdScheduler, Quartz, Version=3.4.0.0, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4", 129 | "Shutdown": false, 130 | "Started": true, 131 | "ThreadPoolSize": 10, 132 | "ThreadPoolType": "Quartz.Simpl.DefaultThreadPool, Quartz, Version=3.4.0.0, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4", 133 | "Version": "3.4.0.0" 134 | } 135 | ``` 136 | 137 | ### Get the currently executing jobs 138 | 139 | Do a `GET` request to `Scheduler/GetCurrentlyExecutingJobs` , this will return the currently executing jobs that will look like this 140 | 141 | ```json 142 | [ 143 | "JobGroup1", 144 | "JobGroup2" 145 | ] 146 | ``` 147 | 148 | ### Get the job group names 149 | 150 | Do a `GET` request to `Scheduler/GetJobGroupNames` , this will return the job group names that will look like this 151 | 152 | ```json 153 | [ 154 | "JobGroup1", 155 | "JobGroup2" 156 | ] 157 | ``` 158 | 159 | ### Get the trigger group names 160 | 161 | Do a `GET` request to `Scheduler/GetTriggerGroupNames` , this will return 162 | 163 | ```json 164 | [ 165 | "TriggerGroup1", 166 | "TriggerGroup2" 167 | ] 168 | ``` 169 | 170 | ### Get the paused trigger groups 171 | 172 | Do a `GET` request to `Scheduler/GetPausedTriggerGroups` , this will return 173 | 174 | ```json 175 | [ 176 | "PausedTriggerGroup1", 177 | "PausedTriggerGroup2" 178 | ] 179 | ``` 180 | 181 | ### Start the scheduler 182 | 183 | Do a `POST` request to `Scheduler/Start` 184 | 185 | ### Start the scheduler with a delay 186 | 187 | Do a `POST` request to `Scheduler/StartDelayed/{delay}` where `{delay}` is the amount of *seconds* you want to delay the start 188 | 189 | ### Check if the scheduler is started 190 | 191 | Do a `GET` request to `Scheduler/IsStarted`, this will return `true` or `false` 192 | 193 | ### Check if the scheduler is in standby mode 194 | 195 | Do a `GET` request to `Scheduler/Standby`, this will return `true` or `false` 196 | 197 | ### Shutdown the scheduler 198 | 199 | Do a `POST` request to `Scheduler/Shutdown` 200 | 201 | ### Shutdown the scheduler but wait for all jobs to complete 202 | 203 | Do a `POST` request to `Scheduler/Shutdown/{waitForJobsToComplete}` where `{waitForJobsToComplete}` is `true` 204 | 205 | ### Schedule a job with a job detail and a trigger 206 | 207 | Do a `POST` request to `Scheduler/ScheduleJobWithJobDetailAndTrigger` with in the body the job detail and the trigger 208 | 209 | ```json 210 | { 211 | "JobDetail": { 212 | "JobKey": { 213 | "Name": "Name", 214 | "Group": "Group" 215 | }, 216 | "Description": "description", 217 | "JobType": "jobType", 218 | "JobDataMap": { 219 | "key": "value" 220 | }, 221 | "Durable": true, 222 | "Replace": false, 223 | "StoreNonDurableWhileAwaitingScheduling": false 224 | }, 225 | "Trigger": { 226 | "TriggerKey": { 227 | "Name": "name", 228 | "Group": "group" 229 | }, 230 | "Description": "description", 231 | "StartTimeUtc": "2022-08-15T17:34:04.5786231+00:00", 232 | "EndTimeUtc": "2022-08-15T17:34:04.5786231+00:00", 233 | "Priority": 5, 234 | "CronSchedule": "0 * * ? * *", 235 | "Priority": 5, 236 | "JobKey": { 237 | "Name": "name", 238 | "Group": "value" 239 | }, 240 | "JobDataMap": { 241 | "key": "value" 242 | } 243 | } 244 | } 245 | ``` 246 | 247 | ### Schedule the give trigger with the job identified by the trigger 248 | 249 | Do a `POST` request to `Scheduler/ScheduleJobIdentifiedWithTrigger` with in the body 250 | 251 | ```json 252 | { 253 | "TriggerKey": { 254 | "Name": "TriggerKeyName", 255 | "Group": "TriggerKeyGroup" 256 | }, 257 | "JobKey": { 258 | "Name": "JobKeyName", 259 | "Group": "JobKeyGroup" 260 | }, 261 | "Description": "Description", 262 | "CalendarName": "CalendarName", 263 | "JobDataMap": { 264 | "Key1": "Value1", 265 | "Key2": "Value2" 266 | }, 267 | "StartTimeUtc": "2022-05-12T16:16:37.7210025+00:00", 268 | "EndTimeUtc": "2022-05-13T02:16:37.7210025+00:00", 269 | "FinalFireTimeUtc": "2022-05-13T22:16:37.7210025+00:00", 270 | "CronSchedule": "0 * * ? * *", 271 | "Priority": 5 272 | } 273 | ``` 274 | 275 | This will return a datetime offset about when the job will be executed, for example `"2022-05-12T16:17:00+00:00"` 276 | 277 | ### Schedule multiple jobs with one or more associated trigger 278 | 279 | TODO: Task ScheduleJobs(IReadOnlyDictionary> triggersAndJobs, bool replace); 280 | 281 | ### Schedule a job with one or more associated trigger 282 | 283 | TODO: Task ScheduleJobs(IReadOnlyDictionary> triggersAndJobs, bool replace); 284 | 285 | ### Schedule a job with a job detail and a related set of triggers 286 | 287 | Do a `POST` request to `Scheduler/ScheduleJobWithJobDetailAndTriggers` with in the body the job detail and a related set of triggers 288 | 289 | ```json 290 | { 291 | "JobDetail": { 292 | "JobKey": { 293 | "Name": "Name", 294 | "Group": "Group" 295 | }, 296 | "Description": "description", 297 | "JobType": "jobType", 298 | "JobDataMap": { 299 | "key": "value" 300 | }, 301 | "Durable": true, 302 | "Replace": false, 303 | "StoreNonDurableWhileAwaitingScheduling": false 304 | }, 305 | "Triggers": [ 306 | { 307 | "TriggerKey": { 308 | "Name": "name", 309 | "Group": "group" 310 | }, 311 | "Description": "description", 312 | "CalendarName": "calenderName", 313 | "CronSchedule": "0 * * ? * *", 314 | "Priority": 5, 315 | "JobKey": { 316 | "Name": "name", 317 | "Group": "value" 318 | }, 319 | "JobDataMap": { 320 | "key": "value" 321 | } 322 | } 323 | ], 324 | "Replace": false 325 | } 326 | ``` 327 | 328 | When you get an error like `Could not find an IJob class with the type ''` then make sure that you have added the full namespace with the `JobType` 329 | 330 | ### Unschedule a job 331 | 332 | Do a `POST` request to `Scheduler/UnscheduleJob` with in the body the trigger of the job 333 | 334 | ```json 335 | { 336 | "Name": "TriggerKeyName", 337 | "Group": "TriggerKeyGroup" 338 | } 339 | ``` 340 | 341 | this will return `true` when the job is unscheduled or `false` when not 342 | 343 | ### Unschedule multiple jobs 344 | 345 | Do a `POST` request to `Scheduler/UnscheduleJobs` with in the body the triggers of the jobs to unschedule 346 | 347 | ```json 348 | [ 349 | { 350 | "Name": "TriggerKeyName1", 351 | "Group": "TriggerKeyGroup1" 352 | }, 353 | { 354 | "Name": "TriggerKeyName2", 355 | "Group": "TriggerKeyGroup2" 356 | } 357 | ] 358 | ``` 359 | 360 | this will return `true` when the jobs are unscheduled or `false` when not 361 | 362 | ### Reschedule job 363 | 364 | Do a `POST` request to `Scheduler/RescheduleJob` with in the body the reschedulejob object 365 | 366 | ```json 367 | { 368 | "CurrentTriggerKey": { 369 | "Name": "CurrentTriggerKeyName", 370 | "Group": "CurrentTriggerKeyGroup" 371 | }, 372 | "NewTrigger": { 373 | "TriggerKey": { 374 | "Name": "NewTriggerKeyName", 375 | "Group": "NewTriggerKeyGroup" 376 | }, 377 | "JobKey": { 378 | "Name": "NewJobKeyName", 379 | "Group": "NewJobKeyGroup" 380 | }, 381 | "Description": "Description", 382 | "CalendarName": "CalendarName", 383 | "JobDataMap": { 384 | "Key1": "Value1", 385 | "Key2": "Value2" 386 | }, 387 | "StartTimeUtc": "2022-05-12T16:16:37.7210025+00:00", 388 | "EndTimeUtc": "2022-05-13T02:16:37.7210025+00:00", 389 | "FinalFireTimeUtc": "2022-05-13T22:16:37.7210025+00:00", 390 | "CronSchedule": "0 * * ? * *", 391 | "Priority": 5 392 | } 393 | } 394 | ``` 395 | 396 | Returns 'null' if a trigger with the given name and group was not found and removed from the store (and the new trigger is therefore not stored), otherwise the first fire time of the newly scheduled trigger 397 | 398 | ### Add a job with no associated trigger 399 | 400 | Do a `POST` request to `Scheduler/AddJob` with in the body the addjob object 401 | 402 | ```json 403 | { 404 | "JobKey": { 405 | "Name": "JobKeyName", 406 | "Group": "JobKeyGroup" 407 | }, 408 | "Description": "Description", 409 | "JobType": "JobType", 410 | "JobDataMap": { 411 | "Key1": "Value1", 412 | "Key2": "Value2" 413 | }, 414 | "Durable": true, 415 | "Replace": false, 416 | "StoreNonDurableWhileAwaitingScheduling": true 417 | } 418 | ``` 419 | 420 | ### Delete a job 421 | 422 | Do a `POST` request to `Scheduler/DeleteJob` with in the body the key of the job 423 | 424 | ```json 425 | { 426 | "Name": "JobKeyName", 427 | "Group": "JobKeyGroup" 428 | } 429 | ``` 430 | 431 | this will return `true` when the job is deleted or `false` when not 432 | 433 | ### Delete multiple jobs 434 | 435 | Do a `DELETE` request to `Scheduler/DeleteJobs` with in the body the keys of the jobs 436 | 437 | ```json 438 | [ 439 | { 440 | "Name": "JobKeyName1", 441 | "Group": "JobKeyGroup1" 442 | }, 443 | { 444 | "Name": "JobKeyName2", 445 | "Group": "JobKeyGroup2" 446 | } 447 | ] 448 | ``` 449 | 450 | ### Trigger a job to execute NOW 451 | 452 | Do a `POST` request to `Scheduler/TriggerJobWithJobkey` with in the body the key of the job 453 | 454 | ```json 455 | { 456 | "Name": "JobKeyName1", 457 | "Group": "JobKeyGroup1" 458 | } 459 | ``` 460 | 461 | ### Trigger a job to execute NOW and associated a JobDataMap 462 | 463 | Do a `POST` request to `Scheduler/TriggerJobWithDataMap` with in the body 464 | 465 | ```json 466 | { 467 | "JobKey": { 468 | "Name": "JobKeyName", 469 | "Group": "JobKeyGroup" 470 | }, 471 | "JobDataMap": { 472 | "Key1": "Value1", 473 | "Key2": "Value2" 474 | } 475 | } 476 | ``` 477 | 478 | ### Pause a job 479 | 480 | Do a `POST` request to `Scheduler/PauseJob` with in the body the key of the job 481 | 482 | ```json 483 | { 484 | "Name": "JobKeyName", 485 | "Group": "JobKeyGroup" 486 | } 487 | ``` 488 | 489 | ### Pause multiple jobs 490 | 491 | Do a `POST` request to `Scheduler/PauseJobs` with in the body the group matching object that defined what jobs to pause 492 | 493 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 494 | 495 | ```json 496 | { 497 | "Type": "Contains", 498 | "Value": "" 499 | } 500 | ``` 501 | 502 | ### Pause a trigger 503 | 504 | Do a `POST` request to `Scheduler/PauseTrigger` with in the body the triggerkey 505 | 506 | ```json 507 | { 508 | "Name": "TriggerKeyName", 509 | "Group": "TriggerKeyGroup" 510 | } 511 | ``` 512 | 513 | ### Pause multiple triggers 514 | 515 | Do a `POST` request to `Scheduler/PauseTriggers` with in the body the group matching object that defined what triggers to pause 516 | 517 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 518 | 519 | ```json 520 | { 521 | "Type": "Contains", 522 | "Value": "" 523 | } 524 | ``` 525 | 526 | ### Resume a job 527 | 528 | Do a `POST` request to `Scheduler/ResumeJob` with in the body the key of the job 529 | 530 | ```json 531 | { 532 | "Name": "JobKeyName", 533 | "Group": "JobKeyGroup" 534 | } 535 | ``` 536 | 537 | ### Resume multiple jobs 538 | 539 | Do a `POST` request to `Scheduler/ResumeJobs` with in the body the group matching object that defined what jobs to resume 540 | 541 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 542 | 543 | ```json 544 | { 545 | "Type": "Contains", 546 | "Value": "" 547 | } 548 | ``` 549 | 550 | ### Resume a trigger 551 | 552 | Do a `POST` request to `Scheduler/ResumeTrigger` with in the body the key of the trigger 553 | 554 | ```json 555 | { 556 | "Name": "TriggerKeyName", 557 | "Group": "TriggerKeyGroup" 558 | } 559 | ``` 560 | 561 | ### Resume multiple triggers 562 | 563 | Do a `POST` request to `Scheduler/ResumeTriggers` with in the body the group matching object that defined what triggers to resume 564 | 565 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 566 | 567 | ```json 568 | { 569 | "Type": "Contains", 570 | "Value": "" 571 | } 572 | ``` 573 | 574 | ### Pause all triggers 575 | 576 | Do a `POST` request to `Scheduler/PauseAllTriggers` 577 | 578 | ### Resume all triggers 579 | 580 | Do a `POST` request to `Scheduler/ResumeAllTriggers` 581 | 582 | ### Get job keys 583 | 584 | Do a `GET` request to `Scheduler/GetJobKeys` 585 | 586 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 587 | 588 | ```json 589 | { 590 | "Type": "Contains", 591 | "Value": "" 592 | } 593 | ``` 594 | 595 | it will return something like this 596 | 597 | ```json 598 | [ 599 | { 600 | "Name": "JobKeyName", 601 | "Group": "JobKeyGroup" 602 | } 603 | ] 604 | ``` 605 | 606 | ### Get triggers of job 607 | 608 | Do a `GET` request to `Scheduler/GetTriggersOfJob` with in the body the key of the job 609 | 610 | ```json 611 | { 612 | "Name": "JobKeyName", 613 | "Group": "JobKeyGroup" 614 | } 615 | ``` 616 | 617 | It will return something like this 618 | 619 | ```json 620 | [ 621 | { 622 | "TriggerKey": { 623 | "Name": "triggerKey", 624 | "Group": "DEFAULT" 625 | }, 626 | "Description": "TestTrigger", 627 | "CalendarName": null, 628 | "CronSchedule": null, 629 | "NextFireTimeUtc": null, 630 | "PreviousFireTimeUtc": "2024-01-28T11:21:14.4966492+01:00", 631 | "StartTimeUtc": "2024-01-28T11:21:14.4966492+01:00", 632 | "EndTimeUtc": null, 633 | "FinalFireTimeUtc": "2024-01-28T11:21:14.4966492+01:00", 634 | "Priority": 5, 635 | "HasMillisecondPrecision": true, 636 | "JobKey": null, 637 | "JobDataMap": null 638 | } 639 | ] 640 | ``` 641 | 642 | ### Get trigger keys 643 | 644 | Do a `GET` request to `Scheduler/GetTriggerKeys` 645 | 646 | The values for `Type` can be: `Contains`, `EndsWith`, `Equals` or `StartsWith` 647 | 648 | ```json 649 | { 650 | "Type": "Contains", 651 | "Value": "" 652 | } 653 | ``` 654 | 655 | it will return something like this 656 | 657 | ```json 658 | [ 659 | { 660 | "Name": "triggerKey", 661 | "Group": "DEFAULT" 662 | } 663 | ] 664 | ``` 665 | 666 | ### Get the job detail 667 | 668 | Do a `GET` request to `Scheduler/GetJobDetail` with in the body the key of the job 669 | 670 | ```json 671 | { 672 | "Name": "JobKeyName", 673 | "Group": "JobKeyGroup" 674 | } 675 | ``` 676 | 677 | It will return something like this 678 | 679 | ```json 680 | { 681 | "JobKey": { 682 | "Name": "JobKeyName", 683 | "Group": "JobKeyGroup" 684 | }, 685 | "Description": "Test", 686 | "JobType": "QuartzWebApi.TestJob", 687 | "JobDataMap": {}, 688 | "Durable": false, 689 | "Replace": false, 690 | "StoreNonDurableWhileAwaitingScheduling": false 691 | } 692 | ``` 693 | 694 | ### Get trigger 695 | 696 | Do a `GET` request to `Scheduler/GetTrigger` with in the body the key of the trigger 697 | 698 | ```json 699 | { 700 | "Name": "TriggerKeyName", 701 | "Group": "TriggerKeyGroup" 702 | } 703 | ``` 704 | 705 | It will return something like this 706 | 707 | ```json 708 | { 709 | "TriggerKey": { 710 | "Name": "triggerKey", 711 | "Group": "DEFAULT" 712 | }, 713 | "Description": "TestTrigger", 714 | "CalendarName": null, 715 | "CronSchedule": null, 716 | "NextFireTimeUtc": null, 717 | "PreviousFireTimeUtc": "2024-01-28T14:09:21.9475007+01:00", 718 | "StartTimeUtc": "2024-01-28T14:09:21.9475007+01:00", 719 | "EndTimeUtc": null, 720 | "FinalFireTimeUtc": "2024-01-28T14:09:21.9475007+01:00", 721 | "Priority": 5, 722 | "HasMillisecondPrecision": true, 723 | "JobKey": null, 724 | "JobDataMap": null 725 | } 726 | ``` 727 | 728 | Do a `GET` request to `Scheduler/GetTriggerState` with in the body the key of the trigger 729 | 730 | ```json 731 | { 732 | "Name": "TriggerKeyName", 733 | "Group": "TriggerKeyGroup" 734 | } 735 | ``` 736 | 737 | It will return something like this 738 | 739 | ```json 740 | "Normal" 741 | ``` 742 | 743 | ### Add calendar 744 | 745 | Do a `POST` request to `Scheduler/AddCalendar` with in the body the body the calendar you want to add, for example 746 | 747 | ```json 748 | { 749 | "Name" : "My new CRON calendar", 750 | "Type": "Cron" 751 | "CronExpression": "0 0-5 14 * * ?", 752 | "Description": "my description" 753 | "Replace": true 754 | "UpdateTriggers": true 755 | } 756 | ``` 757 | 758 | ### Delete a calendar 759 | 760 | Do a `DELETE` request to `Scheduler/DeleteCalendar/{calName}` where `calName` is het name of the calendar to delete, this will return `true` or `false` 761 | 762 | ### Get a calendar 763 | 764 | Do a `GET` request to `Scheduler/GetCalendar/{calName}` where `calName` is het name of the calendar to get, when the calendar exists it will return something like this 765 | 766 | ```json 767 | { 768 | "CronExpression": "0 0-51 4 * * ?", 769 | "Name": null, 770 | "Type": "Cron", 771 | "TimeZone": { 772 | "Id": "W. Europe Standard Time", 773 | "DisplayName": "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", 774 | "StandardName": "W. Europe Standard Time", 775 | "DaylightName": "W. Europe Daylight Time", 776 | "BaseUtcOffset": "01:00:00", 777 | "AdjustmentRules": [ 778 | { 779 | "DateStart": "0001-01-01T00:00:00", 780 | "DateEnd": "9999-12-31T00:00:00", 781 | "DaylightDelta": "01:00:00", 782 | "DaylightTransitionStart": { 783 | "TimeOfDay": "0001-01-01T02:00:00", 784 | "Month": 3, 785 | "Week": 5, 786 | "Day": 1, 787 | "DayOfWeek": 0, 788 | "IsFixedDateRule": false 789 | }, 790 | "DaylightTransitionEnd": { 791 | "TimeOfDay": "0001-01-01T03:00:00", 792 | "Month": 10, 793 | "Week": 5, 794 | "Day": 1, 795 | "DayOfWeek": 0, 796 | "IsFixedDateRule": false 797 | }, 798 | "BaseUtcOffsetDelta": "00:00:00" 799 | } 800 | ], 801 | "SupportsDaylightSavingTime": true 802 | } 803 | } 804 | ``` 805 | 806 | ### Get calendar names 807 | 808 | Do a `GET` request to `Scheduler/GetCalendarNames`, it will return something like this 809 | 810 | ```json 811 | [ 812 | "monthlyCalendar", 813 | "MynewCRONcalendar" 814 | ] 815 | ``` 816 | 817 | 818 | Errors returned 819 | =============== 820 | 821 | When an error occures this is returned as a .NET exception in JSON format like this 822 | 823 | ```json 824 | { 825 | "Message": "An error has occurred.", 826 | "ExceptionMessage": "Unable to store Trigger: 'TriggerKeyGroup.TriggerKeyName', because one already exists with this identification.", 827 | "ExceptionType": "Quartz.ObjectAlreadyExistsException", 828 | "StackTrace": "... the .NET stack trace ..." 829 | } 830 | ``` 831 | --------------------------------------------------------------------------------