How to properly migrate from WCF DatacontractSerializer to Protobuf-net? - c#

We have a huge application with a lot of classes. We are currently porting this .net application to IPad with Monotouch. We have some problems with the DataContractSerializer and we would like to use Marc Gravell's protobuf-net serializer.
The communication between the client and the server is managed by a WCF Service.
A WCF service is made of one Interface exposed to the client and the server, and one implementation of this interface on the server.
The interface looks like that:
[ServiceContract]
public interface IMyService
{
[OperationContract]
SomeObject MyFunction(SomeObject myObject);
}
The server side implementation looks like that:
[ServiceBehavior(...)]
public class MyService
{
public SomeObject MyFunction(SomeObject myObject)
{
}
}
Our classes looks like that:
[DataContract]
public class MyClass
{
[DataMember]
public int SomeProp {get; set;}
[OnSerialized]
public void OnSerialized(StreamingContext context)
{
}
}
So here are my questions:
What would be the changes to do to my classes, wcf interface and wcf implementation.
How would I replace the default WCF DataContractSerializer to the Protobuf Serializer.
Please note that on monotouch, I only have access to Protobuf and Protobuf.Meta namespaces.
[EDIT]
I found a way to swap the serializer runtime:
Custom WCF DataContractSerializer
The above solution uses the DataContractSerializerOperationBehavior. Does Protobuf-net provides such behavior?

In all honesty, I am unfamiliar with the WCF options available to you in monmotouch; they are very different between regular .NET and Silvelight, for example - and I see no reason to assume that monotouch has the ability to swap serializer at runtime (which "full" .NET does, at least under the MS version). This makes it hard to do the transition silently, as we can't wrestle control from DataContractSerializer.
As such, IMO the simplest option is to seize control of the data manually, and send raw byte[] - ideally with MTOM encoding enabled if monotouch can do that. Then once you have your byte[] the world is your mollusc, as they say.
Re changes to your types... well, MyFunction() is an oddity, in that it doesn't transfer any data, so I'm not sure what you want me to suggest on that one. With MyClass, all it needs is a unique number (unique within the type, not globally) per member, i.e.
[DataContract]
public class MyClass
{
[DataMember(Order=1)] // <==== this provides the 1 as the key
public int SomeProp {get; set;}
// see below re callback
}
You also have a serialization callback; these are fully supported, but it expects to find a familiar pattern - StreamContext is not one that I know of (although it should work with StreamingContext and a few others).
Finally, note that by default protobuf-net executes the constructor, which is different to DataContractSerializer. If you desire, you can suppress this via:
[DataContract(SkipConstructor=true)]
public class MyClass {...}
If I've missed the intent here, let me know.
Note there are also ways of doing all the configuration without changing/adding any attributes if you prefer.

Related

ServiceRemoting V2_1 still throwing serialization exception when working with interface return types

