Доступ к переменным модели во всем проекте MVC5 Razor — используйте Basecontroller для установки BaseViewModel и используйте его в макете.

Я немного новичок в MVC5, и я пытался использовать метод, показанный в следующем ответе, для установки глобальных переменных во всем проекте: Razor MVC, куда поместить глобальные переменные, доступные на главной странице, partiview и представлении?

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

Проблема, с которой я столкнулся, заключается в следующем: я создал базовый контроллер, который наследуется всеми другими контроллерами;

public class BaseController : Controller
    {
        protected ViewModelBase ModelBase { get; private set; }

        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.Result is ViewResultBase)//Gets ViewResult and PartialViewResult
            {

                object viewModel = ((ViewResultBase)filterContext.Result).Model;

                if (viewModel != null && viewModel is ViewModelBase)
                {
                    ViewModelBase baseVM = viewModel as ViewModelBase;

                    ALM_APP objALM_APP = new ALM_APP();
                    objALM_APP = DalContext.getAppInformation();


                    baseVM.ApplicationName = objALM_APP.ApplicationName;
                    baseVM.AppVersion = objALM_APP.Version;
                }
            }

            base.OnActionExecuted(filterContext);//this is important!
        }  
    }

Затем я создал класс ViewModelBase, строго типизированный с помощью _Layout.cshtml.

namespace TestProject.Models
{
    public abstract class ViewModelBase
    {
        public string ApplicationName { get; set; }
        public string AppVersion { get; set; }
        public string Name { get; set; }
        public string Domain { get; set; }
        public string UserID { get; set; }
        public string Groups { get; set; }
        public string LoginTime { get; set; }

        public Dictionary<string, string> MenuList { get; set; }
    }
}

public class CommonViewModel : ViewModelBase
{
}

В файле _Layout.cshtml я вызываю viewmodelbase следующим образом:

@model TestProject.Models.ViewModelBase

а затем я использовал атрибут модели следующим образом в макете:

@Model.ApplicationName

В этом случае viewModel всегда имеет значение null в BaseController, когда filterContext.Result приводится к ViewResultBase:

object viewModel = ((ViewResultBase)filterContext.Result).Model;

Из-за чего @Model.ApplicationName выдает исключение ссылки Null следующим образом:

"В App_Web_3t5b2o3k.dll произошло исключение типа "System.NullReferenceException", но оно не было обработано в пользовательском коде"

Я также попытался создать новый объект класса CommonViewModel в базовом контроллере и установить в нем атрибуты модели, но безуспешно.

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


person Ali Haider    schedule 07.12.2014    source источник
comment
Чтобы filterContext.Result не был нулевым... в вашем действии вам нужно передать модель в представление. Фильтр запускается после завершения действия и до отображения представления. Может быть, вы можете поделиться действием, которое вы используете.   -  person Romias    schedule 07.12.2014
comment
@Romias, макет (который использует viewmodelbase) и соответствующее представление вызываются другим контроллером, в котором вызывается следующий результат действия: [HttpPost] public ActionResult Index(string Username, string Password) { return View("~/Views/Dashboard/Dashboard.cshtml"); }   -  person Ali Haider    schedule 07.12.2014
comment
Макет со строкой @Model и действиями, не передающими модель, с моей точки зрения, неверен. Вы можете попробовать поместить эту информацию в ViewBag... чтобы не полагаться на модели. Или попробуйте передать модель в действии Index в качестве второго параметра вызова View().   -  person Romias    schedule 07.12.2014
comment
Можете ли вы сказать мне, какие изменения мне нужно внести, если я хочу продолжать использовать @Model в макете и задавать необходимую информацию в базовом контроллере?   -  person Ali Haider    schedule 07.12.2014
comment
@Romias Вроде сработало. Я попытался передать модель следующим образом: return View("~/Views/Dashboard/Dashboard.cshtml", new CommonViewModel()); Теперь мне нужно проверить, является ли объект CommonViewModel постоянным для одного сеанса. Большое спасибо за наводку! оценил.   -  person Ali Haider    schedule 07.12.2014
comment
Даже то, как вы возвращаете представление из действия Index без соответствующей модели, должно по-прежнему вызывать исключение нулевой ссылки в приложении MVC по умолчанию, не имеющем BaseController и т. д. ниже.   -  person Siva Gopal    schedule 07.12.2014
comment
Этот подход, который вы используете, заставит вас отправлять в каждый просмотр модели. Вот почему я предложил перейти на подход ViewBag. Я имею в виду, поместите нужные вам переменные во ViewBag, а не в модель Base.   -  person Romias    schedule 07.12.2014
comment
@SivaGopal Спасибо за внимание. Постараюсь в следующий раз так не делать. Все еще разбираюсь с MVC :)   -  person Ali Haider    schedule 07.12.2014
comment
@Romias Если я помещу переменные в ViewBag и изменю представления, будут ли переменные ViewBag по-прежнему сохраняться в макете? Сначала я пытался использовать ViewBag, но терял все значения ViewBag в файле макета при переходе на другой вид.   -  person Ali Haider    schedule 07.12.2014
comment
Проверьте мой ответ ниже...   -  person Romias    schedule 07.12.2014


Ответы (1)


Я использую тот же подход, что и вы, в представлениях CRUD, чтобы перейти к флагам представления с разрешением пользователя (CanCreate, CanUpdate и т. д.). Но в данном случае я знаю, когда это сделать. В вашем случае это широкое приложение.

Вы можете попробовать это:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var controller = filterContext.Controller as BaseController;

    // IController is not necessarily a Controller
    if (controller != null)
    {
        ALM_APP objALM_APP = new ALM_APP();
        objALM_APP = DalContext.getAppInformation();

        controller.ViewBag.ApplicationName = objALM_APP.ApplicationName;
        controller.ViewBag.AppVersion = objALM_APP.Version;

     }
}

Таким образом, при каждом новом выполняемом действии переменные ViewBag перезагружаются. Если вы вызываете PartialView, макет не выполняется... так что нет проблем (переменные ViewBag перезагружаются, но не будут использоваться макетом).

person Romias    schedule 07.12.2014
comment
Я попробую с несколькими представлениями и свяжусь с вами. Спасибо! - person Ali Haider; 07.12.2014