1

我有一个解释起来有点复杂的问题(否则我不会有问题:)),但我会试一试。

我有一个 asp.net web 应用程序,我试图在运行时从另一个项目加载用户控件,而原始网站没有对包含用户控件的项目/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

加载的程序集之间的唯一区别是属性 Location 给出了错误。我假设程序集的位置已传递给构建器。

有没有人可以就如何解决这个问题提供任何想法?(除了:将程序集写入磁盘上的临时文件夹)

我正在考虑我自己的 buildprovider 或这个方向的东西,但我担心我可能会遇到同样的问题。

最终这似乎是同一个问题: 从内存而不是磁盘向 CompilerParameters ReferencedAssemblies 提供程序集?

现在为了更好地理解,并可能帮助其他人:完整的堆栈跟踪和完整的源代码:

完整的堆栈跟踪

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 Drive\Lab\DLLLoading\WebApplication1\Default.aspx.vb:line 29

我有 2 个 web 应用程序,一个普通的,一个只有 ascx(usercontrol) 文件。

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 应用程序所需的全部内容。

Web应用程序1:

这里是魔法发生的地方

全球.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
4

1 回答 1

0

ascx 编译器仅支持通过路径引用 dll。这样做的原因是安全性。在我的问题示例中,我必须将所需的 dll 保存到磁盘上的临时文件夹中,然后从该临时位置加载它。由于安全原因,没有其他解决方案。

于 2016-09-27T08:11:39.403 回答