I'm trying to use VirtualPathUtility.ToAbsolute
to resolve app-relative paths, such as ~/MyPage.aspx
, to application-absolute paths, such as /MySite/MyApp/MyPage.aspx
. However, with some paths, I receive an HttpException
saying that my path is "not a valid virtual path". Examples:
// This works:
var abs1 = VirtualPathUtility.ToAbsolute("~/MyPage.aspx#anchor");
// This errors:
var abs2 = VirtualPathUtility.ToAbsolute("~/MyPage.aspx?key=value");
What's going on?
Because you're using .NET 3.5, you're using the 2.0
System.Web
assembly, which has the defect that ?
is considered an illegal path character by this method. This is mentioned in the community comments on the version-specific MSDN page.
By disassembling, it can be seen that the call ends up in the (internal
) VirtualPath.Create
, which has:
else if (VirtualPath.ContainsIllegalVirtualPathChars(virtualPath))
{
throw new HttpException(System.Web.SR.GetString("Invalid_vpath", new object[1]
{
(object) virtualPath
}));
}
which references
private static char[] s_illegalVirtualPathChars = new char[4]
{
':',
'?',
'*',
char.MinValue
};
Some of these can reasonably be regarded as bad characters for a path, but ?
shouldn't really be so rejected.
Disassembly of the 4.0
System.Web
shows that VirtualPath.Create
has been rewritten to be more discerning.
This web.archive capture of a now-defunct blogs.msdn post shows one of the earliest mentions of this problem. The MS employee responds:
Sunday, February 26, 2006 11:49 PM by DmitryR Exception on ~/path?qs
is a bug that I'll need to fix...
The easiest fix is to save/restore query string in
ResolveAppRelativeLinkToUrl
around the call to
VirtualPathUtility.ToAbsolute
.
A workaround is to use fully qualified UTLs instead of "~/...".
Thanks,
Dmitry
where ResolveAppRelativeLinkToUrl
refers to the reporter's code's method name.
Another workaround would be to replace ?
with a safe token before the call to VirtualPathUtility.ToAbsolute
, and reverse the replacement afterwards:
public static string SafeToAbsolute(string path)
{
var madeSafe = path.Replace("?", "UNLIKELY_TOKEN");
var absolute = VirtualPathUtility.ToAbsolute(madeSafe);
var restored = absolute.Replace("UNLIKELY_TOKEN", "?");
return restored;
}
choosing a suitably unlikely token for your application.