c# - route - Obtener URL absolutas utilizando ASP.NET Core
tag helpers asp net core (8)
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
ya que ya no hay una propiedad estáticaHttpContext.Current
.
Por lo que puedo ver, ahora requeriría que también se pasen los objetos
HttpContext
o
HttpRequest
.
Estoy en lo cierto?
¿Hay alguna forma de obtener la solicitud actual?
¿Estoy incluso en el camino correcto? ¿Debería el dominio ser ahora una variable de entorno, que se agrega simplemente a la URL relativa? ¿Sería este un mejor enfoque?
Para ASP.NET Core 1.0 en adelante
Puede usar el código a continuación o usar el paquete Boxed.AspNetCore NuGet o ver el código en el repositorio Dotnet-Boxed/Framework GitHub.
/// <summary>
/// <see cref="IUrlHelper"/> extension methods.
/// </summary>
public static class UrlHelperExtensions
{
/// <summary>
/// Generates a fully qualified URL to an action method by using the specified action name, controller name and
/// route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="contentPath">The content path.</param>
/// <returns>The absolute URL.</returns>
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();
}
/// <summary>
/// Generates a fully qualified URL to the specified route by using the route name and route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="routeName">Name of the route.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
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.
Resolver una instancia de
IUrlHelper
requiere que use
IUrlHelperFactory
e
IActionContextAccessor
.
Sin embargo, puede hacer lo siguiente como acceso directo:
services
.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddScoped<IUrlHelper>(x => x
.GetRequiredService<IUrlHelperFactory>()
.GetUrlHelper(x.GetRequiredService<IActionContextAccessor>().ActionContext));
En un nuevo proyecto MVC de ASP.Net 5 en una acción de controlador, aún puede hacer esto.
this.Context
y
this.Context.Request
this.Context
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 desea usar esto. El contexto o la inyección de la propiedad es otra conversación. Inyección de dependencias en ASP.NET vNext
Esta es una variación de la respuesta de , con la clase uniéndose parasitariamente a la clase MVC de .net core existente del mismo nombre, para que todo funcione.
namespace Microsoft.AspNetCore.Mvc
{
/// <summary>
/// <see cref="IUrlHelper"/> extension methods.
/// </summary>
public static partial class UrlHelperExtensions
{
/// <summary>
/// Generates a fully qualified URL to an action method by using the specified action name, controller name and
/// route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="contentPath">The content path.</param>
/// <returns>The absolute URL.</returns>
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();
}
/// <summary>
/// Generates a fully qualified URL to the specified route by using the route name and route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="routeName">Name of the route.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
public static string AbsoluteRouteUrl(
this IUrlHelper url,
string routeName,
object routeValues = null)
{
return url.RouteUrl(routeName, routeValues, url.ActionContext.HttpContext.Request.Scheme);
}
}
}
No necesita crear un método de extensión para esto
@Url.Action("Action", "Controller", null, this.Context.Request.Scheme);
Puede obtener la URL de esta manera:
Request.Headers["Referer"]
Explicación
Request.UrlReferer
arrojará un
System.UriFormatException
si el encabezado HTTP de referencia tiene un formato incorrecto (lo que puede suceder ya que generalmente no está bajo su control).
En cuanto al uso de
Request.ServerVariables
,
por MSDN
:
Request.ServerVariables Collection
La colección ServerVariables recupera los valores de variables de entorno predeterminadas y solicita información de encabezado.
Propiedad Request.Headers
Obtiene una colección de encabezados HTTP.
Supongo que no entiendo por qué preferiría
Request.ServerVariables
sobre
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, tenga en cuenta las advertencias de Microsoft sobre la codificación HTML del valor si va a mostrarlo en un formulario.
Si simplemente desea un Uri para un método que tiene una anotación de ruta, lo siguiente funcionó para mí.
Pasos
Obtener URL relativa
Observando el nombre de ruta de la acción de destino, obtenga la URL relativa utilizando 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<Child> GetChild()
{
return _context.Child;
}
[HttpGet("uris")]
public IEnumerable<Uri> GetChildUris()
{
return from c in _context.Child
select
new Uri(
$"{Request.Scheme}://{Request.Host}{Url.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);
}
}
Si solo desea convertir una ruta relativa con parámetros opcionales, creé un método de extensión para IHttpContextAccessor
public static string AbsoluteUrl(this IHttpContextAccessor httpContextAccessor, string relativeUrl, object parameters = null)
{
var request = httpContextAccessor.HttpContext.Request;
var url = new Uri(new Uri($"{request.Scheme}://{request.Host.Value}"), relativeUrl).ToString();
if (parameters != null)
{
url = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(url, ToDictionary(parameters));
}
return url;
}
private static Dictionary<string, string> ToDictionary(object obj)
{
var json = JsonConvert.SerializeObject(obj);
return JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
Luego puede llamar al método desde su servicio / vista usando el IHttpContextAccessor inyectado
var callbackUrl = _httpContextAccessor.AbsoluteUrl("/Identity/Account/ConfirmEmail", new { userId = applicationUser.Id, code });
Después de RC2 y 1.0
ya no necesita inyectar un
IHttpContextAccessor
en su clase de extensión.
Está inmediatamente disponible 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);
}
Dejar 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 el
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, podría 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 puede hacer en su clase de
Startup
(archivo Startup.cs):
public void Configure(IApplicationBuilder app)
{
...
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
UrlHelperExtensions.Configure(httpContextAccessor);
...
}
Probablemente podría 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, deberá 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 la uri absoluta de la solicitud actual, puede usar los métodos de extensión
GetDisplayUrl
o
GetEncodedUrl
de la clase
UriHelper
.
(Que es diferente del ayudante Ur
L
)
GetDisplayUrl . Devuelve los componentes combinados de la URL de solicitud en un formato completamente sin escape (excepto el QueryString) adecuado solo para su visualización. Este formato no debe usarse en encabezados HTTP u otras operaciones HTTP.
GetEncodedUrl . Devuelve los componentes combinados de la URL de solicitud en un formato totalmente escapado adecuado 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 las vistas de afeitar), pero en otras puede que necesite inyectar unIHttpContextAccessor
como se explicó anteriormente. -
Luego, solo utilícelos como en
this.Context.Request.GetDisplayUrl()
Una alternativa a esos métodos sería crear manualmente la uri absoluta utilizando 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());