2017-12-22 1 views
5

Ich versuche, dynamische Menü (in DB gespeichert) zu machen, die auf allen Web-App-Seiten angezeigt wird. Mit Google fand ich, dass es besser ist, die Menüansicht als Teil der Master-Ansicht (_Layout.cshtml) zu machen. Und deshalb muss jede Aktionsmethode des Controllers Daten mit dem Menümodell enthalten. Um zu vermeiden, Code-Duplizierung fand ich die Lösung, die eine Basis-Controller zu erstellen und liefern Daten über den Konstruktor:MVC Async-Methode in Konstruktor-Controller

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

Auch ich versuche async/verwenden warten Möglichkeiten und meine PageService (Menü) wird mit ToListAsync() um Daten von der DB zu bekommen. So, jetzt habe ich ein Problem, dass Base Konstruktor hat eine Asynchron-Methode:

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

Ich weiß, dass dies BAD CODE, aber ich weiß nicht, wie diese Situation richtig zu gestalten. Vielleicht gibt es einen anderen besseren Weg, um das dynamische Menü oder eine andere Möglichkeit, Daten asynchron zu bekommen, zu erstellen?

Auch fand ich diesen Artikel, aber ich weiß nicht, ob ich seine Lösungen anwenden kann, weil ich weiß nicht, ob ich Controller-Instanz Schöpfung umgehen kann:

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

+0

Das ist schlechtes Design, Sie sind dort richtig. Sie sollten stattdessen einen Middleware- oder Actionfilter betrachten. –

+0

Danke für die Antwort! Können Sie bitte einige Links zu Artikeln mit passenden Designs bereitstellen? Weil ich 1-2 Stunden gegoogelt habe, um zu finden, wie man das dynamische Menü implementiert. –

+2

Das klingt wie ein guter Kandidat für eine [Child Action] (https://stackoverflow.com/questions/12530016/what-is-an-mvc-child-action). Siehe auch diese Frage https: // stackoverflow.com/questions/21948909/asp-net-mvc-Controller-für-Layout – Jasen

Antwort

6

Statt alles abzuleiten von einer Basissteuerung (die eine Menge zusätzlicher Arbeit und Prüfung sein kann) Sie einen Controller einfach erstellen können MenuController, erstellen Sie eine Methode Default genannt und dann rufen Sie es von Ihrem Plan genannt:

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

in Ihrem Layout:

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

Dies ist wirklich die einfachste und sauberste Lösung. Die größte PRO ist, dass Sie den Cache für das Menü getrennt von der Methode aufrufen können. Es gibt keine gute Lösung für asp.net-mvc (1-5), Async-Code auf diese Weise auszuführen. (ActionFilters can't be async und (Render) Partials nicht async sein. Sie können nach wie vor ein Asynchron-Methode aufrufen, es wird nur Sync laufen.

Render vs Non-Render Performance.

+0

Vielen Dank für die Antwort! Ich bin neu in MVC, also werde ich über RenderAction lesen und werde Ihre Lösung versuchen. Auch Cache-Möglichkeiten sind hier groß! –

+0

Ihre Lösung angewendet, aber es hat einige Nuancen: untergeordnete Aktionen können nicht async sein: https://stackoverflow.com/questions/24072720/async-partialview-causes-httpserverutility-execute-blocked-exception/47962963#47962963 Also habe ich beschlossen, die Aktion nicht als ChildAction zu machen. Ist es notwendig, nur ein Kind zu machen? Können Sie bitte auch Ihre Antwort ändern, damit die Annahme richtig wäre? Weil Ihr Beispiel jetzt Async-Code in ChildAction hat –

+0

Async-Code async/erwarten Schlüsselwörter. Mine verwendet diese Schlüsselwörter nicht. Es sollte mit einer Warnung kompiliert werden. Andernfalls könnten Sie einfach [async-Code innerhalb einer Synchronisierungsmethode aufrufen] (https://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c/25097498#25097498) . –

-1

Ich änderte Funktionalität Html.RenderAction in meiner Ansicht zu nennen, wie Erik Philips vorgeschlagen:

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

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

Aber Render funktioniert nicht mit Asynchron-Controller Aktionen:

Async PartialView causes "HttpServerUtility.Execute blocked..." exception

scheint So wie sync Aufruf der einzige hier möglich ist.