3

AppHarborでMVC3アプリケーション(FunnelWeb)をホストしようとしています。まだはっきりしない理由で、ルートがController + Actionのみの場合(たとえば、mysite/adminがAdmin+Indexで、mysite/loginがAdmin+loginである場合)、すべてが正常に機能しますが、ルートに他に何かがある場合(たとえば、{* page}のような変数)私のURLはmysite:12345 / mypageになります(12345はAppHarborによって割り当てられたポート番号であり、mypageは要求しているページの名前です)。これにより、ポート12345が公開されていないため、要求が失敗します。

AppHarborは、負荷分散を使用して、複数のIIS間で要求を分散します。これが彼らのやり方であり、これが内部的にリクエストがいくつかの非標準ポートにルーティングされる理由です。問題はありませんが、その内部URLにルーティングしようとするMVCに問題があります。

ここでは指を指さしていません。それは誰のせいでもありません:)それでは質問に移りましょう:

  1. Controller + Actionのみでルートをリクエストすることと、{* page}のような変数でルートをリクエストすることの違いがあるのはなぜですか?技術的にしてください:)
  2. AppHarborでリクエストを処理する方法の例を次に示しますが、すべてのコントローラー(OMG)を変更する必要があるようです。コントローラを変更せずにこれを実装する方法はありますか?
  3. 他の提案は大歓迎です:)

前もって感謝します。

更新:偶然にも、私が観察した行動は、私が到達した結論と一致しています。ただし、この問題はASP.NetMVCルーティングとは何の関係もありません。簡単に言うと、FunnelWebは小文字のURLを強制するため、リソースへのリクエストを受信するたびに、必要に応じて小文字に変換し、301応答を発行します。問題は、301応答のURLを作成するときに、要求URL(絶対URL)が、クライアントからの要求ではなく、ロードバランサーからIISへの要求時に使用されるURLになることです。したがって、要求は失敗します。

4

3 に答える 3

3

これは、AppHarborでのFunnelWebURL生成の既知の問題です。標準のMVCメソッドを使用して相対URLを生成する場合、これは問題ではありません。AppHarborには、ナレッジベースでパブリックURLを生成する方法に関する短いガイドとサンプルがあります。

于 2011-08-19T22:01:17.627 に答える
2

方法はありますが、いくつかのクラスが必要です。

ASP.NET MVCはルートを登録するときに、ルートハンドラーを定義します。このルートハンドラーは、要求を処理するHTTPハンドラーを返します。カスタムHTTPハンドラーを返すカスタムルートハンドラーを使用する場合は、いくつかのデコレータークラスを使用してHTTPコンテキストを書き換えることができます。

基本クラスから派生し、すべてのメソッドとプロパティを内部インスタンスにラップするaHttpContextProxyとを作成することから始めます。HttpRequestProxy私はハードワークを利用できるようにしました。

次に、デコレータを作成します。最初にHTTPコンテキストデコレータを作成します。

using System.Web;

public class HttpContextDecorator : HttpContextProxy
{
    public HttpContextDecorator(HttpContextBase innerHttpContext)
        : base(innerHttpContext)
    {
    }

    public override HttpRequestBase Request
    {
        get
        {
            return new HttpRequestDecorator(base.Request);
        }
    }
}

HTTPリクエストデコレータ:

using System;
using System.Web;

public class HttpRequestDecorator : HttpRequestProxy
{
    public HttpRequestDecorator(HttpRequestBase innerHttpRequest)
        : base(innerHttpRequest)
    {
    }

    public override bool IsSecureConnection
    {
        get
        {
            return string.Equals(Headers["X-Forwarded-Proto"], "https", StringComparison.OrdinalIgnoreCase);
        }
    }

    public override Uri Url
    {
        get
        {
            var url = base.Url;
            var urlBuilder = new UriBuilder(url);

            if (IsSecureConnection)
            {
                urlBuilder.Port = 443;
                urlBuilder.Scheme = "https";
            }
            else
            {
                urlBuilder.Port = 80;
            }

            return urlBuilder.Uri;
        }
    }

    public override string UserHostAddress
    {
        get
        {
            const string forwardedForHeader = "HTTP_X_FORWARDED_FOR";
            var forwardedFor = ServerVariables[forwardedForHeader];
            if (forwardedFor != null)
            {
                return forwardedFor;
            }

            return base.UserHostAddress;
        }
    }
}

前述のように、MVCクラス(ここではHTTPハンドラー)もオーバーライドする必要があります。

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

public class CustomMvcHandler : MvcHandler
{
    public CustomMvcHandler(RequestContext requestContext)
        : base(requestContext)
    {
        requestContext.HttpContext = new HttpContextDecorator(requestContext.HttpContext);
    }

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        httpContext = new HttpContextDecorator(httpContext);
        return base.BeginProcessRequest(httpContext, callback, state);
    }

    protected override void ProcessRequest(HttpContextBase httpContext)
    {
        httpContext = new HttpContextDecorator(httpContext);
        base.ProcessRequest(httpContext);
    }
}

次に、ルートハンドラー:

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

public class CustomMvcRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new CustomMvcHandler(requestContext);
    }
}

最後に、登録されているすべてのルートに関連付けられているハンドラーを置き換える必要があります(または最初から適切にマップします)。

var routes = RouteTable.Routes.OfType<Route>().Where(x => x.RouteHandler is MvcRouteHandler);
foreach (var route in routes)
{
    route.RouteHandler = new CustomMvcRouteHandler();
}
于 2011-08-19T23:23:57.870 に答える
2

必要なのは次のとおりである可能性があります。

<appSettings>
  <!-- AppHarbor Setting to stop AppHb load balancer internal port numbers from showing up in URLs-->
  <add key="aspnet:UseHostHeaderForRequestUrl" value="true" />
</appSettings>

これは、AppHarborのサポートページ(http://support.appharbor.com/kb/getting-started/workaround-for-generated-absolute-urls-without-port-number )の更新として記載されています。

MSDNは、UseHostHeaderForRequestUrlについて次のように述べています。

aspnet:UseHostHeaderForRequestUrl-このvalue属性がfalse [デフォルト]の場合、Urlプロパティは、Webサーバーによって提供されるホスト、ポート、およびパスから動的に構築されます。このvalue属性がtrueの場合、Urlプロパティは、着信「Host」ヘッダーによって提供されるホストとポート、およびWebサーバーによって提供されるパスを使用して動的に構築されます。

于 2014-08-12T14:15:38.107 に答える