ResolveUrl in ASP.NET - The Perfect Solution

原文:ResolveUrl in ASP.NET - The Perfect Solution

If you are looking for ResolveUrl outside of Page/Control, and even if you are not, this is for you.

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:

  1. When the URL begins with a slash (either / or \), it will not touch it!
  2. When the URL begins with ~/, it will replace it with the AppVirtualPath.
  3. When the URL is an absolute URL, it will not touch it. (ResolveUrl has a bug with this, as I said before...)
  4. In any other case (even beginning with ~, but not slash), it will append the URL to the AppVirtualPath.
  5. 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 Code

public 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.

时间: 2024-10-24 07:22:15

ResolveUrl in ASP.NET - The Perfect Solution的相关文章

Android 自定义 ListView 显示网络歌曲列表

本文内容 环境 项目结构 演示自定义 ListView 显示网络歌曲列表 参考资料 本文最开始看的一个国人的文章,没有源代码,根据文中提供的源代码,自己新建的项目(最可气的是,没有图标图片资源,只能自己乱编),但程序不是很稳定,有时能显示出列表中的缩略图,有时显示不出来,还在主线程访问了网络.后看文章评论,作者给出英文原文链接,本来想这下没事了吧,结果下载源代码运行后,还是有问题~仔细看英文原文,原来他也是根据 Github 上一个项目的基础上搞的,只是添加了式样,以及显示完整的歌曲列表,包括歌

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Polymorphism

Polymorphism is the third essential feature of an object-oriented programming language,after data abastraction and inheritance. It provides another dimension of separation of interface from implementation, to decouple what from how. Polymorphism allo

HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript

HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript Though it's not widely known, you can write native-feeling iOS apps for the iPhone and iPad in JavaScript (+ HTML and CSS). In this article, I'll explain how to: stri

Select2 在jquery UI Dialog 搜索项失效且不能focus到搜索框解决方案

今天在项目到遇到一个select2插件在jquery UI Dialog 不能focus到搜索框的问题,后来在js 代码中加入(位置可以自己选 ,我选的位置是select2.min.js 后面,因为很多地方都用到,不用针对一个一个功能去修改): $.ui.dialog.prototype._allowInteraction = function(e) {     return !!$(e.target).closest('.ui-dialog, .ui-datepicker, .select2-

PAT Judge

本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师.何钦铭老师的<数据结构> 10-排序5 PAT Judge   (25分) The ranklist of PAT is generated from the status list, which shows the scores of the submissions. This time you are supposed to generate the ranklist for PAT. Input Specification: Ea

卷积神经网络和CIFAR-10:Yann LeCun专访 Convolutional Nets and CIFAR-10: An Interview with Yann LeCun

Recently Kaggle hosted a competition on the CIFAR-10 dataset. The CIFAR-10 dataset consists of 60k 32x32 colour images in 10 classes. This dataset was collected by AlexKrizhevsky, Vinod Nair, and Geoffrey Hinton. Many contestants used convolutional n

Cool!15个超炫的 CSS3 文本特效【上篇】

每一个网页设计师都希望创建出让用户能够赏识的网站.当然,这是不可能满足每个人的口味的.幸运的是,我们有最强大的工具和资源.实际上,我们非常多的网站模板,框架,内容管理系统,先进的工具和其他的资源可以使用. 这篇文章展示了使用一组使用 CSS3 制作的文本特效,快来欣赏. 您可能感兴趣的相关文章 小伙伴们惊呆了!8个超炫的 Web 效果 8个惊艳的 HTML5 和 JavaScript 特效 10大 Metro UI 风格 Bootstrap 主题 35款精致的 CSS3 和 HTML5 网页模板

开源网络通信库参考

Sockets tcp/ip communication library C++ Sockets Library This is a GPL licensed C++ class library wrapping the berkeley sockets C API, and therefore works on most unixes and also win32. The library is in use in a number of real world applications, bo

Membrane Filter Press for sale

Society has always been competitive, but nowadays life is perhaps more competitive than in any previous era. Can you imagine the level of competition on the market when there are thousands of rivals in every sphere of industry? One has to work very h