Как установить свойства ViewBag для всех представлений без использования базового classа для controllerов?

Раньше я придерживался общих свойств, таких как текущий пользователь, в ViewData / ViewBag глобально, за счет того, что все controllerы наследуются от общего базового controllerа.

Это позволило мне использовать IoC на базовом controllerе, а не просто использовать глобальные общие для таких данных.

Мне интересно, есть ли альтернативный способ вставки такого кода в конвейер MVC?

    Не пробовал я, но вы можете посмотреть на регистрацию своих представлений и затем установить данные просмотра во время процесса активации.

    Поскольку представления регистрируются «на лету», синтаксис регистрации не помогает вам подключиться к Activated событию, поэтому вам нужно настроить его в 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"; }; } } } 

    Это может быть одним из тех предложений «только инструмент в молотке» от меня; там могут быть более простые способы с поддержкой MVC.

    Изменить: Альтернативный, меньше кода – просто присоединитесь к controllerу

     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(); viewBag.Identity = e.Context.Resolve(); }; } } } 

    Изменить 2: Другой подход, который работает непосредственно из регистрационного кода controllerа:

     builder.RegisterControllers(asm) .OnActivated(e => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.Config = e.Context.Resolve(); viewBag.Identity = e.Context.Resolve(); }); 

    Лучший способ – использовать ActionFilterAttribute и зарегистрировать свой собственный class в вашем глобальном. 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; } } } 

    зарегистрируйте свой собственный class в своем глобальном. asax (Application_Start)

     protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalFilters.Filters.Add(new UserProfilePictureActionFilter(), 0); } 

    Затем вы можете использовать его во всех представлениях

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

    Также есть другой способ

    Создание метода расширения на HtmlHelper

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

    Затем вы можете использовать его во всех представлениях

     @Html.MyTest() 

    Поскольку свойства ViewBag по определению привязаны к представлению представления и любой логике световых представлений, которые могут быть необходимы, я бы создал базовый WebViewPage и установил свойства при инициализации страницы. Это очень похоже на концепцию базового controllerа для повторной логики и общей функциональности, но для ваших просмотров:

      public abstract class ApplicationViewPage : WebViewPage { protected override void InitializePage() { SetViewBagDefaultProperties(); base.InitializePage(); } private void SetViewBagDefaultProperties() { ViewBag.GlobalProperty = "MyValue"; } } 

    А затем в \Views\Web.config задайте свойство pageBaseType :

                

    Сообщение Брэндона прямо на деньги. На самом деле, я бы сделал еще один шаг и сказал, что вы должны просто добавлять свои общие объекты в качестве свойств базового WebViewPage, поэтому вам не нужно бросать элементы из ViewBag в каждый вид View. Таким образом, я создаю свою настройку CurrentUser.

    Вы можете использовать пользовательский ActionResult:

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

    Или даже ActionFilter:

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

    Если проект MVC 2 будет открыт, но оба метода будут применяться с незначительными изменениями.

    Если вы хотите проверять время компиляции и intellisense для свойств в ваших представлениях, то ViewBag не подходит.

    Рассмотрим class BaseViewModel и наследуйте ваши другие модели представления от этого classа, например:

    Базовый ViewModel

     public class BaseViewModel { public bool IsAdmin { get; set; } public BaseViewModel(IUserService userService) { IsAdmin = userService.IsAdmin; } } 

    Просмотреть конкретную ViewModel

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

    Теперь код просмотра может получить доступ к свойству непосредственно в представлении

     

    Is Admin: @Model.IsAdmin

    Вам не нужно возиться с действиями или изменять модель, просто используйте базовый controller и отбросьте существующего controllerа из контекстного представления layout.

    Создайте базовый controller с требуемыми общими данными (название / страница / местоположение и т. Д.) И инициализацию действий …

     public abstract class _BaseController:Controller { public Int32 MyCommonValue { get; private set; } protected override void OnActionExecuting(ActionExecutingContext filterContext) { MyCommonValue = 12345; base.OnActionExecuting(filterContext); } } 

    Убедитесь, что каждый controller использует базовый controller …

     public class UserController:_BaseController {... 

    _Layout.cshml существующий базовый controller из контекста представления на страницу _Layout.cshml

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

    Теперь вы можете ссылаться на значения в своем базовом controllerе со страницы макета.

     @myController.MyCommonValue 

    Я нашел, что следующий подход является наиболее эффективным и дает отличный контроль, используя файлы _ViewStart.chtml и условные операторы, когда это необходимо:

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

    Примечание .

    PageData отлично работает в Views; однако в случае PartialView он должен быть передан из представления в дочерний Partial.

    Давайте будем гением компьютера.