【问题标题】:How to send XElement object across AppDomains如何跨 AppDomains 发送 XElement 对象
【发布时间】:2012-09-21 00:28:17
【问题描述】:

我有一个从不同的 dll 文件加载外部程序集的应用程序。我正在将程序集加载到之前创建的另一个域。所有程序集都返回 XElement 对象,我需要将此对象用于主 AppDomain 中的其他方法,但 XElement 对象没有 Serializable 属性,这就是我无法按原样发送此对象的原因。从外部库中获取 XElement 对象非常重要。我尝试为此使用序列化,但每次我都失败了。

我尝试创建一些包装类。这个类只是从 XElement 创建流,我尝试在主域中从这个流中读取,但是这个流当时是关闭的。

如果有人能帮我解决这个问题,我会很高兴。 提前致谢。

private XElement CallModule(string modulePath, string moduleName, 
  Dictionary<string, string> parameters)
{
  AppDomainSetup moduleDomainSetup = new AppDomainSetup();
  moduleDomainSetup.ApplicationBase = AppDomain.CurrentDomain.RelativeSearchPath;
  AppDomain moduleDomain = 
    AppDomain.CreateDomain("moduleDomain", null, moduleDomainSetup);

  try
  {
     Module remoteobj =  (Module)moduleDomain.CreateInstanceFromAndUnwrap(
       HttpContext.Current.Request.MapPath(modulePath),
       moduleName + "." + moduleName);
     Module.WrappedStream remoteResult = 
       remoteobj.Execute(queryString["command"], parameters);

     XElement res = XElement.Load(remoteResult.Stream);
     return res;
  }
  catch (Exception ex)
  {
    throw ex;
  }
  finally
  {
    AppDomain.Unload(moduleDomain);
  }
}

【问题讨论】:

  • 我觉得很奇怪,XElement 确认了 IXmlSerializable 接口 - ( public class XElement : XContainer, IXmlSerializable ) 你测试过只返回字符串还是 int,对你有用吗。
  • @orn,XElement 不是二进制可序列化的,也不是通过引用编组的,这是跨应用程序域使用它所必需的。
  • Yaroslav,您的示例缺少在另一个 AppDomain 中运行并创建流的代码部分。因此,无法诊断该特定调用失败的原因。 (无论如何,我认为这不是一个好主意 - 似乎是我的回答)。

标签: c# appdomain


【解决方案1】:

您可以使用XElement.Save 将其保存到 TextWriter 或 Stream

【讨论】:

    【解决方案2】:

    您不能使用 XElement 跨 AppDomain 边界。潜在原因 - XElement 可以表示必须跨 AppDomain 边界编组的巨大对象树/大量数据。

    虽然您可以让您的代码正常工作(即通过保存到流和重新加载),但这可能不是最好的主意。您将丢失元素(即父级)的上下文,并且您可能会无意中序列化/反序列化大量数据。考虑以这样一种方式进行重构,即在创建 XElement 的新 AppDomain 中处理 XElement 的数据,然后将自定义对象(可序列化或通过 ref 编组)返回到主 AppDomain。

    注意事项:

    • 我假设您的示例代码只是示例,创建/拆除 AppDomain 以调用单个方法并不是地球上最快的事情。如果是一次性操作可能完全没问题,但如果它以任何非平凡的频率重复,请务必检查性能是否符合您的目标。
    • 如果你只需要finally,你就不需要catch/throw(再次假设实际代码比throw更多)

    【讨论】:

    • 我很乐意拒绝使用应用程序域,但是当我尝试在主域中加载 dll 库时,此 dll 文件将被锁定,我无法删除/替换此库,直到进程将不会被杀死。这也是一个重要问题,因为我应该能够在运行时将旧库替换为新库
    【解决方案3】:
    Module remoteobj =  (Module)moduleDomain.CreateInstanceFromAndUnwrap(
           HttpContext.Current.Request.MapPath(modulePath),
           moduleName + "." + moduleName);
         Module.WrappedStream remoteResult = 
           remoteobj.Execute(queryString["command"], parameters);
    
         XElement res = XElement.Load(remoteResult.Stream);
         return res;
    

    与其尝试序列化 XElement,是否可以序列化 modulePath、moduleName 和参数,然后使用 modulePath、moduleName 和参数重新创建 XElement 对象。

    你也可以用命令模式试试这个吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-04
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多