2013-10-04 4 views
19

レイザーの.cshtmlビューのタスクでawaitに可能ですか?レイザービューでの待機の使用

デフォルトでは、それはasyncとマークされたメソッドでしか使用できないと言っているので、それを可能にする隠しスイッチがあるのだろうか?

+9

は、あなたのコントローラで行うか、バックエンドのコードでスタックをさらに何かのように思えます。 –

答えて

16

いいえ、それは不可能であり、とにかく行う必要はありません。レイザービューにはマークアップが含まれている必要があります。 async/awaitはバックエンドロジックに属します。

+13

"これをしないでください"の部分の下降。データが到着する前に最初のバイトをレンダリングすることは奇妙ではなく、ビューに必要なデータの必要もありません。たとえば、私がRazorインターンを手渡して、DBを呼び出す方法を知らずにページを一緒に投げる必要があった場合、あなたはこの壁にぶつかるのを除いて、単純なインターフェイスを使って遅延読み込みリポジトリを介してデータを呼び出すように教えてくれますRazorで非同期(おそらく)制限されています。 –

+2

@ChrisMoschiniそれはまったく意味がありません。 「View-Dictated Data Need」はViewModelであり、コントローラによって既に提供されています。 「データが到着する前にレンダリング」は、遅いデータ取得の問題を間違った方法で見ているだけです。そのためのキャッシングがあります。 –

+0

@ssg誰もが訪れるたびに異なるページを考えてみてください。結果を計算するのに時間がかかります。それがもののリストだとします。あなたが持っているとすぐに出力ストリームにレンダリングし、バッファリングされていないものをレンダリングする方が、すべてが到着するまでユーザーを待たせるほうがよいでしょう。 ViewModelのアプローチでは、後悔する結果が得られます。 Viewのデータをリアルタイムで受信してレンダリングすると、前回の結果よりもすぐれた結果が得られます。 –

-1

私はこれが古いスレッドだと知っていますが、他の誰かが役に立つと思った場合に備えて、私は入力を追加します。私はASP.Netの新しいMongoDBドライバで動作するこの問題に遭遇しました。新しいドライバ(今のところ)はasyncメソッドを実装し、asynccursorがIEnumerableを実装していないのでforeachで使用できない非同期カーソルを返します。ビューは、本質的に非同期ではなく、それをカットしていません待つので、これは、かみそりでは動作しません、

while(await cursor.movenextasync) 
    var batch=cursor.current 
    foreach(var item in batch) 
     --do stuff here-- 

しかし:サンプルコードでは、通常のように見えます。

私はそれが最初の行に変更することで動作するようになった:カーソルが最後のエントリにヒットするまで、trueを返します

while(cursor.MoveNextAsync().Result) 

を。

希望に役立ちます!

+1

正解は「あなたは間違っている」ということです。これはコントローラのメソッドで*非同期の方法*で行う必要があります。コントローラ、モデル、およびデータレイヤの両方をバイパスして、ビューから直接データベースに対話しようとすると、MVCとまったく反対になり、単にレンダリングの遅延を招きます。ビューは、ビューモデル内のデータをレンダリングするだけです。ビューモデルには、そのビューに必要なデータのみが含まれている必要があります。データを取得してDTO /モデルを構築してビューに送信するのは*コントローラの仕事です。 –

+0

@PanagiotisKanavos大規模なリスティングの場合、データベースから1つ1つ取り出して実際にクライアントへの出力は、フルリストがメモリにロードされるまで発生しませんか?これは間違いなくコントローラにロジックを持たせるのは間違いありませんが、私が言及したケースでは、非同期の列挙型を渡すことができず、非同期的に視覚的にレンダリングできるほうがよいでしょうか?それとも、技術的な限界がありますか? –

+0

@martinh_kenticoいいえ、まったくありません。エントリを1つずつロードする場合、データアクセスロジックに重大な問題があります。 *なぜ*クエリが*すべての*結果を一度に返すときに1つずつロードするのですか?あなたが*表示できないときに*たくさんの結果を返すのはなぜですか?この場合、* paging *を使用しないのはなぜですか?なぜLINQで '.Contains()'句を使用したり、IDのリストを渡すためにSQLの '(?)'を使わないのですか? –

-1

本当に必要な場合は、これを行うことができますが、それは醜いですが、それは動作します。コントローラ

public async Task<ActionResult> Index() 
     { 
      ViewBag.foo = await _some.getFoo(); 
      ViewBag.bar = await _some.getBar(); 
      return View("Index"); 
     } 
+0

これはvar foo = await ... bar = await ... return View( "Index"、new {foo = foo、bar = bar}) - あなたはまだawait/async経由でデータをロードしています。コントローラーは通常どおり、面倒ではありません。 –

0

ビュー

@{ 
var foo = ViewBag.foo; 
var bar = ViewBag.bar; 
} 

