Why do I get an HttpException from VirtualPathUtil

2019-06-26 02:40发布

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?

1条回答
成全新的幸福
2楼-- · 2019-06-26 03:34

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.

查看更多
登录 后发表回答