- A module then picks up on the querystring and sets some core data about that page within the xslt extensions framework.
- I call my xslt extension to return the cached data from the xslt extensions
My question is, is it possible to have the xslt extension called only once, and available to the entire page as a variable / parameter / whatever, so as to not make repeated calls to the method in multiple macros within the same page?
ie: something like <xsl:param name="$region" select="generaldata:GetCurrentRegion()"/> so as its available to any macro in the page without recalling it..
First of all, maybe you should look into using the default URL rewriting module that's already in Umbraco ;-)
Other than that, I'm not sure why you'd want to do this? I see no problem in calling an XSLT extension a few times. If you're trying to gain some performance, then just cache this XSLT macro as long as you can.
I am not aware of anything umbraco specific that would help you do this, so it would be a general ASP.NET question. I guess it could be compared to two usercontrols sharing data per request. I would think that your extension should have some internal caching that only lasts for one request cycle.
I am using the default url rewriting module (as in urlrewritingnet)...
Maybe I am misunderstanding a little, but surely adding the same xml data (which can be multiple pieces of data each potentially a few hundred lines long) to multiple xml / xslt translations happening on the same page is a little inefficient when compared to adding it just once to a global variable / xml cache, even more so when you consider each one of these calls could potentially be calling a WCF service (if its not previously been stored in the http runtime cache).
Our primary site is getting 100,000+ pagevisits per day (without bot traffic), thats a lot of xml?
Umbraco uses the urlRewriting.net model indeed, but it's being configured by the /config/urlrewriting.config (there's an example of how to set it up in the config file itself).
For caching: go to Developer > Macro's > then pick an XSLT macro and change the cache period from 0 to something you feel is appropriate. Then experience a world of difference!
It sounds a bit like you're trying to use XSLT as a complete programming language (and taking the object oriented approach). XSLT is mostly a templating language. If you want a true object oriented approach then I'd suggest you use user controls instead of XSLT macro's.
That being said, I'm quite sure that, with the right amount of caching, Umbraco can handle that kind of traffic just fine.
I am using xslt to translate the xml that is already returned from my wcf services, I don't consider I am using it for anything more than its intended to do, my previous cms had the entire template written in xslt, but all I am doing is templating a mix of xml from different sources.
I know how to set the cache, but am a little reluctant to cache what will be in excess of a few thousand pages on a page by page basis
mods - can you please unmark the solution, it has not solved my issue
Sorry, there is no tool for us to do that at the moment.
Did you take a look at the link I posted? You could build into your xslt extension that the first time it is called, it saves the xml to httpcontext.items and the remaining times it is called, it just fetches the xml from the httpcontext.items without querying the database (or wherever it gets the data).
You can do that, it's how things like GetXmlNodeById() work. The problem is probably with GetCurrentRegion(), which should be doing something like this:
public static XPathNodeIterator GetCurrentRegion() { var doc = new XmlDocument();
// Add items to the xml tree here
var navigator = doc.CreateNavigator().Select("/"); return navigator; }
Ahh the missing piece! Yes it would depend on what the Umbraco library stuff returns to allow it to work. So you have to return a navigator not just raw xml or an XML doc. Nicely cleared up Rick :)
Rick is correct on the static code, and it in turn pulls back from a httpruntime cache where it has been called in the last 2 minutes...
I was just thinking if there was the data in like the global data calling ie: like passing it in as $currentPage then the same xml wouldn't be generated multiple times in the same page.
In short, the data is always cached, but I wanted it to be called once and reused for every macro on that page, cause I could have 5 - 6 of the GetRegion type calls per page.
If its cached then there is no real performance hit when you pull it out in .net (well obviously there is some processing required but its so amazingly quick its not even worth mentioning). If you've cached it then you've don't enough there I think and relax :)
I did like Morten's idea of caching it in the HttpContext.Items collection, then it would only last for the length of that request and you know it would but up-to-date but application cache will do just as well from what you've described.
if you were to cache the amount of data we use for even 60 seconds using the httpcontext cache then the site will hit the 2GB IIS application limit and blow up in a matter of 30 - 40 mins. Just the core site gets around 3 million page views per month, it has at least 500,000 pages
My biggest issue right now with this scenario is that I have already got about 8 xslt macros on my page pulling similar data.
I am having to recreate the same variable in all of the macros, if i need to change anything its already getting labourious to modify all of the xslt files. Hence the reasoning for looking into this as a solution. I can't utilise the XSLT extension to do any more of the leg work for me... ie: each macro in the page already has
Ok sounds like the caching is as good as its going to get, your next problem is to DRY up your design/code
<xsl:include href="" /> might just do it (http://www.w3schools.com/xsl/el_include.asp)
I've not used it yet in Umbraco but have used it plenty in other XSL work I've done. Allows you to include another XSL file in another one. So you can have all your variables/param goodies in one file and then include that at the top (well before any templates at least) of each of the marco files that need these goodies.
out into another XSL (wrapped in all the usual XSL tags) and just include it in your Macros. That "should" work unless Umbraco is doing some weird custom magic under the hood rather than using the built in .net XSL processors but I doubt that.
I am such a div ;-) completely forgot if you declared your variables in the right place on an include, they would be available across other xslt's... It does indeed work, would kinda prefer that you could say run your common code (now in a common xslt file) once per page and have it available across the other xslt translations - this was the basis of the question in the first place, but this as a solution is satisfactory for now.
Glad you got it sorted. I'm really enjoying finding out the best way of build Umbraco sites, seems lots of quirks and tricks we all have would be nice to have them somewhere for reference (well I guess thats what this forum is for?).
Remember the XSL processors are damn good at there job (not as good as the old COM version though believe it or not, guy who wrote those has since been hired back by MS to re-jig their .net version which is groovy) so I would not worry too much about the fact you include it a few times. Under the hood they do all sorts of caching just as we would (and you have) in our apps.
Point in case, heres a nasty gotcha, sometime when you modify an include template it won't get picked up, this is because the file watcher for the cache is on the parent file not the child so you will have to "tickle" the parent for the mods to get picked up. An annoying (and horrific to debug) nasty which I lost a few hours over long ago.
Global XSLT Extensions
I have a whole bunch of extensions built for our site and I am trying to "lean it out". A good example of which is as follows
- The url "http://www.mydomain.com/regions/north" is called, I have a rewrite rule that rewrites it to http://www.mydomain.com/regions/north?region=north.
- A module then picks up on the querystring and sets some core data about that page within the xslt extensions framework.
- I call my xslt extension to return the cached data from the xslt extensions
My question is, is it possible to have the xslt extension called only once, and available to the entire page as a variable / parameter / whatever, so as to not make repeated calls to the method in multiple macros within the same page?
ie: something like <xsl:param name="$region" select="generaldata:GetCurrentRegion()"/> so as its available to any macro in the page without recalling it..
First of all, maybe you should look into using the default URL rewriting module that's already in Umbraco ;-)
Other than that, I'm not sure why you'd want to do this? I see no problem in calling an XSLT extension a few times. If you're trying to gain some performance, then just cache this XSLT macro as long as you can.
I am not aware of anything umbraco specific that would help you do this, so it would be a general ASP.NET question. I guess it could be compared to two usercontrols sharing data per request. I would think that your extension should have some internal caching that only lasts for one request cycle.
This just might be it:
http://aspnet.4guysfromrolla.com/articles/060904-1.aspx
I am using the default url rewriting module (as in urlrewritingnet)...
Maybe I am misunderstanding a little, but surely adding the same xml data (which can be multiple pieces of data each potentially a few hundred lines long) to multiple xml / xslt translations happening on the same page is a little inefficient when compared to adding it just once to a global variable / xml cache, even more so when you consider each one of these calls could potentially be calling a WCF service (if its not previously been stored in the http runtime cache).
Our primary site is getting 100,000+ pagevisits per day (without bot traffic), thats a lot of xml?
The core WCF data already has caching set up where appropriate, and the site is not performing as well as my own CMS solution.
mods - can you please unmark the solution, it has not solved my issue
Umbraco uses the urlRewriting.net model indeed, but it's being configured by the /config/urlrewriting.config (there's an example of how to set it up in the config file itself).
For caching: go to Developer > Macro's > then pick an XSLT macro and change the cache period from 0 to something you feel is appropriate. Then experience a world of difference!
It sounds a bit like you're trying to use XSLT as a complete programming language (and taking the object oriented approach). XSLT is mostly a templating language. If you want a true object oriented approach then I'd suggest you use user controls instead of XSLT macro's.
That being said, I'm quite sure that, with the right amount of caching, Umbraco can handle that kind of traffic just fine.
I am using the urlrewriting correctly.
I am using xslt to translate the xml that is already returned from my wcf services, I don't consider I am using it for anything more than its intended to do, my previous cms had the entire template written in xslt, but all I am doing is templating a mix of xml from different sources.
I know how to set the cache, but am a little reluctant to cache what will be in excess of a few thousand pages on a page by page basis
Sorry, there is no tool for us to do that at the moment.
Did you take a look at the link I posted? You could build into your xslt extension that the first time it is called, it saves the xml to httpcontext.items and the remaining times it is called, it just fetches the xml from the httpcontext.items without querying the database (or wherever it gets the data).
Would this be a solution?
Am I missing something here? Is it not possible to stash your XML nodeset into a variable like you said?
<xsl:variable name="region" select="generaldata:GetCurrentRegion()"/>
(couple of points, I'd use a variable rather than param and you should have have a $ in your name when you declare it)
Then you "should" be able to do:
<xsl:value-of select="$region/name" />
(assuming a name element exists in the returned XML of course)
I do exactly this in one of my Macros using umbracos extentions:
<xsl:variable name="mediaID" select="/macro/mediaID"/>
<xsl:if test="$mediaID != ''">
<xsl:variable name="media" select="umbraco.library:GetMedia( '1135', 'false' )" />
<xsl:variable name="url" select="$media/data[@alias='umbracoFile']" />
</xsl:if>
<img src="{$url}" />
So I can't see why it would not work.
You can do that, it's how things like GetXmlNodeById() work. The problem is probably with GetCurrentRegion(), which should be doing something like this:
public static XPathNodeIterator GetCurrentRegion()
{
var doc = new XmlDocument();
// Add items to the xml tree here
var navigator = doc.CreateNavigator().Select("/");
return navigator;
}
Ahh the missing piece! Yes it would depend on what the Umbraco library stuff returns to allow it to work. So you have to return a navigator not just raw xml or an XML doc. Nicely cleared up Rick :)
Rick is correct on the static code, and it in turn pulls back from a httpruntime cache where it has been called in the last 2 minutes...
I was just thinking if there was the data in like the global data calling ie: like passing it in as $currentPage then the same xml wouldn't be generated multiple times in the same page.
In short, the data is always cached, but I wanted it to be called once and reused for every macro on that page, cause I could have 5 - 6 of the GetRegion type calls per page.
If its cached then there is no real performance hit when you pull it out in .net (well obviously there is some processing required but its so amazingly quick its not even worth mentioning). If you've cached it then you've don't enough there I think and relax :)
I did like Morten's idea of caching it in the HttpContext.Items collection, then it would only last for the length of that request and you know it would but up-to-date but application cache will do just as well from what you've described.
if you were to cache the amount of data we use for even 60 seconds using the httpcontext cache then the site will hit the 2GB IIS application limit and blow up in a matter of 30 - 40 mins. Just the core site gets around 3 million page views per month, it has at least 500,000 pages
My biggest issue right now with this scenario is that I have already got about 8 xslt macros on my page pulling similar data.
I am having to recreate the same variable in all of the macros, if i need to change anything its already getting labourious to modify all of the xslt files. Hence the reasoning for looking into this as a solution. I can't utilise the XSLT extension to do any more of the leg work for me... ie: each macro in the page already has
<xsl:variable name="region" select="generaldata:GetCurrentRegion()"/>
<xsl:variable name="pagedata" select="generaldata:GetCurrentPageData()"/>
<xsl:variable name="make" select="makedata:GetCurrentMake()"/>
as a bare minimum, plus any additional calls specific to the macro.
This problem will only get worse, so if anyone can think of an alternative idea...
Thank you in advance
In short, httpruntime cache is the only one available to me ;-)
Ok sounds like the caching is as good as its going to get, your next problem is to DRY up your design/code
<xsl:include href="" /> might just do it (http://www.w3schools.com/xsl/el_include.asp)
I've not used it yet in Umbraco but have used it plenty in other XSL work I've done. Allows you to include another XSL file in another one. So you can have all your variables/param goodies in one file and then include that at the top (well before any templates at least) of each of the marco files that need these goodies.
So you can move this lot:
<xsl:variable name="region" select="generaldata:GetCurrentRegion()"/>
<xsl:variable name="pagedata" select="generaldata:GetCurrentPageData()"/>
<xsl:variable name="make" select="makedata:GetCurrentMake()"/>
out into another XSL (wrapped in all the usual XSL tags) and just include it in your Macros. That "should" work unless Umbraco is doing some weird custom magic under the hood rather than using the built in .net XSL processors but I doubt that.
I am such a div ;-) completely forgot if you declared your variables in the right place on an include, they would be available across other xslt's... It does indeed work, would kinda prefer that you could say run your common code (now in a common xslt file) once per page and have it available across the other xslt translations - this was the basis of the question in the first place, but this as a solution is satisfactory for now.
I'm more of a <span> man than a div :)
Glad you got it sorted. I'm really enjoying finding out the best way of build Umbraco sites, seems lots of quirks and tricks we all have would be nice to have them somewhere for reference (well I guess thats what this forum is for?).
Remember the XSL processors are damn good at there job (not as good as the old COM version though believe it or not, guy who wrote those has since been hired back by MS to re-jig their .net version which is groovy) so I would not worry too much about the fact you include it a few times. Under the hood they do all sorts of caching just as we would (and you have) in our apps.
Point in case, heres a nasty gotcha, sometime when you modify an include template it won't get picked up, this is because the file watcher for the cache is on the parent file not the child so you will have to "tickle" the parent for the mods to get picked up. An annoying (and horrific to debug) nasty which I lost a few hours over long ago.
is working on a reply...