27

私は ASP.NET MVC の読み取りに取り組んでおり、WebForms から MVC に移行する予定の Web アプリを使用しています。このプロセスで私が期待する機能要求の 1 つは、ユーザーがモバイル デバイスからアクセスしている場合に簡略化されたビューを返すことです。

そのタイプのロジックを実装するのに最適な場所がどこにあるのか、私にはよくわかりません。ビューを返すすべてのアクションで Browser.IsMobileDevice の if/else を追加するよりも良い方法があると確信しています。これを行うにはどのようなオプションが必要ですか?

4

5 に答える 5

21

更新: このソリューションには微妙なバグがあります。MVC フレームワークはFindView/FindPartialViewを 2 回呼び出します。1 回は でuseCache=true、それが結果を返さない場合は で 1 回useCache=falseです。すべてのタイプのビューに対してキャッシュが 1 つしかないため、デスクトップ ブラウザーが最初に登場した場合、モバイル ユーザーはデスクトップ ビューを見ることになる可能性があります。

この問題を解決するためにカスタム ビュー エンジンを使用することに興味がある人のために、Scott Hanselman はここで彼のソリューションを更新しました。

http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx

(答えのハイジャックをお詫びします。他の誰かにこれを経験させたくないだけです!)

roufamatic 編集 (2010-11-17)


最初に行うことは、モバイル デバイス ブラウザー ファイルをプロジェクトに導入することです。このファイルを使用すると、デバイスがヘッダーで送信する内容の詳細を知らなくても、サポートしたいデバイスをターゲットにすることができます。このファイルはすでに作業を行っています。次に、Request.Browser プロパティを使用して、返すビューを調整します。

次に、Views フォルダーの下でビューをどのように整理するかについて戦略を立てます。私は、デスクトップ バージョンをルートに残してから、Mobile フォルダを作成することを好みます。たとえば、ホーム ビュー フォルダは次のようになります。

    • モバイル
      • iPhone
        • インデックス.aspx
      • ブラックベリー
        • インデックス.aspx
    • インデックス.aspx

カスタムビューエンジンの使用について@Mehrdadに同意する必要があります。ビュー エンジンは複数の目的を果たしますが、その目的の 1 つはコントローラーのビューを見つけることです。これを行うには、FindView メソッドをオーバーライドします。このメソッドでは、ビューの場所を確認できます。サイトを使用しているデバイスがわかったら、ビューを整理するために思いついた戦略を使用して、そのデバイスのビューを返すことができます。

public class CustomViewEngine : WebFormViewEngine
{
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        // Logic for finding views in your project using your strategy for organizing your views under the Views folder.
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        // iPhone Detection
        if (request.UserAgent.IndexOf("iPhone",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
        }

        // Blackberry Detection
        if (request.UserAgent.IndexOf("BlackBerry",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/BlackBerry/" + viewName, masterName, useCache);
        }

        // Default Mobile
        if (request.Browser.IsMobileDevice)
        {
            result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
        }

        // Desktop
        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }
}

上記のコードを使用すると、戦略に基づいてビューを設定できます。デバイスのビューが見つからない場合、またはデフォルトのモバイル ビューがない場合は、フォール バックはデスクトップ ビューです。

ビューエンジンを作成する代わりに、コントローラーにロジックを配置することにした場合。最良の方法は、コントローラーを装飾できるカスタムActionFilterAttributeを作成することです。次に、OnActionExecutedメソッドをオーバーライドして、サイトを表示しているデバイスを特定します。方法については、このブログ投稿をご覧ください。この投稿には、まさにこのテーマに関するいくつかの Mix ビデオへの素敵なリンクもあります。

于 2009-09-07T04:29:52.253 に答える
2

この機能をプラグインする適切な場所は、カスタム ViewEngine だと思います。IViewEngine.FindViewただし、メソッドが によって呼び出される方法に注意する必要がありますViewEngineCollection(詳細については、こちらを参照してください)。

Scott Hanselman によって提案された更新されたソリューションは正しく機能しません。このアプローチのサンプル実装はこちらにあります。誤った動作を繰り返す方法について説明している readme ファイルを確認してください。

元の ViewEngine でビューが見つからないかどうかを確認する別のアプローチを提案します。useCacheパラメーターがtrueの場合、ビューが元の ViewEngine にパラメーター で存在するかどうかを確認しますuseCache=false

すべてのコードをここに置くのは複雑すぎますが、私のオープンソース プレイグラウンドで実装された提案されたアプローチを見つけることができますMobileViewEngineクラスと単体テストを確認してください。

一部の MobileViewEngine 機能:

