• ResolveUrl in ASP.NET


    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 Smile | :)

    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:

    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.

  • 相关阅读:
    2. Python语言基本语法
    wx.onMenuShareTimeline使用注意事项
    a different object with the same identifier value was already associated with the session:
    linux 下压缩大批量文件
    mysql sleep进程过多,应用级配置
    一次心惊肉跳的服务器误删文件的恢复过程
    分享一个css3写的气泡对话框,适合于即时通讯和留言本的动态内容
    一次Mysql 死锁事故
    adb server is out of date. killing...
    Redis 数据序列化方法 serialize, msgpack, json, hprose 比较
  • 原文地址:https://www.cnblogs.com/njl041x/p/4176617.html
Copyright © 2020-2023  润新知