Selective serialization with SubSonic generated classes - c#

I've been using SubSonic 2 for a while now, but as I am starting a new project, I'd like to upgrade to 3. In my old project, I used a custom, non-sustainable hack to serialize things for web services. I really would like to find a more elegant solution.
I'm using Mono, so I need to stay within implemented classes, e.g. DataContractSerializer is probably out. Still on ASMX, though would love to upgrade to WCF as soon as the support is solid. Moonlight/Silverlight will be the initial clients. JSON/protobuf in the future...
The standard Xml serializer is opt-out, so I'd need some way to take control of it. Which brings me to IXmlSerializable. I'm rather unfamiliar with SS's templates, but it seems that editing these would allow me to generate the serialization code necessary to not touch the rest of the hierarchy chain. Is this a "good idea"?
I'd love to just use SS's POCO support, but I don't think it supports complex types or arrays.
Other thoughts/options?

IXmlSerializable is IMO more than a little awkward to get right. Note that if you are handling the XmlSerializer code yourself you can override everything at runtime by using the constructor that accepts XmlAttributeOverrides (but if you use this you should cache and re-use the XmlSerializer instance, or it will leak like a sieve).
You briefly mention protobuf; note that protobuf-net (even in v1) allows you to add member-level serialization data at the type level, so you can include that information in a partial class alongside a generated type:
// file 1
partial class GeneratedClass
{
public int Foo { get; set; }
public string Bar { get; set; }
}
// file 2
[ProtoPartialMember(1, "Foo")]
[ProtoPartialIgnore("Bar")]
partial class GeneratedClass {}

Related

Changing method Attributes at runtime

