Chế độ xem có tồn tại trong ASP.NET MVC không?


95

Có thể xác định xem một tên chế độ xem cụ thể có tồn tại từ bên trong bộ điều khiển hay không trước khi hiển thị chế độ xem?

Tôi có yêu cầu xác định động tên của chế độ xem để hiển thị. Nếu một chế độ xem tồn tại với tên đó thì tôi cần hiển thị chế độ xem đó. Nếu không có chế độ xem theo tên tùy chỉnh thì tôi cần hiển thị chế độ xem mặc định.

Tôi muốn làm điều gì đó tương tự như mã sau trong bộ điều khiển của tôi:

public ActionResult Index()
{
    var name = SomeMethodToGetViewName();

    // The 'ViewExists' method is what I've been unable to find.
    if (ViewExists(name))
    {
        retun View(name);
    }
    else
    {
        return View();
    }
}

14
Chỉ cần đọc tiêu đề của điều này, nó có vẻ giống như một câu hỏi triết học rất sâu sắc.

Câu trả lời:


154
 private bool ViewExists(string name)
 {
     ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, name, null);
     return (result.View != null);
 }

Đối với những người đang tìm kiếm phương pháp sao chép / dán tiện ích mở rộng:

public static class ControllerExtensions
{
    public static bool ViewExists(this Controller controller, string name)
    {
        ViewEngineResult result = ViewEngines.Engines.FindView(controller.ControllerContext, name, null);
        return (result.View != null);
    }
}

2
Điều này có lẽ tốt hơn. Tôi không biết rằng có một phương thức FindView nằm ngoài bộ sưu tập ViewEngines.
Lance Harper

1
Nhưng làm thế nào để kiểm tra xem chế độ xem có tồn tại cho bộ điều khiển khác không?
SOReader

Loại sang một bên: một trong những kỹ sư của chúng tôi (kể từ khi chuyển sang) đã xây dựng một công cụ chế độ xem tùy chỉnh (được gọi là MultiTenantViewEngine, vì vậy bạn sẽ hiểu được mục đích của nó) triển khai FindView để ném HttpException (404) nếu nó không thể tìm thấy lượt xem. Đây có phải là thực hành tốt? Tôi không có ý kiến. Nhưng sẽ không ngạc nhiên nếu có những triển khai khác như vậy. Vì bạn sẽ không biết hoạt động bên trong của công cụ xem khi mã này thực thi, bạn có thể muốn ném một hàm catch {return false; } xung quanh con chó con này, chỉ để được an toàn.
Brian Colavito

1
@SOReader, tôi đã thử nghiệm nhưng, bộ điều khiển IController = new HomeController (); và sau đó controller.ControllerContext sẽ cung cấp thứ mà bạn có thể chuyển cho các phương thức findview.
Vishal Sharma

Cảm ơn vì câu trả lời này. Nó đã giúp tôi trong một vấn đề khác. Tôi cần phải kiểm tra xem quan điểm của tôi là một phần hay không và như tất cả partials tôi tên bắt đầu bằng gạch dưới bây giờ tôi có thể làm việc với các giải pháp của tôi kiểm tra nếu 'result.View = null!'
Deise Vicentin

19

Điều gì về việc thử một cái gì đó như sau, giả sử bạn đang chỉ sử dụng một công cụ xem:

bool viewExists = ViewEngines.Engines[0].FindView(ControllerContext, "ViewName", "MasterName", false) != null;

Có vẻ như câu này đã được đăng 3 phút trước khi câu trả lời được chấp nhận và chưa có tình yêu ?! +1 từ tôi.
Trevor de Koekkoek 19/12/12

@TrevordeKoekkoek ... hmmm ... + 1
Vishal Sharma

8

Đây là một cách khác [không nhất thiết được khuyến nghị] để làm điều đó

 try
 {
     @Html.Partial("Category/SearchPanel/" + Model.CategoryKey)
 }
 catch (InvalidOperationException) { }

đây là để kiểm tra sự tồn tại của chế độ xem một phần trong tệp .cshtml. nó không thực sự là một câu trả lời cho câu hỏi này, nhưng một câu hỏi khác có liên kết ở đây đã bị đóng không chính xác, vì vậy tôi để lại câu trả lời của mình ở đây
Simon_Weaver

2
Điều này thực sự đã được phát hiện để sử dụng cho tôi, vì tôi đang tìm cách sử dụng một góc nhìn cụ thể về văn hóa. Vì vậy, tôi chỉ gọi điều này với tên chế độ xem cụ thể của nền văn hóa, và sau đó gọi là chế độ xem mặc định bên trong bắt. Và tôi đang thực hiện điều này trong một hàm tiện ích, vì vậy tôi không có quyền truy cập vào ControllerContexttùy chọn FindViewphương thức cần.
kinh ngạc

2

Nếu bạn muốn sử dụng lại điều này trên nhiều hành động của bộ điều khiển, dựa trên giải pháp do Dave đưa ra, bạn có thể xác định kết quả dạng xem tùy chỉnh như sau:

public class CustomViewResult : ViewResult
{
    protected override ViewEngineResult FindView(ControllerContext context)
    {
        string name = SomeMethodToGetViewName();

        ViewEngineResult result = ViewEngines.Engines.FindView(context, name, null);

        if (result.View != null)
        {
            return result;
        }

        return base.FindView(context);
    }

    ...
}

Sau đó, trong hành động của bạn, chỉ cần trả về một phiên bản của chế độ xem tùy chỉnh của bạn:

public ActionResult Index()
{ 
    return new CustomViewResult();
}

1
ViewEngines.Engines.FindView(ViewContext.Controller.ControllerContext, "View Name").View != null

2 xu của tôi.


1

Trong asp.net core 2.x, thuộc ViewEnginestính không còn tồn tại nên chúng tôi phải sử dụng ICompositeViewEnginedịch vụ. Đây là một biến thể của câu trả lời được chấp nhận bằng cách sử dụng chèn phụ thuộc:

public class DemoController : Controller
{
    private readonly IViewEngine _viewEngine;

    public DemoController(ICompositeViewEngine viewEngine)
    {
        _viewEngine = viewEngine;
    }

    private bool ViewExists(string name)
    {
        ViewEngineResult viewEngineResult = _viewEngine.FindView(ControllerContext, name, true);
        return viewEngineResult?.View != null;
    }

    public ActionResult Index() ...
}

Đối với những người tò mò: Giao diện cơ sở IViewEnginekhông được đăng ký như một dịch vụ, vì vậy chúng tôi phải đưa ICompositeViewEnginevào thay thế. Các FindView()tuy nhiên phương pháp được cung cấp bởi IViewEnginevì các biến thành viên có thể sử dụng giao diện cơ bản.


0

Đây là cách thực hiện trong Razor dành cho Core 2.2, v.v. Lưu ý rằng lệnh gọi là "GetView", không phải "Find View)

@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
...
@if (Engine.GetView(scriptName, scriptName, isMainPage: false).Success) 
{
    @await Html.PartialAsync(scriptName)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.