web-dev-qa-db-ja.com

ASP.NETMVCコアコントローラーのコンストラクターでViewBagプロパティを設定します

私のテーマには、ある種のパンくずリストがあります。コントローラは常にカテゴリです。繰り返しになるのを避けるために、次のようなすべてのアクションについて、コントローラーのコンストラクターに設定します。

class MyController:Controller{
    public MyController() {
        ViewBag.BreadcrumbCategory = "MyCategory";
    }
}

レイアウトビューでViewBag.BreadcrumbCategoryにアクセスすると、nullになります。アクションでは、それは機能します:

class MyController:Controller{
    public IActionResult DoSomething() {
        ViewBag.BreadcrumbCategory = "MyCategory";
    }
}

コンストラクターでViewBagプロパティを設定できないのではないかと思いますか?この作業を行うすべてのアクションで関数が呼び出されるのは煩わしく、良い習慣ではありません。 別の質問 では、コンストラクターの使用は受け入れられた答えでしたが、私が言ったように、少なくともASP.NETCoreではこれは機能しません。

12
Lion

GitHubの問題 があり、これは仕様によるものであると述べられています。リンクした答えは、古いレガシーASP.NETスタックであるASP.NETMVC3に関するものです。

ASP.NET Coreはゼロから作成され、さまざまな概念を使用して、移植性(複数のプラットフォーム)と、依存性注入の組み込みサポートなどのパフォーマンスと最新のプラクティスの両方を考慮して設計されています。

最後の1つでは、コンストラクターでViewBagを設定できません。これは、渡す必要がないことに気付いたかもしれないので、Constructor基本クラスの特定のプロパティをプロパティインジェクションを介して注入する必要があるためです。派生コントローラーのこれらの依存関係。

つまり、Controllerのコンストラクターが呼び出されたときに、HttpContextControllerContextなどのプロパティは設定されません。それらは設定されるだけですafterコンストラクターが呼び出され、このオブジェクトへの有効なインスタンス/参照があります。

また、GitHubの問題で指摘されているように、これは仕様によるものであるため、修正されません。

ご覧のとおり、 ここ 、ViewBagはViewDataに依存しており、コントローラーの初期化後にViewDataが設定されます。 ViewBag.Something = "something"を呼び出すと、DynamicViewDataクラスの新しいインスタンスが作成され、コンストラクターが初期化された後にインスタンスに置き換えられます。

@SLaksが指摘しているように、コントローラーごとに構成するアクションフィルターを使用できます。

次の例では、alwaysコントローラーをController基本クラスから派生させることを前提としています。

public class BreadCrumbAttribute : IActionFilter
{
    private readonly string _name;

    public BreadCrumbAttribute(string name)
    {
        _name = name;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        base.OnActionExecuting(context);

        var controller = context.Controller as Controller;
        if (controller != null) 
        {
            controller.ViewBag.BreadcrumbCategory = _name;
        }
    }
}

これで、コントローラーをそれで飾ることができるはずです。

[BreadCrumb("MyCategory")]
class MyController:Controller
{
}
19
Tseng

私は同じ問題を抱えており、コントローラーのOnActionExecutedメソッドをオーバーライドして解決します。

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        base.OnActionExecuted(context);
        ViewBag.Module = "Production";
    }
5
FcoJavier99