diff --git a/Endpoint/App.config b/Endpoint/App.config
new file mode 100644
index 0000000..e83ee72
--- /dev/null
+++ b/Endpoint/App.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Endpoint/Endpoint.csproj b/Endpoint/Endpoint.csproj
new file mode 100644
index 0000000..a86a8cb
--- /dev/null
+++ b/Endpoint/Endpoint.csproj
@@ -0,0 +1,105 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}
+ Library
+ Properties
+ Endpoint
+ Endpoint
+ v2.0
+ 512
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+ False
+ References\HtmlAgilityPack.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Endpoint/HtmlEndpoint.cs b/Endpoint/HtmlEndpoint.cs
new file mode 100644
index 0000000..a8254a5
--- /dev/null
+++ b/Endpoint/HtmlEndpoint.cs
@@ -0,0 +1,112 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Xml;
+using HtmlAgilityPack;
+
+namespace Endpoint
+{
+ ///
+ /// A website endpoint
+ ///
+ public class HtmlEndpoint : HttpEndpoint
+ {
+ ///
+ /// Gets or sets the xpath query for the html document
+ ///
+ /// The xpath query.
+ public string XpathQuery { get; set; }
+
+ ///
+ /// Gets or sets the expected query results.
+ ///
+ /// The expected query results.
+ public string ExpectedXpathResult { get; set; }
+
+ ///
+ /// Gets or sets the post.
+ ///
+ /// The post.
+ public string RequestContent { get; set; }
+
+ ///
+ /// Returns the HTML parsed into a standard .
+ /// Uses the library for "out of the web" (poorly formatted) html file support.
+ ///
+ /// The HTML
+ /// An from the HTML
+ private static XmlDocument getHtmlXml(string html)
+ {
+ var htmlDocument = new HtmlDocument();
+ htmlDocument.LoadHtml(html);
+
+ var xmlDocument = new XmlDocument();
+ using (Stream stream = new MemoryStream())
+ {
+ XmlWriter xmlTextWriter = new XmlTextWriter(stream, Encoding.UTF8);
+
+ htmlDocument.Save(xmlTextWriter);
+
+ stream.Seek(0, SeekOrigin.Begin);
+
+ using (var sr = new StreamReader(stream))
+ xmlDocument.Load(sr);
+
+ xmlTextWriter.Close();
+ }
+ return xmlDocument;
+ }
+
+ ///
+ /// Returns the HTML grabbed from the passed in URL parsed into a standard .
+ /// Uses the library for "out of the web" html file support.
+ ///
+ /// The URL.
+ /// The post data.
+ /// An from the HTML
+ private static XmlDocument getHtmlXml(Uri url, string requestContent)
+ {
+ return getHtmlXml(GetUrlContent(url, "application/x-www-form-urlencoded", requestContent, null));
+ }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ public override Status GetStatus()
+ {
+ var baseStatus = base.GetStatus();
+ if (baseStatus != Status.Up)
+ return baseStatus;
+
+ try
+ {
+ var xml = getHtmlXml(Uri, RequestContent);
+
+ // xml.Save(@"c:\test.xml");
+
+ var nodes = xml.SelectNodes(XpathQuery);
+
+ // verify html has expected value
+ if (nodes == null || nodes.Count == 0)
+ {
+ StatusDescription = "Couldn't find expected value in html";
+ return Status.Error;
+ }
+ var value = nodes[0].Value.Trim();
+ if (value != ExpectedXpathResult)
+ {
+ StatusDescription = String.Format("Result was: '{0}', was expecting '{1}'", value,
+ ExpectedXpathResult);
+ return Status.Error;
+ }
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = ex.Message;
+ return Status.Error;
+ }
+ return Status.Up;
+ }
+ }
+}
diff --git a/Endpoint/HttpEndpoint.cs b/Endpoint/HttpEndpoint.cs
new file mode 100644
index 0000000..9bd5b99
--- /dev/null
+++ b/Endpoint/HttpEndpoint.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace Endpoint
+{
+ ///
+ /// Http Endpoint - such as a webserver, a webservice, etc
+ ///
+ [Serializable]
+ public class HttpEndpoint : IEndpoint
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ public string Name { get; set; }
+
+ ///
+ /// URI of the service
+ ///
+ public Uri Uri { get; set; }
+
+ ///
+ /// Gets or sets the URI string.
+ ///
+ /// The URI string.
+ public string UriString
+ {
+ get { return Uri.ToString(); }
+ set { Uri = new Uri(value); }
+ }
+
+ ///
+ /// Returns the response string grabbed from the passed in URL.
+ ///
+ /// The URL.
+ /// The HTTP content type.
+ /// The request content.
+ /// The web headers.
+ /// A string containing response
+ protected static string GetUrlContent(Uri url, string contentType, string requestContent,
+ Dictionary webHeaders)
+ {
+ // POST request
+ if (!string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(requestContent))
+ {
+ var webRequest = (HttpWebRequest) WebRequest.Create(url);
+
+ // NOTE: need a proxy? Here's where it would go
+ // webRequest.Proxy = new WebProxy();
+
+ // SOAP
+ webRequest.ContentType = contentType;
+ if (webHeaders != null && webHeaders.Count > 0)
+ {
+ foreach (var webHeader in webHeaders)
+ webRequest.Headers.Add(webHeader.Key, webHeader.Value);
+ }
+
+ webRequest.Method = "POST";
+
+ //We need to count how many bytes we're sending. Post'ed Faked Forms should be name=value&
+ var bytes = Encoding.ASCII.GetBytes(requestContent);
+ webRequest.ContentLength = bytes.Length;
+ using (var requestStream = webRequest.GetRequestStream())
+ {
+ requestStream.Write(bytes, 0, bytes.Length); //write it to the stream
+ }
+ var webResponse = webRequest.GetResponse();
+ if (webResponse == null)
+ return null;
+ using (var streamReader = new StreamReader(webResponse.GetResponseStream()))
+ {
+ return streamReader.ReadToEnd();
+ }
+ }
+
+ // GET Request
+ var client = new WebClient();
+ using (var data = client.OpenRead(url))
+ using (var reader = new StreamReader(data))
+ {
+ return reader.ReadToEnd();
+ }
+ }
+
+ ///
+ /// Returns a string explaining details on the current status
+ ///
+ /// string with status message
+ public virtual string StatusDescription { get; protected set; }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ public virtual Status GetStatus()
+ {
+ try
+ {
+ var request = WebRequest.Create(Uri);
+
+ using (var response = (HttpWebResponse) request.GetResponse())
+ {
+ StatusDescription = response.StatusDescription;
+ return response.StatusCode == HttpStatusCode.OK
+ ? Status.Up
+ : Status.Unreachable;
+ }
+ }
+ catch (WebException ex)
+ {
+ StatusDescription = ex.Message + " (" + ex.Status + ")";
+
+ return ex.Status == WebExceptionStatus.Timeout
+ ? Status.Timeout
+ : Status.Unreachable;
+ }
+ }
+ }
+}
diff --git a/Endpoint/IEndpoint.cs b/Endpoint/IEndpoint.cs
new file mode 100644
index 0000000..aa77d42
--- /dev/null
+++ b/Endpoint/IEndpoint.cs
@@ -0,0 +1,26 @@
+
+namespace Endpoint
+{
+ ///
+ /// Describes a service endpoint, and the methods to find its current status
+ ///
+ public interface IEndpoint
+ {
+ ///
+ /// Gets the service name
+ ///
+ string Name { get; }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ Status GetStatus();
+
+ ///
+ /// Returns a string explaining details on the current status
+ ///
+ /// string with status message
+ string StatusDescription { get; }
+ }
+}
diff --git a/Endpoint/Properties/AssemblyInfo.cs b/Endpoint/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..aa6cc70
--- /dev/null
+++ b/Endpoint/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Endpoint")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Endpoint")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("aef466bc-73b7-4f86-a374-8db991adb437")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Endpoint/References/HtmlAgilityPack.dll b/Endpoint/References/HtmlAgilityPack.dll
new file mode 100644
index 0000000..413539d
Binary files /dev/null and b/Endpoint/References/HtmlAgilityPack.dll differ
diff --git a/Endpoint/References/Oracle.DataAccess.dll b/Endpoint/References/Oracle.DataAccess.dll
new file mode 100644
index 0000000..283ac96
Binary files /dev/null and b/Endpoint/References/Oracle.DataAccess.dll differ
diff --git a/Endpoint/SoapEndpoint.cs b/Endpoint/SoapEndpoint.cs
new file mode 100644
index 0000000..2ce3959
--- /dev/null
+++ b/Endpoint/SoapEndpoint.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace Endpoint
+{
+ ///
+ /// A SOAP webservice endpoint.
+ ///
+ public class SoapEndpoint : HttpEndpoint
+ {
+ private string _xpathNamespaces = string.Empty;
+ private Dictionary _namespaceToUri;
+
+ ///
+ /// Gets or sets the xpath query for the html document
+ ///
+ /// The xpath query.
+ public string XpathQuery { get; set; }
+
+ ///
+ /// Gets or sets the namespaces used in the xpath query
+ ///
+ /// The xpath namespaces.
+ public string XpathNamespaces
+ {
+ get { return _xpathNamespaces; }
+ set
+ {
+ _xpathNamespaces = value;
+ if (string.IsNullOrEmpty(_xpathNamespaces)) return;
+
+ var split = _xpathNamespaces.Split(',');
+ if (split.Length != 2)
+ throw new ArgumentException("Need a comma separated pair in XpathNamespaces.");
+
+ _namespaceToUri = new Dictionary();
+ _namespaceToUri.Add(split[0], split[1]);
+ }
+ }
+
+ ///
+ /// Gets or sets the expected query results.
+ ///
+ /// The expected query results.
+ public string ExpectedXpathResult { get; set; }
+
+ ///
+ /// Gets or sets the SOAP action.
+ ///
+ /// The post.
+ public string SoapAction { get; set; }
+
+ ///
+ /// Gets or sets the SOAP request.
+ ///
+ /// The post.
+ public string SoapRequest { get; set; }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ public override Status GetStatus()
+ {
+ var baseStatus = base.GetStatus();
+ if (baseStatus != Status.Up) // if we can't even get to the webserver, no need to try and call a WS.
+ return baseStatus;
+
+ try
+ {
+ var headers = new Dictionary {{"SOAPAction", SoapAction}};
+
+ var xml = new XmlDocument();
+
+ xml.LoadXml(GetUrlContent(Uri, "text/xml; charset=utf-8", SoapRequest, headers));
+
+ XmlNodeList nodes;
+ if (_namespaceToUri != null)
+ {
+ var nsMgr = new XmlNamespaceManager(xml.NameTable);
+ foreach (var namespaceToUri in _namespaceToUri)
+ {
+ nsMgr.AddNamespace(namespaceToUri.Key, namespaceToUri.Value);
+ }
+
+ nodes = xml.SelectNodes(XpathQuery, nsMgr);
+ }
+ else
+ nodes = xml.SelectNodes(XpathQuery);
+
+ //xml.Save(@"c:\soap.xml");
+
+ // verify response has expected value
+ if (nodes == null || nodes.Count == 0)
+ {
+ StatusDescription = "Couldn't find expected value in SOAP response";
+ return Status.Error;
+ }
+ var value = nodes[0].Value.Trim();
+ if (value != ExpectedXpathResult)
+ {
+ StatusDescription = String.Format("Result was: '{0}', was expecting '{1}'", value,
+ ExpectedXpathResult);
+ return Status.Error;
+ }
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = ex.Message;
+ return Status.Error;
+ }
+ return Status.Up;
+ }
+ }
+}
diff --git a/Endpoint/Status.cs b/Endpoint/Status.cs
new file mode 100644
index 0000000..6ebecc3
--- /dev/null
+++ b/Endpoint/Status.cs
@@ -0,0 +1,30 @@
+namespace Endpoint
+{
+ ///
+ /// Status of an endpoint
+ ///
+ /// The expects these to be in order of best-to-worst descending.
+ public enum Status
+ {
+ ///
+ /// Service state is unknown - this will occur only before the first poll.
+ ///
+ Unknown,
+ ///
+ /// Service is working
+ ///
+ Up,
+ ///
+ /// Service can be resolved, but does not respond
+ ///
+ Timeout,
+ ///
+ /// Service can not be resolved
+ ///
+ Unreachable,
+ ///
+ /// Service is available, but returns an error message
+ ///
+ Error
+ }
+}
\ No newline at end of file
diff --git a/Endpoint/StatusComparer.cs b/Endpoint/StatusComparer.cs
new file mode 100644
index 0000000..51c0173
--- /dev/null
+++ b/Endpoint/StatusComparer.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+
+namespace Endpoint
+{
+ ///
+ /// Compares a Status for which is the worst status.
+ ///
+ public class StatusComparer : IComparer
+ {
+ ///
+ /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// Value
+ /// Condition
+ /// Less than zero
+ /// is less than .
+ /// Zero
+ /// equals .
+ /// Greater than zero
+ /// is greater than .
+ ///
+ public int Compare(Status x, Status y)
+ {
+ return y.CompareTo(x);
+ }
+ }
+}
diff --git a/Endpoint/WindowsServiceEndpoint.cs b/Endpoint/WindowsServiceEndpoint.cs
new file mode 100644
index 0000000..ac5d432
--- /dev/null
+++ b/Endpoint/WindowsServiceEndpoint.cs
@@ -0,0 +1,73 @@
+using System;
+using System.ServiceProcess;
+
+namespace Endpoint
+{
+ ///
+ /// Endpoint for a Windows Service
+ ///
+ public class WindowsServiceEndpoint : IEndpoint
+ {
+ ///
+ /// Gets the service name
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Returns a string explaining details on the current status
+ ///
+ /// string with status message
+ public string StatusDescription { get; protected set; }
+
+ ///
+ /// Gets or sets the name of the windows service.
+ ///
+ /// The name of the service.
+ public string ServiceName { get; set; }
+
+ ///
+ /// Gets or sets the name of the machine the service runs on.
+ ///
+ /// The name of the machine.
+ public string MachineName { get; set; }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ public Status GetStatus()
+ {
+ ServiceController myservice;
+ try
+ {
+ if (!string.IsNullOrEmpty(MachineName))
+ myservice = new ServiceController(ServiceName, MachineName);
+ else
+ myservice = new ServiceController(ServiceName);
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = ex.Message;
+ return Status.Unreachable;
+ }
+
+ try
+ {
+ switch (myservice.Status)
+ {
+ case ServiceControllerStatus.Running:
+ StatusDescription = "Running";
+ return Status.Up;
+ default:
+ StatusDescription = myservice.Status.ToString();
+ return Status.Error;
+ }
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = ex.Message;
+ return Status.Error;
+ }
+ }
+ }
+}
diff --git a/Endpoint/WmiEndpoint.cs b/Endpoint/WmiEndpoint.cs
new file mode 100644
index 0000000..0ac17da
--- /dev/null
+++ b/Endpoint/WmiEndpoint.cs
@@ -0,0 +1,244 @@
+using System;
+using System.Management;
+
+namespace Endpoint
+{
+ ///
+ /// Endpoint for Windows Management Instrumentation (WMI)
+ ///
+ public class WmiEndpoint : IEndpoint
+ {
+ ///
+ /// Gets the service name
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Returns a string explaining details on the current status
+ ///
+ /// string with status message
+ public string StatusDescription { get; protected set; }
+
+ ///
+ /// Gets or sets the name of the machine to query with WMI.
+ ///
+ /// The name of the machine.
+ public string MachineName { get; set; }
+
+ ///
+ /// Gets or sets the object query string.
+ ///
+ /// The object query string.
+ public string ObjectQueryString { get; set; }
+
+ ///
+ /// Gets or sets the connection username.
+ ///
+ /// The connection username.
+ public string ConnectionUsername { get; set; }
+
+ ///
+ /// Gets or sets the connection password.
+ ///
+ /// The connection password.
+ public string ConnectionPassword { get; set; }
+
+ ///
+ /// Gets or sets the name of the result property - this needs to be returned by the query.
+ ///
+ /// The name of the result property.
+ public string ResultPropertyName { get; set; }
+
+ ///
+ /// Report error when result is this value.
+ ///
+ /// A result indicating an error.
+ public string ErrorResult { get; set; }
+
+ ///
+ /// Report up when result is this value.
+ ///
+ /// A result indicating everything is ok.
+ public string UpResult { get; set; }
+
+ ///
+ /// Report error when result is below this number
+ ///
+ ///
+ public double MinimumThreshold { get; set; }
+
+ ///
+ /// Report error when result is above this number
+ ///
+ ///
+ public double MaximumThreshold { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WmiEndpoint()
+ {
+ MinimumThreshold = double.MinValue;
+ MaximumThreshold = double.MaxValue;
+ }
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ public Status GetStatus()
+ {
+ var connectionOptions = new ConnectionOptions();
+ if (!string.IsNullOrEmpty(ConnectionUsername) && !string.IsNullOrEmpty(ConnectionPassword))
+ {
+ connectionOptions.Username = ConnectionUsername;
+ connectionOptions.Password = ConnectionPassword;
+ }
+
+ ManagementScope managementScope;
+ try
+ {
+ managementScope = new ManagementScope(MachineName, connectionOptions);
+ }
+ catch (Exception e)
+ {
+ StatusDescription = string.Format("Management Scope for MachineName \"{1}\" Failed : \"{0}\"", e.Message, MachineName);
+ return Status.Error;
+ }
+
+ ObjectQuery objectQuery;
+ try
+ {
+ objectQuery = new ObjectQuery(ObjectQueryString);
+ }
+ catch (Exception e)
+ {
+ StatusDescription = string.Format("ObjectQuery initialization \"{1}\" Failed : \"{0}\"", e.Message, ObjectQueryString);
+ return Status.Error;
+ }
+
+ ManagementObjectSearcher results;
+ try
+ {
+ //Execute the query
+ results = new ManagementObjectSearcher(managementScope, objectQuery);
+ }
+ catch (Exception e)
+ {
+ StatusDescription = string.Format("Building Query failed : \"{0}\"", e.Message);
+ return Status.Error;
+ }
+
+ ManagementObjectCollection managementObjectCollection;
+ try
+ {
+ //Get the results
+ managementObjectCollection = results.Get();
+
+ if (managementObjectCollection.Count == 0)
+ {
+ StatusDescription = string.Format("Query returned 0 results : \"{0}\"", ObjectQueryString);
+ return Status.Error;
+ }
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = "Error retrieving results. Exception: " + ex.Message;
+ return Status.Unreachable;
+ }
+
+ ManagementObject firstResult = null;
+
+ //take only the first result if there are more than one
+ foreach (ManagementObject result in managementObjectCollection)
+ {
+ firstResult = result;
+ break;
+ }
+
+ if (firstResult == null)
+ {
+ StatusDescription = "Problem accessing first result object";
+ return Status.Error;
+ }
+
+ object resultValue;
+ try
+ {
+ resultValue = firstResult[ResultPropertyName];
+ }
+ catch (Exception ex)
+ {
+ StatusDescription = string.Format("Error retrieving result property \"{0}\". Exception: {1}",
+ ResultPropertyName, ex.Message);
+ return Status.Error;
+ }
+
+ if (resultValue == null)
+ {
+ StatusDescription = string.Format("Result value was null for property \"{0}\".", ResultPropertyName);
+ return Status.Error;
+ }
+
+ return getStatus(resultValue.ToString());
+ }
+
+ ///
+ /// Gets the status.
+ ///
+ /// The result value string.
+ ///
+ private Status getStatus(string resultValueString)
+ {
+ // Up Value
+ if (!string.IsNullOrEmpty(UpResult) && UpResult != resultValueString)
+ {
+ StatusDescription =
+ string.Format("Result for property \"{0}\" was not expected value. Expected \"{1}\" but was \"{2}\"",
+ ResultPropertyName, UpResult ?? "(NULL)", resultValueString);
+ return Status.Error;
+ }
+
+ // Error Value
+ if (!string.IsNullOrEmpty(ErrorResult) && ErrorResult == resultValueString)
+ {
+ StatusDescription =
+ string.Format("Result for property \"{0}\" was error value - \"{1}\"",
+ ResultPropertyName, resultValueString);
+ return Status.Error;
+ }
+
+ if (MinimumThreshold != double.MinValue || MaximumThreshold != double.MaxValue)
+ {
+ double resultValueDouble;
+ if (Double.TryParse(resultValueString, out resultValueDouble))
+ {
+ if (resultValueDouble < MinimumThreshold)
+ {
+ StatusDescription =
+ string.Format("Result for property \"{0}\" was less then threshold - {1} < {2}",
+ ResultPropertyName, resultValueDouble, MinimumThreshold);
+ return Status.Error;
+ }
+ if (resultValueDouble > MaximumThreshold)
+ {
+ StatusDescription =
+ string.Format("Result for property \"{0}\" was more then threshold - {1} > {2}",
+ ResultPropertyName, resultValueDouble, MaximumThreshold);
+ return Status.Error;
+ }
+ }
+ else
+ {
+ StatusDescription =
+ string.Format("Result for property \"{0}\" was not a number - \"{1}\"",
+ ResultPropertyName, resultValueString);
+ return Status.Error;
+ }
+ }
+
+ StatusDescription = resultValueString;
+ return Status.Up;
+ }
+ }
+}
diff --git a/EndpointTest/EndpointTest.csproj b/EndpointTest/EndpointTest.csproj
new file mode 100644
index 0000000..675c9b0
--- /dev/null
+++ b/EndpointTest/EndpointTest.csproj
@@ -0,0 +1,117 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {76D78812-B640-4EF0-957B-15D0E9000A84}
+ Library
+ Properties
+ EndpointTest
+ EndpointTest
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+ False
+ ..\Endpoint\References\HtmlAgilityPack.dll
+
+
+
+ False
+ ..\Endpoint\References\Oracle.DataAccess.dll
+
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}
+ Endpoint
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/EndpointTest/HtmlEndpointTest.cs b/EndpointTest/HtmlEndpointTest.cs
new file mode 100644
index 0000000..4201f83
--- /dev/null
+++ b/EndpointTest/HtmlEndpointTest.cs
@@ -0,0 +1,53 @@
+using System;
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace EndpointTest
+{
+ ///
+ ///This is a test class for HtmlEndpointTest and is intended
+ ///to contain all HtmlEndpointTest Unit Tests
+ ///
+ [TestClass]
+ public class HtmlEndpointTest
+ {
+ // Random website for functional testing
+ private readonly Uri _goodUri = new Uri("http://www.seekwellness.com/sca/");
+
+ ///
+ ///A test for HtmlEndpointConfiguration
+ ///
+ [TestMethod]
+ public void HtmlEndpointConfigurationTest()
+ {
+ var target = new HtmlEndpoint
+ {
+ UriString = _goodUri.OriginalString,
+ XpathQuery = "//td[contains(text(), 'Use this form')]/text()",
+ ExpectedXpathResult = "Use this form to order your",
+ RequestContent = "redeem_coupon=true&f_coupon_code=stuff"
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status, target.StatusDescription);
+ }
+
+ ///
+ ///A test for HtmlEndpointConfiguration
+ ///
+ [TestMethod]
+ public void HtmlEndpointFormTest()
+ {
+ var target = new HtmlEndpoint
+ {
+ UriString = _goodUri.OriginalString,
+ XpathQuery = "//p[@class='errorMsg']/text()",
+ ExpectedXpathResult = "- Please enter a valid coupon code.",
+ RequestContent = "redeem_coupon=true&f_coupon_code=stuff"
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status, target.StatusDescription);
+ }
+ }
+}
diff --git a/EndpointTest/HttpEndpointTest.cs b/EndpointTest/HttpEndpointTest.cs
new file mode 100644
index 0000000..bb4213e
--- /dev/null
+++ b/EndpointTest/HttpEndpointTest.cs
@@ -0,0 +1,90 @@
+using System;
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace EndpointTest
+{
+ ///
+ ///This is a test class for HttpEndpointTest and is intended
+ ///to contain all HttpEndpointTest Unit Tests
+ ///
+ [TestClass]
+ public class HttpEndpointTest
+ {
+ private readonly Uri _goodUri = new Uri("http://www.google.com");
+ private readonly Uri _missingUri = new Uri("http://www.google.com/gasdfasdh598yqwejbiasalsdjfhaogle");
+ private readonly Uri _unreachableDomainUri = new Uri("http://gasdfasdh598yqwejbiasalsdjfhaogle");
+ private readonly Uri _downUri = new Uri("http://192.168.0.153");
+ private readonly Uri _httpsUri = new Uri("https://sourceforge.net/");
+
+ ///
+ ///A test for HttpEndpoint Constructor
+ ///
+ [TestMethod]
+ public void HttpEndpointConstructorTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _goodUri};
+ Assert.AreEqual(_goodUri, endpoint.Uri);
+ }
+
+ ///
+ ///A test for UrlString
+ ///
+ [TestMethod]
+ public void UrlStringTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {UriString = "http://uri/"};
+ Assert.AreEqual("http://uri/", endpoint.Uri.AbsoluteUri);
+ }
+
+ ///
+ ///A test for GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusGoodTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _goodUri};
+ Assert.AreEqual(Status.Up, endpoint.GetStatus());
+ }
+
+ ///
+ ///A test for GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusMissingTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _missingUri};
+ Assert.AreEqual(Status.Unreachable, endpoint.GetStatus());
+ }
+
+ ///
+ ///A test for GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusUnreachableTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _unreachableDomainUri};
+ Assert.AreEqual(Status.Unreachable, endpoint.GetStatus());
+ }
+
+ ///
+ ///A test for GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusDownTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _downUri};
+ Assert.AreEqual(Status.Unreachable, endpoint.GetStatus());
+ }
+
+ ///
+ ///A test for GetStatus
+ ///
+ [TestMethod]
+ public void GetHttpsTest()
+ {
+ HttpEndpoint endpoint = new HttpEndpoint {Uri = _httpsUri};
+ Assert.AreEqual(Status.Up, endpoint.GetStatus());
+ }
+ }
+}
diff --git a/EndpointTest/Properties/AssemblyInfo.cs b/EndpointTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b7ed628
--- /dev/null
+++ b/EndpointTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("EndpointTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("EndpointTest")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM componenets. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b5dcbcfc-f05e-4e58-bd8b-e4cbf660065d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/EndpointTest/ServiceEndpointConfigurationTest.cs b/EndpointTest/ServiceEndpointConfigurationTest.cs
new file mode 100644
index 0000000..6474f2d
--- /dev/null
+++ b/EndpointTest/ServiceEndpointConfigurationTest.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections.Generic;
+
+namespace EndpointTest
+{
+ /////
+ /////This is a test class for ServiceEndpointConfigurationTest and is intended
+ /////to contain all ServiceEndpointConfigurationTest Unit Tests
+ /////
+ //[TestClass()]
+ //public class ServiceEndpointConfigurationTest
+ //{
+ // private readonly Uri _uri = new Uri("http://www.google.com");
+ // private const string _testFilename = "testFilename.xml";
+
+ // ///
+ // ///A test for SaveConfigurationList
+ // ///
+ // [TestMethod]
+ // public void SaveAndLoadConfigurationListTest()
+ // {
+ // try
+ // {
+ // HttpEndpointConfiguration httpEndpoint = new HttpEndpointConfiguration("", _uri);
+ // OracleEndpointConfiguration oracleEndpoint = new OracleEndpointConfiguration("", "connection", "query", "result");
+
+ // List serviceEndpointConfigurations
+ // = new List { httpEndpoint, oracleEndpoint };
+
+ // IServiceEndpointConfiguration.SaveConfigurationList(serviceEndpointConfigurations, _testFilename);
+
+ // // load the results
+ // List loadedList = IServiceEndpointConfiguration.LoadConfigurationList(_testFilename);
+
+ // // verify that they're the same
+ // foreach (IServiceEndpointConfiguration serviceEndpointConfiguration in serviceEndpointConfigurations)
+ // {
+ // IServiceEndpointConfiguration tmp = serviceEndpointConfiguration;
+
+ // IServiceEndpointConfiguration foundConfig
+ // = loadedList.Find(loadedEndpointConfig => loadedEndpointConfig.Equals(tmp));
+ // Assert.IsNotNull(foundConfig);
+ // }
+ // }
+ // finally
+ // {
+ // FileInfo f = new FileInfo(_testFilename);
+ // // f.CopyTo(@"c:\test.xml");
+ // if (f.Exists)
+ // f.Delete();
+ // }
+ // }
+ //}
+}
diff --git a/EndpointTest/SoapEndpointTest.cs b/EndpointTest/SoapEndpointTest.cs
new file mode 100644
index 0000000..6c47471
--- /dev/null
+++ b/EndpointTest/SoapEndpointTest.cs
@@ -0,0 +1,62 @@
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace EndpointTest
+{
+ ///
+ /// Functional Tests for SoapEndpoint
+ ///
+ [TestClass]
+ public class SoapEndpointTest
+ {
+ // Random internet webservice
+ private const string URISTRING = @"http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php";
+
+ private const string SOAPACTION =
+ @"http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl#GmlTimeSeries";
+
+ private const string SOAPREQUEST =
+ @""
+ + @" "
+ + @" "
+ + @" "
+ + @" ?"
+ + @" ?"
+ + @" ?"
+ + @" ?"
+ + @" ?"
+ + @" ?"
+ + @" "
+ + @" "
+ + @"";
+
+ private const string XPATHNAMESPACES =
+ @"a,http://www.opengis.net/ows";
+
+ private const string XPATHQUERY =
+ @"//a:Exception[1]/@ExceptionText";
+
+ private const string EXPECTEDXPATHRESULT =
+ @"VERSION key not found";
+
+ ///
+ /// Runs GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusTest()
+ {
+ var target = new SoapEndpoint
+ {
+ UriString = URISTRING,
+ XpathQuery = XPATHQUERY,
+ ExpectedXpathResult = EXPECTEDXPATHRESULT,
+ SoapAction = SOAPACTION,
+ SoapRequest = SOAPREQUEST,
+ XpathNamespaces = XPATHNAMESPACES
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status);
+ }
+ }
+}
diff --git a/EndpointTest/WindowsServiceEndpointTest.cs b/EndpointTest/WindowsServiceEndpointTest.cs
new file mode 100644
index 0000000..65f991c
--- /dev/null
+++ b/EndpointTest/WindowsServiceEndpointTest.cs
@@ -0,0 +1,32 @@
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace EndpointTest
+{
+ ///
+ /// Tests for WindowsServiceEndpoint
+ ///
+ [TestClass]
+ public class WindowsServiceEndpointTest
+ {
+ ///
+ /// Use a service that should always be running on localhost
+ ///
+ private const string SERVICENAME = "Windows Time";
+
+ ///
+ /// Runs GetStatus
+ ///
+ [TestMethod]
+ public void GetStatusTest()
+ {
+ var target = new WindowsServiceEndpoint
+ {
+ ServiceName = SERVICENAME
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status);
+ }
+ }
+}
diff --git a/EndpointTest/WmiEndpointTest.cs b/EndpointTest/WmiEndpointTest.cs
new file mode 100644
index 0000000..efb80e1
--- /dev/null
+++ b/EndpointTest/WmiEndpointTest.cs
@@ -0,0 +1,141 @@
+using Endpoint;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace EndpointTest
+{
+ ///
+ /// Tests for WmiEndpoint
+ ///
+ [TestClass]
+ public class WmiEndpointTest
+ {
+ private const string MACHINENAME = @"\\localhost";
+
+ ///
+ /// Run GetStatus using "UpResult" expecting an up status.
+ ///
+ [TestMethod]
+ public void GetStatusUpPositiveTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "Select * from Win32_Process",
+ ResultPropertyName = "Name",
+ UpResult = "System Idle Process"
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status);
+ Assert.AreEqual("System Idle Process", target.StatusDescription);
+ }
+
+ ///
+ /// Run GetStatus using "UpResult" expecting an error status.
+ ///
+ [TestMethod]
+ public void GetStatusUpNegativeTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "Select * from Win32_Process",
+ ResultPropertyName = "Name",
+ UpResult = "Not A Real Process"
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Error, status);
+ }
+
+ ///
+ /// Run GetStatus using "ErrorResult" expecting an error status.
+ ///
+ [TestMethod]
+ public void GetStatusErrorPositiveTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "Select * from Win32_Process",
+ ResultPropertyName = "Name",
+ ErrorResult = "System Idle Process"
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Error, status);
+ }
+
+ ///
+ /// Run GetStatus using "MinimumThreshold" expecting an up status.
+ ///
+ [TestMethod]
+ public void GetStatusMinimumThresholdPositiveTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "select FreeSpace from Win32_LogicalDisk where DeviceID='C:'",
+ ResultPropertyName = "FreeSpace",
+ MinimumThreshold = 10 // assume you have more than 10B free on C:
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status);
+ }
+
+ ///
+ /// Run GetStatus using "MinimumThreshold" expecting an up status.
+ ///
+ [TestMethod]
+ public void GetStatusMinimumThresholdNegativeTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "select FreeSpace from Win32_LogicalDisk where DeviceID='C:'",
+ ResultPropertyName = "FreeSpace",
+ MinimumThreshold = 1e15 // assume you have less than a petabyte free on C:
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Error, status);
+ }
+
+ ///
+ /// Run GetStatus using "MaximumThreshold" expecting an up status.
+ ///
+ [TestMethod]
+ public void GetStatusMaximumThresholdPositiveTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "select FreeSpace from Win32_LogicalDisk where DeviceID='C:'",
+ ResultPropertyName = "FreeSpace",
+ MaximumThreshold = 1e15 // assume you have less than a petabyte free on C:
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Up, status);
+ }
+
+ ///
+ /// Run GetStatus using "MaximumThreshold" expecting an up status.
+ ///
+ [TestMethod]
+ public void GetStatusMaximumThresholdNegativeTest()
+ {
+ var target = new WmiEndpoint
+ {
+ MachineName = MACHINENAME,
+ ObjectQueryString = "select FreeSpace from Win32_LogicalDisk where DeviceID='C:'",
+ ResultPropertyName = "FreeSpace",
+ MaximumThreshold = 10 // assume you have less than a 10B free on C:
+ };
+
+ var status = target.GetStatus();
+ Assert.AreEqual(Status.Error, status);
+ }
+ }
+}
diff --git a/LocalTestRun.testrunconfig b/LocalTestRun.testrunconfig
new file mode 100644
index 0000000..dd8747e
--- /dev/null
+++ b/LocalTestRun.testrunconfig
@@ -0,0 +1,5 @@
+
+
+ This is a default test run configuration for a local test run.
+
+
\ No newline at end of file
diff --git a/ServiceDashBored.sln b/ServiceDashBored.sln
new file mode 100644
index 0000000..1af2e98
--- /dev/null
+++ b/ServiceDashBored.sln
@@ -0,0 +1,41 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA481DF1-5754-4499-AEA2-21F809256F35}"
+ ProjectSection(SolutionItems) = preProject
+ LocalTestRun.testrunconfig = LocalTestRun.testrunconfig
+ ServiceDashBored.vsmdi = ServiceDashBored.vsmdi
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDashBored", "ServiceDashBored\ServiceDashBored.csproj", "{2D46A996-7DEF-4592-B401-70090686B3F2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Endpoint", "Endpoint\Endpoint.csproj", "{7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndpointTest", "EndpointTest\EndpointTest.csproj", "{76D78812-B640-4EF0-957B-15D0E9000A84}"
+EndProject
+Global
+ GlobalSection(TestCaseManagementSettings) = postSolution
+ CategoryFile = ServiceDashBored.vsmdi
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2D46A996-7DEF-4592-B401-70090686B3F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D46A996-7DEF-4592-B401-70090686B3F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D46A996-7DEF-4592-B401-70090686B3F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D46A996-7DEF-4592-B401-70090686B3F2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {76D78812-B640-4EF0-957B-15D0E9000A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {76D78812-B640-4EF0-957B-15D0E9000A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {76D78812-B640-4EF0-957B-15D0E9000A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {76D78812-B640-4EF0-957B-15D0E9000A84}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/ServiceDashBored.vsmdi b/ServiceDashBored.vsmdi
new file mode 100644
index 0000000..3a2f48b
--- /dev/null
+++ b/ServiceDashBored.vsmdi
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ServiceDashBored/EndpointStatus.cs b/ServiceDashBored/EndpointStatus.cs
new file mode 100644
index 0000000..247ae5b
--- /dev/null
+++ b/ServiceDashBored/EndpointStatus.cs
@@ -0,0 +1,309 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Threading;
+using BitFactory.Logging;
+using Endpoint;
+using ServiceDashBored.Properties;
+
+namespace ServiceDashBored
+{
+ ///
+ /// Monitors a single Endpoint's Status
+ ///
+ public class EndpointStatus : INotifyPropertyChanged, IDisposable
+ {
+ #region Private Members
+
+ private readonly IEndpoint _endpoint;
+ private readonly Timer _lastUpdateTimer;
+ private DateTime _lastUpdate;
+ private readonly Logger _logger;
+ private readonly TimeSpan _updatePeriod;
+ private static readonly object _propertyUpdateSyncObject = new Object();
+ private static readonly object _callbackSyncObject = new Object();
+ private bool _insideCallback;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets the icon based on the status.
+ ///
+ public Icon StatusIcon { get; private set; }
+
+ ///
+ /// Gets service's current status.
+ ///
+ /// The status.
+ public Status Status { get; private set; }
+
+ ///
+ /// Returns a string explaining details on the current status
+ ///
+ public string StatusDescription { get; private set; }
+
+ ///
+ /// Gets the time since the last update
+ ///
+ ///
+ public string TimeSinceLastUpdate
+ {
+ get
+ {
+ if (_lastUpdate == DateTime.MinValue)
+ return "never";
+ if (_lastUpdate == DateTime.MaxValue)
+ return "updating";
+
+ var timeSpan = DateTime.Now - _lastUpdate;
+ if (timeSpan.Minutes > 0 )
+ return String.Format("{0}m {1}s", timeSpan.Minutes, timeSpan.Seconds);
+ return
+ timeSpan.Seconds + 1 + "s";
+ }
+ }
+
+ ///
+ /// Gets the name of the service.
+ ///
+ /// The name of the service.
+ public string ServiceName
+ {
+ get
+ {
+ return _endpoint.Name;
+ }
+ }
+
+ ///
+ /// Sets the last update time.
+ ///
+ /// The last update time.
+ private DateTime lastUpdate
+ {
+ set
+ {
+ _lastUpdate = value;
+ SignalPropertyChanged("TimeSinceLastUpdate");
+ }
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Callback for the threadpool
+ ///
+ /// The thread context.
+ /// The callback was triggered from a timeout
+ public void ThreadPoolCallback(object threadContext, bool isTimeOut)
+ {
+ lock(_callbackSyncObject)
+ {
+ if (_insideCallback)
+ return;
+ _insideCallback = true;
+ }
+ try
+ {
+ // turn off the timer while waiting for an update
+ _lastUpdateTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ updateStatus();
+ }
+ catch (Exception ex)
+ {
+ // log exception
+ _logger.LogError(_endpoint.Name + ": " + ex);
+ }
+ finally
+ {
+ _lastUpdateTimer.Change(_updatePeriod, _updatePeriod);
+ _insideCallback = false;
+ }
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Gets the current status result of the endpoint
+ ///
+ /// Status
+ private void updateStatus()
+ {
+ lastUpdate = DateTime.MaxValue;
+ var newStatus = _endpoint.GetStatus();
+ if (Status != newStatus)
+ {
+ Status = newStatus;
+ StatusDescription = _endpoint.StatusDescription;
+ StatusIcon = GetStatusIcon(Status);
+ // NOTE: wait to signal the property changes until all of them have been updated
+ SignalPropertyChanged("Status");
+ SignalPropertyChanged("StatusDescription");
+ SignalPropertyChanged("StatusIcon");
+ }
+ lastUpdate = DateTime.Now;
+ }
+
+ ///
+ /// Callback for the timer
+ ///
+ /// The obj.
+ private void timerCallback(object obj)
+ {
+ SignalPropertyChanged("TimeSinceLastUpdate");
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ ///
+ /// Gets the status icon.
+ ///
+ /// The status.
+ ///
+ public static Icon GetStatusIcon(Status status)
+ {
+ switch (status)
+ {
+ case Status.Unknown:
+ return Resources.question;
+ case Status.Up:
+ return Resources.up;
+ case Status.Error:
+ case Status.Unreachable:
+ return Resources.remove;
+ case Status.Timeout:
+ return Resources.warning;
+ default:
+ return Resources.up;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The endpoint.
+ /// The logger.
+ public EndpointStatus(IEndpoint endpoint, Logger logger)
+ {
+ _endpoint = endpoint;
+ lastUpdate = DateTime.MinValue;
+ _logger = logger;
+ _updatePeriod = new TimeSpan(0, 0, 0, 1);
+ _lastUpdateTimer = new Timer(timerCallback, 0, _updatePeriod, _updatePeriod);
+ StatusIcon = GetStatusIcon(Status);
+ Status = Status.Unknown;
+ StatusDescription = string.Empty;
+ }
+
+ #endregion
+
+ #region PropertyChanged event
+
+ ///
+ ///Occurs when a property value changes.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ #endregion
+
+ #region PropertyChanged methods
+
+ ///
+ /// Checks if the property () has been updated or changed.
+ ///
+ /// Name of the property.
+ /// The old value.
+ /// The new value.
+ /// True if the value was updated, false otherwise.
+ protected bool CheckPropertyChanged(string propertyName, ref T oldValue, ref T newValue) where T : class
+ {
+ if (oldValue == null && newValue == null)
+ {
+ return false;
+ }
+
+ if (oldValue == null || !oldValue.Equals(newValue))
+ {
+ oldValue = newValue;
+
+ SignalPropertyChanged(propertyName);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Checks if the property () has been updated or changed.
+ ///
+ /// Name of the property.
+ /// The old value.
+ /// The new value.
+ /// True if the value was updated, false otherwise.
+ protected bool CheckValuePropertyChanged(string propertyName, ref T oldValue, ref T newValue) where T : struct
+ {
+ if (!oldValue.Equals(newValue))
+ {
+ oldValue = newValue;
+
+ SignalPropertyChanged(propertyName);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Creates the event that a property has changed value
+ ///
+ ///
+ protected void SignalPropertyChanged(string propertyName)
+ {
+ if (PropertyChanged == null)
+ return;
+ try
+ {
+ lock (_propertyUpdateSyncObject) // send only one property changed event at once
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+ catch (InvalidOperationException) // HACK: Ignore the "BindingSource cannot be its own data source."
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning("SignalPropertyChanged: " + ex);
+ }
+ }
+
+ #endregion
+
+ #region IDisposable
+
+ ///
+ ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ ///2
+ public void Dispose()
+ {
+ _lastUpdateTimer.Dispose();
+ }
+
+ #endregion
+ }
+}
diff --git a/ServiceDashBored/Main.Designer.cs b/ServiceDashBored/Main.Designer.cs
new file mode 100644
index 0000000..3160e23
--- /dev/null
+++ b/ServiceDashBored/Main.Designer.cs
@@ -0,0 +1,256 @@
+namespace ServiceDashBored
+{
+ partial class Main
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (notifyIcon != null)
+ {
+ notifyIcon.Visible = false;
+ notifyIcon.Dispose();
+ notifyIcon = null;
+ }
+
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main));
+ this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
+ this.trayContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.dataGridView = new System.Windows.Forms.DataGridView();
+ this.statusIconDataGridViewImageColumn = new System.Windows.Forms.DataGridViewImageColumn();
+ this.ServiceName = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.TimeSinceLastUpdate = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.endpointBindingSource = new System.Windows.Forms.BindingSource(this.components);
+ this.cellTextBox = new System.Windows.Forms.TextBox();
+ this.statusTextBox = new System.Windows.Forms.RichTextBox();
+ this.splitContainer = new System.Windows.Forms.SplitContainer();
+ this.dataGridContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.updateNowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.trayContextMenuStrip.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.endpointBindingSource)).BeginInit();
+ this.splitContainer.Panel1.SuspendLayout();
+ this.splitContainer.Panel2.SuspendLayout();
+ this.splitContainer.SuspendLayout();
+ this.dataGridContextMenuStrip.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // notifyIcon
+ //
+ this.notifyIcon.ContextMenuStrip = this.trayContextMenuStrip;
+ this.notifyIcon.Text = "Service DashBored";
+ this.notifyIcon.Visible = true;
+ this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
+ //
+ // trayContextMenuStrip
+ //
+ this.trayContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.exitToolStripMenuItem});
+ this.trayContextMenuStrip.Name = "trayContextMenuStrip";
+ this.trayContextMenuStrip.Size = new System.Drawing.Size(104, 26);
+ //
+ // exitToolStripMenuItem
+ //
+ this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
+ this.exitToolStripMenuItem.Size = new System.Drawing.Size(103, 22);
+ this.exitToolStripMenuItem.Text = "Exit";
+ this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
+ //
+ // dataGridView
+ //
+ this.dataGridView.AllowUserToAddRows = false;
+ this.dataGridView.AllowUserToDeleteRows = false;
+ this.dataGridView.AllowUserToResizeColumns = false;
+ this.dataGridView.AllowUserToResizeRows = false;
+ this.dataGridView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.dataGridView.AutoGenerateColumns = false;
+ this.dataGridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
+ this.dataGridView.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.DisplayedCells;
+ this.dataGridView.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.dataGridView.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
+ this.dataGridView.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
+ this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
+ this.dataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+ this.statusIconDataGridViewImageColumn,
+ this.ServiceName,
+ this.TimeSinceLastUpdate});
+ this.dataGridView.DataSource = this.endpointBindingSource;
+ this.dataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
+ this.dataGridView.EnableHeadersVisualStyles = false;
+ this.dataGridView.Location = new System.Drawing.Point(12, 12);
+ this.dataGridView.MultiSelect = false;
+ this.dataGridView.Name = "dataGridView";
+ this.dataGridView.ReadOnly = true;
+ this.dataGridView.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
+ this.dataGridView.RowHeadersVisible = false;
+ this.dataGridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
+ this.dataGridView.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.dataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
+ this.dataGridView.Size = new System.Drawing.Size(368, 126);
+ this.dataGridView.TabIndex = 1;
+ this.dataGridView.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_RowEnter);
+ this.dataGridView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.dataGridView_MouseUp);
+ this.dataGridView.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.dataGridView_DataError);
+ //
+ // statusIconDataGridViewImageColumn
+ //
+ this.statusIconDataGridViewImageColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None;
+ this.statusIconDataGridViewImageColumn.DataPropertyName = "StatusIcon";
+ this.statusIconDataGridViewImageColumn.HeaderText = "";
+ this.statusIconDataGridViewImageColumn.Name = "statusIconDataGridViewImageColumn";
+ this.statusIconDataGridViewImageColumn.ReadOnly = true;
+ this.statusIconDataGridViewImageColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.statusIconDataGridViewImageColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
+ this.statusIconDataGridViewImageColumn.Width = 30;
+ //
+ // ServiceName
+ //
+ this.ServiceName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.ServiceName.DataPropertyName = "ServiceName";
+ this.ServiceName.HeaderText = "Service";
+ this.ServiceName.MinimumWidth = 100;
+ this.ServiceName.Name = "ServiceName";
+ this.ServiceName.ReadOnly = true;
+ //
+ // TimeSinceLastUpdate
+ //
+ this.TimeSinceLastUpdate.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None;
+ this.TimeSinceLastUpdate.DataPropertyName = "TimeSinceLastUpdate";
+ this.TimeSinceLastUpdate.HeaderText = "Last Update";
+ this.TimeSinceLastUpdate.Name = "TimeSinceLastUpdate";
+ this.TimeSinceLastUpdate.ReadOnly = true;
+ this.TimeSinceLastUpdate.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.TimeSinceLastUpdate.Width = 90;
+ //
+ // endpointBindingSource
+ //
+ this.endpointBindingSource.DataSource = typeof(ServiceDashBored.EndpointStatus);
+ //
+ // cellTextBox
+ //
+ this.cellTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.cellTextBox.Location = new System.Drawing.Point(12, 144);
+ this.cellTextBox.Name = "cellTextBox";
+ this.cellTextBox.ReadOnly = true;
+ this.cellTextBox.Size = new System.Drawing.Size(368, 20);
+ this.cellTextBox.TabIndex = 2;
+ //
+ // statusTextBox
+ //
+ this.statusTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.statusTextBox.BackColor = System.Drawing.SystemColors.Window;
+ this.statusTextBox.Location = new System.Drawing.Point(12, 3);
+ this.statusTextBox.Name = "statusTextBox";
+ this.statusTextBox.ReadOnly = true;
+ this.statusTextBox.Size = new System.Drawing.Size(368, 85);
+ this.statusTextBox.TabIndex = 3;
+ this.statusTextBox.Text = "";
+ //
+ // splitContainer
+ //
+ this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.splitContainer.Location = new System.Drawing.Point(0, 0);
+ this.splitContainer.Name = "splitContainer";
+ this.splitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal;
+ //
+ // splitContainer.Panel1
+ //
+ this.splitContainer.Panel1.Controls.Add(this.cellTextBox);
+ this.splitContainer.Panel1.Controls.Add(this.dataGridView);
+ this.splitContainer.Panel1MinSize = 135;
+ //
+ // splitContainer.Panel2
+ //
+ this.splitContainer.Panel2.Controls.Add(this.statusTextBox);
+ this.splitContainer.Panel2MinSize = 100;
+ this.splitContainer.Size = new System.Drawing.Size(392, 270);
+ this.splitContainer.SplitterDistance = 166;
+ this.splitContainer.SplitterWidth = 3;
+ this.splitContainer.TabIndex = 4;
+ //
+ // dataGridContextMenuStrip
+ //
+ this.dataGridContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.updateNowToolStripMenuItem});
+ this.dataGridContextMenuStrip.Name = "dataGridContextMenuStrip";
+ this.dataGridContextMenuStrip.Size = new System.Drawing.Size(145, 26);
+ //
+ // updateNowToolStripMenuItem
+ //
+ this.updateNowToolStripMenuItem.Name = "updateNowToolStripMenuItem";
+ this.updateNowToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
+ this.updateNowToolStripMenuItem.Text = "Update Now";
+ this.updateNowToolStripMenuItem.Click += new System.EventHandler(this.updateNowToolStripMenuItem_Click);
+ //
+ // Main
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(392, 270);
+ this.Controls.Add(this.splitContainer);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(400, 300);
+ this.Name = "Main";
+ this.Text = "Service DashBored";
+ this.Load += new System.EventHandler(this.main_Load);
+ this.Resize += new System.EventHandler(this.main_Resize);
+ this.trayContextMenuStrip.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.endpointBindingSource)).EndInit();
+ this.splitContainer.Panel1.ResumeLayout(false);
+ this.splitContainer.Panel1.PerformLayout();
+ this.splitContainer.Panel2.ResumeLayout(false);
+ this.splitContainer.ResumeLayout(false);
+ this.dataGridContextMenuStrip.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.NotifyIcon notifyIcon;
+ private System.Windows.Forms.ContextMenuStrip trayContextMenuStrip;
+ private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
+ private System.Windows.Forms.DataGridView dataGridView;
+ private System.Windows.Forms.BindingSource endpointBindingSource;
+ private System.Windows.Forms.TextBox cellTextBox;
+ private System.Windows.Forms.DataGridViewImageColumn statusIconDataGridViewImageColumn;
+ private System.Windows.Forms.DataGridViewTextBoxColumn TimeSinceLastUpdate;
+ private System.Windows.Forms.RichTextBox statusTextBox;
+ private System.Windows.Forms.SplitContainer splitContainer;
+ private System.Windows.Forms.DataGridViewTextBoxColumn ServiceName;
+ private System.Windows.Forms.ContextMenuStrip dataGridContextMenuStrip;
+ private System.Windows.Forms.ToolStripMenuItem updateNowToolStripMenuItem;
+ }
+}
+
diff --git a/ServiceDashBored/Main.cs b/ServiceDashBored/Main.cs
new file mode 100644
index 0000000..eab70b6
--- /dev/null
+++ b/ServiceDashBored/Main.cs
@@ -0,0 +1,428 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Threading;
+using System.Windows.Forms;
+using BitFactory.Logging;
+using Endpoint;
+
+namespace ServiceDashBored
+{
+ ///
+ /// DashBored's UI.
+ ///
+ public partial class Main : Form
+ {
+ ///
+ /// Number of seconds between trying to poll an endpoint for its status
+ ///
+ private const int ENDPOINT_POLL_TIME_INTERVAL = 30;
+
+ ///
+ /// Number of milliseconds to display status updates on the system tray notify balloon
+ ///
+ private const int NOTIFY_BALLOON_UPDATE_DELAY = 300;
+
+ ///
+ /// Win32 message for when the user ends their session.
+ ///
+ /// http://msdn.microsoft.com/en-us/library/aa376890(VS.85).aspx
+ private const int WM_QUERYENDSESSION = 0x11;
+
+ ///
+ /// The status to display in the system tray
+ ///
+ private Status _systemTrayStatusIcon = Status.Timeout;
+ private readonly BindingList _endpoints;
+ private readonly Dictionary _endpointStatuses;
+ private readonly Dictionary _endpointEventWaitHandle;
+
+ ///
+ /// Default font for the Status Description text box
+ ///
+ private readonly Font _defaultFont = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Regular);
+ ///
+ /// Bold font for the Status Description text box
+ ///
+ private readonly Font _boldFont = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Bold);
+ ///
+ /// Different colors to use for each Status
+ ///
+ private readonly Dictionary _statusColor
+ = new Dictionary
+ {
+ {Status.Error, Color.DarkRed},
+ {Status.Timeout, Color.DarkOrange},
+ {Status.Unknown, Color.DarkOrange},
+ {Status.Unreachable, Color.DarkRed},
+ {Status.Up, Color.DarkGreen},
+ };
+
+ ///
+ /// Set to true when windows is closing the current session.
+ ///
+ private bool _endSessionPending;
+
+ ///
+ /// Logger instance.
+ ///
+ private readonly Logger _logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Main(IEnumerable endpoints, Logger logger)
+ {
+ InitializeComponent();
+
+ _logger = logger;
+
+ _logger.LogInfo("Starting.");
+
+ loadMainIcon(Status.Up);
+
+ _endpoints = new BindingList();
+ endpointBindingSource.DataSource = _endpoints;
+ _endpointStatuses = new Dictionary();
+ _endpointEventWaitHandle = new Dictionary();
+
+ foreach (var serviceEndpoint in endpoints)
+ {
+ registerServiceEndpoint(serviceEndpoint);
+ }
+ }
+
+ ///
+ /// Override to intercept WM_QUERYENDSESSION - so we know when the current OS session is ending.
+ ///
+ ///
+ /// http://www.pixvillage.com/blogs/devblog/archive/2005/03/26/174.aspx
+ protected override void WndProc(ref Message m)
+ {
+ if (m.Msg == WM_QUERYENDSESSION)
+ _endSessionPending = true;
+ base.WndProc(ref m);
+ }
+
+ ///
+ /// Minimize when the close button is clicked
+ ///
+ ///
+ protected override void OnClosing(CancelEventArgs e)
+ {
+ if (!_endSessionPending)
+ {
+ e.Cancel = true;
+ WindowState = FormWindowState.Minimized; // minimize instead of close
+ }
+ base.OnClosing(e);
+ }
+
+ ///
+ /// Handles the Resize event of the Main control.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ void main_Resize(object sender, EventArgs e)
+ {
+ ShowInTaskbar = WindowState != FormWindowState.Minimized;
+ }
+
+ ///
+ /// Handles the Load event of the Main control.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ private void main_Load(object sender, EventArgs e)
+ {
+ notifyIcon.BalloonTipTitle = "Service DashBored";
+ notifyIcon.BalloonTipClicked += notifyIcon_BalloonTipClicked;
+ }
+
+ ///
+ /// Handles the PropertyChanged event of an Endpoint.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ void endpoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName != "Status") return;
+
+ var senderEndpointStatus = sender as EndpointStatus;
+ if (senderEndpointStatus == null)
+ throw new ArgumentException("sender is not EndpointStatus - it is: " + sender.GetType());
+
+ Invoke((MethodInvoker)(()=>updateStatus(senderEndpointStatus)));
+ }
+
+ ///
+ /// Handles the BalloonTipClicked event of the notifyIcon control.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
+ {
+ TopMost = true;
+ WindowState = FormWindowState.Normal;
+ Focus();
+ TopMost = false;
+ }
+
+ ///
+ /// Handles the Click event of the exitToolStripMenuItem control.
+ ///
+ /// The source of the event.
+ /// The instance containing the event data.
+ private void exitToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ _logger.LogInfo("User Exiting.");
+ Application.Exit();
+ }
+
+ ///
+ /// When notify is double clicked, show the main window
+ ///
+ ///
+ ///
+ private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
+ {
+ if (WindowState == FormWindowState.Normal)
+ {
+ WindowState = FormWindowState.Minimized;
+ }
+ else
+ {
+ TopMost = true;
+ WindowState = FormWindowState.Normal;
+ Focus();
+ TopMost = false;
+ }
+ }
+
+ private void dataGridView_RowEnter(object sender, DataGridViewCellEventArgs e)
+ {
+ var endpointStatus = (EndpointStatus)dataGridView.Rows[e.RowIndex].DataBoundItem;
+ cellTextBox.Text = string.Format("{0}. Status Description: {1}",
+ endpointStatus.ServiceName, endpointStatus.StatusDescription);
+ }
+
+ private void dataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
+ {
+ _logger.LogError(e.Exception);
+ }
+
+ ///
+ /// Registers the service endpoint.
+ ///
+ /// The service endpoint.
+ private void registerServiceEndpoint(IEndpoint endpoint)
+ {
+ var endpointStatus = new EndpointStatus(endpoint, _logger);
+
+ // Time Interval MasterThread will be executed
+ var timeOut = TimeSpan.FromSeconds(ENDPOINT_POLL_TIME_INTERVAL);
+
+ // Register a timed callback method in the threadpool.
+ var waitObject = new AutoResetEvent(false);
+ ThreadPool.RegisterWaitForSingleObject(
+ waitObject,
+ endpointStatus.ThreadPoolCallback,
+ null,
+ timeOut,
+ false
+ );
+
+ _endpoints.Add(endpointStatus);
+ _endpointStatuses.Add(endpointStatus, endpointStatus.Status);
+ _endpointEventWaitHandle.Add(endpointStatus, waitObject);
+ endpointStatus.PropertyChanged += endpoint_PropertyChanged;
+
+ waitObject.Set(); // signal an initial callback when done registying
+ }
+
+ ///
+ /// Loads the icon based on the status.
+ ///
+ /// The status.
+ private void loadMainIcon(Status status)
+ {
+ if (_systemTrayStatusIcon == status)
+ return;
+
+ notifyIcon.Icon = EndpointStatus.GetStatusIcon(status);
+
+ notifyIcon.BalloonTipIcon = (status == Status.Up) ? ToolTipIcon.Info : ToolTipIcon.Error;
+
+ _systemTrayStatusIcon = status;
+ }
+
+ ///
+ /// Updates the status for the given endpoint.
+ ///
+ /// Execute on UI thread
+ /// The endpoint status.
+ private void updateStatus(EndpointStatus endpointStatus)
+ {
+ if (endpointStatus == null)
+ throw new ArgumentNullException("endpointStatus");
+
+ lock (_endpoints)
+ {
+ // if the status hasn't changed, don't do anything...
+ if (_endpointStatuses[endpointStatus] == endpointStatus.Status) return;
+
+ // if the status has changed...
+ var oldStatus = _endpointStatuses[endpointStatus];
+ _endpointStatuses[endpointStatus] = endpointStatus.Status;
+
+ // find the worst status of all
+ var statuses = new List(_endpointStatuses.Values);
+ statuses.Sort(new StatusComparer());
+ loadMainIcon(statuses[0]);
+
+ // update the system tray notify ballon info
+ notifyIcon.BalloonTipText = getShortServiceStatusMessage(endpointStatus);
+ notifyIcon.Text = endpointStatus.Status == Status.Up ? "Service Running" : "Service Problem";
+
+ // update the info in the status text box
+ updateStatusTextBox();
+
+ if (oldStatus != Status.Unknown || endpointStatus.Status != Status.Up)
+ {
+ notifyIcon.ShowBalloonTip(NOTIFY_BALLOON_UPDATE_DELAY);
+ _logger.LogInfo(string.Format("{0}. {1} : {2}", endpointStatus.ServiceName, endpointStatus.Status,
+ endpointStatus.StatusDescription));
+ }
+ }
+ }
+
+ ///
+ /// Updates the status text box - call this from the UI thread.
+ ///
+ private void updateStatusTextBox()
+ {
+ statusTextBox.Text = String.Empty;
+ var first = true;
+ foreach (var endpointStatus in _endpoints)
+ {
+ if (endpointStatus.Status == Status.Up || endpointStatus.Status == Status.Unknown)
+ continue;
+
+ if (!first)
+ {
+ statusTextBox.SelectedText = Environment.NewLine + Environment.NewLine;
+ }
+ else
+ {
+ first = false;
+ }
+
+ // Make the service description all pretty in the rich text box
+ statusTextBox.SelectionColor = _statusColor[endpointStatus.Status];
+ statusTextBox.SelectionFont = _defaultFont;
+ statusTextBox.SelectedText = endpointStatus.ServiceName;
+
+ statusTextBox.SelectionColor = Color.Black;
+ statusTextBox.SelectionFont = _defaultFont;
+ statusTextBox.SelectedText = ". ";
+
+ statusTextBox.SelectionColor = _statusColor[endpointStatus.Status];
+ statusTextBox.SelectionFont = _boldFont;
+ statusTextBox.SelectedText = endpointStatus.Status.ToString();
+
+ statusTextBox.SelectionColor = Color.Black;
+ statusTextBox.SelectionFont = _defaultFont;
+ statusTextBox.SelectedText = " : " + endpointStatus.StatusDescription;
+ }
+ }
+
+ ///
+ /// Gets the service status message.
+ ///
+ /// The sender endpoint status.
+ ///
+ private static string getShortServiceStatusMessage(EndpointStatus senderEndpointStatus)
+ {
+ var msg = string.Empty;
+ switch (senderEndpointStatus.Status)
+ {
+ case Status.Error:
+ msg = "Service Error: " + senderEndpointStatus.ServiceName;
+ break;
+ case Status.Timeout:
+ msg = "Service Timeout: " + senderEndpointStatus.ServiceName;
+ break;
+ case Status.Unknown:
+ msg = "Status Unknown: " + senderEndpointStatus.ServiceName;
+ break;
+ case Status.Unreachable:
+ msg = "Service Unreachable: " + senderEndpointStatus.ServiceName;
+ break;
+ case Status.Up:
+ msg = "Service Running: " + senderEndpointStatus.ServiceName;
+ break;
+ }
+ return msg;
+ }
+
+ private void dataGridView_MouseUp(object sender, MouseEventArgs e)
+ {
+ var hitTestInfo = dataGridView.HitTest(e.X, e.Y);
+ if (hitTestInfo.Type != DataGridViewHitTestType.Cell)
+ {
+ // deselect everything
+ var selectedEndpointStatus = getSelectedDataGridViewRow();
+ if (selectedEndpointStatus != null)
+ selectedEndpointStatus.Selected = false;
+ return;
+ }
+
+ if (e.Button == MouseButtons.Right && hitTestInfo.RowIndex >= 0)
+ {
+ // select row on right click as well
+ if (hitTestInfo.RowIndex >= 0)
+ {
+ var selectedEndpointStatus = getSelectedDataGridViewRow();
+ if (selectedEndpointStatus != null)
+ selectedEndpointStatus.Selected = false;
+
+ var clickedRow = dataGridView.Rows[hitTestInfo.RowIndex];
+ clickedRow.Selected = true;
+ }
+
+ // show the context menu
+ dataGridContextMenuStrip.Show(dataGridView, e.Location);
+ }
+ }
+
+ private DataGridViewRow getSelectedDataGridViewRow()
+ {
+ return dataGridView.SelectedRows.Count > 0
+ ? dataGridView.Rows[dataGridView.SelectedRows[0].Index]
+ : null;
+ }
+
+ private EndpointStatus getSelectedEndpointStatus()
+ {
+ var dataGridViewRow = getSelectedDataGridViewRow();
+ return dataGridViewRow != null
+ ? dataGridViewRow.DataBoundItem as EndpointStatus
+ : null;
+ }
+
+ private void updateNowToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ var endpointStatus = getSelectedEndpointStatus();
+ if (endpointStatus != null)
+ _endpointEventWaitHandle[endpointStatus].Set();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex);
+ }
+ }
+ }
+}
diff --git a/ServiceDashBored/Main.resx b/ServiceDashBored/Main.resx
new file mode 100644
index 0000000..e54c8b6
--- /dev/null
+++ b/ServiceDashBored/Main.resx
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 160, 17
+
+
+ 17, 17
+
+
+ True
+
+
+ 245, 17
+
+
+ 395, 17
+
+
+ True
+
+
+
+
+ AAABAAEAMDAAAAEAIACoJQAAFgAAACgAAAAwAAAAYAAAAAEAIAAAAAAAAAAAABMLAAATCwAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAADAAAABQAA
+ AAUAAAAFAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABQAAAAUAAAADAAAAAgAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
+ AAMAAAACAAAACQAAAA0AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADQAAAAkAAAACAAAAAgAA
+ AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAABAAAAABAPDjQ4NzSmPTw5qURDQKtMSkesU1FNq1hWUqtbWlarV1ZSq1FPTKtKSEWrQkA+qzo5
+ Nqk0MzGnEhIRPQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8uLGWLiIH/hoN9/4iFf/+Kh4H/jImC/42Kg/+NioP/i4iC/4iF
+ f/+EgXz/gH14/3x5df+AfXj/ODc1ggAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PDiRcWVXsYl9a/15cV/9eW1b/XFpV/1tY
+ VP9aV1P/WVZS/1hWUf9XVVH/V1VQ/1dVUf9UUk70EBAPLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAABGRkdZcHFxj3R1doh3d3iIfH19iISEhIhcXFyITk5Pik5OT4hqaWnZenp4/3t6
+ eP99fHr/fn58/39/ff9/f37/f359/319fP98fHr/enp5/3h4d/9ub23oU1RUjFNTVIpeXl+Jg4SFiIKC
+ goh7fHyId3h4iHV2d45MTExcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMTU67SktM/0tMTv9MTU7/TU5P/09QUf9XWFn/W1xd/15f
+ YP9dX2D/X2Fh/2JjZP9kZWf/Zmdp/2hpav9pamv/aWpr/2hqa/9oaWr/Z2hq/2VmaP9lZmf/Z2hp/2Nk
+ Zv9tbWr/iYh5/1hZWf9SU1T/UFFS/01OT/9DQ0TOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFiYgNJSku/Pj8//zk6Ov84OTn/Nzc4/zU1
+ Nv80NTX/NDU1/zQ1Nf80NTb/NTY2/zY3N/82Nzj/Nzg4/zc4Of84ODn/ODg5/zg5Of84OTn/ODk6/zg5
+ Of84OTr/ODk5/zY3OP9HR0L/c3Jg/zw9O/83ODn/Nzc4/z4/P/82NzjSAAAABwAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaAJPUVK/LS0s/yUk
+ If8nJiP/JiUi/yUkIf8kIyD/IiIf/yEhHv8gIB3/Hx8c/x4eG/8dHRr/HRwa/xwcGv8cHBr/HBsZ/xwb
+ Gf8bGxn/GxoZ/xoaGf8aGhj/GhoY/xoaGP8ZGBf/FRQU/xkZF/8YGBb/FRUT/yYnJ/9FQj73JxwNogIC
+ AGEAAAA6AAAAIAAAAAsAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJz
+ dAJYWVq/Li4t/ykoJP8rKib/Kikl/ykoJf8nJiP/JiUi/yUkIf8kIyD/IiIf/yEhHv8hIR7/ICAd/yAg
+ Hf8gHxz/Hx8c/x8fHP8fHhv/Hh4b/x4eG/8dHRv/HRwa/xwcGv8cGxr/GxsZ/xsbGf8bGxn/GBgW/yMl
+ Jv9PSUH/e1kt/2VII/QsIA+7AgEBfgAAAFoAAAA5AAAAGwAAAAkAAAACAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAHd3dwJeX2C/MjIw/ywrJ/8uLSn/LSwo/ywrJ/8rKib/KSgl/ycmJP8nJSL/JSQh/yQj
+ IP8kIyD/IyMg/yMiH/8jIh//IiIf/yEhHv8hIR7/ISEe/yAgHf8fHxz/Hx8c/x4eG/8eHhv/HR0b/x0d
+ G/8dHRv/GhoY/yQlJ/9NRz//fFkt/39cLv9/XC7/WEAg5RMOB6AAAAB5AAAAXwAAADwAAAAeAAAACwAA
+ AAMAAAABAAAAAAAAAAAAAAAAAAAAAHh4eAJkZWa/NTUz/zAvKv8yMCz/MS8r/zAuKv8uLSn/LCso/ysq
+ Jv8qKSX/KCck/ygnJP8nJiP/JyYj/yYlIv8mJSL/JSQh/yUkIf8lJCH/JCMg/yMiH/8iIh//ISEe/yEg
+ Hf8gIB3/Hx8d/x8fHf8eHhz/HBwa/yQmJ/9MRj7/gFor/35aLP99Wi3/gV0v/3NUKvgmHA6xAAAAfQAA
+ AG4AAABPAAAALgAAABYAAAAJAAAAAwAAAAEAAAAAAAAAAH6AgwJra22/ODg2/zUyLv82NDD/NTMv/zQy
+ Lv8yMCz/MC8r/y8uKv8uLSn/LCsn/ysqJ/8rKib/Kikm/yopJv8qKCX/KSgl/ykoJf8oJyT/JyYj/yYl
+ Iv8mJSL/JCQh/yQjIP8jIyD/IiIf/yIiH/8hIR7/Hh4b/yQmJ/9MRj3/hl8u/4ReLv+BXC7/flsu/31b
+ Lv94WC39MCMStQAAAHkAAABtAAAAUgAAADQAAAAcAAAADQAAAAUAAAAAAAAAAIqKigJxcnS/PDs5/zk3
+ Mv87OTX/OTcz/zg2Mv83NTD/NTMv/zMxLf8yMCz/MS8r/zAuKv8vLir/Ly4q/y8tKf8uLSn/LSwp/y0s
+ KP8sKyf/Kyon/yopJf8oJyT/KCck/ycmI/8mJSL/JSUi/yUkIf8kJCH/ISEe/yUmJ/9MRj3/jGUy/4lj
+ Mf+GYTH/g2Aw/35cL/9lSif/blEq/ygdD7YAAABwAAAAZAAAAEsAAAAyAAAAHQAAAA0AAAAAAAAAAIuL
+ iwN2eHnAPz88/z48N/8/PTj/Pjw3/z07Nv87OTX/Ojgz/zg2Mv83NTH/NjQw/zY0MP81My//NDIv/zQy
+ Lv80Mi7/MzEt/zIwLP8xLyv/Ly4q/y4tKf8tLCj/LCsn/yopJv8qKSb/KSgl/ygnJP8nJiP/JSQh/yYn
+ KP9MRj3/k2s4/49pNv+LZjX/iGQ0/4djM/9kSij/Uj0h/1hBIv8fFgyhAAAAYQAAAFUAAAA/AAAAKgAA
+ ABcAAAAAAAAAAIuLiwN6e3zARENA/0NBPP9FQj3/Q0E8/0I/Ov9APjn/Pz04/z48N/89Ozb/PDo1/zs5
+ NP86ODT/Ojg0/zo4M/85NzP/ODYy/zc1Mf82NDD/NDIu/zMxLf8xMCz/MC8r/y8uKv8uLSn/LSwo/ywr
+ KP8rKif/KCck/ycoKP9NRz7/mHNA/5ZwPf+RbTz/jmo5/4toN/9/XjL/XUYm/1dBJP9RPCHyDQkFdgAA
+ AFEAAABDAAAAMAAAAB0AAAAAAAAAAJGRkgN+f4DASUhG/0pHQv9LSUT/SkdC/0hGQf9HRD//RUM+/0RC
+ PP9DQTz/QkA7/0E/Ov9BPzr/QD45/z89OP8/PTj/Pjw3/zw6Nf86ODX/OTcz/zg2Mv82NDD/NTMv/zMy
+ Lv8yMS3/MTAs/zAvK/8vLir/LCsn/ygpKv9MRz7/nXxJ/5t4Rv+YdUT/k3FA/49tPf+Nazv/gmE1/2BI
+ Kf9hSSn/RzUdwwAAAEsAAABBAAAAMQAAAB8AAAAAAAAAAJubmwODg4XAUE5M/1NQSv9SUEn/UU5I/09N
+ R/9OTEb/TUpE/0xJQ/9LSEP/SkdC/0lGQf9IRkD/R0U//0ZEP/9FQz7/Q0E8/0E/Ov9APTn/Pjw3/zw7
+ Nv87OTT/OTcz/zg2Mv83NTH/NjQw/zUzL/8zMi7/MC8r/ykqK/9MSED/oIVU/5+BUP+dfU3/mXlK/5V1
+ Rv+Pb0H/jGs9/4JjOP96XTT/f181/yEZDnEAAAAyAAAALQAAAB0AAAAAAAAAAJubmwOFh4jAVFNQ/15c
+ Vf9dW1T/WlhR/1hWT/9XVU7/VlNM/1RSS/9TUUr/U1BJ/1FPSP9QTkf/T01G/01LRf9MSUP/SkdC/0dF
+ QP9FQz7/Q0E8/0E/Ov9APjj/Pjw4/z07N/88OjX/Ojg0/zk3M/83NjL/NDMv/yssLP9MSUL/pY5f/6OK
+ XP+hhlj/noFU/5l8T/+Kb0b/h2tB/4ZpP/+FaD3/clg0/1xHKccAAAAqAAAAJQAAABkAAAAAAAAAAJub
+ mwOIiYrAWVhU/2ZkXP9pZl//aGVe/2ZjW/9kYFn/Yl9X/19cVf9eW1T/XFpS/1pYUP9ZVk//VlRN/1RS
+ S/9SUEn/UE1H/05LRf9LSEP/SUZB/0ZEP/9EQj7/Q0E8/0JAO/9BPzr/Pz04/z07N/87OTX/ODYy/ywt
+ Lf9MSkP/qpZp/6iTZ/+ljmP/pIpf/5h/V/+OdU7/gmpG/4VrRf+Ha0P/f2U+/4NnPvsdFw5JAAAAFgAA
+ ABMAAAAAAAAAAJycnAOLi43AXl1a/3FuZv9zcGj/c3Bo/3NvZ/9zb2f/cW5l/29sY/9taWH/a2df/2hl
+ Xf9mY1v/ZGBZ/2FeVv9eW1T/W1hR/1hWT/9VU03/U1BL/1BNSP9OS0b/SkdC/0dFQP9FQj3/Q0E8/0E/
+ Ov8/PTn/PDk1/y4tLf9NTEf/rqB5/6yacv+qlW3/p5Fp/6CJYv+dhV3/moBY/5N6Uf+PdU3/i3BI/45y
+ SP9PQCmTAAAABwAAAA4AAAAAAAAAAJydnQONj5DAZGNf/3x4cP9+enL/f3tz/397c/9/e3L/f3ty/316
+ cP98eG//eXVs/3Zyaf9zb2f/b2xk/2toYP9nZFz/ZGFa/2BeV/9dW1T/WlhR/1dVT/9VU03/U1BL/1FO
+ Sf9MSUT/R0VA/0RCPf9CQDv/Pz04/y8vLv9OTkr/tKuR/7GliP+unnr/qJVw/6OPbP+ciGT/m4Vg/5iA
+ Wv+Te1T/jnVP/450Tf9vWzzGAQEBBwAAAAcAAAAAAAAAAJ2dnQOPkJHAamhl/4iEev+Lh37/jIl//42J
+ f/+Nin//jIl+/4uHfP+IhXr/hoJ4/4J+dP99enD/eXVt/3Vxaf9wbWX/bGlg/2hlXf9jYVr/YF5X/11b
+ VP9bWFL/WFZQ/1ZTTv9TUEv/UE1I/0tIQ/9FQz7/QT86/zEwL/9QT0z/uK+W/6yiif+zqZD/rqCB/6WT
+ c/+mknD/nYpn/5qFYf+XgVz/kXtW/411Uf+Lc0/4HRgQKgAAAAAAAAAAAAAAAJ2dnQKPkJG/b25q/5OP
+ hf+Wk4n/mJSK/5qWi/+blov/mZWK/5iUif+VkYb/ko6D/42Kf/+IhXv/g4B2/356cf95dG3/dHBp/29s
+ ZP9raGD/Z2Rd/2NhWv9fXVb/XFtU/1lXUf9XVE//U1BL/1BNSP9LSUT/REI9/zExMP9SUk//ubCX/6qd
+ hP+6sZv/r6SN/5iJcP+olnb/oY9v/5+Laf+ahWP/lH9c/5B6V/+Se1b/MioeUgAAAAAAAAAAAAAAAJyc
+ nAOPkJHAdXRv/56bj/+inpP/paGW/6eil/+no5f/pqGW/6WglP+hnZH/nZmO/5iUif+Tj4T/jYl//4aD
+ ef+BfXT/e3hw/3Zza/9ybmf/bWpj/2lnX/9lY1z/YV9Y/15bVf9aV1L/V1RP/1NQS/9PTEf/SkhD/zMz
+ Mv9UVFH/vrWc/6qbgf+4rZf/p5uD/5+Sev+tnoP/ppZ3/6ORcf+di2n/l4Ri/5J+XP+VgFz/QjgoaQAA
+ AAAAAAAAAAAAAJ2dnQKPkJG/enhz/6ikmf+tqZ7/r6ug/7Gtof+yraH/sayg/6+qnv+rppr/p6KW/6Gd
+ kv+cmI3/lZGG/46Lgf+IhXv/gn52/315cf94dW3/c3Bo/25rZP9qZ2D/ZWNc/2FfWP9dW1T/WVZR/1VS
+ Tf9QTkn/TEpE/zY2Nf9TUk//uq2T/7Gjiv+toIj/p5uD/6KVfv+fk3z/p5h+/6aWeP+gjm//moho/5SC
+ Yf+YhGL/ST8uegAAAAAAAAAAAAAAAJ2dnAONjo+/fnx3/7Gtov+1saX/ubSo/7u2qv+7tqr/urWp/7ez
+ p/+0r6P/r6qe/6mkmf+jnpP/nJiN/5WSh/+Oi4H/iIR7/4J+dv98eXH/eHVt/3NwaP9ua2T/aWdg/2Ri
+ W/9fXlf/W1lT/1dUT/9SUEv/TktG/zc3Nv9SUEz/vrCX/7mtk/+ypo7/raGK/6echP+flH3/ppmD/6qb
+ f/+jk3X/nItt/5aFZv+UgmL/gXFVggAAAAAAAAAAAAAAAJ2dnQKMjY6/gH96/7q1qf++uKz/wLuv/8K9
+ sf/CvbH/wbyv/765rf+6tan/tbCk/6+qnv+opJj/op2S/5qXjP+TkIb/jYmA/4eDev+Bfnb/fHlx/3d0
+ bP9yb2j/bGpj/2dlXv9iYFr/XltW/1pXUv9VUk3/UE5I/zg4N/9VU0//x7uh/8G0nP+5rpb/s6eQ/6yg
+ iv+lmYP/q6CM/6ibhP+gkXX/n49x/5mIav+TgmT/k4JkggAAAAAAAAAAAAAAAJydnQKKjI2/gH54/7y3
+ qv/Auq7/wr2x/8S/sv/Ev7L/w72x/8C7rv+8t6r/t7Gl/7Crn/+ppZn/op6T/5uXjP+UkIb/jYmA/4eD
+ ev+Bfnb/fHlx/3d0bP9yb2j/bWtj/2dmXv9jYVr/X1xX/1pXUv9VUk3/UE1I/zk4N/9WVVH/0MOq/8i8
+ pP/AtJ3/ua2W/7Glj/+qnoj/rKGM/6qfif+jlXr/oJB0/5qLbv+UhWn/kYFlegAAAAAAAAAAAAAAAKGh
+ oQOJiovAYmFf/2tpZP9vbWj/cG5p/3JxbP9ycWz/cG9r/29uaf9ta2f/amhk/2ZlYP9jYV3/Xl1Z/1pZ
+ Vf9WVVH/UlFN/01MSf9KSUb/R0ZD/0NCQP9APz3/PT06/zs6OP83Nzb/NDQz/zIxMP8vLi3/Kioo/yYn
+ Kf9TUk//2Mux/9DDqv/GuqL/vLGa/7Spk/+soYv/pJmC/6aahP+mmYD/oZJ2/5yNcf+Wh2z/koRpagAA
+ AAAAAAAAAAAAAAAAAACVlpeQh4iJ1oeIic2HiInNh4eJzn98ePh/e3T/gHx2/398dv99enb/fHp3/3x6
+ d/95eHX/eHd0/3h3dP92dXL/dXRy/3h3c/93d3P/d3Zz/3Z2cv92dnL/c3Ju/3Fvav9wbmr/b21o/2tq
+ Zf9oZ2L/ZGNe/1taV/+GgHb/4dS6/9THsP/Kvqb/wLSe/7arlf+uoo3/pZmD/56Tff+lmID/o5V5/52P
+ c/+XiW//k4VsUQAAAAAAAAAAAAAAAAAAAAClpqYBm5ubApmZmQKZmpsBAAAAAIVxUrqQd1H/l4Bb/5WB
+ Yf+PgGf/lodv/52Qef+bkHv/o5iC/66jjv+qoI3/uK6Z/8vCrf/UzLb/3tW//+nhyv/17dX/9evS//Pk
+ yP/77M////PV///22f//9dj//fDU//Xozf/w4sj/4tW8/9fKs//MwKn/wrag/7itlv+vo43/p5uF/6CU
+ fv+lmIH/oZN6/5uOdP+YinH3lIdvJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH5n
+ Q4KLc0//kXpX/4p4XP+NfmT/lIVt/5uOd/+dkXz/qp6H/7GlkP+too//v7Sg/8vBrP/VzLX/39W//+ri
+ y//069P/+fHZ///64v//+eL///zh///84f//+97///bZ//zt0v/w4sj/49a9/9jLs//Nwan/wraf/7is
+ lv+vo43/ppqE/6ichv+sn4j/m493/5qNdf+Yi3PDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAIFrSz6IclD/kHpY/4d3XP+OfmT/lIVt/5uNd/+ekn3/pJiD/7Clj/+zqJT/wLWg/8rA
+ q//Rx7L/3dO9/+nfyP/069P/+vPb////6f///e3////x////6f///+f///vh//3y2f/z5s7/5trD/9rO
+ uP/Pw63/xLii/7qvmf+xppD/qZ6I/6aahv+mmoT/npJ7/5qNd/+ZjHSIAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFcVC7kXtY/4l4Xf+NfWT/k4Rs/5uNdv+iloD/n5SA/6me
+ iv+yp5P/uK2a/8a8p//Euqf/2s+6/+fdx//z6NH//fXc//303P/+9uD///7t///95v///eX///jg//zw
+ 2f/y5s//59vF/9vQu//RxrH/xrun/72ynf+0qZT/rKGN/6Wahv+elID/mo97/5aLdveZjHQqAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEcFBej3lX/5J+Xv+VhGb/mYpv/56S
+ eP+kmYH/pp2G/6ich/+vpJD/tauX/8K4o/+/taP/0siz/97Tvv/q38n/+e3W//3z2//68Nn///jg///3
+ 3///9t//+/DY//To0v/r38j/4dW//9bLtv/Mwaz/w7ei/7qumf+xppH/qp+L/6SYhf+dkn//mI56/5mN
+ drQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHclIEinVUzJaA
+ Xf+ah2b/nY9w/56Qdf+hk3z/qZ+I/6echv+nnYn/t6yY/8C1oP+9s6D/x7yp/9jNuP/k2cP/8OXN//ru
+ 1v/269T/9OnS//ft1f/88dn/9OjQ/+vfyP/l2cL/28+5/9DFr//HvKb/v7Od/7aqlf+uo47/p5yI/6OY
+ g/+iln7/nZF5/5uNdTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAiHNTSpF8Wv+ZhGL/nIxs/5+SdP+jl3z/qJ+F/6qhif+rn4j/t6uU/7yxm/+6r5z/v7Wi/87D
+ rv/f07z/5tvE/+7jy//z58//7OHK//Llzv/569L/9OfO/+vfxv/d0br/0saw/8m+p//Btp//ua2Y/7So
+ kv+ypo//qp+J/6mchP+jln3/nZB3nQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIt3VpuWgV7/m4hn/56PcP+ilXj/ppyA/6yiif+pnof/sKOL/7er
+ lP+zqpb/urCc/8O5pP/UybL/3dG6/+PXv//o3MT/697G/+3gx//s38b/5dm//+PWvP/bzrX/z8Kq/8C2
+ n/+7sJn/u66W/7eqkv+ypo7/rKCI/6aZgP+gk3rfnZB3GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIt3VQ+QfFrMmYVj/52MbP+gk3P/pJl7/6mf
+ g/+qn4f/qJuF/66ii/+to47/s6iV/7yynf/MwKn/08av/9jLs//cz7b/3tG4/9/SuP/f0bf/2syz/9XH
+ rv/Uxaz/zL6l/7+zm/+4rJX/uayT/7Snjv+toYn/qJuC/6OVfPueknlHAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACNeVgklH9d4JuI
+ Zv+ejm7/opV2/6ebff+roYT/qp6G/6WXgv+onIf/rKGM/7arlP/Et57/yLyj/83Ap//NwKj/0cOq/9LE
+ q//SxKr/0MKn/8y+pP/Ju6H/xLac/7+xl/+5rJL/tKaN/6+hiP+pm4P/pJd+/qCTemAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAj3taKZeCYdudimj/oJBw/6SWd/+onX7/rKKG/6yhh/+qnIP/p5uE/7GkjP+7rpP/v7GX/8K1
+ mv/As5r/w7Wb/8e5nv/HuZ3/xbec/8O1mv+/spf/u66T/7epj/+zpYv/rqGH/6qcg/+kl377oZR7XgAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJJ9XRyYhGO+notr/6GRcf+klnf/qJx+/62jhf+vpYb/q52B/66e
+ g/+zpIj/tqeL/7mqjv+7rZD/vK2R/72ukv+9rpL/vK2R/7qrkP+3qI3/tKaK/7CiiP+tn4X/qZuB/6SW
+ feugk3pIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUgGADmYVlfJ6La/WhkXH/pZZ2/6ib
+ e/+soIH/rqOE/6yegP+rmn3/rp2A/7Cgg/+yooT/s6OG/7Skh/+0pYj/tKSI/7Kih/+voIX/rZ6D/6qb
+ gP+mmH3/opR6uKGTeh8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJuH
+ Zymei2uioY9v+qSUdP+nmHn/qpx9/62ggP+snn7/qZh5/6iXeP+pmHr/q5l8/6ybfv+sm3//q5t//6qa
+ f/+omH3/pZZ7/6KTeM6hkndXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAn4xrK6GObYmjkXDgpZRz+aiYd/+qnHr/rJ18/6qaev+mlXb/pJJ0/6SS
+ df+kk3b/o5N3/qOSdu2hkXWsoJB0R6GQdQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACij24Io5BvJqSRcGCllHOYp5Z0wamY
+ d9WqmXjXqZh4yqWVdqyfjXB4no1wOp+PchEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP///////wAA//AAf///
+ AAD/8AA///8AAP/wAH///wAA8AAAAH//AADgAAAAP/8AAOAAAAA//wAA4AAAAB//AADgAAAAB/8AAOAA
+ AAAB/wAA4AAAAAD/AADgAAAAAH8AAOAAAAAAPwAA4AAAAAAfAADgAAAAAB8AAOAAAAAADwAA4AAAAAAP
+ AADgAAAAAAcAAOAAAAAABwAA4AAAAAADAADgAAAAAAMAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAOAA
+ AAAAAwAA4AAAAAABAADgAAAAAAEAAOAAAAAAAwAA4AAAAAADAADgAAAAAAMAAP8AAAAAAwAA/wAAAAAD
+ AAD/gAAAAAMAAP+AAAAABwAA/8AAAAAHAAD/wAAAAA8AAP/gAAAADwAA/+AAAAAfAAD/8AAAAD8AAP/4
+ AAAAfwAA//wAAAD/AAD//gAAAf8AAP//gAAD/wAA///AAA//AAD///AAP/8AAP///wP//wAA////////
+ AAA=
+
+
+
\ No newline at end of file
diff --git a/ServiceDashBored/Program.cs b/ServiceDashBored/Program.cs
new file mode 100644
index 0000000..e0da7bb
--- /dev/null
+++ b/ServiceDashBored/Program.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Windows.Forms;
+using BitFactory.Logging;
+using Castle.Core.Resource;
+using Castle.Windsor;
+using Castle.Windsor.Configuration.Interpreters;
+
+namespace ServiceDashBored
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ IWindsorContainer container =
+ new WindsorContainer(
+ new XmlInterpreter(new ConfigResource("castle")));
+
+ // Request the component to use it
+ var form = (Main)container[typeof(Main)];
+
+ try
+ {
+ // Use the component
+ Application.Run(form);
+ }
+ catch (Exception ex)
+ {
+ var logger = (Logger)container[typeof(Logger)];
+ logger.LogFatal(ex);
+ }
+ finally
+ {
+ // Release it
+ container.Release(form);
+ }
+ }
+ }
+}
diff --git a/ServiceDashBored/Properties/AssemblyInfo.cs b/ServiceDashBored/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3f25458
--- /dev/null
+++ b/ServiceDashBored/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ServiceDashBored")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ServiceDashBored")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ff0209e6-0dad-4e5c-8dc2-c1f004eafab0")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ServiceDashBored/Properties/DataSources/EndpointStatus.datasource b/ServiceDashBored/Properties/DataSources/EndpointStatus.datasource
new file mode 100644
index 0000000..5e3fa60
--- /dev/null
+++ b/ServiceDashBored/Properties/DataSources/EndpointStatus.datasource
@@ -0,0 +1,10 @@
+
+
+
+ ServiceDashBored.EndpointStatus, ServiceDashBored, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+
\ No newline at end of file
diff --git a/ServiceDashBored/Properties/Resources.Designer.cs b/ServiceDashBored/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..fbd6897
--- /dev/null
+++ b/ServiceDashBored/Properties/Resources.Designer.cs
@@ -0,0 +1,98 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ServiceDashBored.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ServiceDashBored.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ internal static System.Drawing.Icon accept {
+ get {
+ object obj = ResourceManager.GetObject("accept", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon question {
+ get {
+ object obj = ResourceManager.GetObject("question", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon remove {
+ get {
+ object obj = ResourceManager.GetObject("remove", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon up {
+ get {
+ object obj = ResourceManager.GetObject("up", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon warning {
+ get {
+ object obj = ResourceManager.GetObject("warning", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+ }
+}
diff --git a/ServiceDashBored/Properties/Resources.resx b/ServiceDashBored/Properties/Resources.resx
new file mode 100644
index 0000000..a551597
--- /dev/null
+++ b/ServiceDashBored/Properties/Resources.resx
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\Resources\accept.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\question.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\remove.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\up.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\warning.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/ServiceDashBored/References/BitFactory.Logging.dll b/ServiceDashBored/References/BitFactory.Logging.dll
new file mode 100644
index 0000000..c56317c
Binary files /dev/null and b/ServiceDashBored/References/BitFactory.Logging.dll differ
diff --git a/ServiceDashBored/References/Castle.Core.dll b/ServiceDashBored/References/Castle.Core.dll
new file mode 100644
index 0000000..a10d597
Binary files /dev/null and b/ServiceDashBored/References/Castle.Core.dll differ
diff --git a/ServiceDashBored/References/Castle.DynamicProxy2.dll b/ServiceDashBored/References/Castle.DynamicProxy2.dll
new file mode 100644
index 0000000..4461908
Binary files /dev/null and b/ServiceDashBored/References/Castle.DynamicProxy2.dll differ
diff --git a/ServiceDashBored/References/Castle.MicroKernel.dll b/ServiceDashBored/References/Castle.MicroKernel.dll
new file mode 100644
index 0000000..9f7616c
Binary files /dev/null and b/ServiceDashBored/References/Castle.MicroKernel.dll differ
diff --git a/ServiceDashBored/References/Castle.Windsor.dll b/ServiceDashBored/References/Castle.Windsor.dll
new file mode 100644
index 0000000..c577e4a
Binary files /dev/null and b/ServiceDashBored/References/Castle.Windsor.dll differ
diff --git a/ServiceDashBored/Resources/DryIcons Free Icons Aesthetica 2.0 Icon Set.URL b/ServiceDashBored/Resources/DryIcons Free Icons Aesthetica 2.0 Icon Set.URL
new file mode 100644
index 0000000..f8f9508
--- /dev/null
+++ b/ServiceDashBored/Resources/DryIcons Free Icons Aesthetica 2.0 Icon Set.URL
@@ -0,0 +1,2 @@
+[InternetShortcut]
+URL=http://dryicons.com/free-icons/preview/aesthetica-version-2/
diff --git a/ServiceDashBored/Resources/Up.ico b/ServiceDashBored/Resources/Up.ico
new file mode 100644
index 0000000..e19d86c
Binary files /dev/null and b/ServiceDashBored/Resources/Up.ico differ
diff --git a/ServiceDashBored/Resources/accept.ico b/ServiceDashBored/Resources/accept.ico
new file mode 100644
index 0000000..a1ebe4e
Binary files /dev/null and b/ServiceDashBored/Resources/accept.ico differ
diff --git a/ServiceDashBored/Resources/question.ico b/ServiceDashBored/Resources/question.ico
new file mode 100644
index 0000000..705634a
Binary files /dev/null and b/ServiceDashBored/Resources/question.ico differ
diff --git a/ServiceDashBored/Resources/remove.ico b/ServiceDashBored/Resources/remove.ico
new file mode 100644
index 0000000..fca3b4a
Binary files /dev/null and b/ServiceDashBored/Resources/remove.ico differ
diff --git a/ServiceDashBored/Resources/warning.ico b/ServiceDashBored/Resources/warning.ico
new file mode 100644
index 0000000..630d345
Binary files /dev/null and b/ServiceDashBored/Resources/warning.ico differ
diff --git a/ServiceDashBored/ServiceDashBored.csproj b/ServiceDashBored/ServiceDashBored.csproj
new file mode 100644
index 0000000..18dfbd1
--- /dev/null
+++ b/ServiceDashBored/ServiceDashBored.csproj
@@ -0,0 +1,148 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {2D46A996-7DEF-4592-B401-70090686B3F2}
+ WinExe
+ Properties
+ ServiceDashBored
+ ServiceDashBored
+ v2.0
+ 512
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+ False
+ References\BitFactory.Logging.dll
+
+
+ False
+ References\Castle.Core.dll
+
+
+ False
+ References\Castle.DynamicProxy2.dll
+
+
+ False
+ References\Castle.MicroKernel.dll
+
+
+ False
+ References\Castle.Windsor.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ Main.cs
+
+
+
+
+ Main.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+
+
+
+
+
+
+
+
+
+ {7686BAA6-A0C5-4FA5-BE6E-FA044C2FFDD4}
+ Endpoint
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/ServiceDashBored/app.config b/ServiceDashBored/app.config
new file mode 100644
index 0000000..154153f
--- /dev/null
+++ b/ServiceDashBored/app.config
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+ - ${google.endpoint}
+ - ${10.21.63.6.endpoint}
+ - ${localhost.freespace.endpoint}
+
+
+
+
+
+
+
+ ServiceDashBored.log
+
+
+
+
+
+ kpcodl06:8080 (paypal)
+ http://kpcodl06:8080/paypal_server/PayPalService
+
+
+
+
+
+ kpapqlz03:8080 (paypal)
+ http://kpapqlz03:8080/paypal_server/PayPalService
+
+
+
+
+
+ kpcoql03:8083 (OrderService)
+ http://kpcoql03.jewelry.qa:8083/catalyst_server/OrderService
+
+
+
+
+
+ 10.21.63.6 (ws-virtual)
+ http://10.21.63.6
+
+
+
+
+
+ 10.21.63.7 (ws-virtual)
+ http://10.21.63.7
+
+
+
+
+
+ 10.21.63.8 (ws-virtual)
+ http://10.21.63.8
+
+
+
+
+
+ 10.21.63.10 (ws-virtual)
+ http://10.21.63.10
+
+
+
+
+
+ 10.21.63.11 (ws-physical)
+ http://10.21.63.11
+
+
+
+
+
+ 10.21.63.12 (ws-physical)
+ http://10.21.63.12
+
+
+
+
+
+ images.jewelry.dmz (ws-virtual)
+ http://images.jewelry.dmz
+
+
+
+
+
+ Google
+ http://www.google.com
+
+
+
+
+
+ localhost D: Freespace
+ \\localhost
+ select FreeSpace from Win32_LogicalDisk where DeviceID='D:'
+ FreeSpace
+ 50e6
+
+
+
+
+
+ kpapdl26:8080 (payment)
+ http://kpapdl26:8080/core_server/paymentservice
+ //jtv:provider/text()
+ jtv,http://jtv.com
+ NoDecision
+ "urn:getPaymentKey"
+
+ ]]>
+
+
+
+
+
+
+ pscoql03:8080 (payment)
+ http://pscoql03:8080/core_server/paymentservice
+ //jtv:provider/text()
+ jtv,http://jtv.com
+ NoDecision
+ "urn:getPaymentKey"
+
+ ]]>
+
+
+
+
+
+
+ 10.20.7.26:8080 (payment)
+ http://10.20.7.26:8080/core_server/paymentservice
+ //jtv:provider/text()
+ jtv,http://jtv.com
+ NoDecision
+ "urn:getPaymentKey"
+
+ ]]>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ServiceDashBored/main.ico b/ServiceDashBored/main.ico
new file mode 100644
index 0000000..7d734dd
Binary files /dev/null and b/ServiceDashBored/main.ico differ
diff --git a/ServiceDashBoredTests/Properties/AssemblyInfo.cs b/ServiceDashBoredTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..912da74
--- /dev/null
+++ b/ServiceDashBoredTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ServiceDashBoredTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ServiceDashBoredTests")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM componenets. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("515c4aa0-000b-4576-b132-a01941b92b89")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ServiceDashBoredTests/ServiceDashBoredTests.csproj b/ServiceDashBoredTests/ServiceDashBoredTests.csproj
new file mode 100644
index 0000000..a3f06be
--- /dev/null
+++ b/ServiceDashBoredTests/ServiceDashBoredTests.csproj
@@ -0,0 +1,51 @@
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {4160DFC0-6484-4B92-A6C8-8EAF8655C1CD}
+ Library
+ Properties
+ ServiceDashBoredTests
+ ServiceDashBoredTests
+ v3.5
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
\ No newline at end of file