Подтвердить что ты не робот

Возможно ли плавное развертывание с помощью компонентных приложений ASP.NET MVC?

Вероятно, это не MVC-специфичный, он может также применяться к ASP.NET WebForms, но мы уже сталкивались с этим на MVC2.

Когда мы начинаем удаленное развертывание с помощью MSDeploy, мы получаем краткую (5-6 секунд) страницу "ошибка сервера" для наших запросов до тех пор, пока не произойдет новое развертывание. Вот текст ошибки:

Ошибка сервера в приложении "/".

Не удалось загрузить файл или сборку "Some.Assembly" или один из его зависимостей. Процесс не может доступ к файлу, поскольку он используемый другим процессом. (Исключение от HRESULT: 0x80070020)

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

Сведения об исключении: Исправление System.IO.FileLoadException: не удалось загрузить файл или сборку "Some.Assembly" или одной из его зависимостей. процесс не может получить доступ к файлу, потому что он используется другим процессом. (Исключение из HRESULT: 0x80070020)

Информация о версии: Microsoft.NET Версия Framework: 4.0.30319; ASP.NET Версия: 4.0.30319.1

Вот трассировки стека, показанные на странице ошибок:

[FileLoadException: Could not load file or assembly 'Some.Assembly' or one of its dependencies. The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0x80070020)]
   System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
   System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +39
   System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks) +132
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +144
   System.Reflection.Assembly.Load(String assemblyString) +28
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +46

[ConfigurationErrorsException: Could not load file or assembly 'Some.Assembly' or one of its dependencies. The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0x80070020)]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +618
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +209
   System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +130
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +178
   System.Web.Compilation.BuildManager.GetPreStartInitMethodsFromReferencedAssemblies() +94
   System.Web.Compilation.BuildManager.CallPreStartInitMethods() +332
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +591

[HttpException (0x80004005): Could not load file or assembly 'Some.Assembly' or one of its dependencies. The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0x80070020)]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +8950644
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +97
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +256

Сборка, которая вызывает этот сбой (Some.Assembly), не является фактической веб-сборкой, а одним из других компонентов под ней "Ссылки", подписанным с .snk.

Через 5-6 секунд сайт идет вверх и ошибка исчезает.

Это, конечно, не желаемое поведение. Интересно, делаем ли мы что-то неправильно с точки зрения подключения компонентов вместе. Должен ли быть другой подход к обеспечению плавного развертывания? Или это может быть ошибка с самим MVC2?

P.S. Взаимодействие IIS с перекрытием включено, оно по умолчанию в любом случае.

Вот компоненты:

  • A.dll
  • Some.Assembly.dll(< --- это неудачный, зависит от A.dll)
  • B.dll(зависит от A.dll и Some.Assembly.dll)
  • Web.dll(это веб-приложение, зависит от всего вышеперечисленного)

Все зависимости устанавливаются с использованием регулярных ссылок на сборку с Copy Local. Все dll являются частью решения в виде отдельных проектов.

MSDeploy только развертывает двоичные файлы, а не источник.

4b9b3361

Ответ 1

Перекрывающееся вращение применяется только к утилизации пула и не предназначено для облегчения типа развертывания, которое вы описываете или требуете. Когда перекрывающееся вращение включено, существующие запросы в пулом "исходящий" рабочий процесс будут разрешены, пока новые запросы будут отправлены новому созданному рабочему процессу. Это механизм для грамотного перехода на новый рабочий процесс, не вытягивая коврик из-под существующих запросов. Это все, что он делает.

Папки теневой копии используются для этой цели:

Что такое папка временных файлов ASP.NET? (Мой ответ)

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

При развертывании приложения ASP.NET сайт будет плохо себя вести. Пока вы копируете свои сборки, эти файлы будут заблокированы (возможно, исключительно) любым процессом, обрабатывающим загрузку (WebDAV или FTP).

Это приводит к исключениям, которые вы наблюдали, и, скорее всего, потому, что механизм теневой копии не может читать новые сборки до их написания (а WebDAV или FTP удаляет блокировки записи).

Кроме того, любые страницы, которые имеют зависимости от этих сборок, не могут (теневые) компилировать, если ожидаемые сигнатуры методов были изменены или удалены до тех пор, пока не будут загружены правильные страницы. Или если сначала загружаются страницы/представления, которые зависят от функциональности в сборках, которые еще не были развернуты, вы также получите ошибки.

Весь сайт будет находиться в противоречивом состоянии до тех пор, пока не будет развернут последний файл.

В IIS нет встроенного механизма для обеспечения "атомного" развертывания, т.е. загрузки всех ваших материалов, а затем переключения на выполнение этого. IIS будет отсылать запросы на сайт, и ASP.NET все равно будет отслеживать изменения файлов при загрузке приложения.

Единственный способ развернуть приложение без создания этих ошибок - включить специальную страницу под названием App_Offline.htm перед развертыванием, а затем переименовать или удалить после развертывания:

App_Offline.htm - Скотт Гатри
App_Offline.htm и работая над функцией "Нежелательные ошибки IE"

Вы также можете найти эту статью полезной:

Практическое руководство. Подготовка к развертыванию веб-проекта

Существует несколько более сложная альтернатива, которая включает в себя наличие двух папок, например:

d:\websites\site\www-A d:\websites\site\www-B

Рабочий сайт указывает на d:\websites\site\www-A, а пока вы развертываете его в d:\websites\site\www-B. Когда вы будете готовы, вы переключите сайт в папку d:\websites\site\www-B.

Когда вы приступаете к развертыванию следующей версии, вы развертываете ее в d:\websites\site\www-A и переключаетесь на нее, когда будете счастливы.

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

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

Ответ 2

Мое развертывание script останавливает веб-сайт и отображает страницу "Подождите, пока сайт обновляется...", которая обновляется каждые 15 секунд. Поскольку развертывание занимает менее минуты, похоже, проблема устранена.