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.
Related
I'm building a class library in C# which uses the XmlTextWriter class to build an XML which is then exported as a HTML document.
However when I save the file with a .html extension using the XmlTextWriter object as content, the resulting file only contains the text "System.Xml.XmlTextWriter"
This comes up in the method defined below, specifically in the final line:-
public void SaveAsHTML(string filepath)
{
XmlTextWriter html;
html = new XmlTextWriter(#"D:/HTMLWriter/XML/HTMLSaveAsConfig.xml", System.Text.Encoding.UTF8);
html.WriteStartDocument();
html.WriteStartElement("html");
html.WriteRaw(Convert.ToString(Head));
html.WriteRaw(Convert.ToString(Body));
html.WriteEndElement();
html.WriteEndDocument();
html.Flush();
html.Close();
System.IO.File.WriteAllText(filepath, html.ToString());
}
For context, the variables Head and Body are also XmlTextWriter objects containing what will become the and elements of the html file respectively.
I've tried using Convert.ToString(), which causes the same issue.
I'm tempted to try overriding the ToString() method for my class as a fix, potentially using the XmlSerializer class. However I was wondering if there's a less noisy way of returning the Xml object as a string?
The following function will extract the string from the System.Xml.XmlTextWriter objects you've created as Head and Body.
private string XmlTextWriterToString(XmlTextWriter writer)
{
// Ensure underlying stream is flushed.
writer.Flush();
// Reset position to beginning of stream.
writer.BaseStream.Position = 0;
using (var reader = new StreamReader(writer.BaseStream))
{
// Read and return content of stream as a single string
var result = reader.ReadToEnd();
return result;
}
}
Some caveats here are that the underlying System.IO.Stream object associated with the System.Xml.XmlTextWriter must support both 'read' and 'seek' operations (i.e., both Stream.CanRead and System.CanSeek properties must return true, respectively).
I've made the following edits to your original code:
Replaced the Convert.ToString() calls with calls to this new function.
Made an assumption that you're intending to write to the file specified by the filepath parameter to your SaveAsHTML() function, and not the hard-coded path.
Wrapped the creation (and use, and disposal) of the System.Xml.XmlTextWriter in a using block (if you're not familiar, see What are the uses of “using” in C#?).
Following is your code with those changes.
public void SaveAsHTML(string filepath)
{
using (var html = new XmlTextWriter(filepath, System.Text.Encoding.UTF8))
{
html.WriteStartDocument();
html.WriteStartElement("html");
html.WriteRaw(XmlTextWriterToString(Head));
html.WriteRaw(XmlTextWriterToString(Body));
html.WriteEndElement();
html.WriteEndDocument();
html.Flush();
html.Close();
}
}
Another thing of which to be mindful is that, not knowing for sure from the code provided how they're being managed, the lifetimes of Head and Body are subject to the same exception-based resource leak potential that html was before wrapping it in the using block.
A final thought: the page for System.Xml.XmlTextWriter notes the following: Starting with the .NET Framework 2.0, we recommend that you create XmlWriter instances by using the XmlWriter.Create method and the XmlWriterSettings class to take advantage of new functionality.
The last line writes the value of XmlTextWriter.ToString(), which does not return the text representation of the XML you wrote. Try leaving off the last line, it looks like your XmlTextWriter is already writing to a file.
#PhilBrubaker's solution seems to be on the right track. There are still a few bugs in my code that I'm working towards getting a fix for, but the good news is that the casting seems to be working now.
protected string XmlToString(XmlWriter xmlBody)
{
XmlTextWriter textXmlBody = (XmlTextWriter)xmlBody;
textxmlBody.BaseStream.Position = 0;
using (var reader = new StreamReader(textXmlBody.BaseStream))
{
var result = reader.ReadToEnd();
reader.Dispose();
return result;
}
}
I've changed the input parameter type from XmlWriter and cast it explicitly to XmlTextWriter in the method, this is so that the method also works when the Create() method is used instead of an initialisation as recommended for .NET 2.0. It's not 100% reliable at the moment as XmlWriter doesn't always cast correctly to XmlTextWriter (depending on the features), but that's out of the scope for this thread and I'm investigating that separately.
Thanks for your help!
On a side note, the using block is something I haven't come across before, but it's provided so many solutions across the board for me. So thanks for that too!
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.
I want to create a HTML document and create table init using C#. I don't want to use ASP or any thing like that. I want to do this by using C# Windows Application.
The created document should not use MS Word or may not depend on any other app and save it to any folder (C:\) etc. It is totally independent of any other MS product and can run in any PC
Something like this :)
String exportdirectory = "c:";
StreamWriter sw;
sw = File.CreateText(exportDirectory + "filename.html");
sw.WriteLine("<table>");
sw.WriteLine("<tr>");
sw.WriteLine("<td>");
sw.WriteLine("contents of table!");
sw.WriteLine("</td>");
sw.WriteLine("</tr>");
sw.WriteLine("</table>");
sw.Close();
This is just creating a string ( maybe using a StringBuilder ) and appending data, then save it with a StreamWriter. If you want something more versatile, try to use some sort of stringtemplate, http://www.antlr.org/wiki/display/ST/StringTemplate+Documentation for example, this could allow you to isolate the "view" portion of your application allowing some sort of configuration to easily drive the output generation.
Well its not clear why you have such requirement or why are u mentioning MS Word... it doesn't make sense...
But what you want is your programme to Create a HTMl File.. (you dont even need ASP.NEt for that.. its for web server programming...)
My best guess is you want something to emit data in HTML format according to some user requirements.
For that..
Simply just create a file with HTML Extension and start Emitting HTML specific tags to it.
Few guys have already mentioned how to do that.
A quick and Dirty way would be somthing like this...
public void CreateFile()
{
StringBuilder sb = new StringBuilder();
sb.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \"> \r\n ");
sb.Append("<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
sb.Append("<head>\r\n");
sb.Append("<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" />\r\n");
sb.Append("<title>My HTMl Page</title>\r\n");
sb.Append("</head>\r\n");
sb.Append("<body>\r\n");
sb.Append("<table>\r\n");
//If you are emiting some data like a list of items
foreach (var item in Items)
{
sb.Append("<tr>\r\n");
sb.Append("<td>\r\n");
sb.Append(item.ToString());
sb.Append("</td>\r\n");
sb.Append("</tr>\r\n");
}
sb.Append("</table>\r\n");
sb.Append("</body>\r\n");
sb.Append("</html>\r\n");
System.IO.StreamWriter sr = new System.IO.StreamWriter("Your file path .html");
sr.Write(sb.ToString());
}
There is also a System.Web.UI.HTML32TextWriter class that is specially ment for this purpose but you didn't wanted anything from ASP, so...
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();