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('/');
}
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));
}
new System.Uri(Page.Request.Url, "/myRelativeUrl.aspx").AbsoluteUri
Celui-ci fonctionne pour moi ...
new System.Uri(Page.Request.Url, ResolveClientUrl("~/mypage.aspx")).AbsoluteUri
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).
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);
}
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
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('/');
}
vérifiez le code suivant pour récupérer une URL absolue:
Page.Request.Url.AbsoluteUri
J'espère être utile.
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);
}
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;
}
}