使用组件化的ASP.NET MVC应用程序可以顺利部署吗?

Sed*_*glu 12 asp.net asp.net-mvc iis-7

这可能不是MVC特有的,它可能适用于ASP.NET WebForms,但到目前为止我们已经在MVC2上体验过它.

每当我们使用MSDeploy启动远程部署时,我们会在新部署之前获得请求的简短(5-6秒)"服务器错误"页面.这是错误文本:

'/'应用程序中的服务器错误.

无法加载文件或程序集"Some.Assembly"或其依赖项之一.该进程无法访问该文件,因为该文件正由另一个进程使用.(HRESULT异常:0x80070020)

描述:执行当前Web请求期间发生未处理的异常.请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息.

异常详细信息: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
Run Code Online (Sandbox Code Playgroud)

导致失败的程序集(Some.Assembly)不是实际的Web程序集,而是其下一个其他组件的"引用",用.snk签名.

5-6秒后,站点上升,错误消失.

这肯定不是理想的行为.我想知道我们是否在将组件连接在一起时做错了什么.是否应该有另一种方法来确保顺利部署?或者这可能是MVC2本身的错误?

PS IIS重叠旋转已启用,无论如何都是默认值.

以下是组件:

  • A.DLL
  • Some.Assembly.dll(<---这是失败的,取决于A.dll)
  • B.dll(取决于A.dll和Some.Assembly.dll)
  • Web.dll(这是Web应用程序,取决于以上所有)

所有依赖项都是使用Copy Local启用的常规程序集引用建立的.所有dll都是解决方案的一部分,作为单独的项目.

MSDeploy仅部署二进制文件,而不是源文件.

Kev*_*Kev 20

重叠轮换仅适用于池回收,并非旨在促进您描述或要求的部署类型.启用重叠旋转后,将允许池中"传出"工作进程中的现有请求完成,同时将新请求发送到创建的新工作进程.这是一种优雅地切换到新的工作进程而不会从现有请求中拉出地毯的机制.就是这样.

卷影副本文件夹用于此目的:

什么是"Temporary ASP.NET Files"文件夹?(我的答案)

同样,它们并非旨在提供一种机制,以便在您上载新站点时保持整个现有代码库的运行.

部署ASP.NET应用程序时,该站点将出现异常.在复制程序集时,这些文件将被处理上载(WebDAV或FTP)的任何进程锁定(可能是唯一的).

这会导致您观察到的异常,并且最有可能是因为卷影复制机制在写入之前无法读取新的程序集(并且WebDAV或FTP会删除写锁定).

此外,如果预期的方法签名已更改或被删除,则在上载正确的页面之前,任何依赖于这些程序集的页面都不能(阴影)编译.或者,如果首先上载的页面/视图依赖于尚未部署的程序集中的功能,则还会出现错误.

在部署最后一个文件之前,整个站点将处于不一致状态.

IIS中没有内置机制来确保"原子"部署,即加载所有内容然后切换到运行它.IIS将继续为站点提供请求,ASP.NET将在您上载应用程序时继续检测文件更改.

部署应用程序而不生成这些错误的唯一方法是App_Offline.htm在部署之前启用一个特殊页面,然后在部署后重命名或删除:

App_Offline.htm - Scott Guthrie
App_Offline.htm并解决"IE Friendly Errors"功能

您可能还会发现本文很有用:

如何:准备部署Web项目

有一个稍微复杂的替代方案,涉及两个文件夹,例如:

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认同)