Obteniendo URLs absolutas usando ASP.NET Core

En MVC 5, tenía los siguientes métodos de extensión para generar URL absolutas, en lugar de las relativas:

public static class UrlHelperExtensions { public static string AbsoluteAction( this UrlHelper url, string actionName, string controllerName, object routeValues = null) { string scheme = url.RequestContext.HttpContext.Request.Url.Scheme; return url.Action(actionName, controllerName, routeValues, scheme); } public static string AbsoluteContent( this UrlHelper url, string contentPath) { return new Uri(url.RequestContext.HttpContext.Request.Url, url.Content(contentPath)).ToString(); } public static string AbsoluteRouteUrl( this UrlHelper url, string routeName, object routeValues = null) { string scheme = url.RequestContext.HttpContext.Request.Url.Scheme; return url.RouteUrl(routeName, routeValues, scheme); } } 

¿Cuál sería el equivalente en ASP.NET Core?

  • UrlHelper.RequestContext ya no existe.
  • No puede obtener el HttpContext porque ya no hay una propiedad HttpContext.Current estática.

Por lo que puedo ver, ahora requeriría que los objetos HttpContext o HttpRequest pasen también. ¿Estoy en lo cierto? ¿Hay alguna forma de obtener la solicitud actual?

¿Estoy incluso en el camino correcto si el dominio ahora es una variable de entorno, que se agrega de manera simple a la URL relativa? ¿Sería este un mejor enfoque?

Después de RC2 y 1.0 ya no necesita inyectar un IHttpContextAccessor a su clase de extensión. Está disponible de inmediato en IUrlHelper través de urlhelper.ActionContext.HttpContext.Request . Luego crearía una clase de extensión siguiendo la misma idea, pero más simple ya que no habrá inyección involucrada.

 public static string AbsoluteAction( this IUrlHelper url, string actionName, string controllerName, object routeValues = null) { string scheme = url.ActionContext.HttpContext.Request.Scheme; return url.Action(actionName, controllerName, routeValues, scheme); } 

Dejando los detalles sobre cómo construirlo, inyectando el accesorio en caso de que sean útiles para alguien. También podría estar interesado en la URL absoluta de la solicitud actual, en cuyo caso eche un vistazo al final de la respuesta.


Puede modificar su clase de extensión para usar la interfaz IHttpContextAccessor para obtener HttpContext . Una vez que tenga el contexto, puede obtener la instancia HttpRequest de HttpContext.Request y usar sus propiedades Scheme , Host , Protocol , etc, como en:

 string scheme = HttpContextAccessor.HttpContext.Request.Scheme; 

Por ejemplo, puede requerir que su clase se configure con un HttpContextAccessor:

 public static class UrlHelperExtensions { private static IHttpContextAccessor HttpContextAccessor; public static void Configure(IHttpContextAccessor httpContextAccessor) { HttpContextAccessor = httpContextAccessor; } public static string AbsoluteAction( this IUrlHelper url, string actionName, string controllerName, object routeValues = null) { string scheme = HttpContextAccessor.HttpContext.Request.Scheme; return url.Action(actionName, controllerName, routeValues, scheme); } .... } 

Que es algo que puedes hacer en tu clase de Startup (archivo Startup.cs):

 public void Configure(IApplicationBuilder app) { ... var httpContextAccessor = app.ApplicationServices.GetRequiredService(); UrlHelperExtensions.Configure(httpContextAccessor); ... } 

Probablemente pueda encontrar diferentes formas de obtener el IHttpContextAccessor en su clase de extensión, pero si desea mantener sus métodos como métodos de extensión al final, necesitará inyectar el IHttpContextAccessor en su clase estática. (De lo contrario, necesitará el IHttpContext como argumento en cada llamada)


Solo obteniendo el Uri absoluto de la solicitud actual

Si solo desea obtener el uri absoluto de la solicitud actual, puede usar los métodos de extensión GetDisplayUrl o GetEncodedUrl de la clase UriHelper . (Que es diferente de Ur L Helper)

