Чи існує подання в ASP.NET MVC?


95

Чи можна визначити, чи існує конкретне ім'я представлення всередині контролера перед тим, як рендерити представлення?

У мене є вимога динамічно визначати назву подання, яке відображатиметься. Якщо представлення даних існує з такою назвою, тоді мені потрібно зробити це подання. Якщо немає подання за спеціальною назвою, мені потрібно зробити подання за замовчуванням.

Я хотів би зробити щось подібне до наступного коду в моєму контролері:

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
Просто читаючи заголовок цього, це здається дуже глибоким філософським питанням.

Відповіді:


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

Для тих, хто шукає метод розширення copy / paste:

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
Це, мабуть, краще. Я не знав, що існує метод FindView з самої колекції ViewEngines.
Lance Harper

1
Але як перевірити, чи існує подання для іншого контролера?
SOReader

Ось осторонь: один з наших інженерів (з тих пір, як продовжив) створив спеціальний механізм подання (званий MultiTenantViewEngine, щоб ви зрозуміли його мету), який реалізує FindView, щоб кинути HttpException (404), якщо він не може знайти даний вид. Це хороша практика? Я поняття не маю. Але не здивуйся, якщо існують інші реалізації, подібні до цього. Оскільки ви не будете знати внутрішню роботу механізму перегляду під час виконання цього коду, можливо, ви захочете кинути catch {return false; } навколо цього цуценя, щоб бути в безпеці.
Брайан Колавіто

1
@SOReader, я перевірив hvnt, але, контролер IController = новий HomeController (); а потім controller.ControllerContext надасть те, що ви можете передати, щоб знайти методи перегляду.
Vishal Sharma

Дякую за цю відповідь. Це допомогло мені в іншій проблемі. Мені потрібно було перевірити, чи мій погляд частковий чи ні, і оскільки ім'я всіх моїх частин починається з підкреслення, тепер я можу працювати зі своїм рішенням, перевіряючи, чи "result.View! = Null"
Deise Vicentin

19

А як щодо спробувати щось на зразок наступного, припускаючи, що ви використовуєте лише один механізм перегляду:

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

схоже на те, що цей був опублікований за 3 хвилини до прийнятої відповіді, і все ж ніякої любові ?! +1 від мене.
Тревор де Куккук,

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

8

Ось ще один (не обов’язково рекомендований) спосіб зробити це

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

це для перевірки існування часткового подання у файлі .cshtml. це насправді не відповідь на це запитання, але ще одне питання, яке тут посилається, було неправильно закрито, тому я залишаю свою відповідь тут
Simon_Weaver

2
Це насправді було використано для мого використання, оскільки я шукав спосіб використовувати частковий погляд на культуру. Тож я просто назвав це з назвою представлення для конкретної культури, а потім викликав подання за замовчуванням всередині улову. І я робив це в утиліті, тому не мав доступу до методу, ControllerContextяк це FindViewпотрібно.
благоговіння

2

Якщо ви хочете повторно використати це для кількох дій контролера, спираючись на рішення, яке надав Дейв, ви можете визначити результат власного перегляду наступним чином:

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

    ...
}

Тоді у вашій дії просто поверніть екземпляр власного подання:

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

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

Мої 2 копійки.


1

В asp.net core 2.x ViewEnginesвластивість більше не існує, тому ми повинні користуватися ICompositeViewEngineпослугою. Це варіант прийнятої відповіді з використанням введення залежності:

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

Для допитливих: базовий інтерфейс IViewEngineне зареєстрований як послуга, тому ICompositeViewEngineзамість цього ми повинні вводити . Однак FindView()метод передбачений, IViewEngineтому змінна-член може використовувати базовий інтерфейс.


0

Ось як це зробити в Razor для Core 2.2 тощо. Зверніть увагу, що виклик "GetView", а не "Пошук подання"

@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
...
@if (Engine.GetView(scriptName, scriptName, isMainPage: false).Success) 
{
    @await Html.PartialAsync(scriptName)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.