web-dev-qa-db-fra.com

Obtenir l'URL absolue du chemin relatif (méthode refactorisée)

Je suis vraiment surpris qu'il n'y ait pas de méthode .NET native pour obtenir une URL absolue à partir d'une URL relative. Je sais que cela a été discuté à plusieurs reprises, mais je n’ai jamais trouvé de méthode satisfaisante pour gérer cela bien. Pouvez-vous aider à peaufiner la méthode ci-dessous?

Je pense qu'il ne me reste plus qu'à choisir le protocole au lieu de le coder en dur (http/https). Quelque chose me manque (mises en garde, performances, etc.)?

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

Cela a toujours été mon approche de cette petite nuisance. Notez que l'utilisation de VirtualPathUtility.ToAbsolute (relativeUrl) permet à la méthode d'être déclarée comme extension dans une classe statique.

/// <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));
}
85
Nathan Taylor
new System.Uri(Page.Request.Url, "/myRelativeUrl.aspx").AbsoluteUri
64
g.breeze

Celui-ci fonctionne pour moi ...

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

Avec ASP.NET, vous devez considérer le point de référence pour une "URL relative" - ​​est-il relatif à la demande de page, à un contrôle utilisateur, ou s’il est "relatif" simplement en vertu de "~ /"?

La classe Uri contient un moyen simple de convertir une URL relative en une URL absolue (à partir d'une URL absolue en tant que point de référence pour l'URL relative):

var uri = new Uri(absoluteUrl, relativeUrl);

Si relativeUrl est en fait une URL absolue, la absoluteUrl est ignorée.

La seule question reste alors de savoir quel est le point de référence et si les URL "~ /" sont autorisées (le constructeur Uri ne les traduit pas).

5
Stephen Cleary

Voici ma propre version qui gère de nombreuses validations et le chemin relatif de l'option de l'emplacement actuel de l'utilisateur. N'hésitez pas à refactorer à partir d'ici :)

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

Si vous êtes dans le contexte d'un contrôleur ou d'une vue MVC, vous pouvez utiliser UrlHelper, qui devrait être accessible via uniquement Url.

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

Ce qui sera complètement étendu à /virtual_directoryname/content/images/myimage.jpg

Ceci peut être utilisé dans un contrôleur ou un fichier .cshtml

Oui, il est un peu étrange que cela s'appelle Content, mais c'est censé être utilisé pour obtenir un chemin absolu vers une ressource, donc c'est logique

1
Simon_Weaver

Toujours rien d’assez bon en utilisant des choses indigènes. Voici ce que j'ai fini avec:

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

vérifiez le code suivant pour récupérer une URL absolue:

Page.Request.Url.AbsoluteUri

J'espère être utile.

0
DEVMBM

La version finale prenant en charge toutes les réclamations précédentes (ports, URL logique, URL relative, URL absolue existante ... etc.) considérant le gestionnaire actuel est la page:

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);
}
0
yazanpro

Lorsque vous souhaitez générer une URL à partir de votre couche Business Logic, vous ne pouvez pas utiliser la classe de page ASP.NET Web Form/ResolveUrl (..) du contrôle, etc. De plus, vous devrez peut-être générer une URL à partir de ASP.NET. MVC controller aussi où non seulement vous manquez la méthode ResolveUrl (..) du formulaire Web, mais vous ne pouvez pas non plus obtenir l'URL.Action (..) même si Url.Action prend uniquement le nom du contrôleur et le nom de l'action, et non l'URL relative . 

J'ai essayé d'utiliser 

var uri = new Uri (absoluteUrl, relativeUrl)

approche, mais il y a aussi un problème. Si l'application Web est hébergée dans le répertoire virtuel IIS, où l'URL de l'application est la suivante: http://localhost/MyWebApplication1/ et l'URL relative est "/ myPage", l'URL relative est résolue sous la forme "http://localhost/MyPage", ce qui pose un autre problème. .

Par conséquent, afin de surmonter de tels problèmes, j’ai écrit une classe UrlUtils qui peut fonctionner à partir d’une bibliothèque de classes. Donc, cela ne dépend pas de la classe Page mais dépend de ASP.NET MVC . Donc, si cela ne vous dérange pas d’ajouter une référence à dll MVC dans votre projet de bibliothèque de classes, ma classe fonctionnera sans à-coups. J'ai testé dans le scénario de répertoire virtuel IIS où l'URL de l'application Web ressemble à ceci: http://localhost/MyWebApplication/MyPage. J'ai réalisé que, parfois, nous devons nous assurer que l'URL absolue est une URL SSL ou une URL non SSL. J'ai donc écrit ma bibliothèque de classes pour supporter cette option. J'ai restreint cette bibliothèque de classes afin que l'URL relative puisse être une URL absolue ou une URL relative commençant par '~ /'. 

En utilisant cette bibliothèque, je peux appeler

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

Renvoie: http://localhost/Contact lorsque l'URL de la page est: http://localhost/Home/About

Renvoie: http://localhost/MyWebApplication/Contact lorsque l'URL de la page est: http://localhost/MyWebApplication/Home/About

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

Renvoie: **https**://localhost/MyWebApplication/Contact lorsque l'URL de la page est: http://localhost/MyWebApplication/Home/About

Voici ma bibliothèque de classe:

 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;
        }
    }   
0
Emran Hussain