Dans MVC 5, j'avais les méthodes d'extension suivantes pour générer des URL absolues, au lieu de celles relatives:
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);
}
}
Quel serait l'équivalent dans ASP.NET Core?
UrlHelper.RequestContext
n'existe plus.HttpContext
car il n’existe plus de propriété statique HttpContext.Current
.Autant que je sache, vous auriez maintenant besoin que les objets HttpContext
ou HttpRequest
soient également transmis. Ai-je raison? Y a-t-il un moyen de mettre la main sur la demande actuelle?
Si je suis même sur la bonne voie, le domaine devrait-il maintenant être une variable d'environnement, qui est simplement ajoutée à l'URL relative? Serait-ce une meilleure approche?
Vous pouvez utiliser le code ci-dessous ou utiliser le package Boxed.AspNetCore NuGet ou consulter le code dans le référentiel 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);
}
}
Vous ne pouvez pas enregistrer directement une IUrlHelper
dans le conteneur DI. La résolution d'une instance de IUrlHelper
nécessite que vous utilisiez IUrlHelperFactory
et IActionContextAccessor
. Toutefois, vous pouvez effectuer les opérations suivantes sous forme de raccourci:
services
.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddScoped<IUrlHelper>(x => x
.GetRequiredService<IUrlHelperFactory>()
.GetUrlHelper(x.GetRequiredService<IActionContextAccessor>().ActionContext));
Après RC2 et 1.0, vous n'avez plus besoin d'injecter une IHttpContextAccessor
dans votre classe d'extension. Il est immédiatement disponible dans la IUrlHelper
au urlhelper.ActionContext.HttpContext.Request
. Vous créeriez alors une classe d'extension en suivant la même idée, mais plus simplement, car aucune injection ne serait impliquée.
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);
}
Laissant les détails sur la façon de le construire en injectant l’accès au cas où ils seraient utiles à quelqu'un. Vous pouvez également vous intéresser à l'URL absolue de la demande en cours, auquel cas, jetez un coup d'œil à la fin de la réponse.
Vous pouvez modifier votre classe d'extension pour utiliser l'interface IHttpContextAccessor
afin d'obtenir le HttpContext
. Une fois que vous avez le contexte, vous pouvez obtenir l'instance HttpRequest
de HttpContext.Request
et utiliser ses propriétés Scheme
, Host
, Protocol
etc comme dans:
string scheme = HttpContextAccessor.HttpContext.Request.Scheme;
Par exemple, vous pouvez exiger que votre classe soit configurée avec 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);
}
....
}
Ce que vous pouvez faire dans votre classe Startup
(fichier Startup.cs):
public void Configure(IApplicationBuilder app)
{
...
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
UrlHelperExtensions.Configure(httpContextAccessor);
...
}
Vous pourriez probablement trouver différentes façons d’obtenir la IHttpContextAccessor
dans votre classe d’extension, mais si vous souhaitez conserver vos méthodes en tant que méthodes d’extension, vous devrez injecter la IHttpContextAccessor
dans votre classe statique. (Sinon, vous aurez besoin de la IHttpContext
comme argument à chaque appel)
Juste en train de récupérer l'absolaireUri de la requête en cours
Si vous voulez simplement obtenir l'URI absolu de la requête en cours, vous pouvez utiliser les méthodes d'extension GetDisplayUrl
ou GetEncodedUrl
de la classe UriHelper
. (Ce qui est différent de l'aide urL)
GetDisplayUrl. Renvoie les composants combinés de l'URL de la demande sous une forme entièrement non échappée (à l'exception de QueryString) appropriée uniquement pour l'affichage. Ce format ne doit pas être utilisé dans les en-têtes HTTP ou autres Opérations HTTP.
GetEncodedUrl. Renvoie les composants combinés de l'URL de la demande sous une forme entièrement échappée, utilisable dans les en-têtes HTTP et autres Opérations HTTP.
Pour les utiliser:
Microsoft.AspNet.Http.Extensions
. HttpContext
. Il est déjà disponible dans certaines classes (comme les vues rasoir), mais dans d'autres, vous devrez peut-être injecter une IHttpContextAccessor
comme expliqué ci-dessus. this.Context.Request.GetDisplayUrl()
Une alternative à ces méthodes serait de vous fabriquer manuellement l'URI absolu en utilisant les valeurs de l'objet HttpContext.Request
(similaire à ce que fait le RequireHttpsAttribute ):
var absoluteUri = string.Concat(
request.Scheme,
"://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent(),
request.Path.ToUriComponent(),
request.QueryString.ToUriComponent());
Si vous voulez simplement un Uri pour une méthode qui a une annotation de route, les éléments suivants ont fonctionné pour moi.
En notant le nom de route de l'action cible, obtenez l'URL relative à l'aide de la propriété URL du contrôleur comme suit:
var routeUrl = Url.RouteUrl("*Route Name Here*", new { *Route parameters here* });
var absUrl = string.Format("{0}://{1}{2}", Request.Scheme,
Request.Host, routeUrl);
var uri = new Uri(absUrl, UriKind.Absolute)
[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);
}
}
Ceci est une variante de la réponse de Muhammad Rehan Saeed , la classe se liant de manière parasite à la classe MVC de noyau .net existante du même nom, de sorte que tout fonctionne correctement.
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);
}
}
}
Dans un nouveau projet ASP.Net 5 MVC dans une action de contrôleur, vous pouvez toujours exécuter this.Context
et this.Context.Request
. Il semble que dans la demande, il n'y a plus de propriété Url, mais que les propriétés enfants (schéma, hôte, etc.) se trouvent toutes dans l'objet de la requête directement.
public IActionResult About()
{
ViewBag.Message = "Your application description page.";
var schema = this.Context.Request.Scheme;
return View();
}
Vous préférez ou non utiliser this.Context ou injecter la propriété est une autre conversation . Injection de dépendance dans ASP.NET vNext
Vous pouvez obtenir l'URL comme ceci:
Request.Headers["Referer"]
Explication
Le Request.UrlReferer
lancera un System.UriFormatException
si l'en-tête HTTP du référent est mal formé (ce qui peut arriver car il n'est généralement pas sous votre contrôle).
Quant à l’utilisation de Request.ServerVariables
, par MSDN :
Collection Request.ServerVariables
La collection ServerVariables récupère les valeurs de variables d'environnement prédéterminées et les informations d'en-tête de demande.
Propriété Request.Headers
Obtient une collection d'en-têtes HTTP.
Je suppose que je ne comprends pas pourquoi vous préféreriez le Request.ServerVariables
au Request.Headers
, puisque Request.ServerVariables
contient toutes les variables d'environnement ainsi que les en-têtes, où Request.Headers est une liste beaucoup plus courte qui ne contient que les en-têtes.
La meilleure solution consiste donc à utiliser la collection Request.Headers
pour lire directement la valeur. Tenez compte des avertissements de Microsoft concernant le codage HTML de la valeur si vous souhaitez l’afficher sur un formulaire.
Si vous voulez simplement convertir un chemin relatif avec des paramètres optionnels, j'ai créé une méthode d'extension pour 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);
}
Vous pouvez ensuite appeler la méthode à partir de votre service/vue à l’aide du paramètre injecté IHttpContextAccessor
var callbackUrl = _httpContextAccessor.AbsoluteUrl("/Identity/Account/ConfirmEmail", new { userId = applicationUser.Id, code });