52

最近MVCを使い始めたばかりのかなり経験豊富なASP.Net開発者として、私は自分の考え方を従来の「サーバーコントロールとイベントハンドラー」のやり方から、より動的なMVCのやり方に変えるのに少し苦労していることに気づきました。私はゆっくりとそこに到達していると思いますが、MVC の "魔法" が私を失望させることがあります。

私の現在のシナリオは、ユーザーがローカル ファイルを参照し、それをサーバーにアップロードして、操作するファイルのリストができるまでこれを繰り返すことができる Web ページを作成することです。ファイル リスト (ページのグリッドに表示される) に満足したら、ボタンをクリックしてファイルを処理し、データベースに保存されるデータを抽出します。

最後の部分はそれほど重要ではありません。現在、ファイルのリストを作成し、リクエスト間でそのリストを永続化するのと同じくらい簡単なことに苦労しています。従来のアプローチでは、これは非常に単純です。データは ViewState に保持されます。しかし、MVC では、コントローラーとビューの間でデータを渡す必要があり、これがどのように機能するのか完全にはわかりません。

問題を説明するために、これをコーディングするかなり不完全な試みを投稿したほうがよいと思います。

ファイル リスト データを保持するために、基本的に型指定されたファイルのリストであるビューモデルをいくつかの追加のメタデータと共に作成しました。

public class ImportDataViewModel
{
    public ImportDataViewModel()
    {
        Files = new List<ImportDataFile>();
    }

    public List<ImportDataFile> Files { get; set; }
...

ビューには、ファイルを参照してアップロードするためのフォームがあります。

<form action="AddImportFile" method="post" enctype="multipart/form-data">
  <label for="file">
    Filename:</label>
  <input type="file" name="file" id="file" />
  <input type="submit" />
  </form>

ビューはビューモデルをモデルとして使用しています:

@model MHP.ViewModels.ImportDataViewModel

これにより、ファイルが私のアクションに送信されます。

public ActionResult AddImportFile(HttpPostedFileBase file, ImportDataViewModel importData)
    {

        if (file.ContentLength > 0)
        {
            ImportDataFile idFile = new ImportDataFile { File = file };
            importData.Files.Add(idFile);
        }

        return View("DataImport", importData);
    }

このアクションは、DataImport ページのビューと、ファイルのリストを含むビューモデル インスタンスを返します。

これは特定のポイントまでうまく機能し、ファイルを参照してアップロードし、アクション内のビューモデル データを確認できます。また、ビュー内にブレークポイントを配置して「this.Model」をデバッグすると、すべてが大丈夫。

しかし、別のファイルをアップロードしようとすると、AddImportFile アクション内にブレークポイントを配置すると、importData パラメータが空になります。したがって、ビューは明らかにそのモデルの現在のインスタンスをアクションに渡していません。

私が経験した MVC サンプルでは、​​モデル インスタンスは「魔法のように」パラメーターとしてアクション メソッドに渡されますが、なぜ今は空なのですか?

本当の問題は、MVC についての私の理解が限られていることであり、おそらくこれには非常に簡単な解決策があると思います。とにかく、誰かが私を正しい方向に向けることができれば、私は非常に感謝しています.

4

2 に答える 2

49

質問を投稿してからしばらく時間が経ちましたが、MVC に関する私の経験と知識が少なかったためにかなり色付けされました。それでも、非常に役立つ情報をいくつか受け取り、最終的に解決策を見つけ、MVC についての洞察を得ることができました。

そもそも私を驚かせたのは、次のように、厳密に型指定されたオブジェクトをパラメーターとして持つコントローラーを使用できることでした。

public ActionResult DoSomething(MyClass myObject)...

このオブジェクトは、同じコントローラから生成されました:

...
return View(myObject);
...

これにより、オブジェクトはこれらの 2 つのステップを通じて存在し、それをビューに送信して何かを実行し、「魔法のように」再びコントローラーに戻すことができると思いました。

モデルバインディングについて読んだ後、もちろんそうではないことがわかりました。ビューは完全に死んで静的であり、どこかに情報を保存しない限り、それは消えてしまいます。

クライアントからファイルを選択してアップロードし、表示するこれらのファイルのリストを作成するという問題に戻ると、一般に、MVC でリクエスト間の情報を保存するには 3 つの方法があることに気付きました。

