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






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

引言
每当您更改 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 服务、数据库、网络共享、文件路径和重要事务是否执行正常。每当您的网站报告有故障时,您可以先运行自诊断页面来确认设置是否都正确。然后,您可以花时间检查特定问题区域。这样的自诊断页面有助于消除手动调查时间,并帮助您快速识别问题区域。