I've setup a Quartz as a windows service (using AdoJobStore if it matters) and have managed to get a ASP.NET site to communication with it via remoting to add/schedule a custom IJob that lives in my own project Company.Project.ServiceLayer.
This took me a while but all works OK on my dev machine provided the Company.Project.ServiceLayer.dll exists in both the windows service folder and the websites bin folder. However in the production environment there is a requirement to have the Company.Project.ServiceLayer.dll added to the GAC. I've tried to simulate this on my dev machine, removing the Company.Project.ServiceLayer.dll from the services folder and adding it into the GAC using gacutil. Unforunately now when the service starts up and tries to instanciate my IJob instance it is unable to load the assembly from the GAC and throws an exception "Could not load file or assembly" (full details below).
I'm guessing Quartz uses reflection along with the DB value in the [QRTZ_JOB_DETAILS].[JOB_CLASS_NAME] field to try and load the class? I could be totally wrong but since this value ("Company.Product.ServiceLayer.SchedulerJobs.QuintilesEasyJob, Company.Product.ServiceLayer") is only a partial description of the class (its missing the version and public key token) doesn't that mean that .NET won't look in the GAC when it does the reflection coz only strong named dll's can live there? Is that the reason my GAC setup is now failing? Could a Quartz windows service ever work with dll's in the GAC?
Any assistance is greatly appreciated.
2012-10-30 11:20:20,203 [4560] ERROR Topshelf.Model.ServiceCoordinator.OnServiceFault(:0) - Fault on quartz.server: Topshelf.Exceptions.ServiceControlException
Service Start Exception: quartz.server (IQuartzServer)
at Topshelf.Builders.LocalServiceBuilder`1.StartService(T service)
at Topshelf.Model.LocalServiceController`1.CallAction[TBefore,TComplete](String text, Action`1 callback, Func`1 before, Func`1 complete)
HelpLink:
Quartz.SchedulerConfigException
Failure occured during job recovery.
at Quartz.Impl.AdoJobStore.JobStoreSupport.SchedulerStarted() in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 591
at Quartz.Core.QuartzScheduler.Start() in c:\Work\OpenSource\quartznet\src\Quartz\Core\QuartzScheduler.cs:line 440
at Quartz.Server.QuartzServer.Start()
at Topshelf.Builders.LocalServiceBuilder`1.StartService(T service)
HelpLink:
Quartz.JobPersistenceException
Couldn't store trigger 'default.remotelyAddedTrigger' for 'default.remotelyAddedJob' job: Could not load file or assembly 'Company.Product.ServiceLayer' or one of its dependencies. The system cannot find the file specified.
at Quartz.Impl.AdoJobStore.JobStoreSupport.StoreTrigger(ConnectionAndTransactionHolder conn, IOperableTrigger newTrigger, IJobDetail job, Boolean replaceExisting, String state, Boolean forceState, Boolean recovering) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 1064
at Quartz.Impl.AdoJobStore.JobStoreSupport.DoUpdateOfMisfiredTrigger(ConnectionAndTransactionHolder conn, IOperableTrigger trig, Boolean forceState, String newStateIfNotComplete, Boolean recovering) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 876
at Quartz.Impl.AdoJobStore.JobStoreSupport.RecoverMisfiredJobs(ConnectionAndTransactionHolder conn, Boolean recovering) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 814
at Quartz.Impl.AdoJobStore.JobStoreSupport.RecoverJobs(ConnectionAndTransactionHolder conn) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 760
at Quartz.Impl.AdoJobStore.JobStoreSupport.<>c__DisplayClass74.<ExecuteInNonManagedTXLock>b__73(ConnectionAndTransactionHolder conn) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 3411
at Quartz.Impl.AdoJobStore.JobStoreSupport.ExecuteInNonManagedTXLock(String lockName, Func`2 txCallback) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 3481
at Quartz.Impl.AdoJobStore.JobStoreSupport.SchedulerStarted() in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 581
HelpLink:
System.IO.FileNotFoundException
Could not load file or assembly 'Company.Product.ServiceLayer' or one of its dependencies. The system cannot find the file specified.
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
at System.Type.GetType(String typeName, Boolean throwOnError)
at Quartz.Simpl.SimpleTypeLoadHelper.LoadType(String name) in c:\Work\OpenSource\quartznet\src\Quartz\Simpl\SimpleTypeLoadHelper.cs:line 51
at Quartz.Impl.AdoJobStore.StdAdoDelegate.SelectJobDetail(ConnectionAndTransactionHolder conn, JobKey jobKey, ITypeLoadHelper loadHelper) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\StdAdoDelegate.cs:line 788
at Quartz.Impl.AdoJobStore.JobStoreSupport.StoreTrigger(ConnectionAndTransactionHolder conn, IOperableTrigger newTrigger, IJobDetail job, Boolean replaceExisting, String state, Boolean forceState, Boolean recovering) in c:\Work\OpenSource\quartznet\src\Quartz\Impl\AdoJobStore\JobStoreSupport.cs:line 1041
I finally sussed this one out myself. I was able to get the service to look in the GAC by adding a partial name to full/strong name mapping in the app.config like so:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="Company.Product.ServiceLayer" fullName="Company.Product.ServiceLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=125c3f237e3350e4"/>
</assemblyBinding>
</runtime>