使用ASP.NET Core获取绝对URL


82

在MVC 5中,我具有以下扩展方法来生成绝对URL,而不是相对的:

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

ASP.NET Core中的等效项是什么?

  • UrlHelper.RequestContext 不复存在。
  • 您无法控制,HttpContext因为不再有静态HttpContext.Current属性。

据我所知,您现在还需要传入HttpContextHttpRequest对象。我对吗?有什么方法可以控制当前请求?

我是否在正确的轨道上,现在该域是否应该是一个环境变量,该变量应简单地附加到相对URL?这会是更好的方法吗?


1
获取绝对URL是什么?
im1dermike 2015年

@ im1dermike,例如http://example.com/controller/action
Muhammad Rehan Saeed

Answers:


74

在RC2和1.0之后,您不再需要为IHttpContextAccessor扩展类注入。它是立即IUrlHelper通过urlhelper.ActionContext.HttpContext.Request。然后,您将按照相同的想法创建一个扩展类,但由于不会涉及注入,因此更简单。

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

保留有关如何构建它的详细信息,以防万一它们对某人有用时将其注入。您可能也只对当前请求的绝对URL感兴趣,在这种情况下,请查看答案的结尾。


您可以修改扩展类以使用IHttpContextAccessor接口获取HttpContext。一旦你的情况下,那么你就可以得到HttpRequest从实例HttpContext.Request和使用其属性SchemeHostProtocol等如:

string scheme = HttpContextAccessor.HttpContext.Request.Scheme;

例如,您可能需要使用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);
    }

    ....
}

您可以在Startup课堂上执行以下操作(Startup.cs文件):

public void Configure(IApplicationBuilder app)
{
    ...

    var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
    UrlHelperExtensions.Configure(httpContextAccessor);

    ...
}

您可能想出了各种方法来获取IHttpContextAccessor扩展类,但是,如果最终想保留扩展方法,则需要将in注入IHttpContextAccessor静态类。(否则,您将需要IHttpContext在每次调用时将用作参数)


只是获取当前请求的absoluteUri

如果只想获取当前请求的绝对uri,则可以使用扩展方法GetDisplayUrlGetEncodedUrlUriHelper类中获取。(与Ur L帮助器不同)

GetDisplayUrl。以完全未转义的形式(仅QueryString)返回请求URL的组合组成部分,仅适用于显示。HTTP标头或其他HTTP操作中不应使用此格式。

GetEncodedUrl。以完全转义的形式返回请求URL的组合组件,适合在HTTP标头和其他HTTP操作中使用。

为了使用它们:

  • 包括名称空间Microsoft.AspNet.Http.Extensions
  • 获取HttpContext实例。在某些类中(例如剃刀视图)它已经可用,但是在其他类中,您可能需要注入IHttpContextAccessor,如上所述。
  • 然后像使用它们一样 this.Context.Request.GetDisplayUrl()

这些方法的替代方法是使用HttpContext.Request对象中的值手动制作绝对uri (类似于RequireHttpsAttribute的功能):

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

现在,我们应该使用IUrlHelper,而不是UrlHelper。在MVC 6中,所有对象都断开了很多连接。我认为您的选择是最好的选择。
穆罕默德·里汉

不适用于RC1。视图使用扩展方法产生运行时错误。此外,UriHelper链接已死。
Mrchief '16

2
@Mrchief我已经更新了链接(RC2的名称空间已更改,因此所有指向dev分支的链接都已失效...)。但是,我刚刚创建了一个RC1项目,将其添加@using Microsoft.AspNet.Http.Extensions到Index.cshtml视图中,并且能够使用这些扩展,例如@Context.Request.GetDisplayUrl()
Daniel JG 2016年

44

对于ASP.NET Core 1.0及更高版本

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

奖金提示

您不能直接IUrlHelper在DI容器中注册。解决的实例IUrlHelper需要您使用IUrlHelperFactoryIActionContextAccessor。但是,您可以作为快捷方式执行以下操作:

