Серверный контроль создает неожиданную разметку

Я создаю редактор базы данных/бизнес-инструмент для клиента, использующего .NET 4.0 и IIS 7. Я хочу условно включить некоторый HTML на свою страницу на основе значений, которые я сохранил в сеансе. Я делаю это на стороне сервера, и для инкапсуляции кода я создал ASP Server Control.

Как вы увидите, разметка, сгенерированная серверным элементом управления, не соответствует моим ожиданиям. Я надеюсь, что кто-то видел это раньше и может помочь мне понять, как управлять выводом генерации разметки.

Вот новый RenderContents для элемента управления MyList. Предполагается генерировать новые записи списка, используя тег ‹li›.

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

После компиляции основного проекта и добавления ссылки на MyList я использую MyList в следующем HTML:

<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>

Теперь я добавляю тест на основе значения сеанса. Свойство Page WebControl предоставляет мне ссылку на контейнер элемента управления и, таким образом, доступ к моему сеансу:

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();
}

Теперь разметка начинает распутываться. Обратите внимание на несоответствие в «мЛ1»:

<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>

И теперь ты знаешь все, что я делаю!


person Thomas McNamee    schedule 22.09.2012    source источник


Ответы (2)


Вам просто нужно переопределить свойство WebControl.TagKey в вашем пользовательском серверном элементе управления:

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

Значение по умолчанию — Span, что объясняет то, что вы видите. Конечно, если вы сделаете это, вы не отобразите тег Li в переопределении RenderContents.

В качестве альтернативы можно было бы переопределить Render, чтобы получить полный контроль над рендерингом, или вместо этого получить от Control. Но вы потеряете некоторые функции WebControl, особенно стили для вашего внешнего тега.

Что касается вашей второй проблемы, вы звоните:

output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, backcolor);

который добавляет атрибут стиля, который будет применяться к следующему вызову RenderBeginTag. Вы не вызываете RenderBeginTag, поэтому это применяется к тегу в следующем элементе управления в дереве.

Еще один момент: Session будет иметь значение null, когда ваш элемент управления будет отображаться в конструкторе Visual Studio. Вы должны проверить значение null или, в качестве альтернативы, проверить, работаете ли вы в режиме разработки:

if ((Site != null) && (Site.DesignMode))
{
    ... running in design mode, Session won't be available
}
person Joe    schedule 22.09.2012
comment
Отличный, исчерпывающий ответ, я ценю это. - person Thomas McNamee; 23.09.2012

Избегайте System.Web.UI.WebControls. Я предлагаю вам подкласс System.Web.UI.Control напрямую.

<span> вставляется классом, из которого вы наследуете (который вы не упомянули). Обратите внимание, что вы переопределяете RenderContents вместо Render, что означает, что управляющий суперкласс может обернуть вывод RenderContents чем угодно, в данном случае <span>.

person Dai    schedule 22.09.2012