Nhận URL tuyệt đối bằng ASP.NET Core


82

Trong MVC 5, tôi có các phương pháp mở rộng sau để tạo URL tuyệt đối, thay vì URL tương đối:

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

Tương tự trong ASP.NET Core là gì?

  • UrlHelper.RequestContext không còn tồn tại.
  • Bạn không thể nắm giữ HttpContextvì không còn thuộc HttpContext.Currenttính tĩnh .

Theo như tôi thấy, bây giờ bạn cũng sẽ yêu cầu HttpContexthoặc HttpRequestcác đối tượng cũng được chuyển vào. Tôi nói đúng chứ? Có cách nào để nắm bắt yêu cầu hiện tại không?

Tôi có đang đi đúng hướng không, tên miền bây giờ có phải là một biến môi trường, được nối đơn giản vào URL tương đối không? Đây sẽ là một cách tiếp cận tốt hơn?


1
Lấy URL tuyệt đối là gì?
im1dermike

@ im1dermike ví dụhttp://example.com/controller/action
Muhammad Rehan Saeed

Câu trả lời:


74

Sau RC2 và 1.0, bạn không cần phải thêm một IHttpContextAccessorlớp mở rộng cho mình nữa. Nó ngay lập tức có sẵn trong IUrlHelperthông qua urlhelper.ActionContext.HttpContext.Request. Sau đó, bạn sẽ tạo một lớp mở rộng theo cùng một ý tưởng, nhưng đơn giản hơn vì sẽ không liên quan đến việc tiêm.

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

Để lại thông tin chi tiết về cách xây dựng nó sẽ tiêm accesor trong trường hợp chúng hữu ích cho ai đó. Bạn cũng có thể chỉ quan tâm đến url tuyệt đối của yêu cầu hiện tại, trong trường hợp đó, hãy xem phần cuối của câu trả lời.


Bạn có thể sửa đổi lớp tiện ích mở rộng của mình để sử dụng IHttpContextAccessorgiao diện để lấy HttpContext. Một khi bạn có bối cảnh, sau đó bạn có thể lấy HttpRequeství dụ từ HttpContext.Requestvà sử dụng tính chất của nó Scheme, Host, Protocolvv như trong:

string scheme = HttpContextAccessor.HttpContext.Request.Scheme;

Ví dụ: bạn có thể yêu cầu lớp của mình được định cấu hình bằng 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);
    }

    ....
}

Đó là điều bạn có thể làm trên Startuplớp của mình (tệp Startup.cs):

public void Configure(IApplicationBuilder app)
{
    ...

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

    ...
}

Bạn có thể nghĩ ra nhiều cách khác nhau để nhận được IHttpContextAccessortrong lớp mở rộng của mình, nhưng nếu bạn muốn giữ các phương thức của mình làm phương thức mở rộng thì cuối cùng, bạn sẽ cần phải đưa IHttpContextAccessorvào lớp tĩnh của mình. (Nếu không, bạn sẽ cần IHttpContextđối số dưới dạng đối số trên mỗi cuộc gọi)


Chỉ nhận được tuyệt đối của yêu cầu hiện tại

Nếu bạn chỉ muốn nhận được tiểu tuyệt đối của yêu cầu hiện tại, bạn có thể sử dụng các phương thức mở rộng GetDisplayUrlhoặc GetEncodedUrltừ UriHelperlớp. (Khác với Ur L Helper)

GetDisplayUrl . Trả về các thành phần kết hợp của URL yêu cầu ở dạng hoàn toàn không thoát (ngoại trừ Chuỗi truy vấn) chỉ phù hợp để hiển thị. Định dạng này không được sử dụng trong tiêu đề HTTP hoặc các hoạt động HTTP khác.

GetEncodedUrl . Trả về các thành phần kết hợp của URL yêu cầu ở dạng thoát hoàn toàn phù hợp để sử dụng trong tiêu đề HTTP và các hoạt động HTTP khác.

Để sử dụng chúng:

  • Bao gồm không gian tên Microsoft.AspNet.Http.Extensions.
  • Lấy HttpContextví dụ. Nó đã có sẵn trong một số lớp (như chế độ xem dao cạo), nhưng ở những lớp khác, bạn có thể cần phải tiêm một IHttpContextAccessornhư giải thích ở trên.
  • Sau đó, chỉ cần sử dụng chúng như trong this.Context.Request.GetDisplayUrl()

Một giải pháp thay thế cho các phương pháp đó sẽ là tạo thủ công cho chính bạn tiểu tuyệt đối bằng cách sử dụng các giá trị trong HttpContext.Requestđối tượng (Tương tự như những gì RequestHttpsAttribute làm):

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

Bây giờ chúng ta nên sử dụng IUrlHelper, thay vì UrlHelper. Tất cả các đối tượng được ngắt kết nối nhiều hơn trong MVC 6. Tôi nghĩ lựa chọn của bạn là lựa chọn tốt nhất.
Muhammad Rehan Saeed

Không hoạt động với RC1. Chế độ xem tạo ra lỗi thời gian chạy với phương thức mở rộng. Ngoài ra, UriHelperliên kết đã chết.
Mrchief

2
@Mrchief Tôi đã cập nhật liên kết (không gian tên đã thay đổi cho RC2, vì vậy tất cả các liên kết đến nhánh nhà phát triển đã chết ...). Tuy nhiên tôi đã vừa tạo ra một dự án RC1, thêm @using Microsoft.AspNet.Http.Extensionsvào xem Index.cshtml và đã có thể sử dụng những phần mở rộng như trong@Context.Request.GetDisplayUrl()
Daniel JG

44

