43

是否可以await在 Razor .cshtml 视图中执行任务?

默认情况下,它抱怨它只能在标记为的方法中使用,async所以我想知道是否有一个隐藏的开关可以启用它?

4

8 回答 8

23

在 ASP.NET Core 2.1 中,您可以await在 Razor 视图中使用。

请参阅https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1

例子:

@await Html.PartialAsync("../Account/_LoginPartial.cshtml")
于 2018-11-09T09:34:32.073 回答
2

我想要这样的东西很久了——我们写的很多页面都可以由 Jr Dev 拼凑起来,如果他们不必写一堆查询的话;而且,无论如何每次都是相同的基本查询样板 - 为什么他们必须为每个控制器编写它们,而他们的大部分工作是获取内容?我使用 C#,所以我不必处理内存管理,为什么 HTML 编码器必须处理查询细节?

您可以使用一个技巧将数据异步加载到视图中。首先,您定义一个类来表达您想要的数据。然后,在每个视图的顶部,实例化该类。回到控制器中,您可以查找您知道要使用的视图,打开它,然后编译该类。然后,您可以使用它以 MVC 强制执行的方式在 Controller 中异步获取 View 所需的数据。最后,按照 MVC 的规定,通过 ViewModel 将其传递给 View,并且通过一些技巧 - 你有一个 View 来声明它将使用哪些数据。

这是一个故事控制器。Jr Devs 将故事编写为简单的 .cshtml 文件,而无需知道控制器、数据库或 LINQ 是什么:

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 获取 View 文件,允许使用 WebForms 之类的东西(MVC 内部和使用 Razor 除外)。但是我们想用一些标准的 ViewModel 和 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);
    }

这是大部分工作。现在 Jr Devs 可以像这样声明他们需要的数据:

@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 {
...
于 2017-12-09T18:54:51.530 回答
0

您可以在剃须刀页面中等待电话吗?我有一个 Blazor 应用程序,我的大多数方法都是异步的:

剃须刀页面:

<MatFAB Icon="@MatIconNames.Autorenew" Style="transform:scale(0.8); background:#333;"
                OnClick="@(async () => await OnInitializedAsync())"></MatFAB>

这是一个调用生命周期事件 OnInitializedAsync() 的 MatBlazor FloatingActionButton

C#代码:

protected override async Task OnInitializedAsync()
{
    // Do something like get data when the form loads
}
于 2019-11-15T07:02:56.747 回答
0

我遇到了这个问题,因为我是 Razor 的新手,我想在我的控制器代码计算数据时显示一个简单的“正在加载...”屏幕。

所以我找到了这个链接:https ://www.codeproject.com/Articles/424745/MVC-Razor-In-Progress-Icon这很有帮助,但是因为我是 Razor 的新手,所以我无法完成这项工作.

最终对我有用的是以下内容。

1) 将代码项目中建议的“正在加载” div 添加到我的 .cshtml 文件中:

<div id="divLoading" style="margin: 0px; padding: 0px; position: fixed; right: 0px;
    top: 0px; width: 100%; height: 100%; background-color: #666666; z-index: 30001;
    opacity: .8; filter: alpha(opacity=70);display:none">
    <p style="position: absolute; top: 30%; left: 45%; color: White;">
        Loading, please wait...<img src="../../Content/Images/ajax-loading.gif">
    </p>
</div>

2) 修改我的 Razor 表单

<input type="submit" value="Go"/>

<input type="button" value="Go" onclick="JavascriptFunction()" />

3) 在我的 .cshtml 页面中创建 JavascriptFunction():

<script type="text/javascript" language="javascript">
    function JavascriptFunction() {
        $("#divLoading").show();
        $('form').submit();
    }
</script>

如果我正确理解了上述所有内容,那么当我按下 Go 按钮时,它的作用是执行函数 JavascriptFunction。

JavascriptFunction 做了两件事: 1) 通过显示先前隐藏的 (display:none) divLoading div 来更改页面的视图。2)提交此页面上的所有表单(我只有一个,所以它提交的表单就像我让他们在按钮上键入提交一样)

表单提交启动的Controller完成后,它在新页面上加载新视图,初始页面(以及“正在加载”的div)消失了。任务完成。

于 2019-04-02T17:57:27.847 回答
-1

No, that's not possible and you shouldn't need to do it anyway. Razor views should contain markup and at most some helper call. async/await belongs to your backend logic.

于 2013-10-04T13:29:27.293 回答
-1

按照 MaxP 的回答,尽管有 Knagis 评论,但很容易从该代码中返回一个值:

@{
    int x = DoAsyncStuffWrapper().Result;
}
@functions {
    async Task<int>DoAsyncStuffWrapper() 
    {
        await DoAsyncStuff();
    }
}
于 2019-12-02T23:33:44.173 回答
-1

如果你真的需要它,你可以这样做,它会很丑,但它会起作用。

在视图中

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

在控制器中

public async Task<ActionResult> Index()
        {
            ViewBag.foo = await _some.getFoo();
            ViewBag.bar = await _some.getBar();
            return View("Index");
        }
于 2016-06-22T11:56:37.213 回答
-2

我知道这是一个较旧的线程,但我会添加我的输入以防其他人发现它有用。我在 ASP.Net MVC 中使用新的 MongoDB 驱动程序时遇到了这个问题——新驱动程序(目前)只实现异步方法并返回异步游标,因为 asynccursor 没有实现 IEnumerable,所以不能在 foreach 中使用. 示例代码通常如下所示:

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

但是,这在 razor 中不起作用,因为视图本质上不是异步的,并且 await 不会削减它。

我通过将第一行更改为:

while(cursor.MoveNextAsync().Result)

在光标碰到最后一个条目之前返回 true。

希望有帮助!

于 2015-09-18T16:35:57.240 回答