I have the following code files:
public interface IMod
{
string Name { get; set; }
string Description { get; set; }
bool Enabled { get; set; }
List<IClassFile> ClassFiles { get; set; }
}
public interface IClassFile
{
string Path { get; set; }
string FileName { get; set; }
bool Enabled { get; set; }
}
public class ClassFile : IClassFile
{
public string Path { get; set; }
public string FileName { get { return System.IO.Path.GetFileName(Path); } }
public bool Enabled { get; set; }
....
}
public class ZippedMod : IMod
{
public string Name { get; set; }
public string Description { get; set; }
public bool Enabled { get; set; }
public List<IClassFile> ClassFiles { get; set; }
....
}
public class ConfigurationBlock
{
public List<IMod> Mods { get; set; }
....
}
Throughout the course of my program, I add a few ZippedMods to the ConfigurationBlock, but now I want to serialize them. I tried doing:
using (var stream = new StreamWriter("config.xml"))
{
var ser = new XmlSerializer(typeof(ConfigurationBlock));
ser.Serialize(stream, configBlock);
}
But I get this error:
There was an error reflecting type 'MinecraftModManager.ConfigurationBlock'.
|-Inner Exception:
Cannot serialize member 'MinecraftModManager.ConfigurationBlock.Mods' of type 'System.Collections.Generic.List`1[[MinecraftModManager.IMod, MinecraftModManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]', see inner exception for more details.
|-Inner Exception:
Cannot serialize member MinecraftModManager.ConfigurationBlock.Mods of type MinecraftModManager.IMod because it is an interface.
Help?
You can't serialize an interface due to the abstract nature of them. Lots of concrete types can implement the same interface, so it creates an ambiguity. You must use a concrete type.
You can't serialize an interface, only a concrete class with the default XmlSerializer. You may be able to implement IXmlSerializable to override this behavior.
Related
I have a xml format in following format mentioned below:-
<JobRunnerPluginStaus PluginName="JobRun">
<JobstepStatus>
<JobStatus StepNumber="1" StepStatus="Done"/>
<JobStatus StepNumber="2" StepStatus="Started" />
</JobstepStatus>
</JobRunnerPluginStaus>
I want to get it converted to following class object using Generics and Reflection.
I want to convert the attributes to simple type(PluginName) and the nested property to a list object(JobstepStatus).
public class JobRunnerPluginStaus
{
public List<JobStatus> JobstepStatus { get; set; }
public string PluginName { get; set; }
}
public class JobStatus
{
public int StepNumber { get; set; }
public string StepStatus { get; set; }
}
I mostly use sites like: https://xmltocsharp.azurewebsites.net/
to do the dirty work for me.
Below is how your class hierarchy would look like:
[XmlRoot(ElementName="JobStatus")]
public class JobStatus {
[XmlAttribute(AttributeName="StepNumber")]
public string StepNumber { get; set; }
[XmlAttribute(AttributeName="StepStatus")]
public string StepStatus { get; set; }
}
[XmlRoot(ElementName="JobstepStatus")]
public class JobstepStatus {
[XmlElement(ElementName="JobStatus")]
public List<JobStatus> JobStatus { get; set; }
}
[XmlRoot(ElementName="JobRunnerPluginStaus")]
public class JobRunnerPluginStaus {
[XmlElement(ElementName="JobstepStatus")]
public JobstepStatus JobstepStatus { get; set; }
[XmlAttribute(AttributeName="PluginName")]
public string PluginName { get; set; }
}
I'm trying to create some interfaces. The IReportSection object will have one string and a collection of items, which could be different depending on what we're working with. Do I need to make it generic?
The IReport will have one string and a collection of IReportSection.
Here's how I'm trying to define it now.
public interface IReport
{
string ReportName { get; set; }
ICollection<IReportSection> ReportSections { get; }
}
public interface IReportSection
{
string ReportSectionName { get; set; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection ReportItems { get; set; }
}
And my models:
pulic class ProjectSubmissionViewModel
{
public int ProjectSubmissionId { get; set; }
public string SubmissionTitle { get; set; }
}
pulic class AffiliateViewModel
{
public int AffiliateId { get; set; }
public string AffiliateName { get; set; }
}
This is how I'm trying to use it in code:
public class ChapterAffiliates : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Affiliates"; } }
public ICollection<AffiliateViewModel> ReportItems { get; set; }
}
public class ChapterTitles : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Titles"; } }
public ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }
}
public class SubmissionListViewModel : IReport
{
public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }
public ICollection<AffiliateViewModel> Affiliates{ get; set; }
public string ReportName { get; set; }
public ICollection<IReportSection> ReportSections
{
get
{
var affiliateSection = new ChapterAffiliates
{
ReportItems = Affiliates
};
var titleSection = new ChapterTitles
{
ReportItems = Submissions.Where(s => s.SubmissionTitle.Contains("SomePhrase")).ToList()
};
var sections = new List<IReportSection> { {subSection}, {titleSection} };
return sections;
}
}
}
I'm not sure how to best define this. I'm pretty sure I've done it before, but it's not coming to me.
Are the type parameters for TRType all the same within a certain report? E.g. will you have report sections with different report types in them?
If all types within a report are the same, the solution is relatively simple:
public interface IReport<T> { ... }
If this is not the case - you'll have to do something different, e.g:
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase<TRType> : IReportSection {
...
}
This allows you to put different underlying types in the ReportSections collection related to the report. You'll have to do some more work to get the exact information that you need out of each report section.
Using some tutorials on the web, I created a metadata class for my needs using the MEF in C#
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ActionMetadataAttribute : Attribute
{
public bool HasSettingsDialog { get; set; }
public bool UseThreadedProcessing { get; set; }
}
public interface IActionMetadata
{
[DefaultValue(false)]
bool HasSettingsDialog { get; }
[DefaultValue(false)]
bool UseThreadedProcessing { get; }
}
I've got different kind of plugin types, so there is e. g. IHandlerMetadata and HandlerMetadataAttribute. Now I load it via the Lazy helper to allow strictly typed metadata.
[ImportMany(typeof(IActionPlugin))]
private IEnumerable<Lazy<IActionPlugin, IActionMetadata>> _plugins = null;
public ActionManager()
{
var catalog = new DirectoryCatalog(".");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
foreach (var contract in _plugins)
{
Debug.WriteLine(contract.Metadata.HasSettingsDialog);
}
}
Works perfectly. Now, I also like to have some information about the plugins. So I've created an PluginInformationAttribute.
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class PluginInformationAttribute : Attribute
{
public string Name { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Url { get; set; }
public string Contact { get; set; }
public string Description { get; set; }
public Version Version { get; set; }
}
The question is now: how can I access this attribute for example in the for loop in the above code snippet? Is there any way or is my design wrong? I don't want to include the PluginInformation stuff to IActionMetadata because I'd like to use it on different types of plugins, e. g. on the IHandlerMetadata.
If you specify the type of your exporting class as a property of ActionMetadataAttribute, then you can access every attribute of the class by reflection with GetCustomAttributes method
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ActionMetadataAttribute : Attribute
{
public bool HasSettingsDialog { get; set; }
public bool UseThreadedProcessing { get; set; }
public Type ClassType { get; set; }
}
var attributes = contract.Metadata.ClassType.GetCustomAttributes(typeof(PluginInformationAttribute), true)
We are currently developping an application using XmlSerializer from the .NET framework.
Here is the structure of our classes:
[XmlInclude(typeof(TimeLineMediaClass))]
[XmlInclude(typeof(ImageMediaClass))]
public abstract class MediaClass
{
public string filename { get; set; }
public string maintitle { get; set; }
public string subtitle { get; set; }
public Type typeOfMedia { get; set; }
}
[XmlInclude(typeof(AudioMediaClass))]
[XmlInclude(typeof(VideoMediaClass))]
public abstract class TimeLineMediaClass : MediaClass
{
public string title { get; set; }
public TimeSpan length { get; set; }
public string genre { get; set; }
}
public class AudioMediaClass : TimeLineMediaClass
{
public string artist { get; set; }
}
public class VideoMediaClass : TimeLineMediaClass
{
public string director { get; set; }
public string studios { get; set; }
}
public class ImageMediaClass : MediaClass
{
public string width { get; set; }
public string height { get; set; }
}
Several medias of different types are added to a List, and this is what we want to serialize.
This is how the serializer is instanciated:
XmlSerializer serializer = new XmlSerializer(typeof(List<MediaClass>));
But when we launch the program and try to serialize, an exception is thrown, stating that "AudioMediaClass was not expected".
EDIT: A few things were missing in the code I have provided. I have added some corrections in it ; more details in comments.
You need to decorate your MediaClass class with
[XmlInclude(typeof(TimeLineMediaClass))]
In your example above, you have the casing wrong on TimelineMediaClass meaning the sample won't compile for me. If you remove it, or if you do have a different class with this name, you'll get the error you describe.
Once you correct the casing, it should work - it does for me [noting that I also had to remove the attribute for ImageMediaClass which also doesn't exist in your sample].
I copy your code, and run removing [XmlInclude(typeof(ImageMediaClass))] and correcting this attribute: [XmlInclude(typeof(TimelineMediaClass))] to [XmlInclude(typeof(TimeLineMediaClass))]. Now, running your code, it works fine.
I have these classes:
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
public class StringCustomField:CustomField
{
public String Value { get; set; }
public Int32 MinLenght { get; set; }
public Int32 MaxLenght { get; set; }
public StringCustomField()
{
this.Type = FieldType.String;
}
}
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List<CustomField>();
}
When I try to transfer CustomGroup through my webservice I get this error:
The remote server returned an error: NotFound
Serialization is failing when C# tries to transfer my StringField through my CustomField.
What am I doing wrong?
Marc Gravel tell me to do that and i understand the solution but some thing is wrong, no effects, cath the same error!! , help!!
[XmlInclude(typeof(StringCustomField))]
[XmlInclude(typeof(IntegerCustomField))]
[XmlInclude(typeof(BooleanCustomField))]
[XmlInclude(typeof(ListCustomField))]
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
If you are sending subclasses as xml, you will need [XmlInclude]:
[XmlInclude(typeof(StringCustomField))]
public abstract class CustomField
{...}
You can add multiple [XmlInclude(...)] markers for any other subclasses in the model.
List<CustomField> will serialize and deserialize to a CustomField[] if you're using a web service, won't it?
use
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List< StringCustomField >();
}
instead
If i understand you correctly, you should
1. connect your web service to your app
2. use the namespace of the WS, so all the classes will be used from the Proxy
i don't think that the local class will be understood by the remote web serivce correctly, even if you're using the same assembly on both parties