  • ビュー キャッシュで正しく動作し、元のビュー エンジン キャッシュを使用します。
  • MvcContrib T4 テンプレートで使用されるショット ビュー名と相対ビュー パス (~/Views/Index) の両方をサポートします。
  • 「インデックス」ビューを次のように解決します。
    • Mobile/Platform/Index– ビューが存在し、モバイル デバイス プラットフォーム (iPhone、Android など) がサポートされているリストに登録されている場合。
    • Mobile/Index - 他のすべてのモバイル デバイスで表示します。ビューが存在しない場合は、オプションでデスクトップ ビュー バージョンにフォールバックできます。
    • Index– デスクトップ ビュー バージョンの場合。
  • デバイス ルールを追加/変更することで、モバイル ビュー階層をカスタマイズMobile/ Platform/Manufacturerしたり (例: )、モバイル ビュー パスの解像度をカスタマイズしたりできます (MobileDeviceRuleおよびを参照PlatformSpecificRule)。

うまくいけば、これは役に立ちます

于 2011-02-07T15:17:19.327 に答える
2

これは、T4MVC とリリース モード (ビューのキャッシュが有効になっている場合) の両方で実際に動作するバージョンです。ユーザーコントロールと絶対/相対URLも処理します。モバイル デバイス ブラウザ ファイルが必要です。

public class MobileCapableWebFormViewEngine : WebFormViewEngine
{

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        if (viewPath.EndsWith(".ascx"))
            masterPath = "";
        return base.CreateView(controllerContext, viewPath, masterPath);
    }
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        useCache = false;
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        if (request.Browser.IsMobileDevice || request["mobile"] != null || request.Url.Host.StartsWith("m."))
        {
            var mobileViewName = GetMobileViewName(viewName);

            result = base.FindView(controllerContext, mobileViewName, masterName, useCache);
            if (result == null || result.View == null)
            {
                result = base.FindView(controllerContext, viewName, "Mobile", useCache);
            }
        }

        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }

    private static string GetMobileViewName(string partialViewName)
    {
        var i = partialViewName.LastIndexOf('/');
        return i > 0
                   ? partialViewName.Remove(i) + "/Mobile" + partialViewName.Substring(i)
                   : "Mobile/" + partialViewName;
    }
}
于 2010-09-29T08:26:35.377 に答える
2

Model-View-Controller パターンではビューを選択するのはコントローラーなので、ifステートメントを追加して適切なビューを返すことはそれほど悪いことではありません。ステートメントをメソッドにカプセル化してif呼び出すことができます。

return AdaptedView(Browser.IsMobileDevice, "MyView.aspx", model);

または、モバイルかどうかに基づいてビューを動的に実行するビュー エンジンを作成することもできます。コントローラーが担当する必要があると信じているため、私はこのアプローチのファンではありません。たとえば、iPhone で閲覧している場合は、代わりに完全なデスクトップ バージョンを表示したい場合があります。前者のアプローチでは、適切なブール値フラグを渡しますが、後者の場合、事態はより複雑になります。

于 2009-09-07T02:47:58.193 に答える
0

コアロジックはコントローラーで同じである必要があり、必要なビューのみが変更されるため、コントローラーは、述べたように各コントローラーアクションの正しいビューを提供するために if/else ステートメントが必要な場所です。

別の方法は、コントローラー ロジックを別の dll にラップしてから、モバイル バージョン用に異なるコントローラー/パスを用意することです。通常のコントローラがモバイル デバイスからリクエストを受信した場合、共有コントローラ ロジックを使用するすべてのモバイル コントローラを含むモバイル エリアにリクエストをリダイレクトできます。このソリューションでは、モバイル コントローラーに固有の「tweeks」を実行することもでき、通常のコントローラーには影響しません。

于 2009-09-07T02:48:34.853 に答える