应该何时将操作标记为异步?

Ant*_*ony 1 c# asp.net-mvc async-await

我在mvc 4 app中有一个控制器动作:

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

        return View(gsModel);
    }
Run Code Online (Sandbox Code Playgroud)

和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 });
    }
}
Run Code Online (Sandbox Code Playgroud)

当我调用此控制器操作时,我收到以下错误:

此时无法启动异步操作.异步操作只能在异步处理程序或模块中启动,或者在页面生命周期中的某些事件中启动.如果在执行页面时发生此异常,请确保将页面标记为<%@ Page Async ="true"%>.

所以,问题:

  1. 我应该以某种方式将控制器或操作或页面本身标记为异步以允许此模型初始化?
  2. 是否可以将所有初始化逻辑封装到viewmodel而不是将其弹出到控制器?
  3. 这个错误的原因是什么?看起来它与WebForms有关,但我使用的是Razor引擎.

svi*_*ick 5

您的代码中存在两个问题:

  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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    有关更多详细信息,请参阅Stephen Cleary关于async构造函数的帖子.

  2. 您还需要使控制器动作async:

    public async Task<ActionResult> Index()
    {
        var gsModel = await GetStartedModel.Create()
    
        return View(gsModel);
    }
    
    Run Code Online (Sandbox Code Playgroud)