2010-09-09 19 views
49

Estoy realmente sorprendido de que no haya un método .NET nativo para obtener una URL absoluta de una URL relativa. Sé que esto se ha discutido muchas veces, pero nunca he encontrado un método satisfactorio que maneje esto bien. ¿Puedes ayudar a afinar el método a continuación?Obtener URL absoluta de la ruta relativa (método refactorizado)

Creo que todo lo que necesito es elegir automáticamente el protocolo en lugar de codificarlo (http/https). ¿Me falta algo más (advertencias, rendimiento, 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('/'); 
    } 
+1

Una pequeña sugerencia para su código. Debería usar String.Format en lugar de concatenar los bits de URL al final. – Bernd

Respuesta

82

Este siempre ha sido mi enfoque para este pequeño inconveniente. Tenga en cuenta que el uso de VirtualPathUtility.ToAbsolute(relativeUrl) permite que el método se declare como una extensión en una clase estática.

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

Nota rápida ... a veces no quiero la raíz de la ruta, sino una raíz donde estoy. Algo como esto: Page.ResolveUrl ("SomePage.aspx"). En su método, supondrá que quiero ~/SomePage.aspx cuando realmente quiero ~/ruta/a/donde/I/actualmente/am/SomePage.aspx. ¡Buen método! – TruMan1

+0

..por cierto, VirtualPathUtility.ToAbsolute requiere que tengas un ~ en el comienzo. Pero si quiero una ruta relativa a donde estoy, entonces (context.Handler as Page) .ResolveUrl funciona. – TruMan1

+0

Hummm ¿Cómo logré hacer esta wiki de la comunidad? >. <@ TruMan1 Sería semánticamente imposible en un método de extensión externo (como este) derivar una ubicación de "Something.aspx", por lo que el método agrega automáticamente un "~ /" al frente de la ruta. Dicho esto, su escenario (context.Handler as Page) funciona siempre que el controlador siempre sea una página. Esa solución ciertamente fallaría si se invoca desde un HttpHandler o similar. –

0

cheque el siguiente código para recuperar URL absoluta:

Page.Request.Url.AbsoluteUri 

espero que sea útil.

4

Con ASP.NET, necesita considerar el punto de referencia para una "URL relativa" - ¿es relativa a la solicitud de página, un control de usuario, o si es "relativa" simplemente por el uso de "~/"¿?"

La clase Uri contiene una manera simple de convertir un URL en relación con una dirección URL absoluta (dada una URL absoluta como punto de referencia para la dirección URL relativa):

var uri = new Uri(absoluteUrl, relativeUrl); 

Si relativeUrl es de hecho un URL abolute , entonces se ignora el absoluteUrl.

La única pregunta sigue siendo cuál es el punto de referencia, y si se permiten las URL "~ /" (el constructor Uri no las traduce).

1

Todavía no hay nada suficientemente bueno usando cosas nativas. Esto es lo que terminé con:

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

Aquí está mi propia versión que maneja muchas validaciones y rutas relativas desde la opción de ubicación actual del usuario. Siéntase libre de refactorizar de aquí :)

/// <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); 
} 
58
new System.Uri(Page.Request.Url, "/myRelativeUrl.aspx").AbsoluteUri 
+1

Gracias. Esto funciona muy bien al menos para una aplicación de Windows Store. – Hong

+0

creo que esta debería ser la respuesta ahora ... también funciona excelente para la aplicación web – Nirman

+0

Esto parece fallar si la URL relativa proporcionada es en realidad una URL absoluta. Por ejemplo, 'new System.Uri (" http://example.com "," http://google.com ")' debe devolver el enlace de google. – Nacht

8

Esta funciona para mí ...

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

ResolveClientUrl vale mi + voto – stackuser83

-1

Esto funciona muy bien también:

HttpContext.Current.Server.MapPath(relativePath) 

Donde ruta relativa es algo como "~/foo/file.jpg"

+1

Tengo que estar en desacuerdo. Server.MapPath se refiere a una ubicación física, no un URI absoluto como la solicitud de OP. Referencia http://stackoverflow.com/questions/275781/server-mappath-server-mappath-server-mappath-server-mappath –

1

Si tu u're en el contexto de un controlador MVC o vista se puede utilizar el UrlHelper que debe ser accesible a través de simplemente Url

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

que será totalmente expandido a /virtual_directoryname/content/images/myimage.jpg

Esto puede ser usado en un controlador o .cshtml presentar

Sí, es un poco extraño que se llama Content sino que está destinado a ser utilizado para obtener una ruta absoluta a un recurso así que tiene sentido

0

Cuando se desea generar URL de su capa de lógica de negocios, no tiene la flexibilidad de usar la clase de página de formulario Web de ASP.NET/ResolveUrl de control (..) etc. Además, puede necesitar generar URL desde controlador ASP.NET MVC donde no solo se pierda el ResolveUrl del formulario web (..) método, pero tampoco puede obtener la acción Url.Action (..) aunque Url.Action solo toma el nombre del Controlador y la Acción, no la URL relativa.

He intentado utilizar

var uri = new Uri (absoluteUrl, URLrelativa)

enfoque, pero hay un problema también. Si la aplicación web está alojada en el directorio virtual de IIS, donde la URL de la aplicación es así: http://localhost/MyWebApplication1/, y la URL relativa es "/ miPágina", la URL relativa se resuelve como "http://localhost/MyPage", que es otro problema.

Por lo tanto, para superar estos problemas, he escrito una clase UrlUtils que puede funcionar desde una biblioteca de clases. Por lo tanto, no dependerá de la clase Page, pero depende de ASP.NET MVC. Entonces, si no le importa agregar una referencia a MVC dll a su proyecto de biblioteca de clase, entonces mi clase funcionará sin problemas. He probado en el escenario del directorio virtual de IIS donde la URL de la aplicación web es así: http://localhost/MyWebApplication/MyPage. Me di cuenta de que, a veces, debemos asegurarnos de que la URL absoluta sea URL url o no SSL. Entonces, escribí la biblioteca de mi clase apoyando esta opción. He restringido esta biblioteca de clases para que la URL relativa pueda ser url absoluta o una URL relativa que comience con '~ /'.

El uso de esta biblioteca, puedo llamar

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

Devuelve: http://localhost/Contact cuando la URL de la página es: http://localhost/Home/About

devuelve: http://localhost/MyWebApplication/Contact cuando la URL de la página es: http://localhost/MyWebApplication/Home/About

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

Devoluciones: **https**://localhost/MyWebApplication/Contact cuando la URL de la página es: http://localhost/MyWebApplication/Home/About

Aquí está mi biblioteca de clases:

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

La versión final el cuidado de todas las quejas anteriores (puertos, url lógica, dirección URL relativa, dirección URL absoluta existentes .. . .etc) considerando el controlador actual es la página:

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); 
} 
Cuestiones relacionadas