从相对路径获取绝对URL(重构方法)

时间:2010-09-09 22:36:24

标签: c# .net asp.net .net-3.5

我真的很惊讶没有本地.NET方法从相对网址获取绝对网址。我知道这已经讨论了很多次,但从来没有遇到过一个能很好地处理这个问题的令人满意的方法。你能帮助微调下面的方法吗?

我认为我需要的只是自动选择协议而不是硬编码(http / https)。我还缺少什么(警告,表演等)?

public static string GetAbsoluteUrl(string url)
    {
        //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
        if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) 
           || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        { 
            return url;
        }

        //GET PAGE REFERENCE FOR CONTEXT PROCESSING
        Page page = HttpContext.Current.Handler as Page;

        //RESOLVE PATH FOR APPLICATION BEFORE PROCESSING
        if (url.StartsWith("~/"))
        {
            url = page.ResolveUrl(url);
        }

        //BUILD AND RETURN ABSOLUTE URL
        return "http://" + page.Request.ServerVariables["SERVER_NAME"] + "/" 
                         + url.TrimStart('/');
    }

11 个答案:

答案 0 :(得分:86)

这一直是我解决这个小麻烦的方法。请注意,使用VirtualPathUtility.ToAbsolute(relativeUrl)允许将方法声明为静态类中的扩展名。

/// <summary>
/// Converts the provided app-relative path into an absolute Url containing the 
/// full host name
/// </summary>
/// <param name="relativeUrl">App-Relative path</param>
/// <returns>Provided relativeUrl parameter as fully qualified Url</returns>
/// <example>~/path/to/foo to http://www.web.com/path/to/foo</example>
public static string ToAbsoluteUrl(this string relativeUrl) {
    if (string.IsNullOrEmpty(relativeUrl))
        return relativeUrl;

    if (HttpContext.Current == null)
        return relativeUrl;

    if (relativeUrl.StartsWith("/"))
        relativeUrl = relativeUrl.Insert(0, "~");
    if (!relativeUrl.StartsWith("~/"))
        relativeUrl = relativeUrl.Insert(0, "~/");

    var url = HttpContext.Current.Request.Url;
    var port = url.Port != 80 ? (":" + url.Port) : String.Empty;

    return String.Format("{0}://{1}{2}{3}",
        url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(relativeUrl));
}

答案 1 :(得分:64)

new System.Uri(Page.Request.Url, "/myRelativeUrl.aspx").AbsoluteUri

答案 2 :(得分:10)

这个对我有用......

new System.Uri(Page.Request.Url, ResolveClientUrl("~/mypage.aspx")).AbsoluteUri

答案 3 :(得分:5)

使用ASP.NET,您需要考虑“相对URL”的参考点 - 它是相对于页面请求,用户控件,还是仅仅因为使用“〜/”它是“相对的” ?

Uri类包含一种将相对URL转换为绝对URL的简单方法(给定绝对URL作为相对URL的参考点):

var uri = new Uri(absoluteUrl, relativeUrl);

如果relativeUrl实际上是一个绝对的网址,则会忽略absoluteUrl

唯一的问题仍然是参考点是什么,以及是否允许“〜/”URL(Uri构造函数不会翻译这些)。

答案 4 :(得分:3)

这是我自己的版本,它处理来自用户当前位置选项的许多验证和相对路径。随意从这里重构:)

/// <summary>
/// Converts the provided app-relative path into an absolute Url containing 
/// the full host name
/// </summary>
/// <param name="relativeUrl">App-Relative path</param>
/// <returns>Provided relativeUrl parameter as fully qualified Url</returns>
/// <example>~/path/to/foo to http://www.web.com/path/to/foo</example>
public static string GetAbsoluteUrl(string relativeUrl)
{
    //VALIDATE INPUT
    if (String.IsNullOrEmpty(relativeUrl))
        return String.Empty;
    //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
    if (relativeUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) 
    || relativeUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        return relativeUrl;
    //VALIDATE CONTEXT
    if (HttpContext.Current == null)
        return relativeUrl;
    //GET CONTEXT OF CURRENT USER
    HttpContext context = HttpContext.Current;
    //FIX ROOT PATH TO APP ROOT PATH
    if (relativeUrl.StartsWith("/"))
        relativeUrl = relativeUrl.Insert(0, "~");
    //GET RELATIVE PATH
    Page page = context.Handler as Page;
    if (page != null)
    {
        //USE PAGE IN CASE RELATIVE TO USER'S CURRENT LOCATION IS NEEDED
        relativeUrl = page.ResolveUrl(relativeUrl);
    }
    else //OTHERWISE ASSUME WE WANT ROOT PATH
   {
        //PREPARE TO USE IN VIRTUAL PATH UTILITY
        if (!relativeUrl.StartsWith("~/"))
            relativeUrl = relativeUrl.Insert(0, "~/");
        relativeUrl = VirtualPathUtility.ToAbsolute(relativeUrl);
    }

    var url = context.Request.Url;
    var port = url.Port != 80 ? (":" + url.Port) : String.Empty;
    //BUILD AND RETURN ABSOLUTE URL
    return String.Format("{0}://{1}{2}{3}",
           url.Scheme, url.Host, port, relativeUrl);
}

答案 5 :(得分:1)

使用原生的东西还不够好。以下是我最终的结果:

