I would guess this is a file permission issue. Check that the owner of the site's application pool has at least modify permission to the /xslt/xsltsearch.xslt file (and the entire /xslt folder for that matter). That should resolve it.
But if not, try viewing the search.aspx page with debugging information shown as well. http://example.com/search.aspx?umbDebugShowTrace=true (change the domain and path to the search page as appropriate for your site). Scroll down and you should see some red text and a more complete description of the problem. That should help pinpoint the issue.
Error loading XSLT XSLTsearch.xslt Could not load file or assembly 'file:///C:\WINDOWS\TEMP\k8ur_9_j.dll' or one of its dependencies. Access is denied. at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
The name of the dll changes when I refresh the page.
The host provider had no idea what the message could mean.
Is it a dll that is generated from the XsltSearch Package?
It isn't related to XSLTsearch specifically because it has only 1 file, the /xslt/xsltsearch.xslt file.
But there's definitely a file permission problem with something being loaded. I would guess it is a dll in the /bin folder since reflection is being called. It seems there's a need to write a temporary file that isn't allowed by the host. Any chance the host would allow CRUD permissions to the temp folder, at least temporarily to see if that resolves the issue?
What happens is that because the XSLT search contains some inline C# code, the XSLT parser will dynamically compile a dll assembly in order to run the code. This is just the way .Net works in this respect. This assembly will be written to the /temp folder because it is just that, temporary.
I hope this explains a bit about why you need the permissions, and maybe your host knows a workaround for this sort of requirement.
Doug - in a hosted environment c:\windows\temp typically is not something the ISP wants you to write to
Have you thought of peeling all your embedded C# code out of the xlst and into app_code as a class then referencing this code from the xslt - when accessed it would auto-compile itself into the bin folder which ISPs more frequently give you a way to grant full acess to.
public static int indexOfMany(string search, string[] find) { int foundIndex = search.Length; foreach (string toFind in find) foundIndex = Math.Min(foundIndex, search.ToUpper().IndexOf(toFind.ToUpper())); return foundIndex; }
public static string contextOfFind(string data, string find, int wordsBefore, int wordsAfter, int maxChars) { // NOTE: This only makes sense if the searchFields and previewFields are identical. // Otherwise, you can find a match but not see its context.
while (output.Length > maxChars) output = output.Substring(0, output.LastIndexOf(" "));
if (after.Length > wordsAfter) output += " ...";
return output; }
catch { return ""; }
}
public static string surround(string data, string find, string before, string after) { // searches for find within data, then surrounds it with before and after tags // note: replace with the actual text found, to preserve the case
string nextWord = getFirstElement(find, " "); string remainingWords = find; while (nextWord != "") { int index = data.ToLower().IndexOf(nextWord.ToLower()); while (index > -1) { string replacement = before + data.Substring(index, nextWord.Length) + after; data = data.Substring(0, index) + replacement + data.Substring(index + nextWord.Length); index = data.ToLower().IndexOf(nextWord.ToLower(), index + replacement.Length); } remainingWords = removeFirstElement(remainingWords, " "); nextWord = getFirstElement(remainingWords, " "); } return data; }
public static long getTime() { // get current time return DateTime.Now.Ticks; }
public static double getTimeSpan(long startTime, long stopTime) { // return time span in milliseconds return TimeSpan.FromTicks(stopTime - startTime).TotalMilliseconds; }
public static string getFirstElement(string delimitedList, string delimiter) { // strip all leading delimiters while (delimitedList.IndexOf(delimiter) == 0) delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();
if (delimitedList.Length == 0) return "";
// searching on a phrase if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1) return delimitedList.Substring(1, delimitedList.IndexOf("'", 1) - 1);
public static string getParameter(string value, string defaultValue) { if (value == "") return defaultValue; return value.Replace(" ", ""); }
public static string getListParameter(string value, string defaultValue) { // remove all spaces value = value.Replace(" ", ""); defaultValue = defaultValue.Replace(" ", "");
if (value == "") return "," + defaultValue + ","; return "," + value + ","; } } }
Hopes this gives you a kick in the right direction - this has been tested for umbracoo 4.0.3, but i imagine it would work for previous versions as well. I have not published this as a package as it would violate some licence in this crazy world, but i works.
XSLTsearch is getting an update for umbraco 4.1 and medium trust... the inline c# code will be put into an xslt extension in the app_code folder. That will make two files but both will be available for easy editing. App_code xslt extensions are an umbraco 4.1 feature to support medium trust. This is the solution that's coming.
Setting umbracoDebugMode=false in the web.config should resolve the issue in most cases with umbraco 4.0.3 or earlier. In umbraco 4.1 I'll update XSLTsearch to put the c# code into an app_code xslt extension, which will definitely resolve the issue going forward.
XsltSearch: Error reading XSLT file
Hi
I recently uploaded an Umbraco project to a remote server. I installed the XsltSearch package which worked out perfect on my local machine.
We had some issues with the provider and getting Umbraco to run on full trust, but it all worked out after a while.
Now the only single thing that doesnt work on the server is the XsltSearch.
All I get on the search.aspx page is:
I have other xslt files in the solution that appears to wotk fine.
Anybody who had similar experience, who know what causes this?
best regards
Sune Fengel
I would guess this is a file permission issue. Check that the owner of the site's application pool has at least modify permission to the /xslt/xsltsearch.xslt file (and the entire /xslt folder for that matter). That should resolve it.
But if not, try viewing the search.aspx page with debugging information shown as well. http://example.com/search.aspx?umbDebugShowTrace=true (change the domain and path to the search page as appropriate for your site). Scroll down and you should see some red text and a more complete description of the problem. That should help pinpoint the issue.
cheers,
doug.
Great! Thanks for the help.
I found the error in the debug trace.
it says
Error loading XSLT XSLTsearch.xslt
Could not load file or assembly 'file:///C:\WINDOWS\TEMP\k8ur_9_j.dll' or one of its dependencies. Access is denied.
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
The name of the dll changes when I refresh the page.
The host provider had no idea what the message could mean.
Is it a dll that is generated from the XsltSearch Package?
best regards
Sune Fengel
It isn't related to XSLTsearch specifically because it has only 1 file, the /xslt/xsltsearch.xslt file.
But there's definitely a file permission problem with something being loaded. I would guess it is a dll in the /bin folder since reflection is being called. It seems there's a need to write a temporary file that isn't allowed by the host. Any chance the host would allow CRUD permissions to the temp folder, at least temporarily to see if that resolves the issue?
cheers,
doug.
Thanks for the swift replies.
I didnt think it was the xslt search, but I thougt I'd ask just in case.
I'll ask the host provider if they'll allow CRUD permissions on the temp folder.
best regards
Sune Fengel
As Doug says, it's a problem with permissions.
What happens is that because the XSLT search contains some inline C# code, the XSLT parser will dynamically compile a dll assembly in order to run the code. This is just the way .Net works in this respect. This assembly will be written to the /temp folder because it is just that, temporary.
I hope this explains a bit about why you need the permissions, and maybe your host knows a workaround for this sort of requirement.
Wow, I learn something new every day. Thanks, Morten!!
cheers,
doug.
Hi Everyone,
I am having what I think is possibly the same problem, could you tell me where the temp folder should be located so I can the permssions?
Many thanks
Lee
Hello Lee. I had to set permissions on the "C:/windows/temp" folder to resolve this problem.
Barney
See my post: http://our.umbraco.org/forum/getting-started/questions-about-runway-and-modules/3511-Problem-with-CWS2-search---suspect-permissions---anyone-help
Doug - in a hosted environment c:\windows\temp typically is not something the ISP wants you to write to
Have you thought of peeling all your embedded C# code out of the xlst and into app_code as a class then referencing this code from the xslt - when accessed it would auto-compile itself into the bin folder which ISPs more frequently give you a way to grant full acess to.
Something to think about anyways.
I didn't know that either.
Doug - Although it's great having XsltSearch in a single file, maybe you could provide a version that ran it's c# code via xslt extensions?
I successfully pulled the c# code out of the xslt for this search to solve this problem by creating a custom xslt extension class.
This was very easy to do :)
The problem with compiling to temp in a hosted environment is no longer an issue once you do this.
Steps required to do this:
Step 1 - Here's the class file I created -
Step 2 - I modified my xlstextensions.config file like this
Step 3 - and finally I changed up the transform line on my XSLTSearch style like this
And... I got rid of the CDATA section of C# code at the bottom
That's it.
Works like a charm.
Beautiful!
Got it to work by extracting it to a dll.
thanks a lot
- Sune
It is absolutely possible to build a DLL with the c# code implemented directly in the xsltsearch.xslt file.
<ext assembly="/bin/PercipientStudios" type="PercipientStudio.XsltSearch" alias="ps" />
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umbraco.library="urn:umbraco.library"
xmlns:ps ="urn:ps"
exclude-result-prefixes="umbraco.library ps">
--------------------------------------------------
using System;
namespace PercipientStudios
{
public class XsltSearch
{
public static double power(double x, double y)
{
return Math.Pow(x, y);
}
public static string uppercase(string s)
{
return s.ToUpper();
}
public static string escapeSearchTerms(string data)
{
return data.Replace(Convert.ToString((char)38), "&");
}
public static string unescapeSearchTerms(string data)
{
return data.Replace("&", Convert.ToString((char)38));
}
public static double hitCount(string data, string find)
{
if (data == null || data == "" || find == null || find == "")
return 0;
string after = data.ToLower().Replace(find.ToLower(), "");
return (data.Length - after.Length) / find.Length;
}
public static int indexOfMany(string search, string[] find)
{
int foundIndex = search.Length;
foreach (string toFind in find)
foundIndex = Math.Min(foundIndex, search.ToUpper().IndexOf(toFind.ToUpper()));
return foundIndex;
}
public static string contextOfFind(string data, string find, int wordsBefore, int wordsAfter, int maxChars)
{
// NOTE: This only makes sense if the searchFields and previewFields are identical.
// Otherwise, you can find a match but not see its context.
try
{
if (data.Length == 0)
return "";
string findList = getFirstElement(find, " ");
find = removeFirstElement(find, " ");
while (find != "")
{
findList += "|" + getFirstElement(find, " ").ToUpper();
find = removeFirstElement(find, " ");
}
string[] findPhrases = findList.Split('|');
string remaining = data;
string output = "";
string[] after = new string[0];
while (output.Length < maxChars && remaining != "")
{
int findIndex = indexOfMany(remaining, findPhrases);
if (findIndex == -1)
break;
findIndex = remaining.IndexOf(" ", findIndex);
if (findIndex == -1)
{
output += remaining;
break;
}
string[] before = remaining.Substring(0, findIndex).Split(' ');
if (before.Length > wordsBefore)
output += " ... ";
output += String.Join(" ", before, Math.Max(0, before.Length - wordsBefore), Math.Min(before.Length, wordsBefore));
remaining = remaining.Substring(findIndex);
after = remaining.Split(' ');
string afterText = String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));
int nextFindIndex = indexOfMany(afterText, findPhrases);
if (nextFindIndex > -1)
nextFindIndex = afterText.IndexOf(" ", nextFindIndex);
while (nextFindIndex > -1)
{
output += afterText.Substring(0, nextFindIndex);
remaining = remaining.Substring(nextFindIndex);
after = remaining.Split(' ');
afterText = String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));
nextFindIndex = indexOfMany(afterText, findPhrases);
if (nextFindIndex > -1)
nextFindIndex = afterText.IndexOf(" ", nextFindIndex);
}
output += afterText;
remaining = remaining.Substring(afterText.Length);
}
maxChars = (after.Length > wordsAfter) ? maxChars - 3 : maxChars;
output = output.Trim();
while (output.Length > maxChars)
output = output.Substring(0, output.LastIndexOf(" "));
if (after.Length > wordsAfter)
output += " ...";
return output;
}
catch
{
return "";
}
}
public static string surround(string data, string find, string before, string after)
{
// searches for find within data, then surrounds it with before and after tags
// note: replace with the actual text found, to preserve the case
string nextWord = getFirstElement(find, " ");
string remainingWords = find;
while (nextWord != "")
{
int index = data.ToLower().IndexOf(nextWord.ToLower());
while (index > -1)
{
string replacement = before + data.Substring(index, nextWord.Length) + after;
data = data.Substring(0, index) + replacement + data.Substring(index + nextWord.Length);
index = data.ToLower().IndexOf(nextWord.ToLower(), index + replacement.Length);
}
remainingWords = removeFirstElement(remainingWords, " ");
nextWord = getFirstElement(remainingWords, " ");
}
return data;
}
public static long getTime()
{
// get current time
return DateTime.Now.Ticks;
}
public static double getTimeSpan(long startTime, long stopTime)
{
// return time span in milliseconds
return TimeSpan.FromTicks(stopTime - startTime).TotalMilliseconds;
}
public static string getFirstElement(string delimitedList, string delimiter)
{
// strip all leading delimiters
while (delimitedList.IndexOf(delimiter) == 0)
delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();
if (delimitedList.Length == 0)
return "";
// searching on a phrase
if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
return delimitedList.Substring(1, delimitedList.IndexOf("'", 1) - 1);
if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
return delimitedList.Substring(1, delimitedList.IndexOf("\"", 1) - 1);
// only one element
if (delimitedList.IndexOf(delimiter) == -1)
return delimitedList.Trim();
// return first element
return delimitedList.Split(delimiter.ToCharArray()[0])[0].Trim();
}
public static string removeFirstElement(string delimitedList, string delimiter)
{
string firstElement = getFirstElement(delimitedList, delimiter);
// handle phrase delimiters
if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
return delimitedList.Remove(0, firstElement.Length + 2).Trim();
if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
return delimitedList.Remove(0, firstElement.Length + 2).Trim();
while (delimitedList.IndexOf(delimiter) == 0)
delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();
return delimitedList.Remove(0, firstElement.Length).Trim();
}
public static string getParameter(string value, string defaultValue)
{
if (value == "")
return defaultValue;
return value.Replace(" ", "");
}
public static string getListParameter(string value, string defaultValue)
{
// remove all spaces
value = value.Replace(" ", "");
defaultValue = defaultValue.Replace(" ", "");
if (value == "")
return "," + defaultValue + ",";
return "," + value + ",";
}
}
}
Hopes this gives you a kick in the right direction - this has been tested for umbracoo 4.0.3, but i imagine it would work for previous versions as well. I have not published this as a package as it would violate some licence in this crazy world, but i works.
<Bo /> - www.boblog.dk - not running yet though.
XSLTsearch is getting an update for umbraco 4.1 and medium trust... the inline c# code will be put into an xslt extension in the app_code folder. That will make two files but both will be available for easy editing. App_code xslt extensions are an umbraco 4.1 feature to support medium trust. This is the solution that's coming.
Until then, setting
should resolve (at least most) of the problems.
You can read more about the reason for this in the comments of my blog post, http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx
cheers,
doug.
Hi Guys,
Doug actually answered this problem very nicely in his comments on his blog.
http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx
It seems that by setting: umbracoDebugMode = false in the web.config it should solve most of the problems.
It did for me anyway. Cheers Mr Robar.
Steve
You're very welcome, Steve!
Setting umbracoDebugMode=false in the web.config should resolve the issue in most cases with umbraco 4.0.3 or earlier. In umbraco 4.1 I'll update XSLTsearch to put the c# code into an app_code xslt extension, which will definitely resolve the issue going forward.
cheers,
doug.
is working on a reply...