WebForms技术在开发Web应用程序时提供了许多便利,但其输出往往包含冗长的ID和不必要的ViewState,这不仅增加了页面的体积,还可能影响性能。本文将探讨如何通过正则表达式来优化WebForms的输出,包括去除ViewState、处理嵌套表单以及缩短ID等技巧。
在WebForms中,页面输出常常包含一些冗余的内容,例如过长的ID和ViewState。这些内容不仅增加了页面的体积,还可能影响页面的性能。例如,一个简单的元素可能会被赋予一个非常长的ID:
<span id="accounts_overview_body_quickAction_quickActionTitleLabel"></span>
此外,ViewState虽然在某些情况下非常有用,但在不需要时,它的存在会增加页面的体积,并且可能导致一些浏览器无法正常工作。
通过重写页面的Render事件,可以在内容发送给用户之前对其进行操作。这为提供了一个机会,可以在内容被发送之前对其进行修改。以下是实现这一操作的基本步骤:
protected override void Render(HtmlTextWriter writer)
{
// render our output
StringWriter output = new StringWriter();
HtmlTextWriter html = new HtmlTextWriter(output);
base.Render(html);
// get the rendered string
string rendered = output.ToString();
// Make our changes
// ... discussed shortly
// cleanup our writers
html.Dispose();
output.Dispose();
// then write it
writer.Write(rendered);
}
通过这种方式,可以在内容被发送给用户之前对其进行修改。
在某些页面上,可能并不需要ViewState。例如,如果页面只显示一些产品信息或图片,并且用户不需要对这些内容进行回传,那么ViewState就显得多余。可以使用正则表达式来去除页面中的ViewState:
rendered = Regex.Replace(
rendered,
"]*>",
string.Empty,
RegexOptions.IgnoreCase
);
这段代码会从页面中完全去除ViewState。如果需要去除其他类似的内容,例如__EVENTSTATE,可以通过修改正则表达式来实现。
在WebForms中,如果想在页面中使用其他表单,那么这些表单必须位于Page Form之外。这是因为并非所有的浏览器都支持嵌套表单。可以通过正则表达式来去除页面中的Page Form,同时保留其他表单:
// find all the forms and closed elements
MatchCollection matches = Regex.Matches(
rendered,
"]*>",
RegexOptions.IgnoreCase
);
// create the expression to match for the ID
Regex expectedId = new Regex(
string.Format(
"id=\"?({0}|aspnetForm)\"?",
this.Form.ID
),
RegexOptions.IgnoreCase
);
// expression to check for a close of a form
Regex closeForm = new Regex(
@"",
RegexOptions.IgnoreCase
);
// loop through and remove the page form
Match open = null;
Match close = null;
int depth = 0;
for (int i = 0; i < matches.Count; i++)
{
Match match = matches[i];
// check if this is the page form
if (expectedId.IsMatch(match.Value) && !(open is Match))
{
open = match;
}
// if we aren't tracking yet, just continue
if (!(open is Match)) continue;
// change the direction of the nesting
depth += closeForm.IsMatch(match.Value) ? -1 : 1;
// if the nesting is back to zero we can assume this
// is the correct tag
if (depth == 0)
{
close = match;
break;
}
}
// remove the tags - make sure to start with the close tag
// since this will affect the index of the Matches
if (open is Match && close is Match)
{
rendered = rendered.Remove(close.Index, close.Length);
rendered = rendered.Remove(open.Index, open.Length);
}
通过这种方式,可以去除页面中的Page Form,同时保留其他表单,以便它们可以正常处理回传。
ASP.NET 4.0提供了一些功能,帮助开发者将有意义的ID推送到客户端。目前,ID是通过使用父级、父级、父级等ID生成的,这在避免命名冲突方面很有用,但如果在客户端进行操作,这可能会带来问题。此外,有时可能会在一些并不打算操作的元素上得到ID,这完全是浪费空间。
可以使用正则表达式来修改页面上的ID:
// lastly, drop any unwanted IDs
MatchCollection extraIds = Regex.Matches(
rendered,
@"<[^>]*actualId=""(?[^""]*)""[^>]*>",
RegexOptions.IgnoreCase
);
// loop backwards to avoid affecting indexes on the matches
for (int i = extraIds.Count; i-- > 0; )
{
Match extra = extraIds[i];
// drop the unwanted parts
string newElement = extra.Value;
string newID = extra.Groups["id"].Value;
// lastly, remove the actual ID field
newElement = Regex.Replace(
newElement,
@"actualId=""""[^""]*""""?",
string.Empty,
RegexOptions.IgnoreCase
);
// if the ID is blank, just remove it
newElement = Regex.Replace(newElement,
@"(id|name)=""""[^""]*""""?",
(str) => {
if (string.IsNullOrEmpty(newID)) {
return string.Empty;
}
return string.Concat(
str.Value.StartsWith("id", StringComparison.OrdinalIgnoreCase) ? "id" : "name",
"=\"", newID, "\" ");
});
// finally, replace the new string
rendered = rendered.Remove(extra.Index, extra.Length);
rendered = rendered.Insert(extra.Index, newElement);
}
这是一个定制的解决方案。可以通过这种方式,在控件上添加“actualId”属性,然后id和name属性将更新以反映该值。此外,actualId属性将完全从元素中移除。
进入渲染输出并对其进行修改,以改变发送给客户端的内容,这是非常有趣的。有很大的权力来完全改变内容的外观。但是要小心——改变得越多,就越有可能破坏ASP.NET的工作方式。