System.Web.Compilation.BulidManager负责站点的动态编译,所有的页面、用户控件、和所有的ASP.NET特殊目录,都会在运行时被BuildManager编译和处理,也包括Bin目录。我们知道在ASP.NET中,所有的页面和控件都包括.ASPX和后台代码文件,除了代码文件在编译时会被静态编译成一个类型外,.ASPX文件在运行时也会被动态编译在一个动态类型中,以便写在.ASPX上的C#代码能够被运行。
而在编译时,如果使用到外部类型,是需要引用外部类型的程序集,否则无法编译成功。我们也经常会遇到类型的编译错误:
CS0246: The type or namespace name '*******' could not be found (are you missing a using directive or an assembly reference?)
而解决问题的最好办法就是我们把编译所需的程序集放到Bin目录,这样就可以保证BuildManager编译成功。但是在某些环境中,我们就是不希望将这样的引用程序集放成Bin目录,而通过动态载入的形式载入所需的程序集。
BuildManager的内部很复杂,但是它所提供的接口却非常的有限,都只是查询类型和程序集的接口。因为在BuildManager中管理着系统中最全的类型和程序集,所有动态编译的类型和程序集都可以通过BuildManager的查询接口得到。也就是说,即使你通过Type.GetType接口无法得到的类型,可能你通过BuildManager.GetType就可以得到,前提是在当前的运行时确实存在着这个类型。BuildManager所维护的程序集列表,也比AppDomain维护的列表多得多,在BuildManager里还订阅了AppDomain.CurrentDomain.AssemblyResolve向当前Domain提供所需的程序集。
在BuildManager编译时,它都会把Bin目录的所有程序集按一定的规则拷贝到"%WINDIR%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files"相应的动态目录里,每个程序集单独一个目录,并配上__AssemblyInfo__.ini。
显然,我们让BuildManager在动态编译时动态增加程序集引用,是无法通过AppDomain来加载程序集来实现。必须想办法让程序集能够被添加到BuildManager的引用列表中,并且最好能够做到,不在Bin目录下的程序集,也会被动态拷贝到相应的动态目录里面,实际上要达到的行为是一个站点目录中可能会同时出现多个Bin目录。
通过搜索,我找到这样的答案,在Web.config做如下的配置,即可在一个站点里面设置多个Bin目录,让站点在编译时能找到引用:
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="WebFileManager/bin" /> </assemblyBinding> </runtime>
全文完