【问题标题】:AppDomains and configSectionsAppDomains 和 configSections
【发布时间】:2009-12-03 20:16:41
【问题描述】:

我们在 .NET 3.5 应用程序中使用 CSLA(一个相当古老的版本),我们利用它的 NetRun 应用程序加载为我们的一些用户。对于那些不熟悉 NetRun 的人来说,NetRun.exe 基本上是一个安装在用户计算机上的应用程序“运行程序”(例如,安装到 c:\Program Files\NetRun\NetRun.exe)。用户只需启动 NetRun.exe 即可启动应用程序。

NetRun.exe 的作用如下:

(1) 创建一个新的 AppDomainSetup

Dim setupDomain As New AppDomainSetup()
setupDomain.ApplicationBase = CurrentDomainPath() ' this will be C:\Program Files\NetRun\
setupDomain.ConfigurationFile = "http://www.ourdomain.com/TheApp.xml" ' The app.config file is actually named TheApp.xml on the server because it has NetRun-specific config settings that don't belong in the standard TheApp.config that is used when the app is running directly from the server.

(2) 然后使用该 AppDomainSetup 创建一个新的 AppDomain

' create new application domain 
Dim newDomain As AppDomain = AppDomain.CreateDomain("TheApp", Nothing, setupDomain)

(3) 然后 NetRun.Launcher(一个启动助手类 -- 主要用于常见的启动屏幕)在新的 AppDomain 中通过以下方式实例化:

' create launcher object in new appdomain
Dim launcher As Launcher = CType(newDomain.CreateInstanceAndUnwrap("NetRun", "NetRun.Launcher"), Launcher)

(4) 然后午餐助手类在新的 AppDomain 中运行应用程序

' use launcher object from the new domain to launch the remote app in that appdomain
launcher.RunApp()

(5) 在所有的启动画面之后,应用程序最终通过以下方式启动

Dim ass = Assembly.LoadFrom("http://www.ourdomain.com/TheApp.exe")
ass.EntryPoint.Invoke(ass.EntryPoint, Nothing)

因此,回顾一下,实际运行的应用程序的 AppDomain 的 ApplicationBase 是 C:\Program Files\NetRun\,而实际应用程序的入口点位于“http://www.ourdomain.com/TheApp.exe”中。到目前为止,一切顺利。

应用程序本身,除了 TheApp.exe 之外,还依赖于 ALibrary.dll。迄今为止,这对我们来说非常有效。即使 ALibrary.dll 具有被拉入 TheApp.xml 文件的配置条目,这些配置条目也始终可以正常读取(并继续这样做)。

在即将发布的版本中,我们添加了一个新的自定义配置文件部分,该部分在 ALibrary.dll 中定义。我们将新部分添加到 TheApp.xml 和 TheApp.config 文件中

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.Applicat...">
      <section name="TheApp.My.MySettings" type="System.Configuration.ClientSettingsS..."/>
      <section name="ALibrary.My.MySettings" type="System.Configuration.ClientSettingsS..."/>
    </sectionGroup>
    <!-- NEW CONFIG SECTION -->
    <section name="fixedPriceExceptionModel" type="ALibrary.Configuration.FixedPrices.FixedPriceExceptionModelSection, ALibrary"/>
</configSections>

(为了节省篇幅,本文删除了部分内容)

但是,当我们尝试通过“正常”方式访问 NetRun 中启动的 TheApp.exe 中的新部分时

CType(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None) _
                             .GetSection("fixedPriceExceptionModel"), FixedPriceExceptionModelSection)

我们得到以下异常:

