Куда должна идти логика мастер-страницы в MVC?

Я экспериментирую с MVC, и мой вопрос: где у меня была логика Page_Load на главных страницах с WebForms, куда она должна идти в MVC? Вот экономическое обоснование:

  • Разные заголовки хостов должны вызывать отображение разных заголовков страниц на (одной) главной странице сайта, то есть на всех страницах. Например, если заголовок хоста — hello.mydomain.com, заголовок страницы должен быть «Hello World» для всех страниц/представлений, а goodbye.mydomain.com — «Goodbye World» для всех страниц/представлений.
  • Если заголовок хоста отличается от всего, что есть в моем списке, независимо от того, где в приложении, он должен перенаправляться на /Error/NoHostHeader.

Раньше я помещал это в событие MasterPage Load(), и похоже, что в MVC я мог сделать это либо в каждом контроллере (не кажется правильным вызывать эту функцию в каждом контроллере), либо где-то в Global.asax (кажется слишком... глобальным?).

Редактировать: я успешно работал, используя метод Global.asax в сочетании с контроллером для фактической обработки данных. Единственная проблема на данный момент заключается в том, что вся информация о заголовке хоста находится в базе данных. Обычно я бы сохранял информацию о «арендаторе», если вы будете в переменной сеанса, и выполнял бы вызов БД только тогда, когда ее там нет; Есть лучший способ сделать это?


person Brandon    schedule 07.03.2009    source источник


Ответы (4)


По какой-то причине в MVC нет эквивалента 1: 1, давайте просто повторим, как думать об этом с точки зрения MVC:

Модель: «Страницы этого сайта всегда запрашиваются в определенном контексте, назовем его арендатором (или пользователем, темой или чем-то еще, что представляют ваши поддомены). Модель домена имеет свойство, представляющее арендатора текущий запрос».

Вид: "Визуализация заголовка страницы в зависимости от арендатора, установленного в модели".

Контроллер: «Установите арендатора в модели в зависимости от заголовка хоста».

Имейте в виду, что мы хотим избежать смешивания контроллера, представления и бизнес-логики. Наличие логики контроллера более чем в одном месте или в месте, которое не называется «контроллером», не является проблемой, пока оно остается разделенным.

А теперь хорошая вещь: Вы можете сделать этот «стиль MVC» даже с веб-формами, и решение по-прежнему работает с ASP.NET MVC!

У вас все еще есть жизненный цикл запроса (а не жизненный цикл страницы), поэтому вы можете реализовать собственный HttpModule, который содержит эту часть логики контроллера для всех запросов. Он обрабатывает событие BeginRequest, проверяет заголовок хоста и сохраняет арендатора во что-то вроде HttpContext.Current.Items["tenant"]. (Конечно, у вас может быть статическая типизированная оболочка для этой словарной статьи.)

Затем все ваши объекты модели (или базовый класс модели, или что-то еще, что подходит для вашего решения) могут получить доступ к HttpContext, чтобы предоставить доступ к этой информации следующим образом:

public string Tenant
{
    get { return HttpContext.Current.Items["tenant"]; }
}

Преимущества:

  • Вы разделили причину (заголовок хоста) и следствие (заголовок страницы рендеринга), улучшив удобство сопровождения и тестируемость.
  • Таким образом, вы можете легко добавить дополнительное поведение в свою доменную модель на основе этого состояния, например загрузку контента из базы данных в зависимости от текущего арендатора.
  • Вы можете легко сделать так, чтобы другие части представления зависели от арендатора, например, подключаемый файл CSS, изображение логотипа и т. д.
  • Позже вы можете изменить логику контроллера, чтобы установить арендатора в модели не только на основе поддомена, но, возможно, на основе файла cookie, реферера, условия поиска, языка пользовательского агента или чего-то еще, о чем вы можете подумать, без изменения какой-либо из них. Ваш код в зависимости от модели.

Обновите ваше редактирование: мне не нравится идея сохранения состояния в сеансе, особенно если ваш файл cookie сеанса может применяться не только к каждому поддомену, но и ко всем доменам. В этом случае вы можете показывать противоречивый контент, если пользователи ранее посещали другой субдомен. Вероятно, информация в базе данных, которая сопоставляет заголовки хостов с арендаторами, не будет меняться очень часто, поэтому вы можете кэшировать ее и не искать базу данных для каждого запроса.

person realMarkusSchmidt    schedule 07.03.2009

Вы можете создать базовый контроллер, который предоставит правильные ViewData для представления главной страницы MVC, а затем получить каждый из ваших фактических контроллеров от этого. Если вы поместите логику в метод ActionExecuting, вы сможете сгенерировать исключение или перенаправить на страницу ошибки, если это необходимо.

person tvanfosson    schedule 07.03.2009

Вы слишком думаете о "WebForms" и недостаточно MVC. Главная страница — это всего лишь оболочка вашего представления, и она должна содержать только HTML-код макета. Вы можете отправлять вещи своему мастеру, но это дорога в один конец, и вы должны стремиться к агностическим взглядам. Итог: забудьте о событиях, которые были у WebForms, поскольку они не будут использоваться здесь.

Поскольку вы имеете дело с заголовками Host, я полагаю, вы могли бы поместить его в Global.asax... отлично, теперь я запутался: P

Украденный код с http://forums.asp.net/t/1226272.aspx

protected void Application_BeginRequest(object sender, EventArgs e)
        {
            string host = string.Empty;

            if (this.Request.ServerVariables["HTTP_HOST"] == this.Request.Url.DnsSafeHost)
            {
                host = this.Request.Url.DnsSafeHost;
            }
            else
            {
                Regex regex = new Regex("http://[^/]*.host/([^/]*)(/.*)");
                Match match = regex.Match(this.Request.Url.AbsoluteUri);

                if (match.Success)
                {
                    host = match.Groups[1].Value;
                    Context.RewritePath(match.Groups[2].Value);
                }
            }

            // Match the host with the portal in the database
            ...
        } 
person rball    schedule 07.03.2009
comment
Итак, объединяя ответы, разумно ли делать это в Global.asax и назначать соответствующую информацию в сеансе, а затем получать доступ к этим объектам сеанса через базовый контроллер? - person Brandon; 07.03.2009

То, что вам нужно, находится здесь http://www.asp.net/mvc/tutorials/passing-data-to-view-master-pages-cs

person DmitryBoyko    schedule 17.08.2011