65.9K
CodeProject 正在变化。 阅读更多。
Home

网站诊断页,用于诊断您的 ASP.NET 网站

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (46投票s)

2010 年 8 月 21 日

CPOL

4分钟阅读

viewsIcon

247401

一个自诊断页面,可以检查您的 web.config 并确认所有设置都正确,是配置更改或生产部署后识别环境问题的快速简便方法。

Diagnostics_page.gif

引言

每当您更改 web.config 文件或在新环境中部署网站时,您都需要尝试许多相关功能来确认配置更改或环境是否正确。有时,您需要对网站进行冒烟测试以安心。此外,如果某些外部数据库、Web 服务或网络连接中断,需要花费时间来精确确定问题所在。在您的网站上有一个自诊断页面,就像打印机上的那样,可以帮助快速确定问题所在。以下是如何使用简单的 AJAX 技术在一个页面中快速创建一个简单的自诊断页面的方法。此诊断页面测试常见的配置设置,如连接字符串、ASP.NET Membership 配置、SMTP 设置、<appSettings> 文件路径和 URL 以及一些应用程序特定的设置,以确认配置是否全部正确。

构建自诊断页面框架

我使用 UpdatePanel 和 AJAX Timer 来执行每个诊断步骤。每隔 500 毫秒,它就会向页面执行一次异步回发,页面一次执行一个特定的诊断步骤。这样,即使整个诊断过程花费很长时间,也不会导致页面超时,并且初始显示页面也不会有很大的延迟。

<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true"
        ScriptMode="Release">
    </asp:ScriptManager>
    <asp:UpdatePanel runat="server" UpdateMode="Conditional">
        <ContentTemplate>
            <asp:Timer runat="server" ID="RefreshTimer" Interval="500" 
		Enabled="true" OnTick="RefreshTimer_Tick" />
            <h1>
                Self Diagnostics</h1>
            <h2>
                Database Configuration</h2>
            <ul>
                <li>
                    <asp:Label CssClass="inprogress" 
		    Text="Can read and write to database using the connection string."
                        runat="server" ID="ConnectionStringStatusLabel" /></li>
            </ul>

AJAX Timer 会在服务器上触发 RefreshTimer_Tick。然后它会逐个执行步骤。对于每个诊断步骤,我都放了一个 Label 来显示步骤标题。如果失败,Label 会用错误和建议进行更新。否则,它会被标记一个显示勾号的 CSS 类。

protected void RefreshTimer_Tick(object sender, EventArgs e)
    {
        this._Tasks[this.CurrentTaskNo]();
        
        this.CurrentTaskNo++;
        if (this.CurrentTaskNo == this._Tasks.Length)
        {
            this.RefreshTimer.Enabled = false;
        }
    }

_Tasks 是一个 delegates 数组。每个步骤只是一个执行特定诊断步骤的函数。一旦您用函数数组构建了 _Tasks,这个 RefreshTimer_Tick 就会逐个执行函数。

诊断步骤列表在 OnInit 事件中定义

 protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        this._Tasks = new Action[] 
        {
            () => TestConnectionString(),
            () => TestMembershipAPI(),
            () => TestWrite(),
            () => TestPaths(),
            () => TestUrls(),
            () => TestSMTP(),
            () => TestAppSettings(),
            () => TestAnonTemplateUser(),
            () => TestRegTemplateUser()
        };
    } 

就是这样。框架非常简单。复杂性在于诊断步骤。

测试 ASP.NET Membership 设置

ASP.NET Membership 有三个应进行测试的配置设置——Membership API、Profile API 和 Role Manager。诊断函数尝试创建一个新用户、一个新的配置文件并检查某个角色是否存在,以确认 membership 设置是否都正确。当然,您可以根据您的需求更改逻辑以执行测试。

