Running Quartz.NET 1.0 on a medium trust host

I'm continuing to add more functionalities to the website and this time I've been working on "e-mail notifications" (which are sent to whoever commented on a post when a new comment is written). In order to send those e-mails asynchronously I decided to add the Quartz.NET Job Scheduler to the project and try to get it working.

So, after struggling to setup NHibernate, use the new ASP.NET MVC framework and getting Lucene.NET and NHibernate.Search to work, let's tackle the next library...  :S

Quartz.NET logo The latest version (1.0) of the library should be compatible with "partial trust" scenarios, but nonetheless still failed to work on the live website. I digged around in the source code to find the pieces of code which didn't work: I've documented my findings on the Quartz.NET mailing list and it should be fixed in the next versions (actually, the Common Logging framework would need to be fixed too for partial trust scenarios).

Anyway, if you need Quartz.NET now, here's what you need to do.

Remove the Common Logging library

After grabbing the source code from SourceForge, the first thing to do is to remove all references to the Common Logging library (which, as said, doesn't run on medium trust right now). To do so, remove the dll reference from the Quartz project:

Remove the Common Logging dll reference from the project.

Ok, now we end up with a lot of errors in the code.  :D Instead of removing the references to the logging library from the code, we can simply re-route all calls to a fake stub of the library, implementing some of the classes and copying the interface signatures with Reflector.

First of all, ILog.cs:

namespace Quartz {
	public interface ILog {
		// Methods
		void Debug(object message);
		void Debug(object message, Exception exception);
		void Error(object message);
		void Error(object message, Exception exception);
		void Fatal(object message);
		void Fatal(object message, Exception exception);
		void Info(object message);
		void Info(object message, Exception exception);
		void Trace(object message);
		void Trace(object message, Exception exception);
		void Warn(object message);
		void Warn(object message, Exception exception);

		// Properties
		bool IsDebugEnabled { get; }
		bool IsErrorEnabled { get; }
		bool IsFatalEnabled { get; }
		bool IsInfoEnabled { get; }
		bool IsTraceEnabled { get; }
		bool IsWarnEnabled { get; }
	}
}

Then ILoggerFactoryAdapter.cs:

namespace Quartz {
	public interface ILoggerFactoryAdapter {
		// Methods
		ILog GetLogger(string name);
		ILog GetLogger(Type type);
	}
}

Then create an implementation of ILog (I called it LogImpl) which simply does nothing on each call and returns false on all properties. Finally, let's implement LogManager.cs:

namespace Quartz {
	public sealed class LogManager {
		public static ILog GetLogger(string name) {
			return new LogImpl();
		}
		public static ILog GetLogger(Type type) {
			return new LogImpl();
		}

		// Properties
		public static ILoggerFactoryAdapter Adapter { get; set; }
	}
}

We don't need to implement the full class, just the methods used by Quartz, and return an instance of our stub logger.

Fixing Quartz.NET

Ok, now that the Common Logging library has been removed cleanly, we need to fix some of the calls in Quartz.NET which are not allowed in partial trust. Let's start with /Impl/StdSchedulerFactory.cs: in the Initialize() method you'll find a call to GetEnvironmentVariable() that must be removed.

string requestedFile = null;// Environment.GetEnvironmentVariable(PropertiesFile);

And then the same function call must be removed from the OverrideWithSysProps() method:

private static NameValueCollection OverrideWithSysProps(NameValueCollection props)
{
    NameValueCollection retValue = new NameValueCollection(props);
    /*ICollection keys = Environment.GetEnvironmentVariables().Keys;

    foreach (string key in keys)
    {
        retValue.Set(key, props[key]);
    }*/
    return retValue;
}

Ok, now to the /Core/QuartzScheduler.cs file. This class calls the GetAssembly() method to get the library's version number when initialized: this isn't allowed either on medium trust, so we'll have to remove that code.

/// 
/// Initializes the <see cref="QuartzScheduler"/> class.
/// 
static QuartzScheduler()
{
	//Assembly asm = Assembly.GetAssembly(typeof(QuartzScheduler));
	//versionInfo = FileVersionInfo.GetVersionInfo(asm.Location);
	//versionInfo = new FileVersionInfo();
}

And finally, remove all code in the "Version" properties with some hard-coded arbitrary values (you won't need them in most cases I think), like so:

public string Version
{
    get {
		//return versionInfo.FileVersion;
		return "1.0.0";
	}
}

That's it! Recompile the whole thing and add the new library to your project.  :)

Lazy?

If you don't want to mess with the source code and simply want a working version of Quartz.NET 1.0, download it here.