在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框架使用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是一个简单的应用程序,可以启动其他进程,有点像start.exe
命令。它的特别之处在于,它还会记录启动进程的参数,如果任何参数包含文件路径,那么这个文件的副本将被创建在FrontMan输出文件夹中。让看看它是如何与csc.exe
和简单的Test.cs
C#文件一起工作的:
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\
,应该看到两个新文件:arg_2_Test.cs
和callargs.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"