  1. ビューのフォーム フィールドに情報を保存し、後でコントローラにポストすることができます。
  2. ファイルやデータベースなど、ある種のストレージに永続化できます
  3. セッション変数など、リクエスト全体で存在するオブジェクトにアクセスすることにより、サーバーメモリに保存できます

私の場合、基本的に 2 種類の情報を永続化する必要がありました。1. ファイル メタデータ (ファイル名、ファイル サイズなど) 2. ファイル コンテンツ

「本による」アプローチは、おそらくメタデータをフォームフィールドに保存し、ファイルの内容をファイルまたはデータベースに保存することです。しかし、別の方法もあります。私のファイルは非常に小さく、ファイルの数も少なく、このソリューションがサーバー ファームなどに展開されることはないことがわかっているため、セッション変数の 3 番目のオプションを検討したいと思いました。ファイルは、セッションを超えて保持することも興味深いものではありません。ファイルは処理されて破棄されるため、データベースに保存したくありませんでした。

この優れた記事を読んだ後: Dynamics を使用した ASP.NET セッション データへのアクセス

私は確信しました。この記事で説明されているようにセッションバッグ クラスを作成するだけで、コントローラーで次のことができます。

    [HttpPost]
    public ActionResult AddImportFile(HttpPostedFileBase file)
    {

        ImportDataViewModel importData = SessionBag.Current.ImportData;
        if (importData == null) importData = new ImportDataViewModel();

        if (file == null)
            return RedirectToAction("DataImport");

        if (file.ContentLength > 0)
        {
            ImportDataFile idFile = new ImportDataFile { File = file };
            importData.Files.Add(idFile);
        }

        SessionBag.Current.ImportData = importData;

        return RedirectToAction("DataImport");
    }

ほとんどの場合、これが悪い解決策になることは十分承知しています。しかし、ファイルが占有する数キロバイトのサーバー メモリの場合、すべてがシンプルであるため、私にとっては非常にうまく機能したと思います。

SessionBag を使用することのもう 1 つの利点は、ユーザーが別のメニュー項目を入力して戻ってきた場合でも、ファイルのリストがまだそこにあるということです。これは、フォーム フィールド/ファイル ストレージ オプションを選択する場合などには当てはまりません。

最後に、SessionBag は簡単に使用できるため、非常に悪用されやすいことを認識しています。でも本来の目的、つまりセッションデータに使えば、強力なツールになると思います。

于 2012-06-03T18:23:59.887 に答える
11

アップロードについて

1)サーバーに送信されるにユーザーが複数のファイルを選択できるように、HTML を使用した AJAX アップローダを検討してください。この BlueImp Jquery AJAX ファイル アップローダーは、Blueimp Jquery File Uploadという非常に優れた API を備えた非常に優れたものです。ユーザーは、複数のファイルをドラッグ アンド ドロップまたは複数選択して、ファイルの順序を編集したり、含める/除外したりすることができます。満足したら、アップロードを押してコントローラーに送信したり、サーバー側で処理するためにハンドラーをアップロードしたりできます。

2) すべてのアップロードをデータベースに永続化することができますが、ページ全体をリロードし、追加のビュー モデルと剃刀コードを記述してリスト効果を実現します。これはおそらく反応しないでしょう...

状態保持について WebForms/MVC

リクエスト間で状態を維持することは、やや黒魔術とブードゥーです。ASP.NET MVC を使用するときは、Web アプリケーションが要求と応答を使用して通信することを理解してください。Web をステートレスとして受け入れ、そこから開発を進めてください。モデルがコントローラーを介して投稿されると、コントローラー内の変数と一緒に送信されます! ただし、消える前に、そのコンテンツをデータベースに保存して、後で取得することができます。

Web アプリケーションは、デスクトップ アプリケーションのように真の状態を維持することはできません。ajax フレームワークにはさまざまな方法があり、人々が HTTP 環境で状態をシミュレートするために使用するブードゥー ツールもあります。そして、状態のシミュレーションは、実際にはステートフルネスの誤った模倣にすぎません。ASP.NET Web フォームは、HTTP のステートレスな性質を開発者から隠すことで、可能な限り状態をシミュレートしようとします。Web フォーム マークアップ コードおよび独自の Ajax フレームワークと連携して独自の AJAX コードを使用しようとすると、多くの頭痛の種に遭遇する可能性があります。

MVCを学んでくれて本当によかった

冗談はさておき、MVC/HTTP/Statelessness の考え方を理解すれば、Ruby on Rails、SpringMVC (java)、Django (python)、CakePHP などの他の非常に人気のあるフレームワークにパターンを適用するのは非常に簡単になります。このように知識を簡単に伝えることで、より優れた開発者になり、Ajax を完全に使いこなせるようになります。

あなたが MVC 3 を学んでくれて本当にうれしいです。データベース内のいくつかの数値を変更するためだけにコードがどこにでも飛び交う、非常に大規模な ASP.NET Web フォーム プロジェクトを持っていた非常に大規模な企業でインターンシップをいくつか経験しました。 (-_-') ハサミで赤ちゃんの靴下を編んでいるような感覚でした。1 つの簡単な間違った動きで、すべてが壊れてしまいました。PHP で開発しているように感じました。汗だくになり、何が起こったのか、どの行で起こったのかよくわかりません。デバッグと更新はほとんど不可能でした。

于 2012-05-25T14:45:11.047 に答える