Trying to get at the BrowserCapabilities class via msxml:script but keep getting an error every time a save.
Code:
<msxsl:script language="c#" implements-prefix="randomTools">
<msxsl:assembly href="../bin/umbraco.dll"/>
<msxml:using namespace="System.Web" />
<![CDATA[
/// <summary>
/// Gets a random integer that falls between the specified limits
/// </summary>
/// <param name="lowerLimit">An integer that defines the lower-boundary of the range</param>
/// <param name="upperLimit">An integer that defines the upper-boundary of the range</param>
/// <returns>A random integer within the specified range</returns>
public static int GetRandom(int lowerLimit,int upperLimit)
{
Random r = umbraco.library.GetRandom();
int returnedNumber = 0;
lock (r)
{
returnedNumber = r.Next(lowerLimit, upperLimit);
}
return returnedNumber;
}
public string GetJavaScript()
{
System.Web.HttpBrowserCapabilities browser = Request.Browser;
return browser.EcmaScriptVersion.ToString();
}
]]>
</msxsl:script>
I know its not the GetRandom method and the new GetJavaScript isn't even called anywhere yet.
Error:
Error occured
Error in XSLT at line 75, char 17
73: public string GetJavaScript()
You'd probably need to explicitly call the Request object via "HttpContext.Current.Request"?
I'd recommend moving any C# code to a separate XsltExtension DLL ... as the <msxml:script> blocks compile for each page request - major performance hog!
<msxsl:script implements-prefix="myFuncs" language="JavaScript">
<![CDATA[
function getClientTime(){
var now = new Date();
return now.getHours();
}
]]>
</msxsl:script>
Replace with your method and using js get whatever u need regarding the browser.
@Lee, I don't think it's true that script blocks are compiled for each page request. If they were, there would be no reason to compile them with the
XslCompiledTransform()
in umbraco as the speed gain would be lost by the compile-time overhead I should think. Instead, the macro is compiled when it is saved in the umbraco UI or when the macro is run the first time after an application pool restart. At least that's my understanding (someone correct me if I'm wrong)
The real reason for not using script blocks is much more about security than performance... you can't use script blocks in a medium trust hosting evironment, which is why Benjamin is pushing for moving script blocks to app_code or dll extensions instead. Performance-wise, there shouldn't be a significant difference.
And, the issue with files being written to the temp folder is only when you have debugging turned on in your web.config, which you should not have in a production environment anyway. More details about temp folders and script blocks in the comments of this blog post...http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx
Be careful, <msxml:script> still hogs regardless of language. You could just write a <script type="text/javascript"> client-side block, or does the browsers capabilities need to be handled/rendered by XSLT?
@Doug, if <msxml:script> is present in the page, yes you are wrong. :-)
When script is present, the code is compiled on each and every request and compiles to the %TEMP% directory, which can very quickly overflow. Microsoft have an article on MSDN about the subject and it's vulnerability, hence the whole removing <msxml:script> on Medium Trust thing and subsequent workaround to use App_Code.
Normal XSLT macros can a) be cached and b) are compiled and cached on first request providing that <msxml:script> is not present.
P.S. Try debugging an Umbraco site with XSLT in it - Cassini will output the precise directory where the <msxml:script>-containing XSLT is compiled to - on Vista and Windows 7 this is somewhere in X:\Users\username\AppData\Local\Temp. This is done on each and every single request for an XSLT macro containing script - if you are running a high-traffic site this could easily max out your OS hard disk space if left unchecked.
P.P.S. This behaviour is by design with XslCompiledTransform, it's not a debug-dependent behaviour.
P.P.P.S. Performance is a massive improvement when not using <msxml:script>. App_Code gets cached at the ASP.NET and IIS level, <msxml:script> doesn't.
Aha... more research and more knowledge... what a great thing!
I'm all in favor of moving to app_code extensions for medium trust support but if the macros will be faster as well... heck, I'm there! (and yes, I've got a blog post half written to explain it all... oh for more hours in the week to do everything!)
Thanks, Benjamin, looking forward to 4.1 even more now!
The simple trickery of it is that App_Code gets treated exactly the same as traditional XSLT extensions do - as pre-compiled assemblies - it's the one place in a web application project where C#/VB code is compiled and treated just like a pre-compiled assembly or library.
This means they're cached = faster. They're strongly-typed = safer. And with the [XsltExtension] header, it's a doddle migrating your <msxml:script> over without breaking an inch of your functionality. And they debug in Visual Studio. And they work in Medium Trust. And with all of that, you can run more Umbraco sites on a single server = cheaper.
I'm assuming if you turn on caching for the Macro that corresponds to the XSLT with the <msxml:script> in it, then that would mitigate effect of the performance / DOS issue?
Unfortunately not. Turning on caching will add the macro to the ASP.NET application cache when first requested, but because of the recompilation every time, the generated temporary file has a unique name, which means the cached macro is never utilised, as there is high-level coupling between the cache and the temp files.
MSXML Script & .NET
Trying to get at the BrowserCapabilities class via msxml:script but keep getting an error every time a save.
Code:
I know its not the GetRandom method and the new GetJavaScript isn't even called anywhere yet.
Error:
75: >>> System.Web.HttpBrowserCapabilities browser = Request.Browser; <<<
Any ideas?
Is the Request object cont available in this context?
Neil
Hi Neil,
You'd probably need to explicitly call the Request object via "HttpContext.Current.Request"?
I'd recommend moving any C# code to a separate XsltExtension DLL ... as the <msxml:script> blocks compile for each page request - major performance hog!
Cheers, Lee.
Neil,
Why not get browser using js eg:
<msxsl:script implements-prefix="myFuncs" language="JavaScript"> <![CDATA[ function getClientTime(){ var now = new Date(); return now.getHours(); } ]]> </msxsl:script>
Replace with your method and using js get whatever u need regarding the browser.
Regards
Ismail
@Lee, I don't think it's true that script blocks are compiled for each page request. If they were, there would be no reason to compile them with the
in umbraco as the speed gain would be lost by the compile-time overhead I should think. Instead, the macro is compiled when it is saved in the umbraco UI or when the macro is run the first time after an application pool restart. At least that's my understanding (someone correct me if I'm wrong)
The real reason for not using script blocks is much more about security than performance... you can't use script blocks in a medium trust hosting evironment, which is why Benjamin is pushing for moving script blocks to app_code or dll extensions instead. Performance-wise, there shouldn't be a significant difference.
And, the issue with files being written to the temp folder is only when you have debugging turned on in your web.config, which you should not have in a production environment anyway. More details about temp folders and script blocks in the comments of this blog post...http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx
@Niel, you may find this blog post helpful as well, giving a good background for the kind of thing you're trying to do. http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx
cheers,
doug.
Be careful, <msxml:script> still hogs regardless of language. You could just write a <script type="text/javascript"> client-side block, or does the browsers capabilities need to be handled/rendered by XSLT?
Best,
Benjamin
@Doug, if <msxml:script> is present in the page, yes you are wrong. :-)
When script is present, the code is compiled on each and every request and compiles to the %TEMP% directory, which can very quickly overflow. Microsoft have an article on MSDN about the subject and it's vulnerability, hence the whole removing <msxml:script> on Medium Trust thing and subsequent workaround to use App_Code.
Normal XSLT macros can a) be cached and b) are compiled and cached on first request providing that <msxml:script> is not present.
Best,
Benjamin
P.S. Try debugging an Umbraco site with XSLT in it - Cassini will output the precise directory where the <msxml:script>-containing XSLT is compiled to - on Vista and Windows 7 this is somewhere in X:\Users\username\AppData\Local\Temp. This is done on each and every single request for an XSLT macro containing script - if you are running a high-traffic site this could easily max out your OS hard disk space if left unchecked.
P.P.S. This behaviour is by design with XslCompiledTransform, it's not a debug-dependent behaviour.
P.P.P.S. Performance is a massive improvement when not using <msxml:script>. App_Code gets cached at the ASP.NET and IIS level, <msxml:script> doesn't.
@Doug, Benjamin Howarth - a fountain of coding knowledge! I wasn't aware of any of these <msxml:script> issues until chatting Benjamin!
We live and learn!
Aha... more research and more knowledge... what a great thing!
I'm all in favor of moving to app_code extensions for medium trust support but if the macros will be faster as well... heck, I'm there! (and yes, I've got a blog post half written to explain it all... oh for more hours in the week to do everything!)
Thanks, Benjamin, looking forward to 4.1 even more now!
cheers,
doug.
The simple trickery of it is that App_Code gets treated exactly the same as traditional XSLT extensions do - as pre-compiled assemblies - it's the one place in a web application project where C#/VB code is compiled and treated just like a pre-compiled assembly or library.
This means they're cached = faster. They're strongly-typed = safer. And with the [XsltExtension] header, it's a doddle migrating your <msxml:script> over without breaking an inch of your functionality. And they debug in Visual Studio. And they work in Medium Trust. And with all of that, you can run more Umbraco sites on a single server = cheaper.
Oh heck, I'll just link to my Feb16 presentation :-D
Benjamin
Cheers,
Doug, your article helped fix my immediate problem - adding the namespace to "System.Web" isn't enough, I had to add the msxsl:assembly for it too.
However, I'll look to get the code out of here altogether and into App_Code as soon as I can.
Thanks for the info.
@Benjamin
I'm assuming if you turn on caching for the Macro that corresponds to the XSLT with the <msxml:script> in it, then that would mitigate effect of the performance / DOS issue?
Neil,
Unfortunately not. Turning on caching will add the macro to the ASP.NET application cache when first requested, but because of the recompilation every time, the generated temporary file has a unique name, which means the cached macro is never utilised, as there is high-level coupling between the cache and the temp files.
Best,
Benjamin
is working on a reply...