创建时出错 配置节处理程序 固定价格异常模型:不能 加载文件或程序集 'ALibrary' 或 它的依赖项之一。系统 找不到指定的文件。 (http://www.ourdomain.com/TheApp.xml 第 8 行)

做一些研究,这是因为 .NET 配置库的程序集解析器在所有常见的地方寻找 ALibrary.dll; ApplicationBase、特定的子目录、.NET 核心目录,然后是 GAC。不幸的是,在这些位置中永远找不到 ALibrary.dll。当此应用程序直接在服务器上运行时,不使用 NetRun,应用程序不会抛出异常并正确读取配置部分。

我尝试过以不同方式设置 AppDomainSetup,因为它的 ApplicationBase 将设置为 http://www.ourdomain.com/,但随后调用 CType(newDomain.CreateInstanceAndUnwrap("NetRun", "NetRun.Launcher"), Launcher ) 炸弹,因为 NetRun.exe 不在服务器上。

这可能涉及很多内容,我希望我描述得足够好(并且没有让您感到厌烦)。也许没有简单的解决方案,但我已经用尽了我对该领域的有限知识,并希望 SO 上的其他人可能有神奇的修复,让我能够在 NetRun 和本地运行应用程序时可靠地访问自定义配置部分。

【问题讨论】:

    标签: .net configuration appdomain


    【解决方案1】:

    据我了解,问题是代码在客户端计算机上运行,​​而没有真正(物理)存在的程序集,因为它们是从服务器加载的。

    知道了,你有两个选择:
    1. 努力寻找现有代码的解决方案 ;)
    2. 不使用自定义配置节处理程序。

    就个人而言,我会选择#2。

    不要使用 ALibrary.Configuration.FixedPrices.FixedPriceExceptionModelSection 作为您的配置部分处理程序(这会导致异常,因为在客户端上找不到此类型),而是像其他部分一样使用默认 System.Configuration.ClientSettingsSection - 这是一部分.NET Framework 的,所以在客户端没有问题。之后,为所需的配置类创建一个工厂(如果您真的需要强类型),它将逐步读取配置并创建您的 FixedPriceExceptionModel 对象,其中填充了数据并可供任何需要它的人使用。

    如果我误解了问题,请告诉我。

    【讨论】:

    • 不,您根本没有误解问题 - 正确。是的,即使我设置了 ShadowCopy 并以物理方式下载文件,由于 ShadowCopy 将程序集文件传播出去的方式,它也无济于事。你的#2 是一个明显的解决方案,但我会继续坚持让某人想出那个神奇的子弹来使你的#1 选项成为真的:) 看到这个失败真的很糟糕:( 谢谢你您的回复。
    • 我最终选择了 #2 :( 只是将我的配置 XML 放入它自己的文件中并自己加载/解析它。
    【解决方案2】:

    我意识到这是对已经回答的问题的非常晚的回复,但我已经设法使用 codebase 元素解决了这个问题。

    示例(如果需要,也可以使用 file:/// url 形式):

    <configuration>
        <runtime>
            <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                 <dependentAssembly>
                   <assemblyIdentity name="AssemblyName" publicKeyToken="null" culture="neutral" />
                   <codeBase version="1.0.0.0" href="http://server.address.com/AssemblyLocation/AssemblyName.dll"/>
                 </dependentAssembly>
              </assemblyBinding>
        </runtime>
    </configuration>
    

    另见:

    Specifying an Assembly's Location

    How the Runtime Locates Assemblies

    【讨论】:

      【解决方案3】:

      我认为这不会像你介绍的那样奏效。

      这行代码有效,因为LoadFrom 是一种神奇的方法,它在特定位置查找程序集及其任何依赖项。 TheApp.exe 及其 DLL 从这个神奇的 LoadFrom 上下文中加载:

      Dim ass = Assembly.LoadFrom("http://www.ourdomain.com/TheApp.exe")
      

      但是,配置部分程序集加载失败,因为加载它的 .NET 框架代码(可能)使用普通的 Assembly.Load 调用,该调用与原始 LoadFrom 调用断开连接并且不知道 www。 ourdomain.com。有多种方法可以将其他目录添加到 .NET 程序集搜索路径中,但这些方法都是相对于应用程序域基目录进行的。

      正如您所指出的,让Assembly.Load 了解 www.ourdomain.com 的唯一其他方法是更改​​应用程序域的基本目录。在这种情况下,将NetRun.exe部署到Web服务器上是不是很糟糕?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-20
        • 2012-11-24
        • 2012-08-01
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多