ビューは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);
 }

コピー/貼り付け拡張メソッドをお探しの方:

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
これはおそらくより良いです。ViewEnginesコレクション自体のFindViewメソッドが存在することは知りませんでした。
ランスハーパー、

1
しかし、ビューが他のコントローラーに存在するかどうかを確認するにはどうすればよいですか?
SOReader 2013年

余談ですが、私たちのエンジニアの1人(先に進んで)は、FindViewを実装して指定されたHttpException(404)をスローするようにFindViewを実装するカスタムビューエンジン(MultiTenantViewEngineと呼ばれる)を構築しました見る。これは良い習慣ですか?何も思いつきません。しかし、そのような他の実装があっても驚かないでしょう。このコードを実行しても、ビューエンジンの内部動作がわからないので、catch {return false; 安全のために、この子犬の周りに。
Brian Colavito 2013年

1
@SOReader、私はテスト済みですが、IController controller = new HomeController(); そして、controller.ControllerContextはfindviewメソッドに渡すことができるものを提供します。
Vishal Sharma

この回答をありがとう。それは別の問題で私を助けました。私のビューが部分的であるかどうかを確認する必要があり、私のすべての部分的な名前が下線で始まっているので、「result.View!= null」であるかどうかをチェックする私のソリューションで作業できます
Deise Vicentin

19

1つのビューエンジンのみを使用していると仮定して、次のようなことを試してみてはどうでしょう。

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

これは承認された回答の3分前に投稿されたようですが、まだ愛はありませんか?私からの+1。
Trevor de Koekkoek 2012

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

8

これは別の方法である[必ずしも推奨されない]方法

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

これは、.cshtmlファイル内の部分ビューの存在をテストするためのものです。これは実際にはこの質問に対する回答ではありませんが、ここにリンクする別の質問が誤って閉じられたため、ここに回答を残します
Simon_Weaver

2
カルチャー固有の部分ビューを使用する方法を探していたため、これは実際に使用するのに適していました。したがって、カルチャ固有のビュー名でこれを呼び出し、次にキャッチ内のデフォルトビューを呼び出しました。そして私はユーティリティ関数でこれを行っていたControllerContextので、FindViewメソッドのニーズに応じてにアクセスできませんでした。
2018年

2

これを複数のコントローラーアクションで再利用したい場合は、Daveによって提供されたソリューションに基づいて、次のようにカスタムビューの結果を定義できます。

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コア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 for Core 2.2などでこれを行う方法を次に示します。呼び出しは「Find View」ではなく「GetView」であることに注意してください。

@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
...
@if (Engine.GetView(scriptName, scriptName, isMainPage: false).Success) 
{
    @await Html.PartialAsync(scriptName)
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.