public static string GetAbsoluteUrl(string url)
{
    //VALIDATE INPUT
    if (String.IsNullOrEmpty(url))
    {
        return String.Empty;
    }

    //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
    if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
    { 
        return url;
    }

    //GET CONTEXT OF CURRENT USER
    HttpContext context = HttpContext.Current;

    //RESOLVE PATH FOR APPLICATION BEFORE PROCESSING
    if (url.StartsWith("~/"))
    {
        url = (context.Handler as Page).ResolveUrl(url);
    }

    //BUILD AND RETURN ABSOLUTE URL
    string port = (context.Request.Url.Port != 80 && context.Request.Url.Port != 443) ? ":" + context.Request.Url.Port : String.Empty;
    return context.Request.Url.Scheme + Uri.SchemeDelimiter + context.Request.Url.Host + port + "/" + url.TrimStart('/');
}

答案 6 :(得分:1)

最终版本处理所有先前的投诉(端口,逻辑URL,相对网址,现有绝对网址等)考虑当前处理程序是页面:

public static string ConvertToAbsoluteUrl(string url)
{
    if (!IsAbsoluteUrl(url))
    {
        if (HttpContext.Current != null && HttpContext.Current.Request != null && HttpContext.Current.Handler is System.Web.UI.Page)
        {
            var originalUrl = HttpContext.Current.Request.Url;
            return string.Format("{0}://{1}{2}{3}", originalUrl.Scheme, originalUrl.Host, !originalUrl.IsDefaultPort ? (":" + originalUrl.Port) : string.Empty, ((System.Web.UI.Page)HttpContext.Current.Handler).ResolveUrl(url));
        }
        throw new Exception("Invalid context!");
    }
    else
        return url;
}

private static bool IsAbsoluteUrl(string url)
{
    Uri result;
    return Uri.TryCreate(url, UriKind.Absolute, out result);
}

答案 7 :(得分:0)

检查以下代码以检索绝对Url:

Page.Request.Url.AbsoluteUri

我希望有用。

答案 8 :(得分:0)

如果你在MVC控制器或视图的上下文中,你可以使用只能通过Url

访问的UrlHelper
Url.Content("~/content/images/myimage.jpg")

哪些内容将完全展开到/virtual_directoryname/content/images/myimage.jpg

这可以在控制器或.cshtml文件中使用

是的,它有点奇怪,它被称为Content,但它的意思是用来获取资源的绝对路径,这样才有意义

答案 9 :(得分:0)

如果要从业务逻辑层生成URL,则无法灵活地使用ASP.NET Web Form的Page class / Control的ResolveUrl(..)等。此外,您可能还需要从 ASP.NET MVC控制器生成URL,您不仅错过了Web Form的ResolveUrl(..)方法,而且还无法获取Url.Action(.. )即使Url.Action只接受控制器名称和操作名称,而不是相对网址。

我尝试使用

  

var uri = new Uri(absoluteUrl,relativeUrl)

接近,但也存在问题。如果Web应用程序托管在IIS虚拟目录中,则应用程序的URL如下所示:http://localhost/MyWebApplication1/,相对URL为&#34; / myPage&#34;然后将相对网址解析为&#34; http://localhost/MyPage&#34;这是另一个问题。

因此,为了克服这些问题,我编写了一个可以在类库中工作的UrlUtils类。因此,它不依赖于Page类,但它依赖于 ASP.NET MVC 。所以,如果您不介意将MVC dll的引用添加到您的类库项目中,那么我的课程将顺利运行。我已在IIS虚拟目录场景中测试过Web应用程序URL如下所示:http://localhost/MyWebApplication/MyPage。我意识到,有时我们需要确保绝对网址是SSL网址或非网址网址。所以,我编写了支持这个选项的类库。我限制了这个类库,以便相对url可以是绝对url或以&#39;〜/&#39;开头的相对url。

使用此库,我可以调用

string absoluteUrl = UrlUtils.MapUrl("~/Contact");

返回:http://localhost/Contact   当页面网址为:http://localhost/Home/About

返回:http://localhost/MyWebApplication/Contact   当页面网址为:http://localhost/MyWebApplication/Home/About

  string absoluteUrl = UrlUtils.MapUrl("~/Contact", UrlUtils.UrlMapOptions.AlwaysSSL);

返回:**https**://localhost/MyWebApplication/Contact   当页面网址为:http://localhost/MyWebApplication/Home/About

这是我的班级资料库:

 public class UrlUtils
    {
        public enum UrlMapOptions
        {
            AlwaysNonSSL,
            AlwaysSSL,
            BasedOnCurrentScheme
        }

        public static string MapUrl(string relativeUrl, UrlMapOptions option = UrlMapOptions.BasedOnCurrentScheme)
        {
            if (relativeUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
                relativeUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                return relativeUrl;

            if (!relativeUrl.StartsWith("~/"))
                throw new Exception("The relative url must start with ~/");

            UrlHelper theHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);

            string theAbsoluteUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) +
                                           theHelper.Content(relativeUrl);

            switch (option)
            {
                case UrlMapOptions.AlwaysNonSSL:
                    {
                        return theAbsoluteUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
                            ? string.Format("http://{0}", theAbsoluteUrl.Remove(0, 8))
                            : theAbsoluteUrl;
                    }
                case UrlMapOptions.AlwaysSSL:
                    {
                        return theAbsoluteUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
                            ? theAbsoluteUrl
                            : string.Format("https://{0}", theAbsoluteUrl.Remove(0, 7));
                    }
            }

            return theAbsoluteUrl;
        }
    }   

答案 10 :(得分:-1)

这也很好用:

HttpContext.Current.Server.MapPath(relativePath)

其中相对路径类似于“〜/ foo / file.jpg”