【问题标题】:Why does reading from an SslStream across AppDomains succeed but return an empty buffer?为什么跨 AppDomains 从 SslStream 读取成功但返回一个空缓冲区?
【发布时间】:2012-06-20 06:25:17
【问题描述】:

当使用Read(byte[] buffer, int offset, int count) 方法从SslStream 正常读取时,我得到了预期的结果。

但是,如果我将 SslStream 对象移动到新的 AppDomain 中,读取功能似乎仍然正常(即返回正确的读取字节数),但 buffer 数组为空。

这是为什么?

【问题讨论】:

    标签: c# attributes marshalling appdomain sslstream


    【解决方案1】:

    some investigation 之后,参数数组的内容似乎没有跨 AppDomain 编组(可能出于性能原因)。

    因此,buffer 参数中的数据只能通过一种方式传递。本地 AppDomain 中的调用者不会看到对远程 AppDomain 中数组的修改。

    强制返回数组参数中数据的方法是在参数中添加[Out]属性。

    要解决问题中所述的问题,请为 SslStream 创建一个包装类并改用它:

    [Serializable]
    internal class SslStreamWrapper : SslStream
    {
        public SslStreamWrapper(
            Stream innerStream,
            Boolean leaveInnerStreamOpen,
            RemoteCertificateValidationCallback validationCallback,
            LocalCertificateSelectionCallback selectionCallback)
         : base(innerStream, leaveInnerStreamOpen, validationCallback, selectionCallback)
        {
        }
    
        // Add the [Out] attribute to the 'buffer' parameter.
        public override Int32 Read([In, Out] Byte[] buffer, Int32 offset, Int32 count)
        {
            return base.Read(buffer, offset, count);
        }
    }
    

    该类具有[Serializable] 属性,允许它在AppDomain 之间传递,并且包含隐式[In] 参数以与其他Stream 类保持一致。

    许多其他继承自Stream 的.NET 类(例如MemoryStreamBufferedStream - 甚至Stream 本身)在Read() 方法中包含buffer 参数的[In, Out] 属性。

    我想知道为SslStream 省略它们是否是故意选择...这适用于所有版本的 .NET。

    【讨论】:

    • 我会使用组合而不是继承 - 编写 CrossAppDomainStreamWrapper 或类似的东西,它将所有调用委托给传递给构造函数的流。这样它就更可重复使用了。
    【解决方案2】:

    这是@JonSkeet 在对已接受答案的评论中建议的使用组合而不是继承的替代解决方案的代码:

    [Serializable]
    public class CrossAppDomainStreamWrapper : Stream
    {
        public CrossAppDomainStreamWrapper(Stream stream) => Stream = stream;
    
        public Stream Stream { get; }
        public override bool CanRead => Stream.CanRead;
        public override bool CanSeek => Stream.CanSeek;
        public override bool CanWrite => Stream.CanWrite;
        public override long Length => Stream.Length;
        public override long Position
        {
            get => Stream.Position;
            set => Stream.Position = value;
        }
    
        public override void Flush() => 
           Stream.Flush();
        public override long Seek(long offset, SeekOrigin origin) =>
            Stream.Seek(offset, origin);
        public override void SetLength(long value) =>
           Stream.SetLength(value);
        public override int Read([In, Out] byte[] buffer, int offset, int count) =>
           Stream.Read(buffer, offset, count);
        public override void Write(byte[] buffer, int offset, int count) =>
           Stream.Write(buffer, offset, count);
    }
    

    【讨论】:

      猜你喜欢
      • 2014-12-03
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      • 1970-01-01
      相关资源
      最近更新 更多