I'm having trouble getting my head round an issue I'm having with async / await.
in a nutshell, I have a controller, decorated with an attribute. This attribute gets the specified content from an i/o intensive process (filesystem / db / api etc...)
It then sets the returned content as a Dictionary<string, string>
on the ViewBag
Then, in a view, I can do something like this, to retrieve the content:
@(ViewBag.SystemContent["Common/Footer"])
The issue I'm having, is the first time it runs, the content hasn't returned, and the call to retrieve the value by string index fails, as it doesn't exist.
Hit F5, and it's fine.
Controller action is pretty simple:
[ProvideContent("Common/Footer")]
public class ContactDetailsController : Controller
{
public async Task<ActionResult> Index()
{
//omitted for brevity - awaits some other async methods
return View();
}
}
The attribute
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);
}
EDIT
Changing the following line in my Attribute:
var content = await _contentManager.GetContent(localPath);
To
var content = Task.Factory.StartNew(() =>
manager.GetContent(localPath).Result, TaskCreationOptions.LongRunning).Result;
solves the problem, but I feel it goes against everything I've read on Stephen Clearys blog...