services
    .AddSingleton<IActionContextAccessor, ActionContextAccessor>()
    .AddScoped<IUrlHelper>(x => x
        .GetRequiredService<IUrlHelperFactory>()
        .GetUrlHelper(x.GetRequiredService<IActionContextAccessor>().ActionContext));

ASP.NET Core积压

更新:这不会使ASP.NET Core 5

有迹象表明,您LinkGenerator无需提供以下操作即可创建绝对URL HttpContext(这是最大的缺点,LinkGenerator为什么IUrlHelper使用以下解决方案设置起来更复杂,却更易于使用),请参阅“使配置变得容易LinkGenerator的绝对URL的主机/方案”


1
那还会做我需要的吗?参见stackoverflow.com/q/37928214/153923
jp2code

4
没关系,但是对我来说似乎太过分了,对于简单的事情来说,代码太多了。我们可以坚持string url = string.Concat(this.Request.Scheme, "://", this.Request.Host, this.Request.Path, this.Request.QueryString);

19

您不需要为此创建扩展方法

@Url.Action("Action", "Controller", values: null);

  • Action -动作名称
  • Controller -控制器名称
  • values -包含路径值的对象:又名GET参数

也有很多其他的重载到Url.Action你可以用它来生成链接。


1
谢谢!这正是我所需要的,但我不需要了解是什么this.Context.Request.Scheme。这是否只是获取URL的协议和域部分?
卢卡斯

this.Context.Request.Schema返回用于请求的协议。将会是httphttps。这是文档,但并没有真正解释Schema的含义。
凯利·艾尔顿

14

如果您只是想为带有路由注释的方法使用Uri,以下方法对我有用。

脚步

获取相对URL

注意目标操作的路由名称,使用控制器的URL属性获取相对URL ,如下所示:

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

创建一个绝对URL

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

创建一个新的Uri

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

9

这是Muhammad Rehan Saeed对anwser的变体,该类寄生于现有的同名.net核心MVC类,因此一切正常。

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

5

我刚刚发现您可以通过以下调用完成此操作:

Url.Action(new UrlActionContext
{
    Protocol = Request.Scheme,
    Host = Request.Host.Value,
    Action = "Action"
})

这将维护方案,主机,端口以及所有内容。


3

在新的ASP.Net 5 MVC项目中,您仍然可以执行控制器操作,this.Context并且this.Context.Request在Request上看起来不再有Url属性,但子属性(架构,主机等)都直接在请求对象上。

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

        return View();
    }

而不是您是否要使用this.Context或注入属性是另一个对话。 ASP.NET vNext中的依赖注入


3

如果您只想使用可选参数转换相对路径,则为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);
}

然后,您可以使用注入的IHttpContextAccessor从服务/视图中调用该方法。

var callbackUrl = _httpContextAccessor.AbsoluteUrl("/Identity/Account/ConfirmEmail", new { userId = applicationUser.Id, code });

2

您可以这样获得网址:

Request.Headers["Referer"]

说明

如果引荐来源的HTTP标头格式错误(如果通常不在您的控制之下,则可能会发生这种情况),Request.UrlReferer它将抛出System.UriFormatException

至于使用Request.ServerVariables根据MSDN

Request.ServerVariables集合

ServerVariables集合检索预定环境变量的值和请求标头信息。

Request.Headers属性

获取HTTP标头的集合。

我想我不明白为什么您会喜欢Request.ServerVariablesover Request.Headers,因为它Request.ServerVariables包含所有环境变量以及标头,其中Request.Headers是一个短得多的列表,仅包含标头。

因此最好的解决方案是使用Request.Headers集合直接读取值。但是,如果要在表单上显示该值,请注意Microsoft有关HTML编码值的警告。


引荐来源网址不可靠,浏览器没有被迫发送。换句话说,用户可以将其浏览器配置为不发送引用,例如,作为一种安全措施。
mikiqex
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.