ASP.NET MVC应用中的邮件发送引擎问题排查

ASP.NET MVC应用中,有一个部分是邮件发送引擎,它使用Razor模板来创建消息正文。在将这个应用部署到IIS之后,开始收到以下错误(不重要的部分已被剥离):

... Line: 0\t Col: 0\t Error: Metadata file 'ev-server/dev2/appname/bin/EmailSystem.Client.DLL' could not be found ...

第一行表明这是一个编译问题,但并不清楚到底是应用的哪一部分抛出了这个错误。认为获取完整的编译器命令行可能会有所帮助。不幸的是,从ASP.NET应用中获取它并不容易。

ASP.NET编译是如何工作的?

默认情况下,ASP.NET框架使用csc.exe来编译.cs文件以执行其中的逻辑。可能想知道指的是哪些.cs文件,因为可能在IIS Web应用程序路径中没有它们(除非使用了App_Code文件夹)。现在,让看看Views文件夹中的所有文件,想象一下,它们每个最终都变成了一个带有一些自动生成名称的.cs文件。每次ASP.NET应用渲染页面时,它首先检查给定页面是否已编译,因此可以执行。如果没有,ASP.NET框架会调用解释器(如RazorTemplateEngine)从.cshtml(或.aspx.asmx等)创建一个.cs文件,然后编译器生成.dll文件。可以很容易地通过使用Process Monitor来观察这一点:

让来看一个ASP.NET的csc.exe命令行调用示例:

"C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /noconfig /fullpaths @"C:\WINDOWS\TEMP\p0ulcxtl.cmdline"

如所见,所有编译参数(可能是因为它们的长度)都是通过一个临时文件传递给编译器的。这个文件在csc.exe进程完成后会被删除。现在想象一下这里出了问题(就像文章开头提到的情况一样)。可能想知道到底传递了哪些参数给编译器,以及为什么会失败。这就是FrontMan诞生的原因。

FrontMan来拯救

FrontMan是一个简单的应用程序,可以启动其他进程,有点像start.exe命令。它的特别之处在于,它还会记录启动进程的参数,如果任何参数包含文件路径,那么这个文件的副本将被创建在FrontMan输出文件夹中。让看看它是如何与csc.exe和简单的Test.csC#文件一起工作的:

PS temp> .\FrontMan.exe csc /debug+ .\Test.cs

ProcDump v5.13 - Writes process dump files

Copyright (C) 2009-2013 Mark Russinovich

Sysinternals - www.sysinternals.com

With contributions from Andrew Richards

Process: csc.exe (2388)

CPU threshold: n/a

Performance counter: n/a

Commit threshold: n/a

Threshold seconds: n/a

Number of dumps: 1

Hung window check: Disabled

Exception monitor: Unhandled

Exception filter: Disabled

Terminate monitor: Disabled

Dump file: c:\Users\admin\AppData\Local\Temp\frontman\20130128_195337.547_csc\csc_YYMMDD_HHMMSS.dmp

Press Ctrl-C to end monitoring without terminating the process.

如果现在打开c:\Users\\AppData\Local\Temp\frontman\20130128_195337.547_csc\,应该看到两个新文件:arg_2_Test.cscallargs.txt。第一个是在编译时Test.cs的副本,第二个包含了命令行:"csc" "/debug+" ".\Test.cs"。可能注意到了上面的procdump消息。这是FrontMan的另一个特性——它不是直接启动请求的进程,而是在procdump下运行它。默认情况下,FrontMan配置procdump在未处理异常时创建一个完整的内存转储,但这种行为可以很容易地更改为procdump支持的任何其他行为。将procdump附加到进程上,为FrontMan提供了成为系统级进程嗅探器的可能性。这可以通过Image File Execution Options实现。通过向注册表添加以下键:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\csc.exe] "Debugger"="c:\\tools\\Frontman.exe"

配置FrontMan记录系统中任何csc.exe调用,包括ASP.NET编译。幸运的是,不需要手动编辑注册表。从提升的命令提示符运行FrontMan -install csc.exe将为创建所需的键。相反,运行FrontMan -uninstall csc.exe将从注册表中删除它们。

让看看它在ASP.NET示例中是如何工作的。如果为csc.exe安装了FrontMan,在进程树中,应该看到调用FrontMan的w3wp.exe,然后运行procdump,最后运行csc.exe。在临时路径中,应该创建了一个名为frontman的新文件夹,其中包含每个csc.exe调用的子文件夹。找到有趣的一个并打开它。在例子中,callargs.txt包含:

C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\csc.exe /noconfig /fullpaths @C:\WINDOWS\TEMP\pbjs1i2y.cmdline

arg_3_pbjs1i2y.cmdline

/t:library /utf8output /R:"\\dev-server\dev2\appname\bin\EmailSystem.Contracts.dll" /R:"\\dev-server\dev2\appname\bin\EmailSystem.Client.dll" /R:"System.dll" /R:"System.Core.dll" /R:"System.Web.Extensions.dll" /R:"Microsoft.CSharp.dll" /R:"ev-server/dev2/appname/bin/EmailSystem.Client.DLL" /out:"C:\WINDOWS\TEMP\pbjs1i2y.dll" /debug- /optimize+ "C:\WINDOWS\TEMP\pbjs1i2y.0.cs"
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485