over the last few days, I tried to equip my application with the service remoting IPC stack. I initially implemented the V2 version, but just noticed thanks to this post (https://github.com/Azure/service-fabric-issues/issues/735) that that does not support returning interfaces.
So, I just now made the switch to V2_1.
However, I still face this problem:
One or more errors occurred. (Type 'MooMed.Core.DataTypes.Session.SessionContext' with data contract name 'SessionContext:http://schemas.datacontract.org/2004/07/MooMed.Core.DataTypes.Session' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.)'
This is the service method that is being called on the endpoint:
[CanBeNull]
public Task<ISessionContext> GetSessionContext(int accountId):
The involved classes/intefaces look like this:
public interface ISessionContext
{
Account Account { get; set; }
}
[DataContract]
public class SessionContext : ISessionContext
{
[DataMember]
public Account Account { get; set; }
}
Also, as I mentioned, I changed my remoting version from V2 to V2_1 just now, so this is added to the Service class which contains the GetSessionContext method:
[assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2_1, RemotingClientVersion = RemotingClientVersion.V2_1)]
So, according to the docs (https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting#use-the-remoting-v2-interface-compatible-stack) I should now be fully equipped to have everything working properly.
The only thing I see myself doing differently than the tutorial is how I declare the endpoint listeners. I'm doing this via FabricTransportServiceRemotingListener like this:
public static ServiceReplicaListener CreateTypedListener([NotNull] IService service)
{
return new ServiceReplicaListener(context => new FabricTransportServiceRemotingListener(context, service),
$"I{service.GetType().Name}");
}
However, I don't see how this could be the culprit, as the request comes in properly and I don't think declaring endpoints does necessarily interfere with how responses are serialized.
So, what am I doing wrong here?
The DataContractSerializer can't serialize an interface. (see how to mark an interface as DataContract in WCF).
However, you can write your own custom serializer to achieve this. From that article you posted at the bottom are instructions on how to do this. You can also look at my example of implementing protobuf-net here:
https://github.com/mikeruhl/Frenetik.Fabric.Remoting.Protobuf
My example should not be used in production. It's a work in progress and there are zero tests written for it at the moment.

How to send c# objects with method implementation over the network

First of all, the requirement : I need to send .net objects over the network. Here is a basic structure of the class -
class something : somethingelse
{
public int count { get; set; }
public List<object> items { get; set; }
public something(string name)
{
//some initialization
}
public object Evaluate(string type)
{
//some logic
}
}
The something class have many different implementation on the server, all derived from an Interface (hence, they have same structure). However, in each of them, the logic inside the Evaluate method changes. Client application have no idea about the implementations beforehand. What we need is that server will send an object to the client, based on an identifier in the client request, and client will use that object to evaluate the data further.
What I already tried:
Basic .net serialization : It seems they do serialize only the state of the object (data members), not the actual object. To use the methods, I need to have the DLL referenced at the client-side. But as I mentioned, client should have no idea about the implementations beforehand.
.NET remoting : I believe this has become an obsolete tech. I would not prefer to build a whole new app based on it.
WCF : I could not find if it fits in, for the same reason as #1
gRPC with Protocol Buffer : I did look into it specifically because it seems to be faster (and we have plans to create large objects). However, I could not figure out a similar way to serialize a whole object, instead of only data members.
Any help any any direction would be greatly appreciated.

creating private data members in WCF service

Is it a good idea to create private data members in WCF service and if it is a good practice then when/where we initilize these member variable as the client is only calling methods of the service.
Use your data contracts merely as DTO's, and extend these in the code that does the processing of the data.
Something like this:
[DataContract]
public class WCFDataClass
{
[DataMember]
public String Foo { get; set; }
}
// Your class, used for internal processing
class MyWCFDataClass : WCFDataClass
{
public String MyFoo { get; set; }
public String DoFoo()
{
return this.Foo + this.MyFoo;
}
}
If you have any interest in interoperability, I dont't believe it is generally a good practice.
First a contract (operation contract, message contract, data contract , etc.) is created to specify, in an unambiguous way, what is supported and what is not. It explicitly specifies those things publicly. It gets very confusing, very quickly, when you start declaring private members to be part of a public contract. It becomes problematic for the programmer who comes after you to discern what is going on.
You are likely attempting to encapsulate logic in your data contracts, which is not the purpose of a data contract. As suggested by #CodeCaster, such manipulation should be performed outside the data contract class. Even simple things like constructors populating default values can be problematic. Such logic should also be performed outside the DataContract class.
In addition, when you declare private members to be [DataMember]s you are relying on a non-standard implementation detail of the data contract serialiser - the fact that it can read/write members that are not public - i.e. the DataConstractSerializer (at least on the .NET platform) can do things you couldn't do in your own code. You are depending on 'magic'. While this 'magic' helps DataConstractSerializer to deliver amazing performance, I don't think you should be depending on its implementation details. For example, you will find that such DataContract classes cannot be shared with Silverlight applications because on that platform the DataConstractSerializer cannot read/write non-public members.
However, like all 'practices', you have to consider your circumstances. If interoperability and maintainability are not a requirement, then most of the above is not relevant and can be disregarded. :)

Selective serialization with SubSonic generated classes

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 {}

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