2011-12-12 20 views
5

Ho un'applicazione host basata su plugin. Le sue impostazioni sono descritte come un contratto dati:Contratti dati: ignora i tipi sconosciuti in fase di deserializzazione

[DataContract(IsReference = true)] 
public class HostSetup 
{ 
    [DataMember] 
    public ObservableCollection<Object> PluginSetups 
    { 
     get 
     { 
      return pluginSetups ?? (pluginSetups = new ObservableCollection<Object>()); 
     } 
    } 
    private ObservableCollection<Object> pluginSetups;   
} 

Qualsiasi plug-in ha il proprio tipo di impostazioni. E. g .:

[DataContract(IsReference = true)] 
public class Plugin1Setup 
{ 
    [DataMember] 
    public String Name { get; set; } 
} 

e

[DataContract(IsReference = true)] 
public class Plugin2Setup 
{ 
    [DataMember] 
    public Int32 Percent { get; set; } 
    [DataMember] 
    public Decimal Amount { get; set; } 
} 

In fase di esecuzione, l'utente ha configurato host e plugin come un modo:

 var obj = new HostSetup(); 
     obj.PluginSetups.Add(new Plugin1Setup { Name = "Foo" }); 
     obj.PluginSetups.Add(new Plugin2Setup { Percent = 3, Amount = 120.50M }); 

Quindi, la mia domanda ha salvato la sua impostazioni tramite DataContractSerializer. I tipi di plugin sono stati passati come tipi noti al costruttore del serializzatore.

La domanda.
L'utente rimuove fisicamente l'assieme con "Plugin2" e quindi avvia la mia applicazione.
Quindi, quando l'host riceve un elenco di plugin disponibili, non sa nulla dell'istanza "Plugin2Setup" serializzata.

Desidero ignorare questa istanza e consentire all'utente di lavorare senza impostazioni "Plugin2".
C'è un modo elegante per farlo?
Posso memorizzare le impostazioni di plugin come contratti dati serializzati in stringhe:

public ObservableCollection<String> PluginSetups 

ma non è a portata di mano e brutto.

Modifica 1
Il problema è come deserializzare HostSetup istanza e ignorare serializzato esempio Plugin2Setup.

Edit 2
mia soluzione attuale è:

[DataContract(IsReference = true)] 
public class PluginSetupContainer 
{ 
    [DataMember] 
    private String typeName; 
    [DataMember] 
    private String rawData; 

    [OnSerializing] 
    private void OnSerializing(StreamingContext context) 
    { 
     if (SetupParameters != null) 
     { 
      using (var writer = new StringWriter()) 
      using (var xmlWriter = new XmlTextWriter(writer)) 
      { 
       var setupParametersType = SetupParameters.GetType(); 
       var serializer = new DataContractSerializer(setupParametersType); 
       serializer.WriteObject(xmlWriter, SetupParameters); 

       xmlWriter.Flush(); 

       typeName = setupParametersType.AssemblyQualifiedName; 
       rawData = writer.ToString(); 
      } 
     } 
    } 

    [OnSerialized] 
    private void OnSerialized(StreamingContext context) 
    { 
     ClearInternalData(); 
    } 

    [OnDeserialized] 
    private void OnDeserialized(StreamingContext context) 
    { 
     if (!String.IsNullOrEmpty(typeName) && !String.IsNullOrEmpty(rawData)) 
     { 
      var setupParametersType = Type.GetType(typeName, false); 
      if (setupParametersType != null) 
      { 
       using (var reader = new StringReader(rawData)) 
       using (var xmlReader = new XmlTextReader(reader)) 
       { 
        var serializer = new DataContractSerializer(setupParametersType); 
        SetupParameters = serializer.ReadObject(xmlReader); 
       } 
      } 

      ClearInternalData(); 
     } 
    } 

    private void ClearInternalData() 
    { 
     typeName = null; 
     rawData = null; 
    } 

    public Object SetupParameters { get; set; } 
} 

[DataContract(IsReference = true)] 
public class HostSetup 
{ 
    [DataMember] 
    public ObservableCollection<PluginSetupContainer> PluginSetups 
    { 
     get 
     { 
      return pluginSetups ?? (pluginSetups = new ObservableCollection<PluginSetupContainer>()); 
     } 
    } 
    private ObservableCollection<PluginSetupContainer> pluginSetups; 
} 

Può essere è terribile, ma funziona. :)

risposta

0

penso che idealmente si dovrebbe avere qualcosa sulle linee di

[DataContract(IsReference = true)] 
[MyPluginCustomAttribute] 
public class Plugin1Setup 
{ 
} 

e quando voi l'applicazione di carichi si dovrebbe inizializzare obj.PluginSetups utilizzando la riflessione sulla base di MyPluginCustomAttribute in modo che solo le assemblee che sono presenti i loro tipi registrati. Quindi non avrai il problema della mancanza di assemblaggi. È inoltre possibile utilizzare Managed Extensibility Framework (MEF) invece della propria MyPluginCustomAttribute

+0

La domanda non è "come ricevere una lista di plugin disponibili e dei loro tipi di impostazioni" o "come inizializzare le impostazioni del plugin". Il problema è la deserializzazione del grafo degli oggetti che contiene tipi sconosciuti. – Dennis

Problemi correlati