Question

Je construis un cadre de notification et que je suis sérialisation et désérialisation une classe de base, à partir de laquelle toutes les classes que je veux envoyer dérivera.

Le problème est que le code compile, mais lorsque je tente en fait de sérialisation cette classe de base je reçois une erreur disant

  

System.Runtime.Serialization.SerializationException: Type 'Xxx.DataContracts.WQAllocationUpdate' à l'Assemblée 'Xxx.DataContract, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' est pas marqué comme sérialisable

.

Voici le code:

public class WCallUpdate : NotificationData
{
    private string m_from = "";
    [DataMember]
    public string From
    {
        get { return m_from; }
        set { m_from = value; }
    }
    private WCall m_wCall = new WCall();
    [DataMember]
    public WCall Call
    {
        get { return m_wCall; }
        set { m_wCall = value; }
    }
}

Le DataContract pour la notification est:

/// <summary>
/// Basic class used in the notification service
/// </summary>
[DataContract]
public class NotificationData
{
}

/// <summary>
/// Enum containing all the events used in the application
/// </summary>
[DataContract]
public enum NotificationTypeKey
{
    [EnumMember]
    Default = 0,
    [EnumMember]
    IWorkQueueServiceAttributionAddedEvent = 1,
    [EnumMember]
    IWorkQueueServiceAttributionUpdatedEvent = 2,
    [EnumMember]
    IWorkQueueServiceAttributionRemovedEvent = 3,
}

Le code utilisé pour sérialiser les données sont:

    #region Create Message
    /// <summary>
    /// Creates a memoryStream from a notificationData
    /// note: we insert also the notificationTypeKey at the beginning of the
    /// stream in order to treat the memoryStream correctly on the client side
    /// </summary>
    /// <param name="notificationTypeKey"></param>
    /// <param name="notificationData"></param>
    /// <returns></returns>
    public MemoryStream CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter formatter = new BinaryFormatter();
        try
        {
            formatter.Serialize(stream, notificationTypeKey);
            formatter.Serialize(stream, notificationData);
        }
        catch (Exception ex)
        {
            Logger.Exception(ex);
        }
        return stream;
    }
    #endregion

Lorsque je tente de créer un message:

WCallUpdate  m_wCallUpdate = new WCallUpdate();
NotificationTypeKey  m_notificationTypeKey = new NotificationTypeKey.Default;
CreateMessage(notificationTypeKey , wCallUpdate );

Je suis l'erreur suivante:

System.Runtime.Serialization.SerializationException: Type 'Xxx.DataContracts.WCall' in Assembly 'Xxx.DataContract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
   at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
   at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
   at Xxx.Notification.NotificationMessageFactory.CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData) in Xxx.Notification\NotificationCenter.cs:line 36

Si je mets le drapeau Serializable avant la DataContract on ne résout pas le problème.


merci pour la réponse rapide. Désolé que j'ai oublié de mettre le code du NotificationData (modifié dans le poste principal)

J'ai essayé de mettre l'attribut Serializable à la fois classe sans succès: (

#region NotificationData
/// <summary>
/// Basic class used in the notification service
/// </summary>
[Serializable]
[DataContract]
public class NotificationData
{
}
#endregion

et

[Serializable]
public class WCallUpdate : NotificationData
{
    private string m_from = "";
    [DataMember]
    public string From
    {
        get { return m_from; }
        set { m_from = value; }
    }
    private WCall m_wCall = new WCall();
    [DataMember]
    public WCall Call
    {
        get { return m_wCall; }
        set { m_wCall = value; }
    }
}

** Edit: ** mea culpa après tout :) Vous étiez tous les deux. J'ai oublié de passer le [Serializable] Confier à toute la classe des enfants. Après la mise à jour et la compilation, je ne suis plus l'exception. merci à vous deux pour vos réponses:)


@Marc Gravel: En fait, je pensais à ce que vous suggérez, et créé le DataContractSerializer suivant, mais je ne suis pas sûr que cela fonctionne? Comme mes classes utilisent d'autres classes? le gros problème avec le DataContractSerializer est que vous devez spécifier le type de l'objet que vous souhaitez sérialiser, et que ma classe utilise autre classe comme champs privés, qui pourraient causer un problème droit?

#region DataContractSerializer
        /// <summary>
        /// Creates a Data Contract Serializer for the provided type. The type must be marked with
        /// the data contract attribute to be serialized successfully.
        /// </summary>
        /// <typeparam name="T">The type to be serialized</typeparam>
        /// <returns>A data contract serializer</returns>
        public static DataContractSerializer CreateDataContractSerializer<T>() where T : class
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(T));
            return serializer;
        }
        #endregion
Était-ce utile?

La solution

mettre [Serializable] au sommet de la classe. Sérialisable n'est pas nécessairement hérité soit AFAIK. ce qui signifie, même si la classe de base a [Serializable], vous devez encore sur la classe descendante.

Autres conseils

Je suis très confus pourquoi vous utilisez BinaryFormatter avec un contrat de données. Il serait normal d'utiliser DataContractSerializer ici ... la logique est alors similaire à l'utilisation [Serializable], sauf que vous avez besoin [DataContract], et il sérialise les nommés membres ([DataMember]), plutôt que les champs qui BinaryFormatter travaille.

En fait, pour de nombreuses raisons ( tels que friabilité ) Je suggère de passer à DataContractSerializer, d'autant plus que cela semble être votre intention. Ou si vous voulez une forme binaire plus compact, protobuf-net peut être utile ( plus est portable entre plates-formes, aussi).

En aparté - vous n'avez pas besoin [DataContract] sur enums -. Il ne fait pas de mal, mais ne fait pas beaucoup, soit

Pour obtenir une classe pour être marque sérialisable avec l'attribut sérialisable ou dérivé à partir MarshalByRefObject.

Vous dérivez NotificationData, est-il sérialisable alors?

Vérifiez aussi: quand les classes de données sérialisables sont mis dans un ensemble vérifier votre projet ou référence de fichier dans Visual Studio pour être sûr que vous obtenez le bon.

Aussi, si vous signez l'assemblage et le mettre dans le GAC, assurez-vous que l'assemblage dans le GAC est la bonne! J'ai rencontré beaucoup de temps parce que je la consommation debugsessions mis à jour l'ensemble de la version 1.0.0.0 à 1.0.0.1 et oublié de remplacer l'ancien dans le GAC. Assemblées dans le GAC sont chargés avant les assemblées locales, gardez cela à l'esprit. Et ... la mise en forme binaire est très stricte depuis les dernières versions d'assemblage.

J'ai créé un XList de classe pour accomplir ceci:

AA D1=new AA(); //Derived type
BB D2=new BB(); //Derived type 
CC D3=new CC(); //Derived type 
X D4=new X(); //Base Class 

XList<X> AllData=new XList<X>(); 
AllData.Add(D1); 
AllData.Add(D2); 
AllData.Add(D3); 
AllData.Add(D4); 
// ----------------------------------- 
AllData.Save(@"C:\Temp\Demo.xml"); 
// ----------------------------------- 
// Retrieve data from XML file 
// ----------------------------------- 
XList<X> AllData=new XList<X>(); 
AllData.Open(@"C:\Temp\Demo.xml"); 
// -----------------------------------

Plus de détails peuvent être trouvés .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top