Jak ustawić właściwości ViewBag dla wszystkich widoków bez użycia klasy bazowej dla kontrolerów?

W przeszłości przyklejałem wspólne właściwości, takie jak obecny użytkownik, do ViewData/ViewBag w sposób globalny, ponieważ wszystkie kontrolery dziedziczą ze wspólnego kontrolera bazowego.

To pozwoliło mi użyć IoC na kontrolerze bazy, a nie tylko dotrzeć do global shared dla takich danych.

Zastanawiam się, czy istnieje alternatywny sposób wstawiania tego typu kodu do rurociągu MVC?

Author: Scott Weinstein, 2011-03-28

8 answers

Nie próbowałem przeze mnie, ale możesz spojrzeć na rejestrowanie widoków , a następnie ustawianie danych widoku podczas procesu aktywacji.

Ponieważ widoki są rejestrowane w locie, składnia rejestracji nie pomaga w połączeniu się ze zdarzeniem Activated, więc musisz skonfigurować je w Module:

class SetViewBagItemsModule : Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistration registration,
        IComponentRegistry registry)
    {
        if (typeof(WebViewPage).IsAssignableFrom(registration.Activator.LimitType))
        {
            registration.Activated += (s, e) => {
                ((WebViewPage)e.Instance).ViewBag.Global = "global";
            };
        }
    }
}

To może być jedna z tych sugestii typu"only tool' s a hammer " ode mnie; mogą być prostsze sposoby na uzyskanie tego.

Edit: Alternate, less podejście kodowe - wystarczy dołączyć do kontrolera

public class SetViewBagItemsModule: Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry cr,
                                                      IComponentRegistration reg)
    {
        Type limitType = reg.Activator.LimitType;
        if (typeof(Controller).IsAssignableFrom(limitType))
        {
            registration.Activated += (s, e) =>
            {
                dynamic viewBag = ((Controller)e.Instance).ViewBag;
                viewBag.Config = e.Context.Resolve<Config>();
                viewBag.Identity = e.Context.Resolve<IIdentity>();
            };
        }
    }
}

Edit 2: inne podejście, które działa bezpośrednio z kodu rejestracyjnego kontrolera:

builder.RegisterControllers(asm)
    .OnActivated(e => {
        dynamic viewBag = ((Controller)e.Instance).ViewBag;
        viewBag.Config = e.Context.Resolve<Config>();
        viewBag.Identity = e.Context.Resolve<IIdentity>();
    });
 23
Author: Nicholas Blumhardt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-20 00:57:52

Najlepszym sposobem jest użycie ActionFilterAttribute i zarejestrowanie własnej klasy w Twoim global. asax (Application_Start)

public class UserProfilePictureActionFilter : ActionFilterAttribute
{

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.Controller.ViewBag.IsAuthenticated = MembershipService.IsAuthenticated;
        filterContext.Controller.ViewBag.IsAdmin = MembershipService.IsAdmin;

        var userProfile = MembershipService.GetCurrentUserProfile();
        if (userProfile != null)
        {
            filterContext.Controller.ViewBag.Avatar = userProfile.Picture;
        }
    }

}

Zarejestruj swoją klasę niestandardową w global. asax (Application_Start)

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        GlobalFilters.Filters.Add(new UserProfilePictureActionFilter(), 0);

    }

Następnie można go używać we wszystkich widokach

@ViewBag.IsAdmin
@ViewBag.IsAuthenticated
@ViewBag.Avatar

Jest też inny sposób

Tworzenie metody rozszerzenia na HtmlHelper

[Extension()]
public string MyTest(System.Web.Mvc.HtmlHelper htmlHelper)
{
    return "This is a test";
}

Następnie można go używać we wszystkich widokach

@Html.MyTest()
 226
Author: Mirak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-21 05:42:10

