MVC异步方法在构造函数控制器中
MVC异步方法在构造函数控制器中
我正在尝试制作一个动态菜单(存储在数据库中),它将显示在所有Web应用程序页面上。
使用Google搜索,我发现最好将菜单视图作为主视图(_Layout.cshtml)的一部分。因此,控制器的每个操作方法都必须包含菜单模型的数据。为了避免代码重复,我找到了创建基本控制器并使用其构造函数提供数据的解决方案:
另外,我正在尝试使用异步/等待的可能性,我的PageService(菜单)正在使用ToListAsync()从数据库获取数据。所以现在我有一个问题,BaseController构造函数有一个异步方法:
public class BaseController : AsyncController, IBaseController { private readonly IPageService _pageService; public BaseController(IPageService pageService) { _pageService = pageService; SetBaseViewModelAsync(); } private async Task SetBaseViewModelAsync() { ViewData["Pages"] = await _pageService.GetAllAsync(); } }
我知道这是糟糕的代码,但我不知道如何正确设计这种情况。也许有另一种更好的方法来创建动态菜单,或者以异步方式获取数据的另一种方法?
此外,我找到了这篇文章,但我不知道是否可以应用其解决方案,因为我不知道是否可以处理控制器实例的创建:
http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
问题的原因是Html.RenderAction方法无法与异步控制器操作一起使用,这导致了"HttpServerUtility.Execute blocked..."异常的出现。解决方法是将控制器操作改为同步调用。
在这个问题中,作者在视图中使用了Html.RenderAction方法来调用控制器的Index操作。控制器是一个异步控制器,实现了AsyncController接口,并且依赖于IPagesService接口。在控制器的构造函数中,通过参数注入的方式将IPagesService的实例赋值给_pagesService字段。
控制器中的IndexAsync操作是一个异步方法,它调用了_pagesService的GetAllAsync方法来获取数据,并将数据传递给MenuPartial部分视图。然而,由于Html.RenderAction不支持异步控制器操作,所以会出现"HttpServerUtility.Execute blocked..."异常。
根据作者提供的链接,可以看到有人在Stack Overflow上提出了同样的问题,并得到了解答。解答中指出,Html.RenderAction方法只能与同步的控制器操作一起使用。因此,解决方法是将异步控制器操作改为同步调用。
经过修改后的控制器代码如下所示:
public class PagesController : Controller, IPagesController { private readonly IPagesService _pagesService; public PagesController(IPagesService pagesService) { _pagesService = pagesService; } [HttpGet] [Route("")] public ActionResult Index() { var viewModel = _pagesService.GetAll(); return PartialView("MenuPartial", viewModel); } }
通过将控制器操作改为同步的Index方法,并在其中直接调用_pagesService的同步方法GetAll来获取数据,就可以解决Html.RenderAction与异步控制器操作不兼容的问题。
本文介绍了在MVC应用程序中使用Html.RenderAction方法时遇到的问题以及解决方法。问题的原因是Html.RenderAction不支持异步控制器操作,解决方法是将异步控制器操作改为同步调用。通过将控制器操作改为同步方法,可以避免"HttpServerUtility.Execute blocked..."异常的出现。
问题出现的原因:
- ASP.NET MVC(1-5)中没有很好的解决方案来运行异步代码。
- 子操作(Child Actions)无法是异步的。
- 渲染(Render)和局部视图(Partials)无法是异步的。
解决方法:
- 不要将所有内容都派生自基本控制器,而是创建一个名为MenuController的控制器。
- 创建一个名为Default的方法,并从布局中调用它。
- 在布局中使用RenderAction方法调用Default方法。
- 调用异步方法,但它将以同步方式运行。
这是最简单和最干净的解决方案。最大的优点是可以控制菜单的缓存,与调用方法分开。为了保持代码同步,决定不使用子操作。调用同步方法似乎是无法解决异步代码的问题。
文章如下:
在ASP.NET MVC中,如果要从一个基本控制器中派生出所有内容,可能需要进行很多的额外工作和测试。但是,有一种更简单和更干净的解决方案。您只需创建一个名为MenuController的控制器,创建一个名为Default的方法,并从布局中调用它。
[ChildActionOnly] public Default() { var viewModel = _pageService.GetAllAsync(); return Partial(viewModel); }
在布局中使用RenderAction方法调用Default方法。
@{Html.RenderAction("Default", "Menu");}
这是最简单和最干净的解决方案。最大的优点是可以控制菜单的缓存,与调用方法分开。在ASP.NET MVC(1-5)中,没有很好的解决方案来运行异步代码。子操作无法是异步的,渲染和局部视图无法是异步的。尽管可以调用异步方法,但它将以同步方式运行。
在调用同步方法中调用异步代码并不是一个好主意。因此,决定不使用子操作。调用同步方法似乎是无法解决异步代码的问题。
希望这篇文章对您有所帮助!感谢您的阅读!