W MVC 5 miałem następujące metody rozszerzeń do generowania bezwzględnych adresów URL zamiast względnych:
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);
}
}
Jaki byłby odpowiednik w ASP.NET Core?
UrlHelper.RequestContext
już nie istnieje.- Nie możesz go zdobyć,
HttpContext
ponieważ nie ma już statycznejHttpContext.Current
właściwości.
O ile widzę, teraz wymagałbyś, aby obiekty HttpContext
lub HttpRequest
zostały również przekazane. Czy mam rację? Czy jest jakiś sposób, aby uzyskać bieżące żądanie?
Czy jestem w ogóle na dobrej drodze, czy domena powinna być teraz zmienną środowiskową, którą można po prostu dodać do względnego adresu URL? Czy byłoby to lepsze podejście?
c#
asp.net-core
Muhammad Rehan Saeed
źródło
źródło
http://example.com/controller/action
Odpowiedzi:
Po RC2 i 1.0 nie musisz już wstrzykiwać sobie
IHttpContextAccessor
klasy rozszerzającej. Jest dostępna wIUrlHelper
poprzezurlhelper.ActionContext.HttpContext.Request
. Następnie utworzyłbyś klasę rozszerzającą zgodnie z tym samym pomysłem, ale prostszą, ponieważ nie będzie wymagało wstrzyknięcia.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); }
Pozostawiając szczegóły, jak to zbudować, wstrzykując accesor na wypadek, gdyby były dla kogoś przydatne. Możesz być także zainteresowany bezwzględnym adresem URL bieżącego żądania, w takim przypadku spójrz na koniec odpowiedzi.
Możesz zmodyfikować swoją klasę rozszerzenia, aby używać
IHttpContextAccessor
interfejsu do pobieraniaHttpContext
. Gdy masz kontekst, a następnie można uzyskaćHttpRequest
instancję odHttpContext.Request
i korzystać z jego właściwościScheme
,Host
,Protocol
etc jak w:string scheme = HttpContextAccessor.HttpContext.Request.Scheme;
Na przykład możesz wymagać, aby Twoja klasa była skonfigurowana za pomocą 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); } .... }
Co możesz zrobić na swojej
Startup
klasie (plik Startup.cs):public void Configure(IApplicationBuilder app) { ... var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>(); UrlHelperExtensions.Configure(httpContextAccessor); ... }
Prawdopodobnie mógłbyś wymyślić różne sposoby uzyskania
IHttpContextAccessor
klasy rozszerzającej, ale jeśli chcesz zachować swoje metody jako metody rozszerzające, ostatecznie będziesz musiał wstrzyknąć theIHttpContextAccessor
do swojej klasy statycznej. (W przeciwnym razie będziesz potrzebowaćIHttpContext
jako argumentu przy każdym połączeniu)Pobieram bezwzględneUri bieżącego żądania
Jeśli chcesz tylko uzyskać bezwzględny identyfikator URI bieżącego żądania, możesz użyć metod rozszerzających
GetDisplayUrl
lubGetEncodedUrl
zUriHelper
klasy. (Co różni się od Ur L Helper)Aby z nich skorzystać:
Microsoft.AspNet.Http.Extensions
.HttpContext
instancję. Jest już dostępny w niektórych klasach (takich jak widoki brzytwy), ale w innych może być konieczne wstrzyknięcie,IHttpContextAccessor
jak wyjaśniono powyżej.this.Context.Request.GetDisplayUrl()
Alternatywą dla tych metod byłoby ręczne utworzenie absolutnego URI przy użyciu wartości w
HttpContext.Request
obiekcie (podobnie do tego, co robi RequireHttpsAttribute ):var absoluteUri = string.Concat( request.Scheme, "://", request.Host.ToUriComponent(), request.PathBase.ToUriComponent(), request.Path.ToUriComponent(), request.QueryString.ToUriComponent());
źródło
UriHelper
link nie działa.@using Microsoft.AspNet.Http.Extensions
do widoku Index.cshtml i mogłem używać tych rozszerzeń, jak w@Context.Request.GetDisplayUrl()
W przypadku ASP.NET Core 1.0 i nowszych
/// <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); } }
Wskazówka bonusowa
Nie możesz bezpośrednio zarejestrować
IUrlHelper
w kontenerze DI. Rozwiązanie wystąpieniaIUrlHelper
wymaga użyciaIUrlHelperFactory
iIActionContextAccessor
. Możesz jednak wykonać następujące czynności jako skrót:ASP.NET Core Backlog
AKTUALIZACJA : To nie spowoduje, że ASP.NET Core 5
Istnieją przesłanki wskazujące na to, że będziesz w stanie
LinkGenerator
utworzyć bezwzględne adresy URL bez konieczności podawania adresuHttpContext
(To była największa wadaLinkGenerator
i dlaczego,IUrlHelper
chociaż bardziej skomplikowana konfiguracja przy użyciu poniższego rozwiązania była łatwiejsza w użyciu) Zobacz „Ułatw konfigurację host / schemat dla bezwzględnych adresów URL z LinkGenerator ” .źródło
string url = string.Concat(this.Request.Scheme, "://", this.Request.Host, this.Request.Path, this.Request.QueryString);
Nie musisz w tym celu tworzyć metody rozszerzenia
@Url.Action("Action", "Controller", values: null);
Action
- nazwa działaniaController
- Nazwa kontroleravalues
- Obiekt zawierający wartości tras: aka parametry GETIstnieje również wiele innych przeciążeń,
Url.Action
których możesz użyć do generowania linków.źródło
this.Context.Request.Scheme
. Czy to tylko pobiera protokół i części domeny adresu URL?this.Context.Request.Schema
zwraca protokół, który został użyty dla żądania. To będziehttp
lubhttps
. Oto dokumenty, ale tak naprawdę nie wyjaśnia, co oznacza Schemat.Jeśli po prostu potrzebujesz Uri dla metody, która ma adnotację trasy, poniższe zadziałały.
Kroki
Pobierz względny adres URL
Zwracając uwagę na nazwę trasy akcji docelowej, pobierz względny adres URL za pomocą właściwości adresu URL kontrolera w następujący sposób:
var routeUrl = Url.RouteUrl("*Route Name Here*", new { *Route parameters here* });
Utwórz bezwzględny adres URL
var absUrl = string.Format("{0}://{1}{2}", Request.Scheme, Request.Host, routeUrl);
Utwórz nowy Uri
var uri = new Uri(absUrl, UriKind.Absolute)
Przykład
[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); } }
źródło
Jest to odmiana odpowiedzi Muhammada Rehana Saeeda , w której klasa zostaje pasożytniczo dołączona do istniejącej klasy MVC .net core o tej samej nazwie, dzięki czemu wszystko po prostu działa.
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); } } }
źródło
Właśnie odkryłem, że możesz to zrobić za pomocą tego połączenia:
Url.Action(new UrlActionContext { Protocol = Request.Scheme, Host = Request.Host.Value, Action = "Action" })
Pozwoli to zachować schemat, hosta, port, wszystko.
źródło
W nowym projekcie ASP.Net 5 MVC w akcji kontrolera nadal możesz wykonać
this.Context
ithis.Context.Request
wygląda na to, że w żądaniu nie ma już właściwości Url, ale właściwości podrzędne (schemat, host itp.) Znajdują się bezpośrednio w obiekcie żądania.public IActionResult About() { ViewBag.Message = "Your application description page."; var schema = this.Context.Request.Scheme; return View(); }
Raczej chcesz użyć this.Context lub wstrzyknąć właściwość to kolejna konwersacja. Wstrzyknięcie zależności w ASP.NET vNext
źródło
Jeśli chcesz tylko przekonwertować ścieżkę względną z opcjonalnymi parametrami, utworzyłem metodę rozszerzenia dla 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); }
Następnie można wywołać metodę z usługi / widoku przy użyciu wstrzykniętego IHttpContextAccessor
var callbackUrl = _httpContextAccessor.AbsoluteUrl("/Identity/Account/ConfirmEmail", new { userId = applicationUser.Id, code });
źródło
Możesz uzyskać adres URL w ten sposób:
Request.Headers["Referer"]
Wyjaśnienie
Request.UrlReferer
RzuciSystem.UriFormatException
jeśli Referer HTTP nagłówek jest niepoprawny (co może się zdarzyć, ponieważ zwykle nie jest pod kontrolą).Jeśli chodzi o używanie
Request.ServerVariables
, według MSDN :Właściwość Request.Headers
Pobiera kolekcję nagłówków HTTP.
Chyba nie rozumiem, dlaczego wolisz
Request.ServerVariables
overRequest.Headers
, ponieważRequest.ServerVariables
zawiera wszystkie zmienne środowiskowe, a także nagłówki, gdzie Request.Headers to znacznie krótsza lista, która zawiera tylko nagłówki.Dlatego najlepszym rozwiązaniem jest użycie
Request.Headers
kolekcji do bezpośredniego odczytania wartości. Zwróć jednak uwagę na ostrzeżenia Microsoftu dotyczące kodowania wartości w formacie HTML, jeśli zamierzasz wyświetlić ją w formularzu.źródło