SerializationException:“类型 . . in assembly…未标记为serializa

本文关键字:记为 serializa assembly 类型 in SerializationException | 更新日期: 2023-09-27 18:11:38

在作为并行下载管理器的双工WCF服务中,我有Downloader类,它表示每个下载状态和一个包含Downloader实例的ObservableCollection。当我试图通过BinaryFormatter序列化ObservableCollection,然后我得到SerializationException消息:"类型'System.Net。ConnectStream' in assembly'System。版本4.0.0.0,Culture=neutral, PublicKey Token=b77a5c561934e089'未标记为可序列化"。下面是Downloader类的精简版本:

[Serializable()]
public class Downloader
{
     /// <summary>
     /// "Download status changed" event.
     /// </summary>
     [field: NonSerialized()]
     public event EventHandler<InServiceHandledDownloadStatusChangedEventArgs>    InServiceHandledDownloadStatusChanged;
     /// <summary>
     /// URL of downloaded resource.
     /// </summary>
     private String _targetUrl;  
     /// <summary>
     /// Path to save downloaded data on local drive.
     /// </summary>
     private String _pathToSave;
     /// <summary>
     /// The number of bytes downloaded from internet resource.
     /// </summary>
     private Int64 _downloadedBytesQuantity = 0;
     /// <summary>
     /// Current status of downloading ("Await", "Running", "Completed").
     /// </summary>
     private String _status = "Added";
     /// <summary>
     /// Task that performs download.
     /// </summary>
     [NonSerialized()]
     public Task TaskPerformingDownload;
     /// <summary>
     /// The source of cancellation token for cancelling of TaskPerformingDownload.
     /// </summary>
     [NonSerialized()]
     public CancellationTokenSource CancelDownloadTokenSource;
     /// <summary>
     ///  Gets or sets stream to read downloaded data from internet.
     /// </summary>
     public Stream ReadСontentStream { get; set; }
     /// <summary>
     /// Gets or sets stream to write downloaded data to local drive.
     /// </summary>
     public Stream SaveСontentStream { get; set; }
     /// <summary>
     /// This method executes in TaskPerformingDownload and performs downloading.
     /// of a resource from internet.
     /// </summary>
     /// <param name="p_CancellationToken">Cancellation Token</param>
     public void PerformDownload(Object p_CancellationToken)
     {
         try
         {
             // Get cancellation token.
             CancellationToken cancellationToken = (CancellationToken)p_CancellationToken;
             // Check was the task canceled?
             cancellationToken.ThrowIfCancellationRequested();
             . . . . . . . . 
             HttpWebRequest webResourceRequest = (HttpWebRequest)WebRequest.Create(TargetUrl);
             HttpWebResponse webResourceResponse = (HttpWebResponse)webResourceRequest.GetResponse();
             this.ReadСontentStream = webResourceResponse.GetResponseStream();
             this.SaveСontentStream = new FileStream(this.PathToSave, FileMode.Create, FileAccess.Write, FileShare.None);
             int bytesReceivedInChank = 0;
             byte[] downloadBuffer = new byte[2048];
             // The downloading loop.
             while ((bytesReceivedInChank = this.ReadСontentStream.Read(downloadBuffer, 0, downloadBuffer.Length)) > 0)
             {
                  if (cancellationToken.IsCancellationRequested)
                    cancellationToken.ThrowIfCancellationRequested();
                  this.SaveСontentStream.Write(downloadBuffer, 0, bytesReceivedInChank);
                  . . . . . . . .
             }
        }
        catch(Exception){. . . .}
        finally
        {
            if (this.ReadСontentStream != null)
            {
                this.ReadСontentStream.Close();
                this.ReadСontentStream.Dispose();
            }
            if (this.SaveСontentStream != null)
            {
                this.SaveСontentStream.Close();
                this.SaveСontentStream.Dispose();
            }
        }
     }
}

TaskPerformingDownload成员是执行一次下载的TPL任务。它是从StartDownload()合约方法启动的,WCF服务在客户端请求时调用该合约方法。本任务执行PerformDownload方法。WCF服务创建与必须执行的下载数量一样多的Downloader实例。每次下载一个Downloader实例。SerializationException异常带有消息:"Type'System.Net. net . "ConnectStream' in assembly'System。版本4.0.0.0,Culture=neutral, PublicKey Token=b77a5c561934e089'未标记为serializable"仅在我尝试序列化已完成下载的ObservableCollection时发生。当下载完成时,它的任务(TaskPerformingDownload成员)也完成了它的工作,不再执行。我尝试在完成的下载中处理任务,但它没有帮助,SerializationException异常仍然存在。但是如果ObservableCollection中只有新的下载,那么下载还没有运行(所以这个下载的TaskPerformingDownload成员还没有运行),在这种情况下,ObservableCollection被序列化得很好,没有任何异常或错误。你能告诉我为什么会出现这种情况吗?这对我来说很重要。

SerializationException:“类型 . . in assembly…未标记为serializa

您正在尝试序列化Stream。这就是灾难的根源:数据流不是数据桶——它们是管道;它们很少以任何有意义的方式序列化,如果有的话。我的建议很简单:不要那样做。事实上,根本不要尝试序列化Downloader ;您应该序列化数据,而不是实现状态。创建一个单独的模型,该模型仅用于序列化,其中包含您希望以最简单、最明显的方式存储的数据。如果要序列化二进制请求/响应:byte[]。等等。

还有:出于多种原因,我强烈建议在几乎所有情况下都不要使用BinaryFormatter

BinaryFormatter。序列化方法文档直接说:

SerializationException在以下情况下抛出:
过程中发生错误序列化,例如如果graph形参中的对象是而不是标记为可序列化

除了不使用问题对象,你什么也做不了。

我甚至不确定为什么你需要System.Net.ConnectStream序列化-它太特定于上下文(机器)了。

你也可以尝试在你的类中实现ISerializableInterface

Stream顾名思义,就是Stream——它只是一个指针,指向一个持续不断的数据流的起点。如果你做过C/c++编程,你应该知道"这是一个灾难的配方"。流不是数据,而是用于读写任意长度数据的管道或套接字。

如果您想要序列化从流中获得的数据,那么首先为数据对象获取数据,特别是POCO - Plain Old CLR object。

例如,

class DownloaderData
{
...
public byte[] ContentData {get;set;}
...
}

和在Downloader类中,应该使用stream将所有数据读入字节数组缓冲区。

将数据和处理函数分离为两个类将使您在不那么复杂的结构中编写更少的代码,从长远来看也更少令人头疼。