我无法解决我遇到异步/等待的问题.
简而言之,我有一个控制器,用属性装饰.此属性从i/o密集型进程(filesystem/db/api等...)获取指定的内容
然后,它将返回的内容设置为Dictionary<string, string>ViewBag上的内容
然后,在视图中,我可以做这样的事情,以检索内容:
@(ViewBag.SystemContent["Common/Footer"])
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,它第一次运行,内容没有返回,并且通过字符串索引检索值的调用失败,因为它不存在.
点击F5,没关系.
控制器动作非常简单:
[ProvideContent("Common/Footer")]
public class ContactDetailsController : Controller
{
public async Task<ActionResult> Index()
{
//omitted for brevity - awaits some other async methods
return View();
}
}
Run Code Online (Sandbox Code Playgroud)
属性
public override async void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Result is ViewResult)
{
var localPath = filterContext.RouteData.Values["controller"] + "/" + filterContext.RouteData.Values["action"];
if (!_useControllerActionAsPath)
localPath = _path;
var viewResult = filterContext.Result as ViewResult;
//this seems to go off and come back AFTER the view requests it from the dictionary
var content = await _contentManager.GetContent(localPath);
if (viewResult.ViewBag.SystemContent == null)
viewResult.ViewBag.SystemContent = new Dictionary<string, MvcHtmlString>();
viewResult.ViewBag.SystemContent[localPath] = new DisplayContentItem(content, localPath);
}
Run Code Online (Sandbox Code Playgroud)
编辑
更改我的属性中的以下行:
var content = await _contentManager.GetContent(localPath);
Run Code Online (Sandbox Code Playgroud)
至
var content = Task.Factory.StartNew(() =>
manager.GetContent(localPath).Result, TaskCreationOptions.LongRunning).Result;
Run Code Online (Sandbox Code Playgroud)
解决了这个问题,但我觉得这与我在Stephen Clearys博客上读到的所有内容相违背......
我不是百分之百熟悉ASP.Net MVC堆栈以及这一切是如何工作的,但我会对它进行一次尝试.
该OnActionExecuting()文件说:
在调用action方法之前调用.
由于您覆盖了以前的同步方法并使其异步,因此期望代码完整,并为下一个执行步骤做好准备.
理论执行路径:
public void ExecuteAction()
{
OnActionExecuting();
OnActionExecution();
OnActionExecuted();
}
Run Code Online (Sandbox Code Playgroud)
既然你推翻了OnActionExecuting()方法,执行堆栈基本上还是一样的,但是要执行的下一个代码(ExecuteAction()和OnActionExecuted()和任何所谓的ExecuteAction())正期待进行的同步调用,所以他们的知识,一切都很好,并准备继续运行.
基本上,归结OnActionExecuting()为不是一种异步方法,没有任何期望它.(它在MVC 6中也不是异步的.)
某些东西,即在OnActionExecuting()顺序调用之后被同步调用,它正在引用viewResult.ViewBag.SystemContent,因此它没有获得你想要的值.正如你在标题中所说的那样,
等待异步方法在结果需要之前不返回.
在"抓"使用的任务是,你不能保证当该任务将完成,但可以保证,它会完成.
潜在解决方案
GetContent()呼叫移出该事件.GetContent(),找到您viewResult.ViewBag.SystemContent使用的下一个位置并检查任务完成情况或等待完成.编辑:用于在控制器中存储任务的代码示例
[ProvideContent("Common/Footer")]
public class ContactDetailsController : Controller
{
/*
* BEGINNING OF REQUIRED CODE BLOCK
*/
private Task<string> _getContentForLocalPathTask;
private string _localPath;
/*
* END OF REQUIRED CODE BLOCK
*/
public async Task<ActionResult> Index()
{
//omitted for brevity - awaits some other async methods
/*
* BEGINNING OF REQUIRED CODE BLOCK
*/
string content = await _getContentForLocalPath;
viewResult.ViewBag.SystemContent[_localPath] = new DisplayContentItem(content, _localPath);
/*
* END OF REQUIRED CODE BLOCK
*/
return View();
}
public override async void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Result is ViewResult)
{
var localPath = filterContext.RouteData.Values["controller"] +
"/" + filterContext.RouteData.Values["action"];
if (!_useControllerActionAsPath)
localPath = _path;
var viewResult = filterContext.Result as ViewResult;
/*
* BEGINNING OF REQUIRED CODE BLOCK
*/
_localPath = localPath;
_getContentForLocalPathTask = _contentManager.GetContent(localPath);
/*
* END OF REQUIRED CODE BLOCK
*/
if (viewResult.ViewBag.SystemContent == null)
viewResult.ViewBag.SystemContent = new Dictionary<string, MvcHtmlString>();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1784 次 |
| 最近记录: |