1

mvc 4アプリにコントローラーアクションがあります:

public ActionResult Index()
    {
        GetStartedModel gsModel = new GetStartedModel();

        return View(gsModel);
    }

およびViewModel:

public class GetStartedModel
{
    public IEnumerable<SelectListItem> listA { get; set; }
    public IEnumerable<SelectListItem> listB { get; set; }

    public GetStartedModel()
    {
        TestDataWebServiceHelper service = new TestDataWebServiceHelper();
        this.GetData(service);
    }

    private async void SetData(TestDataWebServiceHelper service)
    {
        listA = await this.SetListA(service);
        listB = await this.SetListB(service);
    }

    private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service)
    {
        List<String> rawList = new List<String>();
        rawList = await service.GetValuesAsync("json");
        return rawList.Select(x => new SelectListItem { Text = x, Value = x });
    }

    private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service)
    {
        List<String> rawList = new List<String>();
        rawList = await service.GetValuesAsync("json");
        return rawList.Select(x => new SelectListItem { Text = x, Value = x });
    }
}

このコントローラーアクションを呼び出すと、次のエラーが発生します。

現在、非同期操作を開始することはできません。非同期操作は、非同期ハンドラーまたはモジュール内で、またはページライフサイクルの特定のイベント中にのみ開始できます。ページの実行中にこの例外が発生した場合は、ページが<%@ Page Async = "true"%>とマークされていることを確認してください。

だから、質問:

  1. このモデルの初期化を可能にするために、どういうわけかコントローラー、アクション、またはページ自体を非同期としてマークする必要がありますか?
  2. すべての初期化ロジックをviewmodelにカプセル化し、コントローラーにポップしないことは可能ですか?
  3. そのエラーの理由は何ですか?WebFormsに関連しているようですが、私はRazorエンジンを使用しています。
4

2 に答える 2

5

コードには2つの問題があります。

  1. async voidこのようなコンストラクターから操作を開始しないでください。実際、通常はasyncコンストラクターから操作を開始しないでください。また、async voidメソッドをまったく使用しないでください(イベントハンドラーを除く)。

    あなたの場合、asyncコンストラクターではなくファクトリメソッドが最も理にかなっていると思います。

    private GetStartedModel()
    {}
    
    public static async Task<GetStartedModel> Create()
    {
        var service = new TestDataWebServiceHelper();
        var result = new GetStartedModel();
        listA = await result.SetListA(service);
        listB = await result.SetListB(service);
        return result;
    }
    

    詳細については、コンストラクターに関するStephenClearyの投稿をasync参照してください。

  2. asyncコントローラのアクションも実行する必要があります。

    public async Task<ActionResult> Index()
    {
        var gsModel = await GetStartedModel.Create()
    
        return View(gsModel);
    }
    
于 2013-03-10T17:29:12.297 に答える
0

「非同期」について注意すべき点は次のとおりです。

  • メソッドは、その中に記述されたコードによってアクションが実行されるのを待つ必要がある場合にのみ「非同期」である必要があります。
  • メソッドに「待機」するものがない場合は、そのメソッドを「非同期」として宣言しないでください。
  • 非同期としてマークされるイベント(またはイベントハンドラー)がある場合、リターンタイプは「void」または特定のリターンタイプである必要があります
  • ただし、他の(一般的な)メソッドを「非同期」としてマークする必要がある場合、戻り値のタイプはまたはである必要がありTaskますTask< return-type >

今あなたの質問に来て、

  • 間違いなく、「コントローラー」、「イベント」、「ページ」を非同期としてマークすることができます(ページを非同期としてマークすることについてはよくわかりませんが、使用したことはありません)。これにより、アクションが実行されるまで、これらのメソッドは休止します。そのメソッドで完全に書かれています。
  • これが、初期化ロジック全体をviewModelにカプセル化する実際のシステムです。
    • そのためには、Floderを作成し、「ViewModels」という名前を付けて、すべてのviewModelコードをそのフォルダーに配置し、必要に応じてそれを使用します。

このコードをViewModelに配置する必要があります。

private async void SetData(TestDataWebServiceHelper service)
{
    listA = await this.SetListA(service);
    listB = await this.SetListB(service);
}

private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service)
{
    List<String> rawList = new List<String>();
    rawList = await service.GetValuesAsync("json");
    return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}

private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service)
{
    List<String> rawList = new List<String>();
    rawList = await service.GetValuesAsync("json");
    return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}

その後、必要に応じて呼び出す必要があります。

(お役に立てれば...)

于 2013-03-10T11:50:52.240 に答える