load a user control programmatically in to a html text writer - asp.net

I am trying to render a user control into a string. The application is set up to enable user to use tokens and user controls are rendered where the tokens are found.
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter writer = new HtmlTextWriter(sw);
Control uc = LoadControl("~/includes/HomepageNews.ascx");
uc.RenderControl(writer);
return sb.ToString();
That code renders the control but none of the events called in the Page_Load of the control are firing. There's a Repeater in the control needs to fire.

I've been using the following code provided by Scott Guthrie in his blog for quite some time:
public class ViewManager
{
public static string RenderView(string path, object data)
{
Page pageHolder = new Page();
UserControl viewControl = (UserControl) pageHolder.LoadControl(path);
if (data != null)
{
Type viewControlType = viewControl.GetType();
FieldInfo field = viewControlType.GetField("Data");
if (field != null)
{
field.SetValue(viewControl, data);
}
else
{
throw new Exception("ViewFile: " + path + "has no data property");
}
}
pageHolder.Controls.Add(viewControl);
StringWriter result = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, result, false);
return result.ToString();
}
}
The object data parameter, enables dynamic loading of data into the user control, and can be used to inject more than one variable into the control via an array or somethin similar.
This code will fire all the normal events in the control.
You can read more about it here
Regards
Jesper Hauge

You would need to attach the control to a Page by adding it to a Controls collection of the Page or a Control on the page. This won't solve all of your problems unless you do something to explicitly disable rendering during the normal page render event.

I took Hauge's/ Scott Guthrie's method above and tweaked it so that you don't need to use reflection, or modify a UserControl to implement any special interface. The key was I added a strongly typed callback that the RenderView method above calls, instead of doing reflection.
I blogged the helper method and usage here
HTH,
Jon

Related

Render ascx control from outside page context

When trying to render the HTML of an ascx UserControl from a WebService, I get the error RegisterForEventValidation can only be called during Render.
This is a duplicate of this question. However the answers given do not work...
The solution always involves EnableEventValidation="false" and override VerifyRenderingInServerForm but these are only available on a Page, not on a Control (what the ascx is).
When changing the ascx to an aspx, the following code fails: page.LoadControl("mycontrol.ascx/aspx") and rendering an aspx is apparently not so easy according to this question.
The Question
How can I render my ascx without the exception?
Bonus question:
Why is EnableEventValidation not available on a Control while there are many examples on the net that claim otherwise? (StackOverflow, CodeProject, ...)
I found the solution:
var page = new System.Web.UI.Page();
// Or RenderControl throws 'RegisterForEventValidation can only be called during Render'
page.EnableEventValidation = false;
// Or generates a second hidden field with ID=_VIEWSTATE
page.EnableViewState = false;
var sb = new StringBuilder();
var ctl = (SomeAscx)page.LoadControl("SomeAscx.ascx");
using (var sw = new StringWriter(sb))
using (var htw = new HtmlTextWriter(sw))
{
ctl.RenderControl(htw);
}
string result = sb.ToString();
Key was setting:
page.EnableEventValidation = false;
page.EnableViewState = false;

RegisterForEventValidation can only be called during Render

I have a webmethod which will be called from jquery ajax:
[WebMethod]
public string TestMethod(string param1, string param2)
{
StringBuilder b = new StringBuilder();
HtmlTextWriter h = new HtmlTextWriter(new StringWriter(b));
this.LoadControl("~/Pages/Controls/Listing.ascx").RenderControl(h);
string controlAsString = b.ToString();
return controlAsString;
}
(it's a non-static method and we are able to hit it. That's not an issue)
When the loadControl() method is executed, I get an error saying: RegisterForEventValidation can only be called during Render.
I have already included EnableEventValidation="false" for the current aspx, disabled viewstate also. but still i get the same error. Any ideas on this?
Solution is to disable the Page's Event Validation as
<%# Page ............ EnableEventValidation="false" %>
and Override VerifyRenderingInServerForm by adding following method in your C# code behind
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
Refer the Below Link
http://www.codeproject.com/Questions/45450/RegisterForEventValidation-can-only-be-called-duri
As per Brian's second link, without hopping further, just do this:
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
Html32TextWriter hw = new Html32TextWriter(sw);
Page page = new Page();
HtmlForm f = new HtmlForm();
page.Controls.Add(f);
f.Controls.Add(ctrl);
// ctrl.RenderControl(hw);
// above line will raise "RegisterForEventValidation can only be called during Render();"
HttpContext.Current.Server.Execute(page, sw, true);
Response.Write(sb);
You need to notify ASP.Net that not to validate the event by setting the EnableEventValidation flag to false.
You can set it in the Web.Config in the following way
<%# Page Language="C#" AutoEventWireup="true" EnableEventValidation = "false"

Can ASCX or ASP.net files be saved as HTML files

