Как мне получить Url.Action, чтобы использовать правильный номер порта? - PullRequest
14 голосов
/ 17 октября 2011

Я создаю веб-сайт с использованием MVC3, я использую синтаксис бритвы для создания представлений, и все это работает под лазурью.

В настоящее время я работаю под эмулятором Azure локально.

У меня есть вид по URL: 'http://localhost:81/Blah/Foo'.

В этом представлении я хочу получить URL для другого действия.

Для этого я использую: Url.Action («SomeAction», «SomeController», null, this.Request.Url.Scheme)

Однако из-за балансировки нагрузки эмулятор Azure делает номер порта, на который делается запрос об изменениях.

т.е. пока он работает на порту 81, запрос может исходить от порта 82.

Это приводит к созданию неправильного URL 'http://localhost:82/Blah/Bar', и я получаю 400, неверное имя хоста.

После информации в этом посте http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9142db8d-0f85-47a2-91f7-418bb5a0c675/ Я обнаружил, что могу получить правильный хост и номер порта, используя HttpContext.Request.Headers ["Host"].

Но я могу только передать имя хоста в Url.Action, если я попытаюсь передать имя хоста и порт, то он все равно добавит, как он считает, правильный порт, поэтому я получу localhost: 81: 82.

РЕДАКТИРОВАТЬ: Я нашел кого-то с той же проблемой. Похоже, они собрали ту же информацию, что и я (за исключением того, что они также содержат репродукцию), но у них нет полезного исправления, поскольку я не могу указать номер порта вручную.

http://social.msdn.microsoft.com/Forums/en-US/windowsazuredevelopment/thread/87c729e8-094c-4578-b9d1-9c8ff7311577/

Полагаю, одним из исправлений было бы создание собственной перегрузки Url.Action, позволяющей указать порт.

Ответы [ 3 ]

23 голосов
/ 09 августа 2012

Для всех, кто приезжает сюда, кому на самом деле нужен абсолютный путь и кто находится за системой с балансировкой нагрузки, вот что я придумал:

///119995/kak-prevratit-otnositelnyi-url-v-polnyi-url
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, object routeValues = null)
{
  Uri publicFacingUrl = GetPublicFacingUrl(url.RequestContext.HttpContext.Request, url.RequestContext.HttpContext.Request.ServerVariables);
  string relAction = url.Action(actionName, controllerName, routeValues);
  //this will always have a / in front of it.
  var newPort = publicFacingUrl.Port == 80 || publicFacingUrl.Port == 443 ? "" : ":"+publicFacingUrl.Port.ToString();
  return publicFacingUrl.Scheme + Uri.SchemeDelimiter + publicFacingUrl.Host + newPort + relAction;
}

А затем от https://github.com/aarnott/dotnetopenid/blob/v3.4/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs до http://go4answers.webhost4life.com/Example/azure-messing-port-numbers-creates-28516.aspx

   /// <summary>
    /// Gets the public facing URL for the given incoming HTTP request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <param name="serverVariables">The server variables to consider part of the request.</param>
    /// <returns>
    /// The URI that the outside world used to create this request.
    /// </returns>
    /// <remarks>
    /// Although the <paramref name="serverVariables"/> value can be obtained from
    /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
    /// in so we can simulate injected values from our unit tests since the actual property
    /// is a read-only kind of <see cref="NameValueCollection"/>.
    /// </remarks>
internal static Uri GetPublicFacingUrl(HttpRequestBase request, NameValueCollection serverVariables)
{
  //Contract.Requires<ArgumentNullException>(request != null);
  //Contract.Requires<ArgumentNullException>(serverVariables != null);

  // Due to URL rewriting, cloud computing (i.e. Azure)
  // and web farms, etc., we have to be VERY careful about what
  // we consider the incoming URL.  We want to see the URL as it would
  // appear on the public-facing side of the hosting web site.
  // HttpRequest.Url gives us the internal URL in a cloud environment,
  // So we use a variable that (at least from what I can tell) gives us
  // the public URL:
  if (serverVariables["HTTP_HOST"] != null)
  {
    //ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
    string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
    Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
    UriBuilder publicRequestUri = new UriBuilder(request.Url);
    publicRequestUri.Scheme = scheme;
    publicRequestUri.Host = hostAndPort.Host;
    publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port
    return publicRequestUri.Uri;
  }
  // Failover to the method that works for non-web farm enviroments.
  // We use Request.Url for the full path to the server, and modify it
  // with Request.RawUrl to capture both the cookieless session "directory" if it exists
  // and the original path in case URL rewriting is going on.  We don't want to be
  // fooled by URL rewriting because we're comparing the actual URL with what's in
  // the return_to parameter in some cases.
  // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
  // session, but not the URL rewriting problem.
  return new Uri(request.Url, request.RawUrl);
}
1 голос
/ 17 октября 2011

Что произойдет, если вы просто используете Url.Action («Действие», «Контроллер»)?Это должно просто сгенерировать относительный URL, который должен работать.

(Или, возможно, лучший вопрос: почему вы не используете эту перегрузку?)

0 голосов
/ 13 сентября 2012

Я обнаружил, что это работает для меня ...

var request = HttpContext.Request;
string url = request.Url.Scheme + "://" +
             request.UserHostAddress +  ":" +
             request.Url.Port;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...