program tip

상대 경로에서 절대 URL 가져 오기 (리팩터링 된 방법)

radiobox 2020. 12. 28. 07:59
반응형

상대 경로에서 절대 URL 가져 오기 (리팩터링 된 방법)


상대 URL에서 절대 URL을 가져 오는 네이티브 .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('/');
    }

이것은 항상이 작은 성가신에 대한 나의 접근 방식이었습니다. 사용 참고 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));
}

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

이것은 나를 위해 작동합니다 ...

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

ASP.NET에서는 "상대 URL"에 대한 참조 지점을 고려해야합니다. 페이지 요청, 사용자 컨트롤에 상대적입니까, 아니면 단순히 "~ /"를 사용하여 "상대적"입니까?

Uri클래스에는 상대 URL을 절대 URL로 변환하는 간단한 방법이 포함되어 있습니다 (상대 URL에 대한 참조 지점으로 절대 URL이 제공됨).

var uri = new Uri(absoluteUrl, relativeUrl);

경우 relativeUrl사실에 abolute URL이며, 그 다음은 absoluteUrl무시됩니다.

유일한 질문은 참조 지점이 무엇인지, "~ /"URL이 허용되는지 여부입니다 ( Uri생성자가이를 번역하지 않음).


다음은 사용자의 현재 위치 옵션에서 많은 유효성 검사 및 상대 경로를 처리하는 내 버전입니다. 여기에서 자유롭게 리팩토링하십시오 :)

/// <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);
}

여전히 네이티브 물건을 사용하면 충분하지 않습니다. 내가 끝내게 된 것은 다음과 같습니다.

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('/');
}

MVC 컨트롤러 또는 뷰의 컨텍스트에있는 경우 UrlHelper를 사용할 수 있습니다. Url

Url.Content("~/content/images/myimage.jpg")

완전히 확장 될 /virtual_directoryname/content/images/myimage.jpg

컨트롤러 또는 .cshtml 파일에서 사용할 수 있습니다.

예, 호출되는 것이 약간 이상 Content하지만 리소스에 대한 절대 경로를 가져 오는 데 사용되므로 의미가 있습니다.


현재 처리기를 고려 하여 이전의 모든 불만 (포트, 논리적 URL, 상대 URL, 기존 절대 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);
}

절대 URL을 검색하려면 다음 코드를 확인하십시오.

Page.Request.Url.AbsoluteUri

도움이 되길 바랍니다.


When you want to generate URL from your Business Logic layer, you do not have the flexibility of using ASP.NET Web Form's Page class/ Control's ResolveUrl(..) etc. Moreover, you may need to generate URL from ASP.NET MVC controller too where you not only miss the Web Form's ResolveUrl(..) method, but also you cannot get the Url.Action(..) even though Url.Action takes only Controller name and Action name, not the relative url.

I tried using

var uri = new Uri(absoluteUrl, relativeUrl)

approach, but there is a problem too. If the web application is hosted in IIS virtual directory, where the url of the app is like this : http://localhost/MyWebApplication1/, and the relative url is "/myPage" then the relative url is resolved as "http://localhost/MyPage" which is another problem.

Therefore, in order to overcome such problems, I have written a UrlUtils class which can work from a class library. So, it wont depend on Page class but it depends on ASP.NET MVC. So, if you dont mind adding reference to MVC dll to your class library project then my class will work smoothly. I have tested in IIS virtual directory scenario where the web application url is like this : http://localhost/MyWebApplication/MyPage. I realized that, sometimes we need to make sure that the Absolute url is SSL url or non SSL url. So, I wrote my class library supporting this option. I have restricted this class library so that the relative url can be absolute url or a relative url that starts with '~/'.

Using this library, I can call

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

Returns : http://localhost/Contact when the page url is : http://localhost/Home/About

Returns : http://localhost/MyWebApplication/Contact when the page url is : http://localhost/MyWebApplication/Home/About

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

Returns : **https**://localhost/MyWebApplication/Contact when the page url is : http://localhost/MyWebApplication/Home/About

Here is my class Library :

 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;
        }
    }   

This works fine too:

HttpContext.Current.Server.MapPath(relativePath)

Where relative path is something like "~/foo/file.jpg"

ReferenceURL : https://stackoverflow.com/questions/3681052/get-absolute-url-from-relative-path-refactored-method

반응형