Can ASCX or ASP.net files be saved as HTML files? if so, how?
yes, it is possible, to get the rendered content of a User Control, do the following :
StringWriter output = new StringWriter();
Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl("path to ascx file");
pageHolder.Controls.Add(viewControl);
HttpContext.Current.Server.Execute(pageHolder, output, true);
string htmlOutput = output.ToString();
Am sure you can adapt the above for ASPX page if required :-)
From there, saving that to a file should be fairly straight forward.
HTH.
D
You can do this directly with the Render method of a Page or UserControl. Since the method is protected, you will need to create a control that subclasses either. From there, you've got access to do whatever you need.
e.g.
public partial class MyPage: Page
{
public string GetPageContents()
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (HtmlTextWriter writer = new HtmlTextWriter(sw))
{
Render(writer);
}
return sb.ToString();
}
}
You probably wouldn't want to call this anytime before the PreRenderComplete event of the page though, since otherwise you can't be sure all child controls/events/etc have finished.

LoadControl from windows application

Is it possible to LoadControl in windows application?
I have email generation as web, but I want to move it to windows service for monthly newsletter.
Emails now are implemented as UserControls, in this way html person can easily modify look & feel.
Current rendering implementation looks like:
StringBuilder sb = new StringBuilder(4000);
StringWriter sw = new StringWriter(sb);
HtmlTextWriter htw = new HtmlTextWriter(sw);
Page page = new Page();
EmailTemplateBase emailCtrl = (EmailTemplateBase)page.LoadControl(
"Controls/EmailTempaltes/Template.ascx");
// Exception here
emailCtrl.DataContext = dataContext;
emailCtrl.Parameter = parameter;
emailCtrl.RenderMode = renderMode;
emailCtrl.DataBind();
emailCtrl.RenderControl(htw);
subject = emailCtrl.Subject;
string MessageText = sb.ToString().Replace("\t", "").Replace(Environment.NewLine, "");
return MessageText;
Solution for me was to call web service, which was able to generate Html from .ascx.
Pass necessary parameters to
webservice
in Webservice, Build
new Page, than LoadControl
Set all parameters
Do rendering to
StringBuilder.
You can see code in question.
instead of the LoadControl method used in asp.net, you can use Controls.Add method of the parent control. Just add a panel to be the parent then:
UserControl uc1 = new UserControl //this is your usercontrol
Panel1.Controls.Add(uc1);

Asp.net error creating usercontrol from WebMethod

I'm referencing the article reference
To create a UserControl dynamically and pass it back to a page via jQuery.
When I just do a simple text in the UserControl "Hello World" everything works great... however, when I tried putting interactive controls on the control, I got the following message in my WebMethod (so the jQuery call stuff is irrelevant) (further testing showed that textboxes, and buttons cause the issue, but not labels)
Error executing child request for handler 'System.Web.UI.Page'
here's the webmethod:
[WebMethod]
public static string GetCtrl(string cname)
{
StringWriter sw = new StringWriter();
Page p = new Page();
Control c = p.LoadControl("~/Controls/" + cname);
p.Controls.Add(c);
try
{
HttpContext.Current.Server.Execute(p, sw, false);
}
catch (Exception err)
{
return err.Message;
}
sw.Close();
return sw.ToString();
}
The exception is happening during the Server.Execute call.
A solution may not be possible, I'd just like to know why interactive controls cause this.
EDIT:
Taking advice below I looked deeper and found the inner exception said something to the effect that it must be within a form tag marked with runat="server", while I'm displaying this control on a aspx page within the form tag... my guess is that there's got to be some sort of 'asp.net magic' connection there for the control to operate... regardless, it'd be nice to know how to render a page with controls on it anyway (even if it wasn't usable in this situation)
So I looked at the output of the above code and for those curious:
<span id="ctl00_lbl1">abc: </span>
So the control is rendering properly (with just the label id='lbl1') on the page, however, the control is itself rendered, and the page content is not there at all... Is there a way to generate the page source as well? (I must not understand the way the Server.Execute function works)
I'd start by narrowing down the problem. For instance, what happens if you leave off the
p.Controls.Add(c);
What happens if you properly implement a using statement?
using (StringWriter sw = new StringWriter()) {
// ...
HttpContext.Current.Server.Execute(p, sw, false);
return sw.ToString();
}
What happens, if you leave off the try/catch? It's costing you all the information in the exception other than the Message property, so why not just leave it off? Your caller might be expecting HTML in any case, so if you keep it, you might (later) want to wrap the output:
return "<p>" + ex.ToString() + "</p>";
Little by little, remove things until the problem goes away.
Based on what you learned from the InnerException, I recommend that you add an HtmlForm control to the page, then add your loaded control as a child control of the HtmlForm.
Using Scott Gu's blog as a reference, I also came across the same problem loading server controls in my widgets (e.g. GridView and RadTreeView controls would cause the same error) for our company's dashboard. Following John Saunders's tip, I added an HTML form control and script manager control (for RadTreeView controls) and it fixed the problem. Now my user controls render out as pure HTML. w00t!
[WebMethod]
public static string[] LoadWidget(string widgetID, string widgetPath)
{
try
{
var pageHolder = new Page();
var form = new HtmlForm();
var viewControl = (UserControl)pageHolder.LoadControl(widgetPath);
var scriptManager = new ScriptManager();
form.Controls.Add(scriptManager);
form.Controls.Add(viewControl);
pageHolder.Controls.Add(form);
var output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return new string[]
{
widgetID, output.ToString()
};
}
catch (Exception e)
{
// handle error...
}
}
I would try rendering the control and sending that string back...
Control ctrl;
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(tw);
ctrl.RenderControl(hw);
return sb.ToString();

Resources