Im trying to find a best practice to load usercontrols using Ajax.
My first approach where simply using an UpdatePanel and popuplating it with LoadControl() on ajax postbacks but this would rerender other loaded usercontrols in the same UpdatePanel. Also I cannot have a predefined set of UpdatePanels since the number of UserControls I need to load will vary.
Is there any best practice for this type of scenario?
If needed I could implement a framework or some type of custom controls if that would be a solution but I would love to do this with ASP.NET 3.5 and the AjaxControlToolkit if possible.
Probably dozens of high-brow reasons for not doing it this way, but simply initalizing a page, adding the usercontrol, then executing and dump the resulting HTML wherever it may behoove you, is (in my simpleminded view) so mind-numbingly fast & fun that I just have to mention it...
Skip the UpdatePanels, just use a Label, a plain old span, or how about an acronym...
Using JQuery on the client side:
$('#SomeContainer').Load("default.aspx?What=GimmeSomeSweetAjax");
ServerSide:
if(Request.QueryString["What"]==GimmeSomeSweetAjax)
{
Page page = new Page();
Control control = (Control)LoadControl("~/.../someUC.ascx");
StringWriter sw = new StringWriter();
page.Controls.Add(control);
Server.Execute(page, sw, false);
Response.Write(sw.ToString());
Response.Flush();
Response.Close();
}
Nothing else executes, and the page's lifecycle has a real Kevorkian moment ;-)
I'm not sure, but maybe this tutorial by Scott Guthrie could be useful.
Had to use this on order to get the properties work!
var page = new Page();
var sw = new StringWriter();
var control = (UserControl)page.LoadControl("~/.../someUC.ascx");
var type = control.GetType();
type.GetProperty("Prop1").SetValue(control, value, null);
page.Controls.Add(control);
context.Server.Execute(page, sw, false);
context.Response.ContentType = "text/html";
context.Response.Write(sw.ToString());
context.Response.Flush();
context.Response.Close();
Related
How do I recover the full html of a page, including what is generated by javascript. The problem is that I want to access the contents of the select tag, but the page but it is coming empty, this probably being generated dynamically. Please I'm about to give up!
I just posted a piece of code because this very large, if I find it necessary to put the whole code.
res = (HttpWebResponse)req.GetResponse();
res.Cookies = req.CookieContainer.GetCookies(req.RequestUri);
cookieContainer.Add(res.Cookies);
sr = new StreamReader(res.GetResponseStream());
getHtml = sr.ReadToEnd();
viewstate = rxViewstate.Match(getHtml).Groups[1].Value;
EventValdidation = rxEventValidation.Match(getHtml).Groups[1].Value;
viewstate = HttpUtility.UrlEncode(viewstate);
EventValdidation = HttpUtility.UrlEncode(EventValdidation);
//Here I should take the contents of the select tag.
getHtml = rxDropDownMenu.Match(getHtml).Groups[2].Value;
You can't just do this with HttpWebRequest, all that does is download the raw HTML and non of the linked JavaScript files.
It also wouldn't run the JavaScript or give you any kind of DOM to inspect.
You'd really need to use WebBrowser or perhaps something like Awesomium.
I am attempting to write a method that will output the content (i.e. HTML) for any renderings that happen to exist within a specific placeholder. The goal is to pass in a Sitecore.Data.Items.Item and the placeholder key that i'm interested in, and the method should return the rendered content.
The issue with this seems to be that there is no page context established, and therefore calling RenderControl() is throwing a null reference error in the GetCacheKey() method of the Sublayout.
Is anyone aware of a way to render a Sublayout or XSLT rendering programmatically?
Here's what I've got so far:
private string GetPlaceholderContent(Item item, string placeHolder)
{
StringWriter sw = new StringWriter();
using (HtmlTextWriter writer = new HtmlTextWriter(sw))
{
foreach (RenderingReference renderingReference in item.Visualization.GetRenderings(Sitecore.Context.Device, false))
{
if (renderingReference.Placeholder == placeHolder)
{
// This ensures we're only dealing with Sublayouts
if (renderingReference.RenderingItem.InnerItem.IsOfType(Sitecore.TemplateIDs.Sublayout))
{
var control = renderingReference.GetControl();
control.RenderControl(writer); // Throws null reference error in GetCacheKey()
}
}
}
}
return sw.ToString();
}
It is almost 8 years since the question was originally asked, and it turn to be Uniform - rendering any item/placeholder fragment!
Yes, it cuts the item you supply into placeholders/renderings:
The next step is to produce markup (for every possible data source out there):
That content is published into CDN and browser picks which version to load = personalization works!
In other words, the question you've asked turned into a cutting-edge product that can do so much more on top of that!
You could reverse-engineer the Uniform assemblies to see how they actually do that ;)
In my opinion, the best way to programmatically render a Sublayout is to use a repeater, and put a <sc:Sublayout> tag in the <ItemTemplate>.
From there you only have to do one or both of the following:
Set the DataSource property of the <sc:Sublayout> to be the string representation of the desired item's GUID (i.e. the data source for the sublayout, if any)
Set the Path property of the <sc:Sublayout> to be the path to the Sublayout that you wish to render.
The server/sitecore will handle the rest.
I am trying to copy data that is displayed in a asp listview.(I want to email it)
I can grab the information using javascript to grab the html but it is unstyled.
I don't want to have to go inside each control to save the data before each time it is outputted. Is their a better solution?
Html is html, if you keep your formatting in a css you will need to attach related css-classes and tags in the e-mails as well which should be quite simple.
I know this has been answered, but I thought I would add this too in case it helps. I use the following to return the HTML of a given control. As mentioned, you would just need to include any CSS in the HTML of the Email.
using System.Text;
using System.IO;
using System.Web.UI;
public string RenderControl(Control ctrl)
{
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(tw);
ctrl.RenderControl(hw);
return sb.ToString();
}
Stolen from several blog sites like this one.
Is there a way to save html content of an aspx page in the pageload part of the cs file and have it loaded again on postback?
Maybe using a streamreader to save it then have the streamreader write the content back in?
If so does anyone have any examples?
Do you mean something like this, capturing the generated HTML by overriding the Render method?
protected override void Render(HtmlTextWriter writer)
{
string pageSource;
// setup a TextWriter to capture the markup
using (var sw = new StringWriter())
using (var htw = new HtmlTextWriter(sw))
{
// render the markup into our surrogate TextWriter
base.Render(htw);
// get the captured markup
pageSource = sw.ToString();
}
// render the markup into the output stream
writer.Write(pageSource);
// now you can do what you like with the captured markup in pageSource
}
ASP.NET has an extensive caching mechanism which is meant to do what you describe
Something along these lines HtmlTextWriter to String - Am I overlooking something? can be done. I've done it with the Render() method of the page, not the RenderContents method. I can't for the life of me remember why I did that, though. It may have been for versions of ASP.net before they introduced the ability to cache most of a page, except for small pieces. Unless you really need to do this, use the built in caching functionality.
I'm trying to generate some XML for a jQuery.get (AJAX) call, and I'm getting the following error from my C# page: "Using themed css files requires a header control on the page. (e.g. <head runat="server" />)."
The file generating the XML is a simple .aspx file, consisting entirely of:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="ChangePeopleService.aspx.cs" Inherits="ChangeRegister.Person.ChangePeopleService" EnableTheming="false" %>
with codebehind using Linq-to-XML, which is working ok:
XElement xml = new XElement("People",
from p in People
select new XElement("Person", new XAttribute("Id", p.Id),
new XElement("FirstName", p.FirstName)));
HttpContext.Current.Response.ContentType = "text/xml";
HttpContext.Current.Response.Write(xml.ToString());
I know that the error relates to the Web.Config's <pages styleSheetTheme="default" theme="default"> tag, because when I remove the 'styleSheetTheme' and 'theme' attributes, the XML gets generated ok. The problem then obviously is that every other page loses its styling. All this leads me to think that I'm approaching this wrong.
My question is: what's an accepted way to generate XML in C#, for consumption by a jQuery AJAX call, say?
If I am returning simple data (not a page), I probably wouldn't use aspx; that is really web-forms, but what you are returning isn't a web-form. Two options leap to mind:
use ASP.NET MVC; sounds corny, but it really is geared up to return different types of response much more elegantly
use a handler (ashx) - which omits all the web-form noise, just leaving you with a HttpContext with which to construct your response
You could also try (within aspx) clearing the response (Clear()?) and calling Close() afterwards. But IMO a lot more roundabout than just using a handler.
You need to use theme=""
example:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="ChangePeopleService.aspx.cs" Inherits="ChangeRegister.Person.ChangePeopleService" Theme="" %>
Try writing to the Response.OutputStream instead:
HttpContext.Current.Response.ContentType = "text/xml";
HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;
using (TextWriter textWriter
= new StreamWriter(HttpContext.Current.Response.OutputStream, Encoding.UTF8))
{
XmlTextWriter writer = new XmlTextWriter(textWriter);
writer.WriteString(xml.ToString());
}