Razor .cshtml视图中的任务是否可以await
?
默认情况下,它会抱怨它只能在标有async
的方法中使用,所以我想知道是否有某个隐藏的开关可以启用它?
答案 0 :(得分:14)
不,这是不可能的,无论如何你都不应该这样做。 Razor视图应包含标记,最多包含一些帮助程序调用。 async / await属于你的后端逻辑。
答案 1 :(得分:9)
在ASP.NET Core 2.1中,可以在Razor视图中使用await
。
请参见https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1
示例:
@await Html.PartialAsync("../Account/_LoginPartial.cshtml")
答案 2 :(得分:1)
我很长一段时间都想要这样的东西 - 我们写的很多页面可能会由Jr Dev抛出,如果他们不必写一堆查询的话;并且,它每次都是相同的基本查询样板 - 当他们的大部分工作是为了获得内容时,为什么他们必须为每个Controller编写它们?我使用C#所以我不必处理内存管理,为什么HTML编码器必须处理查询细节?
您可以使用一种技巧来隐式地将数据异步加载到View中。首先,定义一个表达所需数据的类。然后,在每个View的顶部,实例化该类。回到Controller中,您可以查找您知道自己将要使用的视图,打开它,然后编译该类。然后,您可以使用它以与MVC强制执行的方式在Controller中获取View将需要的数据async。最后,使用ViewModel将其传递给View作为MVC规定,并且通过一些技巧 - 你有一个View来声明它将要使用的数据。
这是一个StoryController。 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 {
...
答案 3 :(得分:0)
我之所以提出这个问题,是因为我是Razor的新手,我想在控制器代码计算数据时显示一个简单的“正在加载...”屏幕。
所以我找到了以下链接:https://www.codeproject.com/Articles/424745/MVC-Razor-In-Progress-Icon,这很有帮助,但是由于我是Razor的新手,所以无法完成这项工作。
最终对我有用的是以下内容。
1)将代码项目中建议的“ loading” 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之后,它将在新页面上加载新视图,并且初始页面(和“ loading” div)消失了。任务完成了。
答案 4 :(得分:0)
您可以等待剃须刀页面中的呼叫吗?我有一个Blazor应用程序,并且大多数方法都是异步的:
剃刀页面:
<MatFAB Icon="@MatIconNames.Autorenew" Style="transform:scale(0.8); background:#333;"
OnClick="@(async () => await OnInitializedAsync())"></MatFAB>
这是一个MatBlazor FloatingActionButton,它调用生命周期事件OnInitializedAsync()
C#代码:
protected override async Task OnInitializedAsync()
{
// Do something like get data when the form loads
}
答案 5 :(得分:-1)
我知道这是一个较旧的主题,但我会添加我的输入以防其他人发现它有用。我遇到了这个问题,使用ASP.Net MVC中的新MongoDB驱动程序 - 新的驱动程序(现在),只实现异步方法并返回异步游标,这些游标不能在foreach中使用,因为asynccursor不实现IEnumerable 。示例代码通常如下所示:
while(await cursor.movenextasync)
var batch=cursor.current
foreach(var item in batch)
--do stuff here--
但是,这在剃刀中不起作用,因为视图本质上不是异步的,等待不会削减它。
我通过将第一行改为:
来实现它while(cursor.MoveNextAsync().Result)
返回true,直到光标到达最后一个条目。
希望有所帮助!
答案 6 :(得分:-1)
遵循MaxP的答案,尽管Knagis做出了评论,但很容易从该代码返回值:
@{
int x = DoAsyncStuffWrapper().Result;
}
@functions {
async Task<int>DoAsyncStuffWrapper()
{
await DoAsyncStuff();
}
}
答案 7 :(得分:-2)
如果你真的需要它,你可以这样做,它会很难看,但它会起作用。
在视图中
@{
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");
}
答案 8 :(得分:-2)
实际上很容易。这是视图代码:
@{
DoAsyncStuffWrapper();
}
@functions {
async void DoAsyncStuffWrapper()
{
await DoAsyncStuff();
}
}