如何制作没有字符转换的绝对URL?

时间:2013-04-03 06:32:22

标签: c# url

关于SO已经有类似的问题,答案是:

new Uri(new Uri(base_url),relative_url);

然而,这不是正确答案,因为它会转换字符。考虑你有相对网址,如:

hello%2Fworld.html

这是有效的网址,当您运行上面的代码时,您将获得一个页面hello/world.html,这在技术上是有效的,但它没用,因为服务器不太可能拥有两个网页的2个页面副本。

在我编写自己的用于组合网址的自定义功能之前,是否有任何现有功能组合网址并且进行任何转换?


我目前的解决方案基于“发现”,即根据方案完成字符转换。对于ftp协议,保留字符。由于它有点hackery,我也确保我不会对未来改变这种行为感到惊讶。我的代码如下:

public static class UrlIO
{
    public static string Combine(string baseUrl, string relativeUrl)
    {
        const string ftp = "ftp";

        var scheme = new Uri(baseUrl).Scheme;
        return scheme + new Uri(new Uri(ftp + baseUrl.DeleteStart(scheme)), relativeUrl).AbsoluteUri.DeleteStart(ftp);
    }

    static UrlIO()
    {
        #if DEBUG
        Assert.AreEqual("ftp://foobar.com/hello_world.html", UrlIO.Combine("ftp://foobar.com/", "/hello_world.html"));
        Assert.AreEqual("ftp://foobar.com/hello_world.html", UrlIO.Combine("ftp://foobar.com/xxx", "/hello_world.html"));
        Assert.AreEqual("ftp://foobar.com/xxx/hello_world.html", UrlIO.Combine("ftp://foobar.com/xxx/", "hello_world.html"));
        Assert.AreEqual("ftp://foobar.com/xxx/hello%2Fworld.html", UrlIO.Combine("ftp://foobar.com/xxx/", "hello%2Fworld.html"));
        Assert.AreEqual("http://foobar.com/xxx/hello%2Fworld.html", UrlIO.Combine("http://foobar.com/xxx/index.html", "hello%2Fworld.html"));
        #endif
    }
}

请将DeleteStart扩展名更改为您库中的内容。

1 个答案:

答案 0 :(得分:2)

您可以使用以下扩展方法。在静态类中添加它。

用法,

string fullUrl=relative_url.ConvertToFullUrl();

扩展方法,

public static string ConvertToFullUrl(this string relativeUrl)
{
    if (!Uri.IsWellFormedUriString(relativeUrl, UriKind.Absolute))
    {
        if (!relativeUrl.StartsWith("/"))
        {
            relativeUrl = relativeUrl.Insert(0, "/");
        }
        if (relativeUrl.StartsWith("~/"))
        {
            relativeUrl = relativeUrl.Substring(1);
        }

        return string.Format(
            "{0}://{1}{2}{3}",
            HttpContext.Current.Request.Url.Scheme,
            HttpContext.Current.Request.Url.Host,
            HttpContext.Current.Request.Url.Port == 80 ? "" : ":" + HttpContext.Current.Request.Url.Port.ToString(),
            relativeUrl);
    }
    else
    {
        return relativeUrl;
    }
}