C# 在 Razor 视图中使用 await
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19182349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use of await in Razor views
提问by Kna?is
Is it possible to await
on tasks in Razor .cshtml views?
是否可以await
在 Razor .cshtml 视图中执行任务?
By default it complains that it can only be used in methods marked with async
so I'm wondering if maybe there is a hidden switch somewhere that enables it?
默认情况下,它抱怨它只能在标记为的方法中使用,async
所以我想知道是否有隐藏的开关可以启用它?
回答by Darin Dimitrov
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.
不,这是不可能的,无论如何您都不需要这样做。Razor 视图应该包含标记和最多一些辅助调用。async/await 属于您的后端逻辑。
回答by EricF
I know this is an older thread, but I'll add my input just in case someone else finds it useful. I ran into this problem working with the new MongoDB driver in ASP.Net MVC - the new driver (for now), only implements async methods and returns async cursors, which can't be used in a foreach because asynccursor doesn't implement IEnumerable. The sample code typically looks like:
我知道这是一个较旧的线程,但我会添加我的输入,以防其他人发现它有用。我在 ASP.Net MVC 中使用新的 MongoDB 驱动程序时遇到了这个问题 - 新驱动程序(目前)仅实现异步方法并返回异步游标,不能在 foreach 中使用,因为 asynccursor 没有实现 IEnumerable . 示例代码通常如下所示:
while(await cursor.movenextasync)
var batch=cursor.current
foreach(var item in batch)
--do stuff here--
But, this doesn't work in razor, because views are inherently not async, and await doesn't cut it.
但是,这在 razor 中不起作用,因为视图本质上不是异步的,并且 await 不会削减它。
I got it to work by changing the first line to:
我通过将第一行更改为:
while(cursor.MoveNextAsync().Result)
which returns true until the cursor hits the last entry.
它返回真,直到光标点击最后一个条目。
Hope that helps!
希望有帮助!
回答by TheZodchiy
If you really need it, you can do this, it will be ugly, but it will work.
如果你真的需要它,你可以这样做,它会很丑,但它会起作用。
In View
在视图中
@{
var foo = ViewBag.foo;
var bar = ViewBag.bar;
}
In Controller
在控制器中
public async Task<ActionResult> Index()
{
ViewBag.foo = await _some.getFoo();
ViewBag.bar = await _some.getBar();
return View("Index");
}
回答by Chris Moschini
I've wanted something like this for a long time - a lot of the pages we write could be thrown together by a Jr Dev if they didn't have to write a bunch of queries; and, it's the same basic query boilerplate every time anyway - why should they have to write them for each Controller, when the majority of their work is to get content up? I use C# so I don't have to deal with memory management, why should an HTML coder have to deal with query details?
我一直想要这样的东西 - 如果他们不必编写一堆查询,我们编写的许多页面可以由 Jr Dev 拼凑在一起;而且,无论如何,它每次都是相同的基本查询样板 - 为什么他们必须为每个控制器编写它们,因为他们的大部分工作是获取内容?我使用 C#,所以我不必处理内存管理,为什么 HTML 编码器必须处理查询细节?
There is a trick you can use to sort of implicitly load data async into the View. First, you define a class that expresses what data you want. Then, at the top of each View, instantiate that class. Back in the Controller, you can lookup the View you know you're going to use, open it, then compile that class. You can then use it to go get the data the View will need, async, in the Controller the way MVC enforces. Finally, pass it off with a ViewModel to the View as MVC prescribes, and, through some trickery - you have a View that declares what data it's going to use.
有一个技巧可以用来将数据异步加载到视图中。首先,您定义一个表示您想要的数据的类。然后,在每个视图的顶部,实例化该类。回到控制器中,您可以查找您知道要使用的视图,打开它,然后编译该类。然后,您可以使用它以 MVC 强制的方式在控制器中异步获取视图所需的数据。最后,按照 MVC 的规定,将它与 ViewModel 一起传递给 View,并且通过一些技巧 - 您有一个 View 来声明它将要使用的数据。
Here's a StoryController. Jr Devs write stories as simple .cshtml files without having to know what a Controller, database or LINQ is:
这是一个 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);
All this does for now is go get the View file based on the URL, allowing something like WebForms (except inside MVC and using Razor). But we want to show some data - in our case, people and projects that accumulate in the database - with some standard ViewModels and Partials. Let's define how and compile that out. (Note that ConservX happens to be the core Project namespace in my case.)
现在所做的就是根据 URL 获取视图文件,允许类似 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);
}
That's the majority of the work. Now Jr Devs can just declare the data they need like so:
这就是大部分的工作。现在 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 {
...
回答by MaxP
It's actually easy. Here is the view code:
其实很简单。这是视图代码:
@{
DoAsyncStuffWrapper();
}
@functions {
async void DoAsyncStuffWrapper()
{
await DoAsyncStuff();
}
}
回答by Kirill Rakhman
In ASP.NET Core 2.1, you can use await
in Razor views.
在 ASP.NET Core 2.1 中,您可以await
在 Razor 视图中使用。
See https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1
请参阅https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1
Example:
例子:
@await Html.PartialAsync("../Account/_LoginPartial.cshtml")
回答by Owen Ivory
I landed on this question because I am a newbie to Razor and I wanted to display a simple "loading..." screen while my Controller Code was calculating data.
我提出这个问题是因为我是 Razor 的新手,我想在我的控制器代码计算数据时显示一个简单的“加载...”屏幕。
So I found this link: https://www.codeproject.com/Articles/424745/MVC-Razor-In-Progress-Iconwhich was helpful, but because I was a total novice at Razor, I was unable to make this work.
所以我找到了这个链接:https: //www.codeproject.com/Articles/424745/MVC-Razor-In-Progress-Icon这很有帮助,但因为我是 Razor 的新手,我无法完成这项工作.
What finally worked for me was the following.
最终对我有用的是以下内容。
1) Add the "loading" div as suggested in the code project to my .cshtml file:
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) Modify my Razor form from
2) 修改我的 Razor 表单
<input type="submit" value="Go"/>
to
到
<input type="button" value="Go" onclick="JavascriptFunction()" />
3) Create the JavascriptFunction() in my .cshtml page:
3) 在我的 .cshtml 页面中创建 JavascriptFunction():
<script type="text/javascript" language="javascript">
function JavascriptFunction() {
$("#divLoading").show();
$('form').submit();
}
</script>
If I understand all of the above correctly, what this does is execute the function JavascriptFunction when I press the Go button.
如果我正确理解了上述所有内容,那么当我按下 Go 按钮时,它会执行 JavascriptFunction 函数。
The JavascriptFunction does 2 things: 1) Change the view of the page by showing the previously hidden (display:none) divLoading div. 2) Submit all the forms on this page (I only have one, so it submits the form the same as if I had they type submit on the button)
JavascriptFunction 做了两件事:1) 通过显示以前隐藏的 (display:none) divLoading div 来改变页面的视图。2)提交此页面上的所有表单(我只有一个,所以它提交的表单与我在按钮上输入提交的表单相同)
After the Controller launched by the form submit is done, it loads a new view on a new page, and the initial page (and the "loading" div) is gone. Mission accomplished.
表单提交启动的控制器完成后,它在新页面上加载一个新视图,初始页面(和“加载”div)消失了。任务完成。
回答by James Heffer
You can await calls in razor pages? I have a Blazor app and most of my methods are async:
您可以在剃刀页面中等待呼叫吗?我有一个 Blazor 应用程序,我的大部分方法都是异步的:
Razor page:
剃须刀页面:
<MatFAB Icon="@MatIconNames.Autorenew" Style="transform:scale(0.8); background:#333;"
OnClick="@(async () => await OnInitializedAsync())"></MatFAB>
This is a MatBlazor FloatingActionButton which calls the life time cycle event OnInitializedAsync()
这是一个调用生命周期事件 OnInitializedAsync() 的 MatBlazor FloatingActionButton
C# Code:
C# 代码:
protected override async Task OnInitializedAsync()
{
// Do something like get data when the form loads
}
回答by Kevin McDowell
Following on MaxP's answer, it's easy to return a value from that code, despite Knagis comment:
按照 MaxP 的回答,尽管 Knagis 评论,很容易从该代码返回一个值:
@{
int x = DoAsyncStuffWrapper().Result;
}
@functions {
async Task<int>DoAsyncStuffWrapper()
{
await DoAsyncStuff();
}
}