Пользователь
0,0
рейтинг
9 апреля 2013 в 22:56

Разработка → ASP.NET MVC Урок 1. Начало tutorial

ASP*, .NET*
Цель урока: Изучить Global.asax и поведение запуска веб-приложения, обработки веб-запроса. Изучение Nuget и Подключение протоколирования.

Начало

Создадим приложение ASP.NET MVC 4 Web Application «Lesson1» (рис 1.):







Не будем запускать приложение, а сразу установим (если до этого не сделали) NuGet расширение:



NuGet Package Manager – это расширение для Visual Studio, которое позволяет добавлять в существующие проекты модули, которые значительно упрощают работу. При создании «Basic» asp.net mvc4 приложения в само приложение было добавлено изначально много модулей. Их список мы можем найти, кликнув в Manage NuGet Packages… в контекстном меню проекта:





О них по порядку:

  • Entity Framework – обеспечивает работу с БД
  • jQuery (+ jQuery UI, jQuery Validation) – популярный javascript framework (о нем еще пойдет речь позже).
  • Json.NET – классы для работы с json-форматом данных.
  • knockoutjs – javascript библиотека для работы с Model View ViewModel архитектурой. (http://knockoutjs.com/)
  • Microsoft.Net Framework 4 Http Client Libraries – программный интерфейс для работы с HttpContext-ом.
  • Microsoft ASP.NET MVC 4 – собственно, классы паттерна проектирования MVC (то, что есть предметом изучения)
  • Microsoft ASP.NET Razor 2 – view-движок. Есть еще ASPX и Spark – мы о них также будем говорить позже
  • Microsoft ASP.NET Universal Providers Core Libraries (Microsoft ASP.NET Universal Providers for LocalDB) – предоставляет инструменты для поддержки всех SQL Server 2005 (и более поздних) и для SQL Azure.
  • Microsoft ASP.NET Web API (Microsoft ASP.NET Web API Client Libraries, Microsoft ASP.NET Web API Core Libraries, Microsoft ASP.NET Web API Web Host) – для создания REST приложений, работа с XML, JSON и так далее
  • Microsoft ASP.NET Web Optimization Framework – оптимизирует передачу данных, например, минимизирует js-код
  • Microsoft ASP.NET WebPages 2 – набор классов для работы во View
  • Microsoft jQuery Unobtrusive Ajax (Microsoft jQuery Unobtrusive Validation) – jQuery библиотека для поддержки ajax/валидации
  • Microsoft.Web.Infrastructure – позволяет динамически регистрировать HTTP-модули во время выполнения
  • Modernizr – js-библиотека, которая позволяет использовать html5 и css3 в старых браузерах
  • WebGrease – позволяет минифицировать html, css, js.

Теперь, когда мы примерно прикинули, из чего состоит наше приложение, давайте запустим его.
Для этого необходимо создать HomeController:





Для метода (действия) Index добавим View и выберем ~Views/Shared/_Layout.cshtml в качестве layout (типа master page):





Собственно, можем запускать.
Всё что мы увидим – это:



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

Global.asax

А сейчас обратим внимание на файл Global.asax:

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

Класс MvcApplication наследует HttpApplication и содержит инструкции для инициализации приложения. Есть еще несколько событий, на которые можно добавить код. Рассмотрим их:

  • public void Init() – приложение инициализируется или при первом вызове. Оно вызывается для всех экземпляров объекта HttpApplication.
  • public void Dispose() – вызывается непосредственно перед уничтожением объекта HttpApplication. Это идеальное место для очистки ранее используемых ресурсов.
  • Application_Error – наступает, когда необработанное исключение случается в приложении.
  • Application_Start – наступает, когда первый экземпляр HttpApplication создается. Это позволяет создавать объекты доступные для всех экземпляров класса HttpApplication.
  • Application_End – наступает, когда все созданные ранее экземпляры класса HttpApplication уничтожены. Это событие наступает только однажды в течение всего времени жизни приложения.
  • Application_BeginRequest – наступает, когда приложение получает запрос. Первый раз это событие наступает для запроса страницы, когда пользователь вводит URL.
  • Application_EndRequest – Последнее событие, которое наступает для запроса к приложению.
  • Application_PreRequestHandlerExecute – наступает прежде, чем ASP.NET запустит обработчик страницы или веб-службу.
  • Application_PostRequestHandlerExecute – наступает, когда ASP.NET заканчивает обработку.
  • Applcation_PreSendRequestHeaders – наступает перед тем, как ASP.NET посылает клиенту (браузеру) HTTP заголовки.
  • Application_PreSendContent – наступает перед тем, как ASP.NET посылает клиенту (браузеру) HTTP содержимое.
  • Application_AcquireRequestState – наступает, когда ASP.NET получает текущее состояние (состояние сессии), связанное с текущим запросом.
  • Application_ReleaseRequestState – наступает, когда ASP.NET завершает исполнение всех событий. В результате все модули сохраняют свои текущие состояния.
  • Application_ResolveRequestCache – наступает, когда ASP.NET выполняет запрос авторизации. Это позволяет модулям кеширования обработать запрос и обслужить из кэша, минуя обработчик выполнения.
  • Application_UpdateRequestCache – наступает, когда ASP.NET завершает выполнение обработчика, чтобы модули кеширования могли сохранить результат для использования в последующих ответах.
  • Application_AuthenticateRequest – наступает, когда модуль идентификации устанавливает личность текущего пользователя как действительную. В текущий момент, учетные данные пользователя уже проверены.
  • Application_AuthorizeRequest – наступает, когда модуль авторизации подтверждает, что пользователь может иметь доступ к ресурсам.
  • Session_Start – наступает, когда новый пользователь заходит на сайт.
  • Session_End – наступает, когда истекает время сессии пользователя, или он покидает сайт.

Хорошо. Теперь, чтобы воочию убедимся, что всё именно так и происходит, добавим протоколирование и сделаем это через добавление NLog модуля в NuGet.

Package Manager Console

В NuGet есть консоль для выполнения команд по установке\удалению\поиску модулей, и других вещей, типа скаффолдинга.
Для вывода всех установленных модулей пишем:
Get-Package

Для получения всех доступных к установке модулей:
Get-Package –ListAvailable

Для получения всех доступных модулей с названием NLog
Get-Package -ListAvailable -Filter NLog

Или
Get-Package -ListAvailable  | where {$_.Id -match "NLog"} (это дольше)

Для установки модуля NLog необходимо вначале выбрать проект (если их в солюшене больше одного) и ввести команду:
Install-Package NLog




Файлы копируются в проект, добавляются ссылки на сборки и web.config может быть обновлен.
Для удаления из проекта модуля необходимо, чтобы он не был связан с другими модулями. Удаляем так:

Uninstall-Package NLog

NLog

После установки пользуемся документацией на NLog (https://github.com/nlog/nlog/wiki/Tutorial) и добавляем в Web.config:
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />


<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
      <target name="logfile" xsi:type="File" fileName="C://file.txt" />
    </targets>
    <rules>
      <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>
  </nlog>

Мы ее потом исправим. Добавим в код (Global.asax.cs):
   public class MvcApplication : NinjectHttpApplication
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

и
protected void Application_Start()
        {
            logger.Info("Application Start");

            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        public void Init()
        {
            logger.Info("Application Init");
        }

        public void Dispose()
        {
            logger.Info("Application Dispose");
        }

        protected void Application_Error()
        {
            logger.Info("Application Error");
        }


        protected void Application_End()
        {
            logger.Info("Application End");
        }

Запустим и завершим приложение (Stop). Откроем файл C://file.txt. Мы увидим, какие события происходили.

2012-09-18 19:18:11.5668|INFO|Lesson1.MvcApplication|Application Start
2012-09-18 19:18:13.7319|INFO|Lesson1.MvcApplication|Application Init
2012-09-18 19:18:14.2709|INFO|Lesson1.MvcApplication|Application Init
2012-09-18 19:18:14.2769|INFO|Lesson1.MvcApplication|Application BeginRequest
2012-09-18 19:18:14.3579|INFO|Lesson1.MvcApplication|Application AuthenticateRequest
2012-09-18 19:18:14.3579|INFO|Lesson1.MvcApplication|Application AuthorizeRequest
2012-09-18 19:18:14.3579|INFO|Lesson1.MvcApplication|Application ResolveRequestCache
2012-09-18 19:18:14.3989|INFO|Lesson1.MvcApplication|Session Start
2012-09-18 19:18:14.3989|INFO|Lesson1.MvcApplication|Application AcquireRequestState
2012-09-18 19:18:14.3989|INFO|Lesson1.MvcApplication|Application PreRequestHandlerExecute
2012-09-18 19:18:15.9580|INFO|Lesson1.MvcApplication|Application PreRequestHandlerExecute
2012-09-18 19:18:15.9580|INFO|Lesson1.MvcApplication|Application ReleaseRequestState
2012-09-18 19:18:15.9580|INFO|Lesson1.MvcApplication|Application UpdateRequestCache
2012-09-18 19:18:15.9580|INFO|Lesson1.MvcApplication|Application EndRequest
2012-09-18 19:18:15.9580|INFO|Lesson1.MvcApplication|Application PreSendRequestHeaders
2012-09-18 19:18:35.6061|INFO|Lesson1.MvcApplication|Session End
2012-09-18 19:18:38.0833|INFO|Lesson1.MvcApplication|Application Dispose
2012-09-18 19:18:38.0833|INFO|Lesson1.MvcApplication|Application End
2012-09-18 19:18:39.1383|INFO|Lesson1.MvcApplication|Application Dispose

В Application_Start выполняется регистрация:
  • Area (области),
  • Filter (фильтры),
  • Bundle (комплекты),
  • Route (маршруты).

Подробности по инициализации Filter, Вundle и Route находятся в папке App_Start.

WebActivator

WebActivator – это модуль, который позволяет запустить код до самого первого старта App_Start. Это может быть необходимо для того, чтобы, к примеру, создать тестовую БД перед запуском.
Установим:

Install-Package WebActivatorEx


Добавим класс в App_Start папку:

[assembly: WebActivator.PreApplicationStartMethod(typeof(PreStartApp), "Start")]
namespace Lesson1.App_Start
{
    public static class PreStartApp
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// Метод запускается один раз перед стартом приложения        
        /// </summary>
        public static void Start()
        {
            logger.Info("Application PreStart");
        }
    }
}

В файле логов увидим, что строка Application PreStart исполняется раньше Application Start:
2012-09-19 10:29:01.3950|INFO|Lesson1.App_Start.PreStartApp|Application PreStart
2012-09-19 10:29:01.6290|INFO|Lesson1.MvcApplication|Application Start

Создадим четыре файла отдельно для trace (трассировки), debug (отладки), info (информации), error (ошибки). Определим место записи: /Contents/logs/[текущая дата] Перепишем конфигурацию:
<nlog autoReload="true" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variable name="logDirectory" value="${basedir}/Content/logs/${shortdate}" />
    <targets>
      <target name="fileLogTrace" xsi:type="File" fileName="${logDirectory}/trace.txt" />
      <target name="fileLogDebug" xsi:type="File" fileName="${logDirectory}/debug.txt" />
      <target name="fileLogInfo" xsi:type="File" fileName="${logDirectory}/info.txt" />
      <target name="fileLogErrors" xsi:type="File" fileName="${logDirectory}/errors.txt" />
    </targets>
    <rules>
      <logger name="*" level="Trace" writeTo="fileLogTrace" />
      <logger name="*" level="Debug" writeTo="fileLogDebug" />
      <logger name="*" level="Info" writeTo="fileLogInfo" />
      <logger name="*" minlevel="Warn" writeTo="fileLogErrors" />
    </rules>
  </nlog>


Log2Console

Для NLog есть еще классная программа Log2Console, которая позволяет получать логи прямо в окне программы.



Запускаем программу и настраиваем приемщик:



В Web.config пишем:

<target name="TcpOutlet" xsi:type="NLogViewer" address="tcp4://localhost:4505"/>

Обращаю внимание, что писать надо address=”tcp4://…”, а не address=”tcp://…”

Все исходники находятся по адресу https://bitbucket.org/chernikov/lessons
chernikov @chernikov
карма
178,9
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (18)

  • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Зачем же все сразу вываливать. Лучше постепенно, раз в неделю, например или через день. Есть возможность попробовать, обсудить.

    А представьте себе человека, который asp.net совсем не интересуется, а у него вся лента им забита.
    • +2
      99.9% уроков, которые выкладывались по хабре, редко состояли больше, чем из одной части, и крайне редко — больше, чем из трех частей. По каким-то причинам обычно авторы не выкладывают продолжение курса обучения дальше «Часть 1», а тут сразу все. Я считаю, автор сделал все правильно, за что ему большое спасибо!
      • +2
        Я не против того, что частей много. Это хорошо. Я против того, чтобы публиковать все одновременно, забивая ленту. Именно потому, что десяток, ладно бы три.
  • 0
    NLog очень медленный. Под нагрузкой логгировать не позволит.
    Я делал свой логгер, работает быстрее чем log4net в 6-8 раз. NLog же еще на порядок(раз в 10) медленнее, чем log4net.
    • 0
      Скажите, а есть какие-нибудь сравнительные тесты. Я сейчас выбираю логгер, хотелось бы выбрать достаточно быстрый. Неужели придется писать свой?
      • 0
        Я писал свой логгер. habrahabr.ru/post/151641/
        Правда я допустил ошибку, надо было log4net с NLog сравнить еще до начала.

        Пропорции у времени выполнения примерно такие: 3 потока бросают по 200 тысяч сообщений каждый. мой логгер отрабатывает меньше чем за полсекунды, log4net 2-3 секунды, у NLog уже время в минутах измеряется. Пишутся одинаковые лог-файлы при этом.
        Результаты различаются на разных ОС, на разных процессорах(AMD, Intel), ну и варьируются в зависимости от количества потоков.

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

        Еще один плюс — и NLog и log4net делают практически все действия в вызывающем потоке, мой же логгер сразу кладет сообщение в ConcurrentQueue, все остальное делается в выделенном потоке. Для веб приложений это важно, поскольку уменьшает время обработки каждого запроса. То есть оно работает как с логгером, так и без логгера практически одинаково, что позволяет включать логи под нагрузкой и не стесняться при этом в удобрении кода логами.
        • 0
          Спасибо, буду смотреть.
        • 0
          А AsyncWrapper не пробовали?
  • 0
    Хотел попробовать asp.net и не решался, теперь буду дерзать.
  • 0
    Не хватает главы про deployment
  • 0
    Столкнулся с проблемой при установке WebActivator в Package Manager Console.

    image

    Visual Studio 2012 Express for Web.
    В чем может быть проблема?
    • 0
      Обновилась версия. Для установки пишите: Install-Package WebActivatorEx
  • +1
    Идея туториала хорошая, но есть моменты совершенно не очевидные.
    Например:
    1. Вы пишете:
    «После установки пользуемся документацией на NLog и добавляем в Web.config:».
    Куда бы в Web.Config я не добавлял этот кусок XML — IIS падает при запуске проекта. Долго мучался, пока не нашел на сайте что можно создать файл NLog.config и положить это все туда.

    2.
    «Добавим в код (Global.asax.cs):»
    тут вы во всех методах используете объект logger, про инициализацию его не сказано ничего, хотя следовало бы, т.к. очевидный путь инициализации, такой как Logger logger = new Logger(); недоступен. Как пользователь должен догадатся, что надо вызвать LogManager.GetCurrentClassLogger(); для инициализации?
    • 0
      Да, я согласен, что не очевидно. Для этого я добавил исходники, т.е. если пробовать их запускать, и сравнивать, то можно найти как это работает. По поводу второго — там дальше есть по тексту инициализация, возможно в первых редакциях этот абзац был выше, а потом я не уследил.

      Я исправил текст, чтобы это стало очевидно. Если в дальнейшем будут еще какие-то подобные случаи, то сообщите мне, я их буду править.
      • 0
        Раз речь зашла про логи, хотел бы добавить, что хранение логов в формате .txt не самая лучшая идея.

        Так как по умолчанию сервер IIS (при настройках отдачи статического содержимого) вернет ваши логи расположенные в каталоге приложения пытливому пользователю или поисковой машине. А на сервере хостера, никто в директорию c:\ сохранить не даст.

        Как решение, нужно использовать специальные системные каталоги или настроить сервер для блокировки отдачи соответствующего содержимого — файлы с расширением *.log относятся как раз к таким.
  • 0
    Это конечно доволоно странно, но после полутора часов постоянных экспериментов с конфигурационным файлом, установкой-удалением кучи LogViewer-ов у меня так и не заработал NLogViewer таргет. Т.е. я не смог увидеть «вживую» обновление файла лога через Log2Console, как у вас на красивом скриншоте (файловый таргет работает прекрасно). Делаю все ДОСКОНАЛЬНО как у вас. Файрвол отключал — не помогло. Пробовал указать вместо tcp4 просто tcp. Пробовал поставить тип Network вместо NLogViewer. Что может быть не так?

       <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <variable name="logDirectory" value="C:/Temp/Content/Logs/${shortdate}" />
            <targets>
                <target name="logFile" xsi:type="File" fileName="${logDirectory}/file.log" />
                <target name="tcpOutlet" xsi:type="NLogViewer" address="tcp4://localhost:4505"/>
            </targets>
            <rules>
                <logger name="*" minlevel="Info" writeTo="logFile,tcpOutlet" />
            </rules>
        </nlog>
    
  • 0
    Какое-то странное название класса-родителя (NinjectHttpApplication):

       public class MvcApplication : NinjectHttpApplication
        {
            private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    

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