Đối với ASP.NET Core 1.0 trở đi

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

Mẹo thưởng

Bạn không thể đăng ký trực tiếp một IUrlHelpertrong DI container. Giải quyết một phiên bản của IUrlHelperyêu cầu bạn sử dụng IUrlHelperFactoryIActionContextAccessor. Tuy nhiên, bạn có thể thực hiện các thao tác sau như một phím tắt:

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

ASP.NET Core Backlog

CẬP NHẬT : Điều này sẽ không làm cho ASP.NET Core 5

Có những dấu hiệu cho thấy bạn có thể sử dụng LinkGeneratorđể tạo URL tuyệt đối mà không cần cung cấp HttpContext(Đây là nhược điểm lớn nhất LinkGeneratorvà tại sao IUrlHelpermặc dù phức tạp hơn để thiết lập bằng giải pháp bên dưới nhưng lại dễ sử dụng hơn) Xem "Giúp dễ dàng định cấu hình một máy chủ / lược đồ cho các URL tuyệt đối với LinkGenerator " .


1
Điều đó có làm được những gì tôi cần không? Xem stackoverflow.com/q/37928214/153923
jp2code

4
Điều này là ổn nhưng nó có vẻ quá mức cần thiết đối với tôi, quá nhiều mã cho một thứ đơn giản. Chúng ta có thể gắn bó vớistring url = string.Concat(this.Request.Scheme, "://", this.Request.Host, this.Request.Path, this.Request.QueryString);
Junior Mayhé 02/02

19

Bạn không cần tạo một phương thức mở rộng cho việc này

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

  • Action - Tên của hành động
  • Controller - Tên người điều khiển
  • values - Đối tượng chứa giá trị tuyến: hay còn gọi là tham số GET

Ngoài ra còn có rất nhiều quá tải khácUrl.Action mà bạn có thể sử dụng để tạo liên kết.


1
Cảm ơn! Đây chính xác là những gì tôi cần, nhưng tôi không hiểu là gì this.Context.Request.Scheme. Điều đó có chỉ nhận được các phần giao thức và miền của URL không?
Lukas

this.Context.Request.Schematrả về giao thức đã được sử dụng cho yêu cầu. Nó sẽ là httphoặc https. Đây là tài liệu nhưng nó không thực sự giải thích ý nghĩa của Schema.
Kelly Elton

14

Nếu bạn chỉ muốn một Uri cho một phương thức có chú thích tuyến đường, thì cách sau phù hợp với tôi.

Các bước

Nhận URL tương đối

Lưu ý tên tuyến của hành động đích, lấy URL tương đối bằng cách sử dụng thuộc tính URL của bộ điều khiển như sau:

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

Tạo một URL tuyệt đối

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

Tạo một Uri mới

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

Thí dụ

[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

Đây là một biến thể của anwser của Muhammad Rehan Saeed , với lớp này được gắn một cách ký sinh vào lớp MVC lõi .net hiện có cùng tên, để mọi thứ hoạt động.

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

4

Tôi vừa phát hiện ra rằng bạn có thể làm điều đó với cuộc gọi này:

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

Điều này sẽ duy trì lược đồ, máy chủ, cổng, mọi thứ.


3

Trong dự án ASP.Net 5 MVC mới trong hành động của bộ điều khiển, bạn vẫn có thể thực hiện this.Contextvà có this.Context.Requestvẻ như trên Yêu cầu không còn thuộc tính Url nữa nhưng các thuộc tính con (lược đồ, máy chủ, v.v.) đều nằm trực tiếp trên đối tượng yêu cầu.

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

        return View();
    }

Thay vào đó bạn muốn sử dụng điều này. Tiếp theo hoặc chèn thuộc tính là một cuộc hội thoại khác. Chèn phụ thuộc trong ASP.NET vNext


3

Nếu bạn chỉ muốn chuyển đổi một đường dẫn tương đối với các tham số tùy chọn, tôi đã tạo một phương thức mở rộng cho 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);
}

Sau đó, bạn có thể gọi phương thức từ dịch vụ / chế độ xem của mình bằng IHttpContextAccessor được đưa vào

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

2

Bạn có thể lấy url như sau:

Request.Headers["Referer"]

Giải trình

Các Request.UrlReferersẽ ném một System.UriFormatExceptionnếu referer tiêu đề HTTP là bị thay đổi (có thể xảy ra vì nó không phải là thường dưới sự kiểm soát của bạn).

Đối với việc sử dụng Request.ServerVariables, theo MSDN :

Bộ sưu tập Request.ServerVariables

Bộ sưu tập ServerVariables truy xuất các giá trị của các biến môi trường xác định trước và yêu cầu thông tin tiêu đề.

Thuộc tính Request.Headers

Nhận một tập hợp các tiêu đề HTTP.

Tôi đoán tôi không hiểu tại sao bạn lại thích cái Request.ServerVariableshơn Request.Headers, vì Request.ServerVariableschứa tất cả các biến môi trường cũng như tiêu đề, trong đó Request.Headers là một danh sách ngắn hơn nhiều chỉ chứa các tiêu đề.

Vì vậy, giải pháp tốt nhất là sử dụng Request.Headersbộ sưu tập để đọc giá trị trực tiếp. Tuy nhiên, hãy chú ý đến cảnh báo của Microsoft về việc mã hóa HTML nếu bạn định hiển thị nó trên một biểu mẫu.


Người giới thiệu không đáng tin cậy, các trình duyệt không bị buộc phải gửi nó. Nói cách khác, người dùng có thể cấu hình trình duyệt của họ không gửi tham chiếu, ví dụ như một biện pháp bảo mật.
mikiqex
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.