GetDisplayUrl . Devuelve los componentes combinados de la URL de la solicitud en un formato totalmente no escapado (excepto para QueryString) adecuado solo para la visualización. Este formato no debe usarse en encabezados HTTP u otras operaciones HTTP.

GetEncodedUrl . Devuelve los componentes combinados de la URL de la solicitud en una forma totalmente escapada adecuada para su uso en encabezados HTTP y otras operaciones HTTP.

Para usarlos:

  • Incluya el espacio de nombres Microsoft.AspNet.Http.Extensions .
  • Obtenga la instancia de HttpContext . Ya está disponible en algunas clases (como vistas de maquinilla de afeitar), pero en otros puede necesitar inyectar un IHttpContextAccessor como se explicó anteriormente.
  • Entonces solo utilícelos como en este this.Context.Request.GetDisplayUrl()

Una alternativa a esos métodos sería crear manualmente el uri absoluto usando los valores en el objeto HttpContext.Request (Similar a lo que hace el RequireHttpsAttribute ):

 var absoluteUri = string.Concat( request.Scheme, "://", request.Host.ToUriComponent(), request.PathBase.ToUriComponent(), request.Path.ToUriComponent(), request.QueryString.ToUriComponent()); 

Para ASP.NET Core 1.0 en adelante

Mientras que la respuesta de @ Daniel-jg es excelente, las cosas cambiaron mucho en RC2 y más, así que aquí está el código actualizado para atender a eso. Puede usar el siguiente código o usar el paquete Boilerplate.AspNetCore NuGet o crear un proyecto a partir de la plantilla de proyecto ASP.NET MVC Boilerplate , que incluye el paquete Boilerplate.AspNetCore NuGet.

 ///  ///  extension methods. ///  public static class UrlHelperExtensions { ///  /// Generates a fully qualified URL to an action method by using the specified action name, controller name and /// route values. ///  /// The URL helper. /// The name of the action method. /// The name of the controller. /// The route values. /// The absolute URL. public static string AbsoluteAction( this IUrlHelper url, string actionName, string controllerName, object routeValues = null) { return url.Action(actionName, controllerName, routeValues, url.ActionContext.HttpContext.Request.Scheme); } ///  /// Generates a fully qualified URL to the specified content by using the specified content path. Converts a /// virtual (relative) path to an application absolute path. ///  /// The URL helper. /// The content path. /// The absolute URL. public static string AbsoluteContent( this IUrlHelper url, string contentPath) { HttpRequest request = url.ActionContext.HttpContext.Request; return new Uri(new Uri(request.Scheme + "://" + request.Host.Value), url.Content(contentPath)).ToString(); } ///  /// Generates a fully qualified URL to the specified route by using the route name and route values. ///  /// The URL helper. /// Name of the route. /// The route values. /// The absolute URL. public static string AbsoluteRouteUrl( this IUrlHelper url, string routeName, object routeValues = null) { return url.RouteUrl(routeName, routeValues, url.ActionContext.HttpContext.Request.Scheme); } } 

Consejo de bonificación

No puede registrar directamente un IUrlHelper en el contenedor DI. La resolución de una instancia de IUrlHelper requiere el uso de IUrlHelperFactory y IActionContextAccessor . Sin embargo, puedes hacer lo siguiente como un atajo:

 services .AddSingleton() .AddScoped(x => x .GetRequiredService() .GetUrlHelper(x.GetRequiredService().ActionContext)); 

Si simplemente quiere un URI para un método que tiene una anotación de ruta, lo siguiente funcionó para mí.

Pasos

Obtener URL relativa

Al tomar nota del nombre de la ruta de la acción objective, obtenga la URL relativa usando la propiedad URL del controlador de la siguiente manera:

 var routeUrl = Url.RouteUrl("*Route Name Here*", new { *Route parameters here* }); 

Crea una URL absoluta

 var absUrl = string.Format("{0}://{1}{2}", Request.Scheme, Request.Host, routeUrl); 

Crea un nuevo Uri

 var uri = new Uri(absUrl, UriKind.Absolute) 

