Иногда в веб-приложении бывает необходимо отослать код, сгенерированный веб-контролом на email пользователю. Чаще всего это встречается в системах со всяческими отчетами. Рассмотрим как это можно реализовать.
Каждый веб-контрол имеет в себе метод , RenderControl(HtmlTextWriter) который при вызове рендерит контрол и возвращает, как результат HtmlTextWriter. Программно это выглядит так:
StringBuilder SB = new StringBuilder();
StringWriter SW = new StringWriter(SB);
HtmlTextWriter htmlTW = new HtmlTextWriter(SW);
WebControlToRenderID.RenderControl(htmlTW);
Непосредственно к коду вы можете подобраться через метод
ToString() объекта HtmlTextWriter.
Однако данный подход прекрасно работающий в ASP.NET 1.1 не подходит для ASP.NET 2.0, так как при выполнении вы получите исключение: RegisterForEventValidation can only be called during Render();
Это происходит потому, что в ASP.NET 2.0 появилась новая возможность - Event Validation. Сделана она для того, чтобы помочь избежать так называемых Injection атак.
К примеру у вас на веб-форме имеется DropDownList контрол:
<asp:DropDownList runat="server" id="MyDropDownList">
<asp:ListItem Value="1">Item 1</asp:ListItem>
<asp:ListItem Value="2">Item 2</asp:ListItem>
<asp:ListItem Value="3">Item 3</asp:ListItem>
</asp:DropDownList>
Если через
postback страница передает значение
4, то ASP.NET генерирует исключение, так как ожидает значения 1, 2 или 3. Это идеальное поведение в том случае, если вы действительно хотите получать только 1, 2 или 3, так как если пришло значение 4, это означает, что что-то пошло не так. Но, если вы, к примеру, на клиенте динамически добавляете элемент к полученому select-у, то вас такое поведение не устроит.
В цикле жизни страницы контрол регистрирует себя на подобную проверку через класс ClientScriptManager методом RegisterForEventValidation. Этот метод может быть вызван только на этапе Render, иначе он генерирует исключение. А так как скорее код для програмной генерации контрола вызывается до этого этапа, к примеру, в событии Button1_Click, то вы гарантировано получаете исключение.
Естественно, сказанное выше применимо только к контролам требующим Event Validation. Вот их список:
- HtmlAnchor
- HtmlButton
- HtmlInputButton
- HtmlInputCheckBox
- HtmlInputHidden
- HtmlInputImage
- HtmlInputText
- HtmlInputPassword
- HtmlInputRadioButton
- HtmlInputReset
- HtmlInputSubmit
- HtmlSelect
- HtmlTextArea
- BulletedList
- Button
- Calendar
- CheckBox
- Table
- ChildTable
- WizardChildTable
- DataControlButton
- ImageButton
- DataControlImageButton
- LinkButton
- DataControlLinkButton
- DataControlPagerLinkButton
- DataGridLinkButton
- DetailsView
- DropDownList
- FormView
- GridView
- HiddenField
- ImageMap
- LayoutTable
- ListBox
- Menu
- PagerTable
- RadioButton
- RadioButtonList
- TextBox
- TreeView
- WizardDefaultInnerTable
- CatalogZone
- ConnectionsZone
- EditorZone
- WebPartZone
- ZoneButton
- ZoneLinkButton
Чтобы исправить подобное поведение требуется одно легкое телодвижение. Необходимо вставить, на страницы, рендерящие контрол програмно такой параметр к директиве
@Page:<% @Page EnableEventValidation="False" ... %>
Или же вы можете начинать рендеринг контрола(ов) в событии
Page_Render.
Перевод статьи Emailing the Rendered Output of an ASP.NET Web Control in ASP.NET 2.0