Подтвердить что ты не робот

Получение абсолютных URL-адресов с помощью ASP.NET Core

В 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.

Насколько я могу видеть, теперь вам потребуется также HttpContext объекты HttpContext или HttpRequest. Я прав? Есть ли способ получить текущий запрос?

Я даже на правильном пути, должен ли домен теперь быть переменной среды, которая просто добавляется к относительному URL? Будет ли это лучший подход?

4b9b3361

Ответ 1

Для ASP.NET Core 1.0 и выше

Вы можете использовать приведенный ниже код или пакет Boxed.AspNetCore NuGet или просмотреть код в репозитории 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);
    }
}

Бонусный совет

Вы не можете напрямую зарегистрировать IUrlHelper в контейнере DI. Для разрешения экземпляра IUrlHelper необходимо использовать IUrlHelperFactory и IActionContextAccessor. Тем не менее, вы можете сделать следующее в качестве ярлыка:

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

Ответ 2

После 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);
}

Оставлять детали о том, как его создать, впрыскивая accesor в случае, если они полезны кому-то. Вы также можете просто заинтересоваться абсолютным URL-адресом текущего запроса, и в этом случае взгляните на конец ответа.


Вы можете изменить свой класс расширения, чтобы использовать IHttpContextAccessor интерфейс, чтобы получить HttpContext. Когда у вас есть контекст, вы можете получить HttpRequest экземпляр HttpContext.Request и использовать его свойства Scheme, Host, Protocol и т.д., как в:

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 в вашем классе расширения, но если вы хотите, чтобы ваши методы были расширенными, в конце вам нужно будет ввести IHttpContextAccessor в свой статический класс. (В противном случае вам понадобится IHttpContext в качестве аргумента для каждого вызова)


Просто получая absoluteUri текущего запроса

Если вы просто хотите получить абсолютный uri текущего запроса, вы можете использовать методы расширения GetDisplayUrl или GetEncodedUrl из UriHelper. (Что отличается от UrLHelper)

GetDisplayUrl. Возвращает комбинированные компоненты URL-адреса запроса в полностью неэкранированной форме (за исключением QueryString), подходящей только для дисплея. Этот формат не должен использоваться в заголовках HTTP или других HTTP-операции.

GetEncodedUrl. Возвращает комбинированные компоненты URL-адреса запроса в полностью экранированной форме, подходящей для использования в заголовках HTTP и других HTTP-операции.

Чтобы использовать их:

  • Включить пространство имен Microsoft.AspNet.Http.Extensions.
  • Получить экземпляр HttpContext. Он уже доступен в некоторых классах (например, виды бритвы), но в других вам может понадобиться ввести IHttpContextAccessor, как описано выше.
  • Затем используйте их как в this.Context.Request.GetDisplayUrl()

Альтернативой этим методам было бы вручную создать абсолютный uri, используя значения в объекте HttpContext.Request (подобно тому, как RequireHttpsAttribute делает):

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

Ответ 3

Если вам просто нужен 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);
    }
}

Ответ 4

Это вариация anwser Мухаммад Рехан Саид, причем класс получает паразитную привязку к существующему классу MVC ядра .net с тем же именем, чтобы все просто работало.

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

В новом проекте ASP.Net 5 MVC в действии контроллера вы все равно можете делать this.Context и this.Context.Request Похоже, что в запросе уже нет свойства Url, но его свойства (схема, хост и т.д.) ) все находятся непосредственно на объекте запроса.

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

        return View();
    }

Скорее или нет, вы хотите использовать this.Context или ввести свойство - это другой разговор. Инъекция зависимостей в ASP.NET vNext

Ответ 6

Вы можете получить URL, как это:

Request.Headers["Referer"]

объяснение

Request.UrlReferer System.UriFormatException если заголовок HTTP Request.UrlReferer имеет неправильный формат (что может произойти, поскольку он обычно не находится под вашим контролем).

Что касается использования Request.ServerVariables, для MSDN:

Request.ServerVariables Collection

Коллекция ServerVariables извлекает значения предопределенных переменных среды и информацию заголовка запроса.

Request.Headers Недвижимость

Получает коллекцию заголовков HTTP.

Думаю, я не понимаю, почему вы бы предпочли Request.ServerVariables Request.Headers, поскольку Request.ServerVariables содержит все переменные среды, а также заголовки, где Request.Headers - гораздо более короткий список, который содержит только заголовки.,

Поэтому лучшим решением является использование коллекции Request.Headers для непосредственного чтения значения. Обратите внимание на предупреждения Microsoft о HTML-кодировке значения, если вы собираетесь отображать его в форме.

Ответ 7

Вам не нужно создавать метод расширения для этого

@Url.Action("Action", "Controller", null, this.Context.Request.Scheme);

Ответ 8

Если вы просто хотите преобразовать относительный путь с необязательными параметрами, я создал метод расширения для 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 });