Ejemplo

 [Produces("application/json")] [Route("api/Children")] public class ChildrenController : Controller { private readonly ApplicationDbContext _context; public ChildrenController(ApplicationDbContext context) { _context = context; } // GET: api/Children [HttpGet] public IEnumerable GetChild() { return _context.Child; } [HttpGet("uris")] public IEnumerable GetChildUris() { return from c in _context.Child select new Uri( $"{Request.Scheme}://{Request.Host}{Uri.RouteUrl("GetChildRoute", new { id = c.ChildId })}", UriKind.Absolute); } // GET: api/Children/5 [HttpGet("{id}", Name = "GetChildRoute")] public IActionResult GetChild([FromRoute] int id) { if (!ModelState.IsValid) { return HttpBadRequest(ModelState); } Child child = _context.Child.Single(m => m.ChildId == id); if (child == null) { return HttpNotFound(); } return Ok(child); } } 

Esta es una variación del borrador de Muhammad Rehan Saeed , con la clase asociada parásitamente a la clase .NET core MVC existente del mismo nombre, por lo que todo funciona.

 namespace Microsoft.AspNetCore.Mvc { ///  ///  extension methods. ///  public static partial class UrlHelperExtensions { ///  /// Generates a fully qualified URL to an action method by using the specified action name, controller name and /// route values. ///  /// The URL helper. /// The name of the action method. /// The name of the controller. /// The route values. /// The absolute URL. public static string AbsoluteAction( this IUrlHelper url, string actionName, string controllerName, object routeValues = null) { return url.Action(actionName, controllerName, routeValues, url.ActionContext.HttpContext.Request.Scheme); } ///  /// Generates a fully qualified URL to the specified content by using the specified content path. Converts a /// virtual (relative) path to an application absolute path. ///  /// The URL helper. /// The content path. /// The absolute URL. public static string AbsoluteContent( this IUrlHelper url, string contentPath) { HttpRequest request = url.ActionContext.HttpContext.Request; return new Uri(new Uri(request.Scheme + "://" + request.Host.Value), url.Content(contentPath)).ToString(); } ///  /// Generates a fully qualified URL to the specified route by using the route name and route values. ///  /// The URL helper. /// Name of the route. /// The route values. /// The absolute URL. public static string AbsoluteRouteUrl( this IUrlHelper url, string routeName, object routeValues = null) { return url.RouteUrl(routeName, routeValues, url.ActionContext.HttpContext.Request.Scheme); } } } 

En un nuevo proyecto ASP.Net 5 MVC en una acción de controlador, puede hacer esto. this.Context y this.Context.Request Parece que en la solicitud ya no hay una propiedad Url, sino las propiedades secundarias (esquema, host, etc.) están todos en el objeto de solicitud directamente.

  public IActionResult About() { ViewBag.Message = "Your application description page."; var schema = this.Context.Request.Scheme; return View(); } 

Más bien o no, quieres usar esto. Contestar o insertar la propiedad es otra conversación. Inyección de dependencias en ASP.NET vNext

Puedes obtener la url así:

 Request.Headers["Referer"] 

Explicación

El Request.UrlReferer arrojará una System.UriFormatException si el encabezado HTTP del referer está mal formado (lo que puede suceder ya que generalmente no está bajo su control).

En cuanto al uso de Request.ServerVariables, por MSDN:

Colección Request.ServerVariables

La colección ServerVariables recupera los valores de variables de entorno predeterminadas y solicita información de encabezado. Propiedad de Request.Headers

Obtiene una colección de encabezados HTTP. Supongo que no entiendo por qué preferiría Request.ServerVariables en Request.Headers, ya que Request.ServerVariables contiene todas las variables de entorno, así como los encabezados, donde Request.Headers es una lista mucho más corta que solo contiene los encabezados. .

Entonces, la mejor solución es usar la colección Request.Headers para leer el valor directamente. Sin embargo, preste atención a las advertencias de Microsoft sobre el código HTML que codifica el valor si va a mostrarlo en un formulario.