Server Control生成意外标记

时间:2012-09-22 04:17:31

标签: c# asp.net .net htmltextwriter

我正在为使用.NET 4.0和IIS 7的客户端构建数据库编辑器/业务线工具。我希望根据我在Session中存储的值在我的页面中有条件地包含一些HTML。我在服务器端这样做,为了封装代码,我创建了一个ASP服务器控件。

正如您将看到的,服务器控件生成的标记不是我的预期。我希望以前有人见过这个,可以帮助我理解如何控制标记生成输出。

这是名为MyList的控件的新RenderContents。它应该使用< li>生成新的列表条目。标签

protected override void RenderContents(HtmlTextWriter output) {
    output.RenderBeginTag(HtmlTextWriterTag.Li);
    output.WriteEncodedText(this.Text);
    output.RenderEndTag();
}

在编译主项目并添加对MyList的引用后,我在以下HTML中使用MyList:

<h1>Favorite Things</h1>
<ul>
    <cc1:MyList ID="mL1" runat="server" Text="Code that works!" />
    <cc1:MyList ID="mL2" runat="server" Text="Going home before 8" />
    <cc1:MyList ID="mL3" runat="server" Text="Cold drinks in fridge" />
</ul>

它会产生以下结果:

<h1>Favorite Things</h1>
<ul>
    <span id="MainContent_mL1"><li>Code that works!</li></span>
    <span id="MainContent_mL2"><li>Going home before 8</li></span>
    <span id="MainContent_mL3"><li>Cold drinks in fridge</li></span>
</ul>

现在我根据会话值添加测试。 WebControl的Page属性为我提供了对控件容器的引用,从而访问了我的Session:

protected override void RenderContents(HtmlTextWriter output) {
    string backcolor = "Yellow";
    if (this.Page.Session["access"] == null) {
        backcolor = "Red";
    }
    output.RenderBeginTag(HtmlTextWriterTag.Li);
    output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, backcolor);
    output.WriteEncodedText(this.Text);
    output.RenderEndTag();
}

现在标记开始解开。请注意'mL1'中的不一致:

<h1>Favorite Things</h1>
<ul>
    <span id="MainContent_mL1"><li>Code that works!</li></span>
    <span id="MainContent_mL2" style="background-color:Red;"><li>Going home before 8</li></span>
    <span id="MainContent_mL3" style="background-color:Red;"><li>Cold drinks in fridge</li></span>
</ul>

在我的实际代码中,更复杂的是,标记变成了span标记。而且,当我在RenderContents()中设置断点时,当我连续有五个标记时,它只被调用一次。

其他信息: 具有cc1:MyList控件的页面具有EnableSession = true。我的web.config指定了正常的会话管理器('rml'和'RoleBasedList'指的是我的'真实'控件,我简化了这个控件以隔离问题并使这篇文章更短):

<system.web>
    <trace enabled="true" localOnly="false" pageOutput="true" requestLimit="20" />
    <compilation debug="true" targetFramework="4.0" />
    <pages>
        <controls>
            <add tagPrefix="rml" assembly="RoleBasedList" namespace="SOTS.ServerControls"/>
        </controls>
    </pages>
    <httpModules>
      <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
    </httpModules>

    <sessionState mode="InProc" cookieless="false" timeout="60"/>
    ...
</system.web>

现在你知道我所做的一切!

2 个答案:

答案 0 :(得分:1)

您只需覆盖自定义服务器控件中的WebControl.TagKey属性:

protected override HtmlTextWriterTag TagKey
{
    get { return HtmlTextWriterTag.Li; }
}

默认值为Span,它解释了您所看到的内容。当然,如果您这样做,则不会在RenderContents覆盖中呈现Li标记。

另一种方法是覆盖Render,完全控制渲染,或者从Control派生。但是你会丢失WebControl的一些功能,特别是外部标签的样式。

关于你的第二个问题,你打电话:

output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, backcolor);

添加一个样式属性,以应用于RenderBeginTag的下一次调用。您无法调用RenderBeginTag,因此这将应用于树中下一个控件中的标记。

在Visual Studio设计器中呈现控件时,另一点是Session将为null。您应该检查null,或者检查您是否在设计模式下运行:

if ((Site != null) && (Site.DesignMode))
{
    ... running in design mode, Session won't be available
}

答案 1 :(得分:0)

避免使用System.Web.UI.WebControls。我建议你直接子类System.Web.UI.Control

<span>正由您派生的类插入(您未提及)。请注意,您将覆盖RenderContents而不是Render,这意味着控件超类可以随意包装RenderContents的输出,在这种情况下<span>