Programmatically Rendering an Umbraco Node - asp.net

I'm using Umbraco 4.5.2 and I have a node with a number of child nodes. Each child node represents a fragment of HTML that will be rendered in a control. The control loops over all the child nodes and renders them.
For the moment I have a bit of a dirty hack going in order to get the thing going (still fairly new to Umbraco) but I'd rather do this better.
The code I have at the moment looks like this:
private string GetItemHtml(Node node)
{
// Work out the URL of the HTML fragment
string url = "http://" + Context.Request.Url.Host +
":" + Context.Request.Url.Port +
node.Url;
// Get the fragment by making a call to the page
WebRequest req = WebRequest.Create(url);
WebResponse res = req.GetResponse();
using (Stream stream = res.GetResponseStream())
{
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
return result;
}
}
As you can see, it is really rather ugly. I'm hoping there is some way to get this without having to make many HTTP calls, even if it is looping back to the same server - it can't be very efficient.

You can use the API to achieve what you are asking, try looking at the umbraco.library.RenderTemplate method. It accepts two parameters, the first is the id of the node to render and the second is the id of the template to use when rendering the node.

This is probably much easier to build using xslt in umbraco. If you want to do something that is not possible in xslt, you can create a XSLT extension function (implemented in C#, called from XSLT) to do that (see http://en.wikibooks.org/wiki/Umbraco/Create_xslt_exstension_like_umbraco.Library_in_C for more info).
For a sample XSLT that list child pages, see BlogListPosts.xslt in the umbraco blog package:
http://blog4umbraco.codeplex.com/SourceControl/changeset/view/54177#916032

Related

Capture text from an Aspx page

I am trying to come up with a neat solution to create automated json schema markup on my aspx pages. The markup in question is FAQPage, but that's irrelevant.
I decided that I needed to scrape the content of the current page to find questions and answers. After a few false starts I came across the HtmlAgilityPack plugin which enables me to achieve what I want, but I've come across some issues.
The HtmlAgililtyPack parser can be initiated in a number of ways, but the only one I could get to work for me and my scenario (scrape current page) was to feed in a string.
First, I created an asp ID with a runat="server" tag.
To get the string, I used HTMLTextWriter; here's the code:
static string ConvertControlToString(Control ctl)
{
string s = null;
var sw = new StringWriter();
using (var w = new HtmlTextWriter(sw))
{
ctl.RenderControl(w);
s = sw.ToString();
}
return s;
}
Now, all that works fine - in most cases.
However, I'm running into edge cases where I use scriptmanager and updatepanels. I suspect there will be more. The error is: ... must be inside a form control with a runat="server". Of course it is but the rendercontrol doesn't realise it.
So, two questions:
Is there a way to feed HtmlAgilityPack parser in another way that doesn't
require a string (and that won't loop)?
Is there a better way to scrape the text other than Control.RenderControl() that won't cause errors?
Incidentally, I've found a solution to the problem I'm having but it involves manipulating each affected page, and that's not great.
So, thought I'd throw it out there and see if there are better workarounds or a better solution.
You can load HTML in a few different ways but ultimately HTML is a string so this is what the parser will operate on. I'm not sure what you mean about looping.
Rather than rendering controls as HTML and then parsing them it might be better to let the entire page load and parse it after it has rendered, this allows your javascript/updatepanels to finish transforming the page before you parse the HTML.
The LoadFromBrowser method (I believe) loads the specified url in a headless browser, allows any javascript to run and then parses the resulting HTML: https://html-agility-pack.net/from-browser
If you need to attach authentication credentials there is a question addressing that here: HtmlAgilityPack and Authentication
Alternatively (keeping your existing code) you might try instantiating a new HtmlControl with the tag "form", adding the the control passed in to ConvertControlToString to it and then parsing that which may avoid your error. You may need to check the control doesn't already have a form tag, this approach doesn't address javascript/update panels and I'm not 100% sure it would work.
HtmlGenericControl form = new HtmlGenericControl("form");
Control ctl = new Control();
form.Controls.Add(ctl);
string s = string.Empty;
var sw = new System.IO.StringWriter();
using (var w = new HtmlTextWriter(sw))
{
form.RenderControl(w);
s = sw.ToString();
}

How to pass data between pages without sessions in ASP.net MVC

I have one application in which I want to pass data between Pages (Views) without sessions. Actually I want to apply some settings to all the pages using query string.
For example if my link is like "http://example.com?data=test1", then I want to append this query string to all the link there after and if there is no query string then normal flow.
I was thinking if there is any way that if we get the query string in any link for the web application then some application level user specific property can be set which can be used for subsequent pages.
Thanks,
Ashwani
You can get the query string using the
Request.Url.Query
and on your links to the other page you can send it.
Here is an idea of how you can find and change your page:
public abstract class BasePage : System.Web.UI.Page
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
// now you render the page on this buffer
base.Render(htmlWriter);
// get the buffer on a string
string html = stringWriter.ToString();
// manipulate your string html, and search all your links (hope full find only the links)
// this is a simple example of replace, THAT PROBABLY not work and need fix
html = html.Replace(".aspx", ".aspx?" + Request.Url.Query);
writer.Write(html);
}
}
I do not suggest it how ever, and I think that you must find some other way to avoid to manipulate all your links...
I don't undestand what kind of data are you trying to pass. Because it sounds weird to me the idea of trapping all links.
Anyway, I believe you may find the class TempData usefull for passing data between redirects.
And a final warning, be carefull about TempData, it has changed a little between MVC 1 and 2:
ASPNET MVC2: TempData Now Persists