I am trying to serialize objects into xml. I have setup up
public class Foo<t>
{
[XmlElement(ElementName ="test")]
public <t> bar {
get
{
var descriptor = TypeDescriptor.GetProperties(this.GetType())["bar"];
var attrib =(XmlElementAttribute)descriptor.Attributes[typeof(XmlElementAttribute)];
FieldInfo ElementName = attrib.GetType().GetProperty("ElementName")
ElementName.SetValue(attrib, "success");
}
set{}
}
I want to change XmlElement.ElementName at run time but so far have been unsucessfull.
According to this blog you should be able to do it. Also this SO post indicates that I am on the right track.
My Questions are Is what I want to do possible? How do I achieve this?
EDIT:
I want the xml node to be called 'Success' instead of 'test'
The technique in that article only works for .NET components that depend on the TypeDescriptor system, which is a higher level abstraction than raw reflection. XmlSerializer is not one of those components as far as I know.
The closest you can come to "changing attributes at runtime" with respect to XmlSerializer is using XmlAttributeOverrides, but I forget how to use that because I've used it so infrequently. That only allows you to change them for the entire type though, not individual instances as you seem to want. This is partly because XmlSerializer actually compiles a serialization delegate internally that it uses over and over to serialize your type for reasons of performance.
Your best bet is probably to just implement the IXmlSerializable interface to customize the serialization for that particular class. XmlSerializer will honor that interface, and it will allow you to have 100% control over the XML by using XmlReader / XmlWriter. It is more difficult to have to manually write the serialization code, but you have much more control. And you only have to do it for the types in your graph that require custom handling. For an example of using IXmlSerializable see my answer to Override XML Serialization Method.

Using Protobuf-Net in an RPG

To make a long story short I am currently writing an RPG using WPF and C#. I recently decided to implement(or try to at least) Protobuf-Net as the BinaryFormatter class just does not give the performance as Protobuf.
Basically, due to a severe lack of documentation I have been trying to put bits and pieces together that google has shown me. My current problem is that I cannot get any inherited classes to serialize using a generic function. I require this as the bulk of my work is an API so any new types that are created can be serialized.
An example of what I require,
public sealed class SomeClass
{
private RuntimeTypeModel protobuf = RuntimeTypeModel.Create();
public T DeepCopy<T>(T template) where T : IsSomeBaseClass
{
Type templateType = template.GetType();
this.protobuf.Add(templateType, true);
// Get inherited classes.
//
//
return (T)this.protobuf.DeepClone(template);
}
}
Is this even possible with Protobuf-Net? If someone could give me a push in the right direction that would be much appreciated.

Serializing extra elements into a IDictionary instance with MongoDb's C# driver

I have recently tried to play around with MongoDb's serialization. Basically, I am trying to use the driver's serializer to store my models while at the same time attempting to avoid any dependencies between my well-known model classes and 10gen's MongoDb C# driver (v1.2, if it matters).
This, by itself, is no issue. What is problematic however is that there can be (dynamic) information stored for some of the objects side by side to well-known elements. I could do this by using the [BsonExtraElements] attribute, but as I said above, I am trying to avoid coupling my models to MongoDb. Model classes that can have this behaviour, implement a certain interface:
public interface IHaveMoreInformation
{
IDictionary<string, object> Extra { get; set; }
}
For this, I have tried to write a custom convention that gets registered in the convention profile at application startup:
public sealed class ExtraElementsConvention : IExtraElementsMemberConvention
{
#region Implementation of IExtraElementsMemberConvention
public string FindExtraElementsMember(Type type)
{
return typeof(IHaveMoreInformation).IsAssignableFrom(type) ? "Extra" : null;
}
#endregion
}
This is where the problem starts. The driver expects a BsonDocument property (again, I don't want to couple). I was hoping there is a way to work around this and serialize this additional information into an IDictionary<string,object> instance.
I am helpful for any ideas to achieve this.
Thanks in advance,
Manny
After looking into the driver's inner workings, I've decided to take the matter to mongoDB's issue tracking system. Until now (1.3.1), the driver seems very keen on only accepting a BsonDocument property for extra elements; this would effectively couple models to types declared by the driver, which is a bit of a pain when you decide to switch technologies.
The issue is currently being tracked here:
https://jira.mongodb.org/browse/CSHARP-395
Hopefully this improvement will find its way into 1.4 and help people looking to achieve something similar in the future.

Using the generated .net classes to extend own classes. HowTo?

I used the OWLGrinder to create the assembly and imported the library into my project. That works fine. Now I want to write my own set of classes. Therefore I extended these with the equivalent of the assembly. But it just doesn't work.
The ontology holds a class named ManagementObject.
I created another Class (C#) called RealWorldObject:
public class RealWorldObject : ManagementObject
{
public RealWorldObject(string uri) : base(uri) { }
public RealWorldObject(string uri, RdfDocument rdfdocument) : base(uri, rdfdocument) { }
public RealWorldObject(RdfDocument rdfdocument) : base(rdfdocument) { }
public String getClassName()
{
return this.OwlClassName;
}
public static RdfDocument addRealWorldObjectIndividualt(RdfDocument rdfDocument)
{
Vehicle vehicle = new Vehicle("vehicle1", rdfDocument);
FixedEvent fxE1 = new FixedEvent("autoGekauft", rdfDocument);
fxE1.agent = new xmlns.com.foaf._01.Person("robert", rdfDocument);
vehicle.hasFixedEvent = fxE1;
return rdfDocument;
}
Which leads to the error:
ObjectManagement.Object.RealWorldObject does declare one (and only one) OwlClassAttribute. This is an implementation bug of the plugin.
How else should I extend the generated classes by the OWLGrinder.
Thx it is a long time ago that I used C#, so I'm kind of rusty.
The auto-generated classes produced by OwlGrinder.exe have not been designed for inheritance in mind. I am not saying it is wrong, it is just not designed for that. The auto-generated classes contain plenty of metadata defined as class attributes and inheritance hides all of that. The infrastructure counts on the presence of these attributes and if they are hidden, you get these runtime error messages.
Using Visual Studio Object Browser, take a look of the attributes over the auto-generated classes. OwlClassAttribute, SubClassOfAttribute, LightVersionAttribute are certainly mandatory. You may simply copy/paste the class attributes of ManagementObject on the top of your RealWorldObject class. I assume, it will work. But again, you might bump into additional show stoppers, as you do not follow the default routes ROWLEX has been designed for. This is a bit living on the edge :)
Instead of inheritance, you might consider reverse engineering your auto-generated assembly to C# using Reflector or other tools. Having the source code in your hand, you may modify the generated classes directly. You might make your ManagementObject class partial, and implement your additional methods in a separate file.

C# - what attributes to use to support serializing using both XMLSerializer and DataContractSerializer?

I have some simple POCO object:
public class ProductCategoryDTO
{
public string Name { get; set; }
public DateTime ModifiedDate { get; set; }
}
As sometimes field order is important (for example, if sending to Infopath forms), I need to keep element order when serializing.
And now I am confused, what attributes I should use for the class and for each field. I know that:
DataContractSerializer uses [DataContract] and [DataMember(Order = n)]
XMLSerializer uses [Serializable] and [XmlElementAttribute(Order = n)].
Then what attributes to use if I want to support both XMLSerializer and DataContractSerializer, so it can used in both WCF or ASP. web services?
Strictly speaking, you don't need to use any attributes for either ;-p It used to be that DataContractSerializer would demand [DataContract] / [DataMember] (and they absolutely should be used), but you can use it without (but it then acts in a very dubious way similar to BinaryFormatter). Likewise, XmlSerializer doesn't need anything unless you want to control things. There are, however, some differences you should note:
XmlSerializer demands (and uses) a public parameterless constructor; DataContractSerializer doesn't use a constructor (at all). So watch out for that, and don't (for WCF) rely on code in the ctor - if you have necessary init code, use a serialization callback for WCF.
XmlSerializer demands either public fields (yeuch) or public properties with both get and set (even for lists); DataContractSerializer will happily work against private members, properties with (for example) a public get and private set, and collections without a `set (as long as your type initialises it).
XmlSerializer demands public types; IIRC DataContractSerializer is less fussy
So yes; you can support both serializers, and you can add any number of attributes in parallel, but note the above if you want total compatibility.
Another option is to just use XmlSerializer; you can configure WCF to use XmlSerializer by using [XmlSerialzerFormat]. Both options support inheritance, via [XmlInclude] and [KnownType].
Finally, note that if you implement IXmlSerializable, this takes precedence over either, but it hard to get right. Don't do that unless you have to.
I don't see any reason why you couldn't put both attributes on the class and member properties, if you really must. Doesn't look nice, but if it works for you, that's just fine!
[DataContract(Namespace="....")]
[XmlType]
public class ProductCategoryDTO
{
[DataMember(Order=1)]
[XmlElementAttribute(Order=1)]
public string Name { get; set; }
[DataMember(Order=2)]
[XmlElementAttribute(Order=2)]
public DateTime ModifiedDate { get; set; }
}
Order of XML elements should be dictated by the WSDL and you don't need to worry about it. Starting from .NET 3.5 SP1 you no longer need to use DataContractAttribute and DataMemberAttribute. The serializer will automatically include all public properties. As far as XmlSerializer is concerned, the SerializableAttribute has no effect. This attribute is used for binary serialization by the BinaryFormatter. So to resume, you could leave the class as a POCO, expose it either in WCF or ASP.NET webservice and leave the clients consume it according to the WSDL.

Categories