Asynchronous MVC method in the constructor controller

I am trying to create a dynamic menu (stored in a database) that appears on all pages of a web application. Using Google, I found it better to make the menu look as part of the Master View (_Layout.cshtml). And because of this, each controller action method must contain data with a menu model. To avoid code duplication, I found a solution to create a basic controller and provide data using its constructor:

https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/views/passing-data-to-view-master-pages-cs

In addition, I am trying to use the features of async / await, and my PageService menu (menu) uses ToListAsync () to retrieve data from the database. So now I have a problem that the BaseController constructor has an async method:

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(); } } 

I know this is BAD CODE , but I do not know how to properly design this situation. Maybe there is another better way to create a dynamic menu or another way to get data asynchronously?

Also, I found this article, but I donโ€™t know if I can apply its solutions, because I donโ€™t know if I can handle the creation of the controller instance:

http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html

+5
source share
2 answers

Instead of outputting everything from the base controller (which can be a lot of extra work and testing), you can simply create a controller called MenuController , create a method called Default and then call it from your layout:

 [ChildActionOnly] public Default() { var viewModel = _pageService.GetAllAsync(); return Partial(viewModel); } 

in your layout:

 @{Html.RenderAction("Default", "Menu");} 

This is really the easiest and cleanest solution. The biggest PRO is that you can manage the cache for the menu separately from the method call. For asp.net-mvc (1-5) there is no good solution to run Async code this way. ( ActionFilters cannot be async and (Render) Particles cannot be asynchronous. You can still call the async method, it will just start Sync.

Render vs Non-Render Performance .

+6
source

I changed the functionality to call Html.RenderAction in my view, as Eric Philips suggested:

 @{ Html.RenderAction("Index", "Pages"); } 

and controller:

 public class PagesController : AsyncController, IPagesController { private readonly IPagesService _pagesService; public PagesController(IPagesService pagesService) { _pagesService = pagesService; } [HttpGet] [Route("")] public async Task<ActionResult> IndexAsync() { var viewModel = await _pagesService.GetAllAsync(); return PartialView("MenuPartial", viewModel); } } 

But RenderAction does not work with an asynchronous controller. Actions:

Async PartialView raises "HttpServerUtility.Execute blocked ..." Exception

Thus, it seems that the only challenge here is possible.

-1
source

Source: https://habr.com/ru/post/1274282/


All Articles