private void TestMembershipAPI()
{
    try
    {
        // Test Membership API
        try
        {
            var newUser = Membership.CreateUser
		(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
        }
        catch (Exception x)
        {
            MarkAsFail(MembershipLabel, x.Message, 
                "Probably wrong connection string name in 
		<membership> block in web.config. 
		Don't use the Entity Framework Connection string");

            return;
        }

同样,您可以测试 Profile Provider 以确认 profile provider 设置是否都正确。

// Test Profile API
try
{
    UserProfile newProfile = ProfileCommon.Create
			(Guid.NewGuid().ToString()) as UserProfile;
    if (newProfile == null)
    {
        MarkAsFail(MembershipLabel, "Cannot create new user.",
        	"You might have wrong connection string name in <profile> block. 
	Ensure it's the simple connection string, not the entity framework one. 
	Or you may not have the 'inherits=\"Dropthings.Web.Framework.UserProfile\" 
	attribute in the <profile> block.");
        return;
    }

    newProfile.IsFirstVisit = false;
    newProfile.Fullname = "Test";
    newProfile.Save();
}
catch (Exception x)
{
    MarkAsFail(MembershipLabel, x.Message,
        "Probably wrong connection string name in <profile> block in web.config. 
	Don't use the Entity Framework Connection string");
    return;
}

这里的测试代码非常特定于我的项目。您可以更改它以按照您想要的方式进行测试。

测试 App_Data 是否具有写入权限

有时,我们会忘记授予 ASPNET 帐户或 NETWORK SERVICE 帐户对 App_Data 文件夹的写入权限。以下测试确认 app_data 文件夹具有正确的权限。

private void TestWrite()
{
    try
    {
        File.AppendAllText(Server.MapPath("~/App_Data/" + Guid.NewGuid().ToString()), 
		Guid.NewGuid().ToString());

        MarkAsPass(AppDataLabel);
    }
    catch (Exception x)
    {
        MarkAsFail(AppDataLabel, x.Message, "Give read, write, 
	modify permission to NETWORK SERVICE account to App_Data folder.");
    }
}

它通过创建一个随机文件来执行测试。它只测试是否存在创建和写入权限。它不测试是否存在删除权限。如果适合您的项目,您可以尝试删除随机创建的文件来添加它。

测试 <appSettings> 块中的文件路径

大多数情况下,我们将文件路径放在 <appSettings> 块中。以下测试确认所有相对路径是否正确并存在。

private void TestPaths()
{
    bool allPathOK = true;
    foreach (string key in ConfigurationManager.AppSettings.AllKeys)
    {
        string value = ConfigurationManager.AppSettings[key];

        if (value.StartsWith("~/"))
        {
            string fullPath = Server.MapPath(value);
            if (!Directory.Exists(fullPath) && !File.Exists(fullPath))
            {
                MarkAsFail(FilePathLabel, "Invalid path: " + key + "=" + 
				fullPath, string.Empty);
                allPathOK = false;
            }
        }
    }

    if (allPathOK)
        MarkAsPass(FilePathLabel);
        
}

它会遍历所有 <appSettings> 条目,并检查是否有任何条目的值是以相对文件路径格式表示的。如果找到一个,它会将其转换为本地绝对路径并确认路径存在。

测试 <appSettings> 块中的外部 URL 是否可达

就像文件路径一样,您可以测试外部 URL 是否正常工作。

private void TestUrls()
{
    bool allUrlOK = true;

    foreach (string key in ConfigurationManager.AppSettings.AllKeys)
    {
        string value = ConfigurationManager.AppSettings[key];
        Uri uri;
        if (Uri.TryCreate(value, UriKind.Absolute, out uri))
        {
            // Got an URI, try hitting
            using (WebClient client = new WebClient())
            {
                try
                {
                    client.DownloadString(uri);
                }
                catch (Exception x)
                {
                    MarkAsFail(URLReachableLabel, x.Message, 
			"Unreachable URL: " + key + "=" + uri.ToString());
                    allUrlOK = false;
                }
            }
        }            
    }

    if (allUrlOK)
        MarkAsPass(URLReachableLabel);
}

该测试会遍历所有 <appSettings> 条目,检查是否有任何值是 URL 格式。如果是,它会尝试对该 URL 执行 HTTP GET 请求。

结论

自诊断完全取决于您的应用程序类型。上面的代码向您展示了一些可以开始使用的示例。您应该添加一些特定于应用程序的测试,以确认外部 Web 服务、数据库、网络共享、文件路径和重要事务是否执行正常。每当您的网站报告有故障时,您可以先运行自诊断页面来确认设置是否都正确。然后,您可以花时间检查特定问题区域。这样的自诊断页面有助于消除手动调查时间,并帮助您快速识别问题区域。

© . All rights reserved.