ResolveUrl in ASP.NET - The Perfect Solution
Introduction/Background
From my personal experience using ASP.NET, and from searching the web, I have found that the ResolveUrlmethod of the Page control (and basically, Control) presents us with some serious problems.
The most common one is that you just cannot use it outside of the page or control context.
Other problems are just bugs. It will not correctly handle some of the URLs you'll give it. For example, tryPage.ResolveUrl("~/test.aspx?param=http://www.test.com"). The result is the very same input string... It will just do nothing. By looking into the ASP.NET code using Reflector, I found that all mechanisms that are supposed to convert the relative URLs to absolute URLs will search first for a "://" inside the string, and will return if found. So a query string is OK, unless you pass in a parameter with ://. Yes, I know that the query string parameter should be UrlEncoded, but if it isn't, it is still an acceptable URL. Seriously, check your browsers!
Other suggested methods on the web involve using VirtualPathUtility.ToAbsolute, which is pretty nice and handy, unless you pass in a query string with the URL... Because it will just throw an exception. It will also throw an exception for an absolute URL!
So I decided to find the ultimate solution.
Using the Code
First, I searched for the perfect variable that will give me the Application Virtual Path at runtime without a page context.
I found this to be HttpRuntime.AppDomainAppVirtualPath. It will work anywhere - even inside a timer callback! It gives the path without a trailing slash (ASP.NET makes a special effort to remove the trailing slash...), but that is OK, we can fix it 
Then, I did some tests on the original ResolveUrl code, and found where I need to replace what with theAppVirtualPath:
- When the URL begins with a slash (either / or \), it will not touch it!
- When the URL begins with ~/, it will replace it with the
AppVirtualPath. - When the URL is an absolute URL, it will not touch it. (
ResolveUrlhas a bug with this, as I said before...) - In any other case (even beginning with ~, but not slash), it will append the URL to the
AppVirtualPath. - Whenever it modifies the URL, it also fixes up the slashes. Removes double slashes and replaces \ with /.
So I replicated all of that, but without the bugs. And here's the code:
Collapse | Copy Codepublic static string ResolveUrl(string relativeUrl)
{
if (relativeUrl == null) throw new ArgumentNullException("relativeUrl"); if (relativeUrl.Length == 0 || relativeUrl[0] == '/' || relativeUrl[0] == '\\')
return relativeUrl; int idxOfScheme = relativeUrl.IndexOf(@"://", StringComparison.Ordinal);
if (idxOfScheme != -1)
{
int idxOfQM = relativeUrl.IndexOf('?');
if (idxOfQM == -1 || idxOfQM > idxOfScheme) return relativeUrl;
} StringBuilder sbUrl = new StringBuilder();
sbUrl.Append(HttpRuntime.AppDomainAppVirtualPath);
if (sbUrl.Length == 0 || sbUrl[sbUrl.Length - 1] != '/') sbUrl.Append('/'); // found question mark already? query string, do not touch!
bool foundQM = false;
bool foundSlash; // the latest char was a slash?
if (relativeUrl.Length > 1
&& relativeUrl[0] == '~'
&& (relativeUrl[1] == '/' || relativeUrl[1] == '\\'))
{
relativeUrl = relativeUrl.Substring(2);
foundSlash = true;
}
else foundSlash = false;
foreach (char c in relativeUrl)
{
if (!foundQM)
{
if (c == '?') foundQM = true;
else
{
if (c == '/' || c == '\\')
{
if (foundSlash) continue;
else
{
sbUrl.Append('/');
foundSlash = true;
continue;
}
}
else if (foundSlash) foundSlash = false;
}
}
sbUrl.Append(c);
} return sbUrl.ToString();
}
Points of Interest
After completing the code and testing over and over again and comparing to the original ResolveUrl, I started to test for performance... In most cases, my code executed faster than the original ResolveUrl by 2.7 times! I also tested inside loops that executed the code 100000s of times on different kinds of URLs.
ResolveUrl in ASP.NET - The Perfect Solution的更多相关文章
- ASP.NET Core Logging Solution
Serilog.Extensions.Logging.File This package makes it a one-liner - loggerFactory.AddFile() - to con ...
- [转]Bootstrap 3.0.0 with ASP.NET Web Forms – Step by Step – Without NuGet Package
本文转自:http://www.mytecbits.com/microsoft/dot-net/bootstrap-3-0-0-with-asp-net-web-forms In my earlier ...
- .NET & C# & ASP.NET
.NET && C# && ASP.NET https://docs.microsoft.com/zh-cn/dotnet/ .NET Documentation We ...
- error_Could not load file or assembly
原文链接 Could you be missing the loaded assembly from your configuration file? Ensure you have somethin ...
- Android 自定义 ListView 显示网络上 JSON 格式歌曲列表
本文内容 环境 项目结构 演示自定义 ListView 显示网络上 JSON 歌曲列表 参考资料 本文最开始看的是一个国人翻译的文章,没有源代码可下载,根据文中提供的代码片段,自己新建的项目(比较可恶 ...
- Thinking in Java——笔记(19)
Enumerated Types Basic enum features When you create an enum, an associated class is produced for yo ...
- Cool!15个超炫的 CSS3 文本特效【上篇】
每一个网页设计师都希望创建出让用户能够赏识的网站.当然,这是不可能满足每个人的口味的.幸运的是,我们有最强大的工具和资源.实际上,我们非常多的网站模板,框架,内容管理系统,先进的工具和其他的资源可以使 ...
- Day14 summary
Since I am writing blog in Ubuntu which has not installed Chinese language package, this blog will b ...
- NodeJS 各websocket框架性能分析
For a current project at WhoScored, I needed to learn JavaScript, Node.js and WebSocket channel, aft ...
随机推荐
- 使用pfile 启动oracle 实例时,启动失败---db_recovery_file_dest參数值在os上不存在。
[oracle@vm22 ~]$ export ORACLE_SID=orcl [oracle@vm22 ~]$ sqlplus / as sysdba SQL*Plus: Release 10.2. ...
- 查询出各个学科的前3名的同学信息的Sql
查找各个学科的成绩前3名的学生信息Sql,有2种方法,一种是利用sql的row_number() over()函数,另一种是用子查询, 表设计如下 如果不考虑各个学科的成绩有并列的情况的话,有如下两种 ...
- Mysql sql声明召回2 --正则表达式
这里简单回顾mysql在过滤后的数据使用正则表达式时.主要利用每方法将样品,或添加一些简短的说明. 下面说说提前,使用正则表达式是用来过滤数据 REGEXPkeyword 基本字符相匹配: SELEC ...
- Jenkins + robot framework自动发送邮件报告
一.Jenkins安装插件 进入系统管理—插件管理—可选插件下安装以下插件Email-ext plugin.Email-ext Template Plugin. 安装完如下: 二.系统设置 1.设置系 ...
- MacOS10.9平台配置Appium+Java环境
1) 安装JDK 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...
- winhec
#winhec# 开发人员刷屏看点 (视频) 今天大家已经被winhec刷屏了,本来不想写这篇了,但看了所有的文章,大家关注的都是windows 10的那些新功能,小米win10刷机,联想千元手机,小 ...
- SSAS系列——【02】多维数据(维度对象)
原文:SSAS系列——[02]多维数据(维度对象) 1.维度是什么? 数学中叫参数,物理学中是独立的时空坐标的数目.0维是一点,1维是线,2维是一个长和宽(或曲线)面积,3维是2维加上高度形成体积面. ...
- 多线程学习之二坚不可摧模式Immutable pattern
Immutable pattern[坚不可摧模式] 一:immutable pattern的参与者--->immutable(不变的)参与者 1.1:immutable参与者是一个 ...
- oracle中的DECODE
原文:oracle中的DECODE DECODE函数相当于一条件语句(IF).它将输入数值与函数中的参数列表相比较,根据输入值返回一个对应值.函数的参数列表是由若干数值及其对应结果值组成的若干序偶 ...
- bat启动/停止oracle服务
原文:bat启动/停止oracle服务 自己的电脑比较慢,尤其装了oracle10g后,服务开启和关闭用bat文件操作省事点 开启服务 @echo offnet start OracleService ...