web-dev-qa-db-ja.com

ASP.NETMVCアクションから部分ビューとJSONを返す

KnockoutJSを既存のアプリに導入しています。私の計画は、すでに作成した既存の部分ビューを変更/利用し、それらをKnockoutの宣言型属性を使用してJSビューモデルにバインドすることです。 AJAXアクションを呼び出すとき、理想的には、アクションが部分ビューのHTMLとJSONオブジェクトの両方を返すようにします。次に、divにHTMLを入力し、変換します。 JSONをKnockoutオブジェクトにバインドし、HTMLにバインドします。しかし、アクションから両方を返す方法がわかりません。

フルビューモデルが必要なのは、それを更新して最終的にサーバーに送り返すためです。

アクションで部分ビュー(すでにモデルにバインドされている)を返し、部分ビュー内にjavascriptを含めて.NetモデルをKnockoutオブジェクトに変換することを考えました。しかし、そのようにJSを分散させるのは面倒で、保守が難しいと感じています。むしろ、すべてを元のajax呼び出しに近づけたいと思います。

もう1つの方法は、2つのアクション呼び出しを行うことだと思います。 1つはJSON用で、もう1つは部分ビュー用です。しかし、より滑らかな方法が必要です。

これを行うための最善の方法に関するアイデアはありますか?

14
nthpixel

これを行うにはさまざまな方法があると確信しています。コントローラからビューを手動でレンダリングしてから、レンダリングされたビューをJSON応答の一部として返します。

これにより、各エンティティの責任が保持されます。ビューは引き続きビューエンジンを使用して配置され、再利用できます。コントローラは、名前とモデルタイプ以外、ビューについてほとんどまたはまったく認識していません。

手動レンダリング

public static class RenderHelper
{
    public static string PartialView( Controller controller, string viewName, object model )
    {
        controller.ViewData.Model = model;

        using( var sw = new StringWriter() )
        {
            var viewResult = ViewEngines.Engines.FindPartialView( controller.ControllerContext, viewName );
            var viewContext = new ViewContext( controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw );

            viewResult.View.Render( viewContext, sw );
            viewResult.ViewEngine.ReleaseView( controller.ControllerContext, viewResult.View );

            return sw.ToString();
        }
    }
}

あなたの行動方法では:

object model = null; // whatever you want
var obj = new { 
    someOtherProperty = "hello", 
    view = RenderHelper.PartialView( this, "_PartialName", model ) 
};

return Json( obj );

匿名型を返すことに注意してください。レンダリングされたビューの文字列プロパティがあれば、任意の(シリアル化可能な)型を返すことができます。

テスト

手動レンダリングを使用するアクションをテストするには、わずかな変更が必要です。これは、MVCパイプラインでレンダリングされるよりも少し早くビューをレンダリングするためです。

手動レンダリング

  1. アクションメソッドを入力してください
  2. ビューを明示的にレンダリングする<-これにより、呼び出しアクションのテストが困難になります
  3. 終了アクションメソッド

自動レンダリング

  1. アクションメソッドを入力してください
  2. ビュー結果を作成する
  3. 終了アクションメソッド
  4. ビューの結果を処理します(したがって、ビューをレンダリングします)

言い換えると、手動レンダリングプロセスは、テストを困難にする他のさまざまな操作(ビルドマネージャーとの対話によるビューのコンパイルなど)を開始します。

ビューの実際のコンテンツではなく、アクションメソッドをテストする場合は、コードがホスト環境で実行されているかどうかを確認できます。

    public static string PartialView( Controller controller, string viewName, object model )
    {
        // returns false from a VS 2013 unit test, true from IIS
        if( !HostingEnvironment.IsHosted )
        {
            // return whatever you want here
            return string.Empty;
        }

        // continue as usual
     }

チェック中HostingEnvironment.IsHostedは安価です(内部的には、単にnullチェックです)。

22
Tim Medora

ViewModelのJSON文字列に値を設定して、パーシャルに非表示の_<input>_を作成できます。次に、部分ビューをレンダリングする前に、そのフィールドからJSON値を取得し、それを解析します。次に、それを部分ビューから削除し、ページに挿入して、ko.applyBindingsToDescendants(viewModel, $("#parentElement")[0])を実行します。

このアプローチについて私がどのように感じているかは完全にはわかりません。それは単なる理論です。私はこれをテストしていませんが、うまくいくと思います。 1つ 戦利品の罠 注意しなければならないのは、ブラウザがGETリクエストをキャッシュしようとしていることです。あなたのajaxリクエストであなたがしたいこと:

_$.ajax({
  url: "/",
  type: 'GET',
  cache: 'false'
});
_

または、_$.post_リクエストを実行します。 ( 参照

これが1つの選択肢です。

1
nwayve