۱۳۸۷/۱۱/۱۵

مونيتور كردن وضعيت يك سايت در دات نت


فرض كنيد مي‌خواهيم وضعيت يك سايت را از لحاظ قابليت دسترسي مونيتور كنيم، آيا Up است، Down است و امثال آن. يك سري از وب سرورها ping را بسته‌اند (ICMP Replies). بنابراين الزاما با استفاده از اين روش ساده نمي‌توان به مقصود رسيد.
خوشبختانه انجام اين‌كار با استفاده از فضاي نام استاندارد System.Net و كلاس HttpWebRequest ، بدون نياز به هيچگونه كلاس يا كامپوننت خارجي، به سادگي قابل انجام است. كلاس زير به همين منظور تهيه شده است:

using System;
using System.Net;

public class CSiteMonitor
{
public struct UrlHeaderInfo
{
public DateTime _lastModified;
public string _statusCode;
public string _errorMessage;
}

/// <summary>
/// آيا آدرس اينترنتي وارد شده معتبر است؟
/// </summary>
/// <param name="url">آدرس مورد نظر جهت بررسي</param>
/// <returns></returns>
public static bool IsValidURL(string url)
{
try
{
Uri uri = new Uri(url);
return (uri.Scheme == Uri.UriSchemeHttp) || (uri.Scheme == Uri.UriSchemeHttps);
}
catch { return false; }
}
/// <summary>
/// آدرس اينترنتي جهت بررسي
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
/// <exception cref="ArgumentException">آدرس اينترنتي وارد شده معتبر نيست</exception>
public static UrlHeaderInfo GetSiteHeaderInfo(string url)
{
if (!IsValidURL(url))
throw new ArgumentException("آدرس اينترنتي وارد شده معتبر نيست", "url");

UrlHeaderInfo hhi = new UrlHeaderInfo { _lastModified = DateTime.Now, _statusCode = "NOK!", _errorMessage = string.Empty };

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
//request.Proxy
request.Method = "HEAD";
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; ; rv:1.8.0.7) Gecko/20060917 Firefox/1.9.0.1";
request.Timeout = 1000 * 300;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

try
{
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
hhi._statusCode = response.StatusCode.ToString();
hhi._lastModified = response.LastModified;
}
}
catch (Exception ex)
{
hhi._errorMessage = ex.Message;
}

return hhi;
}
}

توضيحات:
- در متد GetSiteHeaderInfo نياز بود تا از يك تابع بيش از يك خروجي داشته باشيم. راه‌هاي زياد براي انجام اين‌كار هست.براي مثال:
الف)ارائه خروجي‌ها به صورت يك آرايه. زياد جالب نيست، چون اگر شخصي دقيقا مستندات متد شما را مطالعه نكند نمي‌داند كه ترتيب خروجي‌ها چگونه است و هر كدام چه معنايي دارند.
ب)ارائه خروجي‌ها با استفاده از آرگومان‌هايي از نوع out يا ref . در دنياي شيء گرايي اين نوع روش‌ها را بايد منسوخ شده در نظر گرفت و صرف سازگاري با زبان‌هايي مانند C كه اين روش در آن‌ها رواج دارد (استفاده از آرگومان‌هايي از نوع اشاره‌گر) بايد به آن نگاه كرد و نه بيشتر.
ج)خروجي‌ها را به صورت يك كلاس يا struct درنظر گرفت تا استفاده كننده دقيقا بداند كه فيلد خروجي چه معنايي دارد و هم چنين دقيقا چه تعداد خروجي مد نظر است.

- حتما بايد از try/finally جهت اطمينان حاصل نمودن از بسته شدن response استفاده شود، در غير اينصورت پس از دو خطاي متوالي حاصل شده عملا ديگر نمي‌توان از شيء response استفاده كرد. البته همانطور كه پيش تر نيز ذكر شد، عبارت using توسط كامپايلر به try/finally بست داده مي‌شود، بنابراين جهت خوانايي بيشتر كد بهتر است از اين روش استفاده شود.
- جهت بلاك نشدن درخواست بهتر است از يك UserAgent كمك گرفته شود.
- جهت بررسي اعتبار يك آدرس اينترنتي يا مي‌توان از Regular expressions استفاده كرد يا از شيء Uri كه روش آن‌را ملاحظه مي‌كنيد.
- اگر در شبكه داخلي خود از پروكسي استفاده مي‌شود، مي‌توان قسمت request.Proxy را با شيء پروكسي تنظيم شده مطابق مشخصات پروكسي سرور خود، بكار برد.
- در اين مثال بيشتر هدف پياده سازي كلاس دريافت اطلاعات هدر سايت بود و از ارائه كدهاي مربوط به تايمر يا يك ترد جهت بررسي متوالي وضعيت سايت صرفنظر شد.

مثالي در مورد نحوه‌ي استفاده از كلاس فوق:

CSiteMonitor.UrlHeaderInfo info = CSiteMonitor.GetSiteHeaderInfo("http://www.google.com");
MessageBox.Show(info._statusCode);