Ponieważ właściwości ViewBag są z definicji powiązane z prezentacją widoku i dowolną logiką widoku świetlnego, która może być konieczna, utworzyłbym bazową stronę WebViewPage i ustawił właściwości przy inicjalizacji strony. Jest bardzo podobny do koncepcji kontrolera bazowego dla powtarzającej się logiki i wspólnej funkcjonalności, ale dla twoich poglądów: {]}

    public abstract class ApplicationViewPage<T> : WebViewPage<T>
    {
        protected override void InitializePage()
        {
            SetViewBagDefaultProperties();
            base.InitializePage();
        }

        private void SetViewBagDefaultProperties()
        {
            ViewBag.GlobalProperty = "MyValue";
        }
    }

A następnie w \Views\Web.config ustaw właściwość pageBaseType:

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="MyNamespace.ApplicationViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
 38
Author: Brandon Linton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 23:46:10

Brandon ' s post is right on the money. W rzeczywistości, chciałbym pójść o krok dalej i powiedzieć, że należy po prostu dodać swoje wspólne obiekty jako Właściwości{[2] } z podstawowej strony WebViewPage , więc nie trzeba rzucać elementów z worka widoków w każdym widoku. Wykonuję moją aktualną konfigurację użytkownika w ten sposób.

 17
Author: Michael Gagne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 04:29:23

Możesz użyć niestandardowego ActionResult:

public class  GlobalView : ActionResult 
{
    public override void ExecuteResult(ControllerContext context)
    {
        context.Controller.ViewData["Global"] = "global";
    }
}

Lub nawet ActionFilter:

public class  GlobalView : ActionFilterAttribute 
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()};

        base.OnActionExecuting(filterContext);
    }
}

Miał otwarty projekt MVC 2, ale obie techniki nadal mają zastosowanie z niewielkimi zmianami.

 9
Author: jfar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-28 00:42:37

Jeśli chcesz sprawdzić czas kompilacji i intellisense dla właściwości w Twoich widokach, to ViewBag nie jest dobrym rozwiązaniem.

Rozważ klasę BaseViewModel i niech inne modele widoku dziedziczą z tej klasy, np.:

Base ViewModel

public class BaseViewModel
{
    public bool IsAdmin { get; set; }

    public BaseViewModel(IUserService userService)
    {
        IsAdmin = userService.IsAdmin;
    }
}

View specific ViewModel

public class WidgetViewModel : BaseViewModel
{
    public string WidgetName { get; set;}
}

Teraz kod widoku może uzyskać dostęp do właściwości bezpośrednio w widoku

<p>Is Admin: @Model.IsAdmin</p>
 3
Author: Steven Quick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-22 02:35:25

Nie musisz zadzierać z akcjami ani zmieniać modelu, wystarczy użyć kontrolera bazowego i rzucić istniejący kontroler z widoku układu.

Utwórz kontroler bazowy z żądanymi wspólnymi danymi (tytuł/strona/lokalizacja itp.) i inicjalizacją akcji...

public abstract class _BaseController:Controller {
    public Int32 MyCommonValue { get; private set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

Upewnij się, że każdy kontroler używa kontrolera bazowego...

public class UserController:_BaseController {...

Wyrzuć istniejący kontroler bazowy z kontekstu widoku na stronie _Layout.cshml...

@{
    var myController = (_BaseController)ViewContext.Controller;
}

Teraz możesz odnosić się do wartości w swoim kontroler bazowy ze strony układu.

@myController.MyCommonValue
 2
Author: Carter Medlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-25 15:49:39

Uznałem następujące podejście za najbardziej efektywne i daje doskonałą kontrolę przy użyciu _ViewStart.plik chtml i instrukcje warunkowe w razie potrzeby:

_ViewStart :

@{
 Layout = "~/Views/Shared/_Layout.cshtml";

 var CurrentView = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();

 if (CurrentView == "ViewA" || CurrentView == "ViewB" || CurrentView == "ViewC")
    {
      PageData["Profile"] = db.GetUserAccessProfile();
    }
}

ViewA :

@{
   var UserProfile= PageData["Profile"] as List<string>;
 }

Uwaga :

PageData sprawdzi się doskonale w widokach, jednak w przypadku PartialView, będzie musiał zostać przekazany z widoku do dziecko częściowe.

 1
Author: usefulBee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 21:20:24