Tengo una aplicación de host basada en complementos. Su configuración se describe como un contrato de datos:Contratos de datos: Ignorar tipos desconocidos en la deserialización
[DataContract(IsReference = true)]
public class HostSetup
{
[DataMember]
public ObservableCollection<Object> PluginSetups
{
get
{
return pluginSetups ?? (pluginSetups = new ObservableCollection<Object>());
}
}
private ObservableCollection<Object> pluginSetups;
}
Cualquier plugin tiene su propio tipo de configuración. Ej .:
[DataContract(IsReference = true)]
public class Plugin1Setup
{
[DataMember]
public String Name { get; set; }
}
y
[DataContract(IsReference = true)]
public class Plugin2Setup
{
[DataMember]
public Int32 Percent { get; set; }
[DataMember]
public Decimal Amount { get; set; }
}
En tiempo de ejecución, el usuario ha configurado anfitrión y plugins de tal manera:
var obj = new HostSetup();
obj.PluginSetups.Add(new Plugin1Setup { Name = "Foo" });
obj.PluginSetups.Add(new Plugin2Setup { Percent = 3, Amount = 120.50M });
Entonces, mi solicitud ha salvado su configuraciones a través de DataContractSerializer. Los tipos de complementos se pasaron como tipos conocidos al constructor del serializador.
La pregunta.
El usuario elimina físicamente el ensamblaje con "Plugin2" y luego inicia mi aplicación.
Por lo tanto, cuando el host recibe una lista de complementos disponibles, no sabe nada acerca de la instancia "Plugin2Setup" serializada.
Quiero ignorar esta instancia y dejar que el usuario trabaje sin la configuración de "Plugin2".
¿Hay alguna manera elegante de hacer esto?
puedo guardar los ajustes de los complementos como contratos de datos serializados en cadenas:
public ObservableCollection<String> PluginSetups
pero no es práctico y feo.
Editar 1
El problema es cómo deserializar HostSetup instancia e ignorar ejemplo Plugin2Setup serializado.
Editar 2
Mi solución actual es:
[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;
}
Puede ser que es terrible, pero funciona. :)
La pregunta no es "la forma de recibir una lista de plugins disponibles y sus tipos de ajustes" o "cómo inicializar la configuración de plug-in". El problema es la deserialización del gráfico de objetos que contiene tipos desconocidos. – Dennis