我有一个问题解释起来有点复杂(否则我不会有问题:),但我会试一试。
我有一个asp.net网络应用程序,我正试图在运行时从其他项目加载用户控件,而原始网站没有对包含用户控件的项目.dll的引用。
当我知道所有需要的文件(dll等)的路径时,我可以让它工作,尤其是对于assembly.loadfile(path)。但现在我使用的是只能为我提供流的virtualpathProvider。所以我不能再使用assembly.loadfile(path)了,但我必须使用assembly.load(byte[])。问题是,当切换到assembly.load(byte[])时,我无法再编译ascx文件了。它给了我一个例外:
The 'ReferencedAssemblies' property cannot contain null or empty strings. Parameter name: options
加载的程序集之间的唯一区别是"位置"属性会给出错误。我假设程序集的位置已传递给生成器。
有谁能提供关于如何解决这个问题的想法吗?(除了:将程序集写入磁盘上的临时文件夹)
我一直在考虑我自己的构建提供者或朝着这个方向发展,但我担心我可能会遇到同样的问题。
这最终似乎是同一个问题:是否从内存而非磁盘向编译器提供程序集参数ReferencedAssembly?
现在,为了更好地理解并可能帮助其他人:完整的堆栈和完整的来源:
全叠流
at Microsoft.VisualBasic.VBCodeGenerator.CmdArgsFromParameters(CompilerParameters options)
at Microsoft.VisualBasic.VBCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
at System.CodeDom.Compiler.CodeCompiler.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames)
at System.Web.Compilation.AssemblyBuilder.Compile()
at System.Web.Compilation.BuildProvidersCompiler.PerformBuild()
at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Compilation.BuildManager.GetCompiledType(VirtualPath virtualPath)
at WebApplication1._Default.CompileAddControl(String path) in E:Google DriveLabDLLLoadingWebApplication1Default.aspx.vb:line 29
我有两个网络应用程序,一个是普通的,还有一个只有ascx(用户控制)文件
Web应用程序2:
这包含用户控件,不包含其他内容。
放映时间.ascx
<%@ Control
Language="vb"
AutoEventWireup="false"
CodeBehind="Showtime.ascx.vb"
Inherits="WebApplication2.Showtime,WebApplication2"
%>
<asp:Label ID="lblTime" runat="server"></asp:Label>
在这里,我将程序集名称添加到了Inherits值=>,否则应用程序将无法理解这一点。必须在不同的程序集中查找代码。
显示时间.ascx.vb
Public Class Showtime
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
lblTime.Text = "Hello world from external :" & Now.ToShortDateString & " - " & Now.ToShortTimeString
End Sub
End Class
这就是这个Web应用程序所需要的全部内容。
WebApplication1:
的神奇之处就在这里
Global.asax
Imports System.Reflection
Imports System.Web.Hosting
Imports System.IO
Public Class Global_asax
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf Global_asax.ResolveEventHandler
End Sub
Public Shared Function ResolveEventHandler(sender As Object, args As System.ResolveEventArgs) As Assembly
Try
If args.Name.StartsWith("WebApplication2") Then
Dim _ret As Assembly
''START OF NOT WORKING CODE
''To make this path work, I added the other application with ascx's as a virtual directory (~/apps/HelloWorld/) in IIS.. (make sure to NOT have a web.config in webapplication2)
Dim _vf As VirtualFile = HostingEnvironment.VirtualPathProvider.GetFile("~/apps/HelloWorld/bin/WebApplication2.dll")
'copy to memorystream so i can use the very handy toArray function (speed of coding)
Using _ms As New MemoryStream, _s As Stream = _vf.Open()
_s.CopyTo(_ms)
_ret = Assembly.Load(_ms.ToArray)
End Using
''END OF NOT WORKING CODE
''START OF WORKING CODE
'Dim _ret As Assembly = Assembly.LoadFile(HostingEnvironment.MapPath("~/apps/HelloWorld/bin/WebApplication2.dll"))
''START OF WORKING CODE
Return _ret
End If
Return Nothing
Catch ex As Exception
'this is a test project so debug.writeline will do..
Debug.WriteLine(ex.ToString)
Return Nothing
End Try
End Function
默认.aspx
这个有这样的控制:
默认.aspx.vb
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
CompileAddControl("~/apps/HelloWorld/Showtime.ascx")
Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try
End Sub
Private Shared m_dict As New Dictionary(Of String, Type)
Public Sub CompileAddControl(path As String)
Try
Dim _t As Type = Nothing
If Not m_dict.TryGetValue(path, _t) Then
_t = BuildManager.GetCompiledType(path)
m_dict.Add(path, _t)
End If
Dim _o As Control = DirectCast(BuildManager.CreateInstanceFromVirtualPath(path, _t), Control)
phControls.Controls.Add(_o)
Catch ex As Exception
phControls.Controls.Add(New LiteralControl(ex.Message))
End Try
End Sub
ascx编译器只支持按路径引用dll。这样做的原因是安全。在我问题中的例子中,我必须将所需的dll保存到磁盘上的临时文件夹中,然后从该临时位置加载它。由于安全原因,没有其他解决方案。