Make an ASP.NET Web service output an RSS Feed

I have been writing some Web services to be used by a few different client apps and i was trying to write a web service method that simply outputs an RSS XML Feed.
I can create the XML using an XmlTextWriter Object
Then i have tryed outputing to the Response (like i have done in the past when its an aspx page) but this only works it the return type is void (and still doesnt seem to output properly)
Then i tryed making the return type a string and using a StringWriter to output the xml from the XmlTextWriter but the output is then wrapped in a tag.
How can i do this?
Obviously create the interfaces and rest of the WCF service as normal.
Mark the class with the following attribute
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
And then this function
public Stream GetRSS()
{
string output;
//output = some_text;
MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(output));
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
return ms;
}
I have some code for this, but it's more than will fit well in an SO post (about 1000 lines). It's really not that hard; the schema is simple enough you can do it yourself, but you don't have to: there are several components you can just plug in to create the xml for you.
You should see this question:
ASP.Net RSS feed
If you must use ASMX, then you can return an XmlDocument. Build the feed XML however you like, but then return the XmlDocument from your web method.

Dynamic XML

What's the ideal way of generating XML without creating and saving a file?
I'm thinking of using an ASP.NET page with code behind to generate the markup as XML.
Is this possible? Or would you have an alternative way?
I have a flash component that reads an XML file and I need to dynamically generate this file. I don't have write permission so I won't have the ability to create and save a file.
I was thinking of having an application page that grabs the data and provide property methods to generate the xml on the Settings.xml.aspx page with Settings.xml.aspx.cs codebehind.
Thanks.
The easiest way is to use System.Xml.XmlDocument or System.Xml.Linq.XDocument to build up the document. Both can be streamed out to the Response.OutputStream.
The smoothest approach (especially if you turn off buffering) is simply to create an XmlTextWriter round the Response.OutputStream. This is a forward only approach to generate XML but if the output is large it means you need less memory and content starts to arrive at the client earlier.
System.Xml.XmlDocument ?
In fact there are many ways to do it. It all depends on your needs. Maybe you could have a look at some examples of XDocument (or XmlDocument in .NET 2.0) and XmlWriter, none of these require you to save the XML to a file. You can either keep the object model in memory when using XDocument or write to a MemoryStream when using XmlWriter:
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (XmlWriter writer = XmlWriter.Create (stream, settings))
{
writer.WriteStartElement ("customer");
writer.WriteElementString ("firstname", "Jim");
writer.WriteElementString ("lastname"," Bo");
writer.WriteEndElement();
}
// do further processing with the stream
}
The difference between the two is basically that the first one gives you access to the DOM whereas the second one simply writes out XML to an underlying stream.
Unfortunately, without knowing more details this question can only be answered vaguely.
Yes, it is perfectly feasible to generate XML "on the fly". Take a look at the XmlDocument class. And more info here.

How to consume data from an ASP.NET MVC from a different website?

I am playing around with ASP.NET MVC for the first time, so I apologize in advance if this sounds academic.
I have created a simple content management system using ASP.NET MVC. The url to retrieve a list of content, in this case, announcements, looks like:
http://www.mydomain.com/announcements/list/10
This will return the top ten most recent announcements.
My questions are as follows:
Is it possible for any website to consume this service? Or would I also have to expose it using something like WCF?
What are some examples, of how to consume this service to display this data on another website? I'm primarily programming in the .NET world, but I'm thinking if I could consume the service using javascript, or do something with Json, it could really work for any technology.
I am looking to dynamically generate something like the following output:
<div class="announcement">
<h1>Title</h1>
<h2>Posted Date</h3>
<p>Teaser</p>
More
</div>
For now ... is it possible to return an Html representation and display it in a webpage? Is this possible using just Javascript?
There is nothing to stop another client just scraping that particular page and parsing through your HTML.
However you would probably want another view using the same controller that generates the data that doesnt contain excess formatting HTML etc. Maybe look at using a well known format such as RSS?
You can return the result as JSON using something like below:
public JsonResult GetResults()
{
return Json(new { message = "SUCCESS" });
}
I think I would offer a view which contains the items as xml and another that returns JSON that way you have the best of both worlds.
I have a small post about how to call and return something using MVC, JQuery and JSON here.
Your ROUTE is perfectly fine and consumable by anyone. The trick is to how you want to expose your data for that route. You said XML. sure. You can even do JSon or Html or just plain ole text.
The trick would be in your controller Method and the view result object.
Here's the list of main view results :-
ActionResult
ContentResult
EmptyResult
JsonResult
RedirectResult
eg.
public <ContentResult> AnnouncmentIndex(int numberOfAnnouncements)
{
// Generate your Xml dynamically.
string xml = "<div class=\"announcement\"><h1>Title</h1><h2>Posted Date</h3><p>Teaser</p>More</div>"
Response.ContentType = "application/xml"; // For extra bonus points!
return Content(xml);
}

Resources