2017-12-22 170 views
5

Tôi đang cố gắng tạo menu động (được lưu trữ trong DB), được hiển thị trên tất cả các trang ứng dụng web. Sử dụng Google Tôi thấy rằng tốt hơn là thực hiện chế độ xem menu như một phần của Chế độ xem chính (_Layout.cshtml). Và do đó, mọi phương thức hành động của bộ điều khiển phải chứa dữ liệu với mô hình menu. Để tránh trùng lặp mã tôi tìm thấy giải pháp để tạo ra một bộ điều khiển cơ sở và cung cấp dữ liệu sử dụng constructor của nó:Phương pháp async MVC trong bộ điều khiển bộ tạo

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

Ngoài ra, tôi đang cố gắng để sử dụng async/chờ đợi khả năng và PageService của tôi (menu) đang sử dụng ToListAsync() để lấy dữ liệu từ DB. Vì vậy, bây giờ tôi có một vấn đề, đó BaseController constructor có một phương pháp async:

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

tôi biết rằng đây là BAD MÃ, nhưng tôi không biết làm thế nào để thiết kế tình huống này đúng cách. Có thể có cách nào khác tốt hơn để tạo menu động hoặc cách khác để lấy dữ liệu không đồng bộ?

Ngoài ra, tôi tìm thấy bài viết này, nhưng tôi không biết nếu tôi có thể áp dụng các giải pháp của nó bởi vì tôi không biết nếu tôi có thể xử lý tạo điều khiển dụ:

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

+0

Thiết kế tồi, bạn chính xác ở đó. Bạn nên xem xét một thiết bị trung gian hoặc bộ lọc hành động thay vì –

+0

Cảm ơn bạn đã trả lời! Bạn có thể vui lòng cung cấp một số liên kết đến các bài viết có thiết kế phù hợp không? Bởi vì tôi đã googled trong khoảng 1-2 giờ để tìm cách triển khai thực đơn động. –

+2

Điều này nghe có vẻ giống như một ứng cử viên tốt cho một [Hành động trẻ em] (https://stackoverflow.com/questions/12530016/what-is-an-mvc-child-action). Xem thêm câu hỏi https: // stackoverflow này.com/questions/21948909/asp-net-mvc-controller-for-layout – Jasen

Trả lời

6

Thay vì phát sinh tất cả mọi thứ từ một bộ điều khiển cơ sở (trong đó có thể có rất nhiều việc làm thêm và thử nghiệm) bạn chỉ có thể tạo ra một bộ điều khiển gọi là MenuController, tạo ra một phương pháp gọi là Default và sau đó gọi nó từ Bố cục của bạn:

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

trong bố cục của bạn:

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

Đây thực sự là giải pháp dễ nhất và sạch nhất. PRO lớn nhất là bạn có thể kiểm soát bộ nhớ cache cho menu tách biệt với phương thức gọi. Không có giải pháp tốt cho asp.net-mvc (1-5) để chạy mã Async trong thời trang này. (ActionFilters can't be async và (Render) Partials không thể async. Bạn vẫn có thể gọi một phương pháp async, nó sẽ chỉ chạy Sync.

Render vs Non-Render Performance.

+0

Cảm ơn bạn đã trả lời! Tôi mới vào MVC, vì vậy tôi sẽ đọc về RenderAction và sẽ thử giải pháp của bạn. Ngoài ra, khả năng bộ nhớ cache là rất tốt ở đây! –

+0

Áp dụng giải pháp của bạn, nhưng nó có một số sắc thái: hành động con không thể không đồng bộ: https://stackoverflow.com/questions/24072720/async-partialview-causes-httpserverutility-execute-blocked-exception/47962963#47962963 Vì vậy, tôi quyết định không thực hiện hành động như ChildAction. Có cần thiết để làm cho nó chỉ trẻ em? Bạn có thể vui lòng sửa đổi câu trả lời của mình, vì vậy việc chấp nhận có phù hợp không? Bởi vì bây giờ ví dụ của bạn có mã không đồng bộ trong ChildAction –

+0

Mã async có từ khóa không đồng bộ/đang chờ. Tôi không sử dụng những từ khóa đó. Nó phải biên dịch với một cảnh báo. Nếu không, bạn có thể chỉ cần [gọi mã async trong một phương thức đồng bộ] (https://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c/25097498#25097498) . –

-1

tôi đã thay đổi chức năng để gọi Html.RenderAction trong quan điểm của tôi, như Erik Philips gợi ý:

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

và điều khiển:

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

Nhưng RenderAction không hoạt động với bộ điều khiển async Actions:

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

Vì vậy, có vẻ như cuộc gọi đồng bộ là người duy nhất có thể thực hiện ở đây.

Các vấn đề liên quan