Wednesday, June 5, 2013

Server Monitor In ASP.Net

I recently had the “privilege” to write a dashboard application that went around and collected a large amount of data and placed it in one central location where it could all be viewed at once.  Let’s be honest, without servers we would all be without a job.  So one of the widgets on the dashboard was to check the availability of servers.  Obviously, they don’t need to be webservers or even servers of any kind, just populate a node on the network. 
So lets look at this in a conceptual view.  The webserver gets a list of servers and IPAddresses.  It then checks for presence on the network, which we then assume if we get a reply that it is accessible to the network and functioning properly.  This could be taken further and you could specifically call web sites and parse the returned header or even the page for information to determine if a specific website is functioning.  However, this article takes a more broader approach and looks for machines on the physical network so as to not limit us to web servers.

NOTE: It is important to remember that when dealing with web pages that use external resources, that those resources exist from the hosting web server’s perspective.  It is therefore feasible that a server is available on the network but can not be resolvable from the web server, thus it will fail this server monitor test.  Just something to keep in mind when trouble shooting.

So lets get started.  Get a new web project going in VS2010.  First thing we need to do is add our folders.  In your Solution Exporer add the APP_CODE folder, BLL and DAL like the following (This article assumes you know how to add .Net framework folders):
image

We then need to add our classes.  Right Click BLL | Add New Item….
Select Class and name it “ServerInformation”.  Thus, now you have the ServerInformation.vb located in your BLL folder in the Solution Explorer.  First things first, we need to decide what information we need.  We need a server name so that we know what server we are dealing with and we need an IP Address.  Therefore, we are defining our ServerInformation object with properties.  We need to declare these properties:

Public Property ServerName As String = String.Empty
Public Property IPAddress As String = String.Empty


Now that we have our properties, we need constructors so we can build the object when the time arrives.  To do this, we will overload the New method like so:



        Public Sub New()
End Sub
Public Sub New
(ByVal servername As String, ByVal ipaddress As String)
Me.ServerName = servername
Me.IPAddress = ipaddress
End Sub


Not quite our final step, but we will need to do some jumping around before we are done with our object.  However, in order to move on we need to add our object to the correct hierarchy.  Therefore we need to define the namespace:



Namespace ServerMonitor.BLL
Public Class ServerInformation
#Region "Properties"
Public Property ServerName As String = String.Empty
Public Property IPAddress As String = String.Empty
#End Region
#Region
"Constructors"
Public Sub New()
End Sub
Public Sub New
(ByVal servername As String, ByVal ipaddress As String)
Me.ServerName = servername
Me.IPAddress = ipaddress
End Sub
#End Region
End Class
End Namespace


Now we need to jump over to the DAL side of things.  So add a class to the DAL, name it the same as you did in the BLL.  This will serve as our datasource.  I simply populate the generic list for our object however, it is extremely feasible to use a database backend and maybe a Reader to populate the List.  Here we will only have one method to define the object:



Namespace ServerMonitor.DAL
Public Class ServerInformation
#Region "Methods"
Public Function loadData() As _
List(Of ServerMonitor.BLL.ServerInformation)
Dim servers As List(Of ServerMonitor.BLL.ServerInformation) = _
New List(Of ServerMonitor.BLL.ServerInformation)
servers.Add(New ServerMonitor.BLL.ServerInformation("LocalHost", _
"127.0.0.1"))
servers.Add(New ServerMonitor.BLL.ServerInformation("Yahoo", _
"98.138.253.109"))
Return servers
End Function
#End Region
End Class
End Namespace




Now we need to go back to our object that exists in BLL and add the calling method to our DAL.  For simplicity, I will add the method and then list the entire code sequence.  We will then list the code sequence for the DAL object:



Public Function loadData() As List(Of ServerInformation)
Dim sm_DAL As ServerMonitor.DAL.ServerInformation = _
New ServerMonitor.DAL.ServerInformation
Return sm_DAL.loadData()
End Function




My entire code sequence for ServerMonitor.BLL.ServerInformation object:



Namespace ServerMonitor.BLL
Public Class ServerInformation
#Region "Properties"
Public Property ServerName As String = String.Empty
Public Property IPAddress As String = String.Empty
#End Region
#Region
"Constructors"
Public Sub New()
End Sub
Public Sub New
(ByVal servername As String, ByVal ipaddress As String)
Me.ServerName = servername
Me.IPAddress = ipaddress
End Sub
#End Region
#Region
"Methods"
Public Function loadData() As List(Of ServerInformation)
Dim sm_DAL As ServerMonitor.DAL.ServerInformation = _
New ServerMonitor.DAL.ServerInformation
Return sm_DAL.loadData()
End Function
#End Region
End Class
End Namespace




My entire code sequence for ServerMonitor.DAL.ServerInformation object:



