Introduction
This article describes how to observe the IIS. My Microsoft home server is connected to the Internet via the DynDNS server from Microsoft. When IIS hangs-up or becomes offline because of an internal error, then can you not re-connect it easily. That is not funny. That is why I have written an IIS observer.
The observer checks whether the domain (by DynDNS) is available and restarts IIS if it is necessary. The observer is a Windows Service application. The home server website URL, the restart application, parameters, and the interval are configured in the app.config.
Background
The application is a Windows Service, and works with local system rights.
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ObserverService() };
ServiceBase.Run(ServicesToRun);
}
}
public interface IObserve
{
string ServerUrl { get; }
int RequestTimeout { get; }
int CheckInterval { get; }
string RestartApp { get; }
string RestartParameter { get; }
}
[Serializable]
public class ServerToObserve : IObserve
{
public int RequestTimeout
{
get
{
#if RELEASE
string value = ConfigurationManager.AppSettings["ResponseTimeout"];
int timeout;
if (string.IsNullOrEmpty(value) || !int.TryParse(value, out timeout))
timeout = 60000;
return timeout;
#else
return 20000;
#endif
}
}
public int CheckInterval
{
get
{
#if RELEASE
string value = ConfigurationManager.AppSettings["CheckInterval"];
int timeout;
if (string.IsNullOrEmpty(value) || !int.TryParse(value, out timeout))
timeout = 1800000;
return timeout;
#else
return 60000;
#endif
}
}
public string ServerUrl
{
get
{
string value = ConfigurationManager.AppSettings["ServerUrl"];
if (string.IsNullOrEmpty(value))
throw new SettingsPropertyNotFoundException(
"ServerUrl setting not found");
else if(value.IndexOf("://") == -1)
throw new FormatException(
"Invalid format in the ServerUrl setting value. The tag must" +
"be contains the prefix http:// or ftp://.");
return value;
}
}
public string RestartApp
{
get
{
return ConfigurationManager.AppSettings["RestartApp"];
}
}
public string RestartParameter
{
get
{
return ConfigurationManager.AppSettings["RestartParameter"];
}
}
}
public partial class ObserverService : ServiceBase
{
Checker _iisObserver;
public ObserverService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_iisObserver = new Checker();
_iisObserver.Start(new ServerToObserve());
}
protected override void OnStop()
{
_iisObserver.Stop();
}
}
[Serializable]
public class Checker
{
private Timer _checkTimer;
private string _eventLogSource;
#region initialize
public Checker()
{
_eventLogSource = Assembly.GetAssembly(GetType()).GetName().Name;
if (EventLog.Exists(_eventLogSource))
EventLog.CreateEventSource(_eventLogSource, "");
}
#endregion
#region public methods
public void Start(IObserve observe)
{
try
{
if (observe == null)
throw new ArgumentNullException("observe");
_checkTimer = new Timer(CheckTimerCallback, observe,
observe.CheckInterval, observe.CheckInterval);
}
catch (Exception ex)
{
EventLog.WriteEntry(_eventLogSource, string.Format(
"Start: {0}\r\n{1}\r\n{2}", ex.Message, ex.InnerException,
ex.StackTrace), EventLogEntryType.Warning);
}
}
public void Stop()
{
try
{
_checkTimer.Dispose();
}
catch (Exception ex)
{
EventLog.WriteEntry(_eventLogSource, string.Format(
"Stop: {0}\r\n{1}\r\n{2}", ex.Message, ex.InnerException,
ex.StackTrace), EventLogEntryType.Warning);
}
}
#endregion
#region non public methods
private void CheckTimerCallback(object objectState)
{
try
{
IObserve observe = (IObserve)objectState;
WebRequest request = CreateRequest(observe);
request.BeginGetResponse(ResponseCallback, new ObserveHelper(observe,
request));
}
catch (Exception ex)
{
EventLog.WriteEntry(_eventLogSource, string.Format(
"CheckTimerCallback: {0}\r\n{1}\r\n{2}", ex.Message,
ex.InnerException, ex.StackTrace), EventLogEntryType.Warning);
}
}
private void ResponseCallback(IAsyncResult asyncResult)
{
ObserveHelper helper = null;
try
{
helper = (ObserveHelper)asyncResult.AsyncState;
HttpWebResponse response =
helper.Request.EndGetResponse(asyncResult) as HttpWebResponse;
if (response == null || (int)response.StatusCode >= 400)
RestartISS(helper);
}
catch (Exception ex)
{
EventLog.WriteEntry(_eventLogSource, string.Format(
"ResponseCallback: {0}\r\n{1}\r\n{2}", ex.Message,
ex.InnerException, ex.StackTrace), EventLogEntryType.Warning);
RestartISS(helper);
}
}
#region CreateRequest
private static HttpWebRequest CreateRequest(IObserve observe)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.CreateDefault(
new Uri(observe.ServerUrl));
request.KeepAlive = false;
request.Timeout = observe.RequestTimeout;
request.AllowAutoRedirect = false;
request.ContentType = "text/html";
request.Method = "GET";
request.ProtocolVersion = HttpVersion.Version11;
request.UserAgent = string.Format(
"Mozilla/5.0 (compatible; Server hangup checker {0}; {1} {2} {3}; {4})",
Environment.Version, Environment.OSVersion.Platform,
Environment.OSVersion.ServicePack, Environment.OSVersion.VersionString,
System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
return request;
}
#endregion
private void RestartISS(ObserveHelper helper)
{
if (helper == null)
{
EventLog.WriteEntry(_eventLogSource, "IIS Restart Helper is null",
EventLogEntryType.Error);
return;
}
EventLog.WriteEntry(_eventLogSource, "Restart IIS start",
EventLogEntryType.Information);
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo(helper.Observe.RestartApp,
helper.Observe.RestartParameter);
proc.Start();
EventLog.WriteEntry(_eventLogSource, "Restart IIS end",
EventLogEntryType.Information);
}
#endregion
private class ObserveHelper
{
private readonly IObserve _observe;
private readonly WebRequest _request;
#region properties
public IObserve Observe
{
get { return _observe; }
}
public WebRequest Request
{
get { return _request; }
}
#endregion
#region initialize
public ObserveHelper(IObserve observe, WebRequest request)
{
_observe = observe;
_request = request;
}
#endregion
}
}