使用 HtmlTextWriter 呈现服务器控件?
我正在编写 ASP.NET 服务器控件的 RenderContents()
方法。 该方法使用 HtmlTextWriter
对象来呈现输出内容。 对于我正在编写的控件,使用 HtmlTextWriter
的方法似乎需要大量代码行来打开和关闭每个标记并将每个属性添加到流中。 最后,我觉得我最终会得到比需要的代码长得多的代码。
我在想,如果我使用 StringBuilder 这样的可链接类,我的代码会更清晰易读且更容易编写。
我想知道的是,是否有任何理由使用 HtmlTextWriter
对象来呈现整个控件的内容? 除了安全检查(我假设)之外,它还包括确保您不会以错误的顺序编写标签或创建无效的标记,我没有看到任何原因。
似乎做这样的事情会更容易:
protected override void RenderContents(HtmlTextWriter output)
{
StringBuilder s = new StringBuilder();
s.Append("lots")
.Append("of")
.Append("strings");
output.BeginRender();
output.Write(s.ToString());
output.EndRender();
}
有什么理由说这是一个坏主意吗?
更新
回应 Mehrdad Afshari 的回答:
我没有过多考虑实例化单独的 StringBuilder 对象的内存要求。 为 HtmlTextWriter 创建一个包装器怎么样,以便可以将其链接起来,这样就不会生成额外的字符串。
public class ChainedHtmlTextWriter
{
private HtmlTextWriter _W;
public ChainedHtmlTextWriter(HtmlTextWriter writer)
{
_W = writer;
}
public ChainedHtmlTextWriter Write<T>(T value)
{
_W.Write(value);
return this;
}
public ChainedHtmlTextWriter WriteLine<T>(T value)
{
_W.WriteLine(value);
return this;
}
}
I'm writing the RenderContents()
method of my ASP.NET server control. The method uses an HtmlTextWriter
object to render the output content. For the control I'm writing, using the HtmlTextWriter
's methods seems like it will require a lot of lines of code to open and close every tag and add every attribute to the stream. In the end I feel like I'm going to end up with code that is a lot longer than it needs to be.
I was thinking that if I used a chainable class such as StringBuilder
, my code would be a lot cleaner to read and easier to write.
What I was wondering was, is there any reason to use the HtmlTextWriter
object to render my entire control's contents? Other than the safety checks (I'm assuming) it includes to make sure you don't write tags in the wrong order or create invalid markup, I don't see a reason.
It seems like it would be easier to just do something like this:
protected override void RenderContents(HtmlTextWriter output)
{
StringBuilder s = new StringBuilder();
s.Append("lots")
.Append("of")
.Append("strings");
output.BeginRender();
output.Write(s.ToString());
output.EndRender();
}
Is there any reason why this would be a bad idea?
Update
In response to Mehrdad Afshari's answer:
I didn't think much about the memory requirements of having a separate StringBuilder
object instantiated. What about making a wrapper for HtmlTextWriter so that it can be chained so that an extra string isn't made.
public class ChainedHtmlTextWriter
{
private HtmlTextWriter _W;
public ChainedHtmlTextWriter(HtmlTextWriter writer)
{
_W = writer;
}
public ChainedHtmlTextWriter Write<T>(T value)
{
_W.Write(value);
return this;
}
public ChainedHtmlTextWriter WriteLine<T>(T value)
{
_W.WriteLine(value);
return this;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从性能角度来看,这将需要完成更多的字符串复制。
HtmlTextWriter
直接写入输出缓冲区。 另一方面,StringBuilder
有自己的缓冲区。 当您在StringBuilder
上调用ToString
时,必须构建一个新字符串,然后通过output.Write
将其写入输出缓冲区。 这还需要做更多的工作。Performance-wise, this will require more string copies to be done.
HtmlTextWriter
writes directly to the output buffer.StringBuilder
on the other hand, has its own buffer. When you callToString
on theStringBuilder
, a new string has to be built and then it will be written to the output buffer byoutput.Write
. It requires much more work to be done.我认为您不应该调用 BeginRender/EndRender,这是由页面完成的。
我不明白使用字符串生成器如何比使用 HtmlTextWriters 自己的方法节省任何工作。
I don't think you ought to be calling BeginRender/EndRender, thats done by the page.
I can't see how using string builder would save any work over using the HtmlTextWriters own methods.
我正在开发一个应用程序,开发人员遵循了您正在探索的可怕路径。 这让人回想起您必须编写自己的 ISAPI dll 来输出 html 代码的日子。 这是一个持续令人头疼的工作。如果您的代码主要是字符串,那么就有问题了。
我更改的大多数此类代码都会实例化服务器对象,根据需要配置它们的属性,然后告诉它们 .RenderControl(writer)。 这使得代码更容易阅读和使用。 如果这带来的开销对性能造成影响,我愿意接受它(事实上,在我进行更改后,应用程序通常运行得更快,所以据说情况并非如此,但我还没有分析过)我的代码)。
在字符串中硬编码内容的一个简单缺点是 HTML 标准发生变化。 我处理的代码是在 04/05 编写的,从那时起
已成为
> 如果他们一直在使用服务器控件,那么这些服务器控件就会更改其输出的 html,而无需我们执行任何操作。 这只是一个简单的例子。
编辑:哦,顺便说一句,BeginRender 和 EndRender 没有任何实现。 它们是占位符,供您在 HtmlTextWriter 派生类中重写和提供自定义功能。
EDIT2:有时总是使用服务器控件(例如容器和其他东西)有点麻烦。 我会做很多 .Controls.Add() ,然后稍后渲染容器。 所以有时我会这样做:
如上所述,即使 div 的 html 将来发生变化,这也会呈现正确的 html,因为我没有任何硬编码的字符串。
I work on an application where the developers followed the horrible path you're exploring. This harkens back to the days when you had to write your own ISAPI dlls that spit out html code. It is a constant headache to work in. If your code is mostly strings, then something is wrong.
Most of the code of this type that I change I instantiate server objects, configure their properties as desired, and then tell them to .RenderControl(writer). This makes the code much easier to read and work with. If there is a performance hit from the overhead this brings, I am willing to accept it (in fact, the application generally runs faster after I've made my changes, so anecdotally this isn't the case, but I haven't profiled my code).
One simple drawback to hard-coding your stuff in strings is when HTML standards change. The code I work on was written in 04/05, and since then <BR> has become <br /> and uppercase html tags aren't kosher anymore, etc. If they had been using server controls, those server controls have changed their outputted html without us needing to do anything. This is just one simple example.
EDIT: Oh, and btw, BeginRender and EndRender don't have any implementation. They are placeholders for you to override and provide custom functionality in a HtmlTextWriter-derived class.
EDIT2: Sometimes it's a bit onerous to always use server controls, like for containers and stuff. I'd be doing lots of .Controls.Add() and then render the container later. So sometimes I do this:
As mentioned, this will render correct html even if the html of a div changes in the future, cause I don't have any hard-coded strings.