私は長い間このような何かを思っていた - 場合は、私たちが書くページの多くは、JRのDevによって一緒にスローされる可能性彼らはたくさんの質問を書く必要はありませんでした。とにかくいつも同じ基本クエリー定型文です - なぜ彼らは仕事の大部分が内容を上げることになっているのであろうか、各コントローラのためにそれらを書く必要がありますか?私はC#を使用するので、メモリ管理に取り組む必要はありません。なぜHTMLコーダーはクエリの詳細を処理する必要がありますか?

暗黙のうちに、非同期にデータを非同期にビューに読み込むためのトリックがあります。まず、必要なデータを表現するクラスを定義します。次に、各ビューの上部で、そのクラスをインスタンス化します。コントローラーに戻って、あなたが使用しようとしているビューをルックアップして開き、そのクラスをコンパイルします。これを使用して、MVCの強制的な方法でコントローラに非同期のビューが必要なデータを取得できます。最後に、ViewModelでViewModelの処方箋に渡し、いくつかのトリッキーで、どのデータを使用するかを宣言するビューがあります。

ここにStoryControllerがあります。

public class StoryController : BaseController 
{ 
    [OutputCache(Duration=CacheDuration.Days1)] 
    // /story/(id) 
    public async Task<ActionResult> Id(string id = null) 
    { 
     string storyFilename = id; 

     // Get the View - story file 
     if (storyFilename == null || storyFilename.Contains('.')) 
      return Redirect("/"); // Disallow ../ for example 

     string path = App.O.AppRoot + App.HomeViews + @"story\" + storyFilename + ".cshtml"; 
     if (!System.IO.File.Exists(path)) 
      return Redirect("/"); 

     return View(storyFilename); 

すべてこれは今のところありませんが、URLに基​​づいて、ビューファイルを取りに行くのWebフォーム(のようなものが可能です:ジュニアのDevはコントローラ、データベースまたはLINQが何であるかを知らなくても、簡単な.cshtmlファイルとして物語を書きますMVC内とRazorを使用している場合を除く)。しかし、いくつかの標準的なViewModelsとPartialsを使用して、いくつかのデータ(ここでは、データベースに蓄積する人やプロジェクト)を表示したいと考えています。どのように定義し、コンパイルしましょう。(ConservXは、私の場合はコアプロジェクトの名前空間であることを起こることに注意してください。)作業の大半だ

public async Task<ActionResult> Id(string id = null) 
    { 
     string storyFilename = id; 

     // 1) Get the View - story file 
     if (storyFilename == null || storyFilename.Contains('.')) 
      return Redirect("/"); // Disallow ../ for example 

     string path = App.O.AppRoot + App.HomeViews + @"story\" + storyFilename + ".cshtml"; 
     if (!System.IO.File.Exists(path)) 
      return Redirect("/"); 

     // 2) It exists - begin parsing it for StoryDataIds 
     var lines = await FileHelper.ReadLinesUntilAsync(path, line => line.Contains("@section")); 

     // 3) Is there a line that says "new StoryDataIds"? 
     int i = 0; 
     int l = lines.Count; 
     for (; i < l && !lines[i].Contains("var dataIds = new StoryDataIds"); i++) 
     {} 

     if (i == l) // No StoryDataIds defined, just pass an empty StoryViewModel 
      return View(storyFilename, new StoryViewModel()); 


     // https://stackoverflow.com/questions/1361965/compile-simple-string 
     // https://msdn.microsoft.com/en-us/library/system.codedom.codecompileunit.aspx 
     // https://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider(v=vs.110).aspx 
     string className = "__StoryData_" + storyFilename; 
     string code = String.Join(" ", 
      (new[] { 
       "using ConservX.Areas.Home.ViewModels.Storying;", 
       "public class " + className + " { public static StoryDataIds Get() {" 
      }).Concat(
       lines.Skip(i).TakeWhile(line => !line.Contains("};")) 
      ).Concat(
       new[] { "}; return dataIds; } }" } 
      )); 


     var refs = AppDomain.CurrentDomain.GetAssemblies(); 
     var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray(); 
     var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler(); 
     var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles); 
     compileParams.GenerateInMemory = true; 
     compileParams.GenerateExecutable = false; 

     var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code); 
     var asm = compilerResult.CompiledAssembly; 
     var tempType = asm.GetType(className); 
     var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null); 

     using (var db... // Fetch the relevant data here 

     var vm = new StoryViewModel(); 
     return View(storyFilename, vm); 
    } 

を。今、ジュニアのDevはちょうどので、彼らは次のように必要なデータを宣言することができます。

@using ConservX.Areas.Home.ViewModels.Storying 
@model StoryViewModel 
@{ 
    var dataIds = new StoryDataIds 
    { 
     ProjectIds = new[] { 4 } 
    }; 

    string title = "Story Title"; 
    ViewBag.Title = title; 
    Layout = "~/Areas/Home/Views/Shared/_Main.cshtml"; 
} 
@section css { 
... 
関連する問題