【问题标题】:How can I run a method without waiting for long running process如何在不等待长时间运行的过程的情况下运行方法
【发布时间】:2017-08-10 15:56:27
【问题描述】:

我有一个Layout,其中有一个@RenderBody 部分和一个index 页面。我的索引页面有一个长时间运行的过程,我希望它无需等待DoSomeAsyncStuff 即可呈现视图。以下代码看起来接近我想要的,但问题在于我的模型在传递给视图时它的属性为空:

public ActionResult Index()
{
    MyModel model = new MyModel();
    Task.Run(() => DoSomeAsyncStuff(model));
    return View(model);
}

private async void DoSomeAsyncStuff(MyModel model)
{
    await Task.Delay(20000);
    model.Name = "Something";
    //Assigning other model properties
}

在我看来,我得到了NullReferenceExceptionValue cannot be null 错误,这当然是因为我的模型的属性仍未填充到DoSomeAsyncStuff 方法中:

<table>
<tr>
    <th colspan="3">
        @Model.Products.Select(c => c.Date).FirstOrDefault()
    </th>

</tr>

@foreach (var item in Model.Products)
{
    <tr>
        <td>
            @item.Title
        </td>
        <td>
            @item.Price
        </td>
    </tr>
}
</table>

【问题讨论】:

  • 假设您的页面可以在没有数据的情况下以某种方式呈现,您唯一真正的选择是使用某种 Ajax 来加载您的绑定标记。例如,jQuery 的 load 函数可以解决这个问题。

标签: c# asp.net-mvc async-await


【解决方案1】:

你还没有展示你的模型,所以这主要是伪代码。首先,将长时间运行的内容移至另一个操作:

public ActionResult Index()
{
    var model = new MyModel();

    return View(model);
}

public async Task<ActionResult> DoSomeAsyncStuff()
{
    var model = new MyModel();
    await Task.Delay(20000);

    model.Name = "Something";
    //Assigning other model properties

    return PartialView("_InnerView", model);
}

模型绑定的所有内容都应该在局部视图中(我称之为_InnerView.cshtml,在这里)。父视图应该只有一个占位符或加载小部件,您的模型绑定标记当前所在的位置:

<div id="load-with-ajax">
    Please wait. Loading...
</div>

然后,在页面的某处,在您的 jQuery 引用之后(我假设您正在使用或愿意使用 jQuery),添加类似的内容:

<script>
    $(function(){
        $('#load-with-ajax').load('@Url.Action("DoSomeAsyncStuff")');
    });
</script>

【讨论】:

  • 谢谢。它看起来不错,但是当我测试它时,它从不调用“DoSomeAsyncStuff”。我错过了什么吗?
  • 如果没有看到您正在做的更完整的版本,这很难回答。您正在做什么来验证它“从不调用”该操作?您是在看开发者控制台,还是在等待 Visual Studio 中的断点?任何一个应该工作。
  • 您是否在浏览器开发者控制台的“网络”选项卡中看到请求?如果没有,您的 JavaScript 代码中可能有错误。
  • 你可以使用 Font Awesome 之类的东西,它是 animation classes。否则,只需替换文本或为动画 gif 添加&lt;img /&gt; 标签。例如:preloaders.net/en/free。如果要屏蔽整个页面,Block UI 效果很好。
【解决方案2】:

您需要将 async 和 await 应用于您的方法。这将确保模型在传递到您的视图时被填充。

public async Task<ActionResult> Index()
{
    var model = new MyModel();
    await DoSomeAsyncStuff(model);
    return View(model);
}

private async Task DoSomeAsyncStuff(MyModel model)
{
    await Task.Delay(20000);
    model.Name = "Something";
    //Assigning other model properties
}

唯一的另一种选择是在两次调用中执行此操作。

public ActionResult Index()
{
    return View();
}

public async Task<ActionResult> PartialIndex()
{
    var model = new MyModel();
    await DoSomethingAsync(model);
    return PartialView(model);
}

private async Task DoSomeAsyncStuff()
{
    await Task.Delay(20000);

    model.Name = "Something";
    //Assigning other model properties
}

为了确保模型被填充,您必须等待异步方法返回。第二种方法可能会被调整为更接近您正在寻找的东西。

【讨论】:

  • 但是通过等待“DoSomeAsyncStuff”它必须等到方法的执行完成然后渲染视图。不是?请再次检查问题的标题。我想在“DoSomeAsyncStuff”漫长的过程中不等待数据可用就呈现页面。
  • 是的,会的。不过真的帮不上忙。要么加载整个页面并等待模型返回视图,要么加载一个空页面然后进行第二次调用以获取部分视图并等待该方法中的模型以水合页面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-26
  • 2011-08-06
  • 2012-04-21
  • 2012-12-11
  • 2021-10-22
  • 2020-11-24
相关资源
最近更新 更多