デバイスの種類に基づいて ASP.NET MVC ビューを変更するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1387354

質問

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

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

役に立ちましたか?

解決

アップデート:このソリューションには微妙なバグがあります。MVC フレームワークは以下を呼び出します。 FindView/FindPartialView 2回:一度一緒に useCache=true, 、そしてそれが結果を返さない場合は、一度 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;
    }
}

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

ビュー エンジンを作成する代わりに、コントローラーにロジックを配置することにした場合。最良のアプローチは、カスタムを作成することです アクションフィルター属性 コントローラーを飾ることができます。次に、 アクションの実行時 どのデバイスがサイトを表示しているかを判断する方法。これを確認できます ブログ投稿 やり方について。この投稿には、まさにこのテーマに関するいくつかの Mix ビデオへの素晴らしいリンクも含まれています。

他のヒント

Model-View-Controllerパターンでは、それが選択されますが、表示することをコントローラなので、それは悪いがif文を追加し、適切なビューを返すようにすることをではありません。あなたはこの方法でif文をカプセル化し、それを呼び出すことができます:

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

また、あなたが動的にそれは携帯電話やないのかどうかに基づいてビューを実行ビューエンジンを作成することができます。私は、コントローラが担当する必要があると考えているので、私は、このアプローチのファンではありません。あなたはiPhone上で閲覧している場合たとえば、あなたは代わりに、完全なデスクトップバージョンを確認したい場合があります。前者のアプローチでは、適切なブールフラグを渡したいが、後者では、物事はより複雑になります。

この機能をプラグインするのに適切な場所はカスタム 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).

これが役立つことを願っています

このは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;
    }
}

あなたのコアロジックは、コントローラに同じであることのみ表示する必要がありますが変更されますので、コントローラはどこあなたが述べたように、各コントローラのアクションのための正しいビューを奉仕するのif / else文を必要としないされている必要。

の代替はあなたに別々のDLL内のコントローラロジックをラップして、モバイル版のための異なるコントローラ/パスを持っているだろう。通常のコントローラは、モバイルデバイスからの要求を受けた場合は、共有コントローラロジックを使用するすべてのあなたの携帯電話のコントローラが含まれているあなたの携帯電話エリアにリダイレクトすることができます。このソリューションはまた、あなたが携帯電話のコントローラに固有の「tweeks」を実行していない、それはあなたの通常のコントローラに影響を与える持つことができるようになります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top