вторник, 2 января 2018 г.

Развертывание Asp Net Core на IIS

Как развертывается Asp Net Core

Asp Net Core - это как Проктор энд Гэмбл т.е. два в одном флаконе: фрэймворк и Web-сервер, а само веб приложение  имеет вид консольного приложения, развертываемого через IWebHost с предварительной настройкой сервисов, миддлваре и т.п. Все относительно просто в случаях, когда разработка идет на машине с установленной Visual Studio. Для запуска веб приложений в Asp Net Core используется веб-сервер Kestrel. И, казалось, бы нет никаких сложностей для запуска веб-приложения на IIS. Но, столкнувшись с такой задачей я набил кучу шишек, о чем и хочу рассказать в этом посте.

Создание Net Core пула и подключение модуля AspNetCore

Как известно в IIS имеются пулы, которые, используются во-первых, для изоляции одних приложений от других, а, во-вторых, для простоты настройки однотипных приложений. И если запустить настройку пула приложения на IIS, то можно увидеть, что Net Core в нем напрочь отсутствует (предварительно я установил Net Core Sdk), всего 3 варианта таргет фрэймворка для пула: 2.0, 4.0 и неуправляемый код. Для Asp Net Core нужно выбрать последний. 

Но и это еще не все: выше я писал, что Asp Net Core веб-приложение развертывается на веб-сервере Kestrel, а как же тогда подключить IIS, дело в том, что IIS подключается как прокси: все запросы, пришедшие на HTTP порт приложения, развернутого на IIS, маршрутизируются через модуль AspNetCore в Kestrel, обрабатываются приложением, а ответ направляется в IIS. За это взаимодействие отвечает AspNetCore модуль, который необходимо установить в IIS отдельно от Net Core Sdk!!!! (https://docs.microsoft.com/ru-ru/aspnet/core/fundamentals/servers/aspnet-core-module). После инсталляции в списке модулей должна быть эта строка (предварительно (сначала) необходимо установить VS2015 C++ Redistributable Package):
Кроме всего этого в Web.config необходимо указать использование этого модуля и путь к целевой сборке (приложению), например, мое приложение - E3App.Web.dll и Web.Config имеет следующий вид:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore
        processPath="dotnet"
        arguments=".\E3App.Web.dll"
        stdoutLogEnabled="true"
        stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>

Этот файл, как и многое другое, генерируется в процессе публикации проекта (Publish), однако, я не думал, что он играет роль, т.к. он в явном виде отсутствует в проекте. Но он очень важный! Особенно атрибут stdoutLogEnabled, по умолчанию этот атрибут имеет значение false, что для разработчика означает следующее: любое исключение произошедшее при запуске приложение будет "проглочено", а в качестве результата мы увидим на странице что-то вроде: "Оопс, а что-то сломалось". Включаем и идем дальше.

Старая добрая БД и EF Core

Следующим приколом на пути к запуску приложения стала сама БД: я поставил Sql Server 2012, предполагая, что EF нет дела до версии SQL сервера, но не тут-то было (хотя мне казалось, что ву меня был рабочий проект под 12 версию сервера). Текст исключения в стандартном выводе мне ничего не говорил о том, почему у меня ломается приложение при старте. Однако, подозрительным было то, что при отладке приложение стартовало без каких-либо проблем, а на IIS - ломалось. Тогда я решил заменить 12 SQL Server на SQL Server 2016 и вуаля, текст ошибки стал другим. Теперь приложение жаловалось на то, что нет прав на создании новой БД при подключении к таблице master (тут все тривиально, нужна роль sysadmin для пользователя под которым выполняется подключение). Хотелось бы сделать ремарку о том, что EF работает с БД по парадигме Code First (сам создает скрипт для создания БД, всех таблиц и связей между ними). Тут тоже пришлось помучиться, т.к. можно сделать строку подключения с полным указаниям логина и пароля (в appsettings.json):

  "ConnectionStrings": {
    "Storage": "Server=DEV-HOST\\SQLEXPRESS;Database=e3app;
    User ID=developer;Password=123;MultipleActiveResultSets=true"
  }


 Но это не всегда удобно использовать заранее созданную учетную запись, иногда необходимо использовать Windows-аутентификацию, казалось бы просто выдал права (роль sysadmin) своей Windows учетной записи:

"ConnectionStrings": {
    "Storage": "Server=DEV-HOST\\SQLEXPRESS;Database=e3app;
    Integrated Security=SSPI;MultipleActiveResultSets=true"
 }


 но нет в БД, оказывается, EF лезет через другую учетку. Экспериментальным способом включая данную роль у логинов по очереди, определил, что это  учетная запись BULTIN\Users (а если посмотреть, кто создал БД - IIS APPPOOL/AspNetCore).



Заключение

Казалось бы тривиальная задача, но она отняла у меня кучу времени, я убил, наверное, пару дней чистого времени пытаясь понять, что происходит и почему все работает не так, как нужно. Надеюсь, что этот пост поможет тем, кто столкнулся с такой же проблемой: деплоя на IIS Asp Net Core веб приложения.



3 комментария:

  1. Как обновлять такое приложение? При попытке заменить файлы в папке развертывания, они оказываются заблокироаанными IIS

    ОтветитьУдалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Для этого необходимо остановить приложение в списке приложений IIS, после этого можно заменить файлы и запустить приложение. Наш блог переехал сюда - https://zen.yandex.ru/id/5f9bbb6eb5987b74e7014a6f

    ОтветитьУдалить

Распространение Windows-приложений (Chocolatey)

Менеджеры пакетов для ОС Windows В большинстве дистрибутивов Linux есть свои менеджеры пакетов: в Ubuntu/Mint это apt и deb, в OpenSuse э...