Namespace ServerMonitor.DAL
Public Class ServerInformation
#Region "Methods"
Public Function loadData() As _
List(Of ServerMonitor.BLL.ServerInformation)
Dim servers As List(Of ServerMonitor.BLL.ServerInformation) = _
New List(Of ServerMonitor.BLL.ServerInformation)
servers.Add(New ServerMonitor.BLL.ServerInformation("LocalHost", _
"127.0.0.1"))
servers.Add(New ServerMonitor.BLL.ServerInformation("Yahoo", _
"98.138.253.109"))
Return servers
End Function
#End Region
End Class
End Namespace




So what is missing?  Well we need another object to keep track of the reply status returns.  We could simply add another property to the already created ServerInformation BLL object but this will help us keep it all straight in our heads during the presentation layer coding.  So we need to right click on the BLL folder again, add another class and name it “ServerReply”.  The only function this object will server is to be a data provider to our grid.  So the only two items it needs are properties and constructors.  We need ServerName and ServerStatus as properties and then an overloaded New constructor methods:



    Public Class ServerReply
#Region "Properties"
Public Property ServerName As String = String.Empty
Public Property ServerStatus As String = String.Empty
#End Region
#Region
"Constructors"
Public Sub New()
End Sub
Public Sub New
(ByVal servername As String, ByVal serverstatus As String)
Me.ServerName = servername
Me.ServerStatus = serverstatus
End Sub
#End Region
End Class




Finally, we need to add the namespace.  The entire code sequence for ServerMonitor.BLL.ServerReply looks like:



Namespace ServerMonitor.BLL
Public Class ServerReply
#Region "Properties"
Public Property ServerName As String = String.Empty
Public Property ServerStatus As String = String.Empty
#End Region
#Region
"Constructors"
Public Sub New()
End Sub
Public Sub New
(ByVal servername As String, ByVal serverstatus As String)
Me.ServerName = servername
Me.ServerStatus = serverstatus
End Sub
#End Region
End Class
End Namespace




Now that we have the backend completed and the engine in place, we need to work on the presentation layer.  First thing we need to do is add a grid to populate.  It only needs two columns, however if you add more information to be presented adding more columns is a breeze:



<asp:GridView ID="gdvServerStatus" runat="server" AllowPaging="True" 
PageSize="50" AutoGenerateColumns="false"
DataKeyNames="ServerName" EmptyDataText="No servers were found in the list."
ShowHeader="True" >
<
Columns>
<
asp:BoundField HeaderText="Server Name" DataField="ServerName" />
<
asp:BoundField HeaderText="Status" DataField="ServerStatus" />
</
Columns>
</
asp:GridView>




Basically simple Grid.  In the code behind, we need a trigger, a helper method and then an aesthetic method (last method to change the color of the text under status based on value).  Before we hit the trigger event, we need to get our data in check and actually perform the ping.   This is the method that gets the data from the list, process through it with a For Each Loop sends the ping.  Then based on the reply, we rate the status:



Protected Function performPing() As List(Of ServerMonitor.BLL.ServerReply)

Dim sm_BLL As ServerMonitor.BLL.ServerInformation = New _
ServerMonitor.BLL.ServerInformation
Dim serverList As List(Of ServerMonitor.BLL.ServerInformation) = _
sm_BLL.loadData()
Dim serverReplies As List(Of ServerMonitor.BLL.ServerReply) = New _
List(Of ServerMonitor.BLL.ServerReply)

For Each server As ServerMonitor.BLL.ServerInformation In serverList
Dim systemPing As Ping = New Ping()
Dim systemPingReply As PingReply = _
systemPing.Send(server.IPAddress.ToString(), 1000)
If (systemPingReply.Status = IPStatus.Success) Then
serverReplies.Add(New _
ServerMonitor.BLL.ServerReply(server.ServerName.ToString(), _
"Success"))
Else
serverReplies.Add(New _
ServerMonitor.BLL.ServerReply(server.ServerName.ToString(), _
systemPingReply.Status.ToString()))
End If
Next
Return
serverReplies
End Function




Now to change the text color based on the result.  We need to make sure that the row is a datarow (as opposed to a header or footer) then based on the status, simply change the color:



Protected Sub gdvServerStatus_RowDataBound(sender As Object, e As _
System.Web.UI.WebControls.GridViewRowEventArgs) _
Handles gdvServerStatus.RowDataBound
If (e.Row.RowType = DataControlRowType.DataRow) Then
If
(e.Row.Cells(1).Text = "Success") Then
e.Row.Cells(1).ForeColor = System.Drawing.Color.Green
Else
e.Row.Cells(1).ForeColor = System.Drawing.Color.Red
End If
End If
End Sub



Finally, to wrap this whole thing up – All you need to do is create the trigger to populate the Grid.  Which for our purposes will be the Page Load Method:




Protected Sub Page_Load(sender As Object, e As System.EventArgs) _
Handles Me.Load
gdvServerStatus.DataSource = performPing()
gdvServerStatus.DataBind()
End Sub




Running this gives us information on which servers are available to talk/receive requests/…etc… and then to add a little flavor, we change the color based on the results -

image 



Håþþ¥ .ñꆆïñg…

No comments:

Post a Comment