Existiert eine Ansicht in ASP.NET MVC?


95

Kann vor dem Rendern der Ansicht festgestellt werden, ob in einem Controller ein bestimmter Ansichtsname vorhanden ist?

Ich muss den Namen der zu rendernden Ansicht dynamisch bestimmen. Wenn eine Ansicht mit diesem Namen vorhanden ist, muss ich diese Ansicht rendern. Wenn es keine Ansicht mit dem benutzerdefinierten Namen gibt, muss ich eine Standardansicht rendern.

Ich möchte etwas Ähnliches wie den folgenden Code in meinem Controller tun:

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
Nur den Titel zu lesen, scheint eine sehr tiefe philosophische Frage zu sein.

Antworten:


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

Für diejenigen, die eine Erweiterungsmethode zum Kopieren / Einfügen suchen:

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
Das ist wahrscheinlich besser. Mir war nicht bekannt, dass es eine FindView-Methode aus der ViewEngines-Auflistung selbst gibt.
Lance Harper

1
Aber wie kann man überprüfen, ob die Ansicht für einen anderen Controller vorhanden ist?
SOReader

Nebenbei bemerkt: Einer unserer Ingenieure (seitdem) hat eine benutzerdefinierte Ansichts-Engine (MultiTenantViewEngine) erstellt, die FindView implementiert, um eine HttpException (404) auszulösen, wenn die angegebene nicht gefunden werden kann Aussicht. Ist das eine gute Praxis? Ich habe keine Ahnung. Aber wäre nicht überrascht, wenn es andere Implementierungen wie diese gibt. Da Sie das Innenleben der View Engine bei der Ausführung dieses Codes nicht kennen, möchten Sie möglicherweise einen catch {return false; } um diesen Welpen herum, nur um sicher zu gehen.
Brian Colavito

1
@SOReader, ich habe aber nicht getestet, IController controller = new HomeController (); und dann wird controller.ControllerContext das Ding geben, das Sie an findview-Methoden übergeben können.
Vishal Sharma

Danke für diese Antwort. Es hat mir bei einem anderen Problem geholfen. Ich musste überprüfen, ob meine Ansicht partiell ist oder nicht, und da der Name aller Partials jetzt mit Unterstreichung beginnt, kann ich mit meiner Lösung prüfen, ob "result.View! = Null"
Deise Vicentin

19

Wie wäre es, wenn Sie Folgendes ausprobieren, vorausgesetzt, Sie verwenden nur eine Ansichts-Engine:

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

sieht so aus, als ob dieser 3 Minuten vor der akzeptierten Antwort gepostet wurde und doch keine Liebe?! +1 von mir.
Trevor de Koekkoek

@ TrevorvorKoekkoek ... hmmm ... + 1
Vishal Sharma

8

Hier ist eine andere [nicht unbedingt empfohlene] Möglichkeit, dies zu tun

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

Dies dient zum Testen der Existenz einer Teilansicht in einer CSHTML-Datei. Es ist nicht wirklich eine Antwort auf diese Frage, aber eine andere Frage, die hier verlinkt ist, wurde falsch geschlossen, so dass ich meine Antwort hier
lasse

2
Dies war genau das Richtige für mich, da ich nach einer Möglichkeit suchte, eine kulturspezifische Teilansicht zu verwenden. Also habe ich dies nur mit dem kulturspezifischen Ansichtsnamen aufgerufen und dann die Standardansicht innerhalb des Catch aufgerufen. Und ich tat dies in einer Utility-Funktion, so dass ich keinen Zugriff auf die hatte, ControllerContextwie es die FindViewMethode benötigt.
Ehrfurcht

2

Wenn Sie dies auf der Grundlage der von Dave angegebenen Lösung für mehrere Controller-Aktionen wiederverwenden möchten, können Sie ein benutzerdefiniertes Ansichtsergebnis wie folgt definieren:

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

    ...
}

Geben Sie dann in Ihrer Aktion einfach eine Instanz Ihrer benutzerdefinierten Ansicht zurück:

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

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

Meine 2 Cent.


1

In asp.net core 2.x ist die ViewEnginesEigenschaft nicht mehr vorhanden, daher müssen wir den ICompositeViewEngineDienst verwenden. Dies ist eine Variante der akzeptierten Antwort mit Abhängigkeitsinjektion:

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

Für Neugierige: Die Basisschnittstelle IViewEngineist nicht als Dienst registriert, daher müssen wir ICompositeViewEnginestattdessen injizieren . Die FindView()Methode wird jedoch bereitgestellt, IViewEnginedamit die Mitgliedsvariable die Basisschnittstelle verwenden kann.


0

Hier erfahren Sie, wie Sie dies in Razor für Core 2.2 usw. tun. Beachten Sie, dass der Aufruf "GetView" und nicht "Find View" lautet.

@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
...
@if (Engine.GetView(scriptName, scriptName, isMainPage: false).Success) 
{
    @await Html.PartialAsync(scriptName)
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.