I would like to use ServiceStack on the server side, and I would like to use protobuf-net as the serialization system used by ServiceStack. However, some of the clients will not be using the ServiceStack client libraries. They will be using protobuf-net directly.
In reading the widely linked ServiceStack protocol buffers howto (http://stevenhollidge.blogspot.in/2012/04/servicestack-rest-with-protobuf.html), it indicates using [DataContract] and [DataMember(Order=i)] attributes on the classes and properties respectively. However, when I read the protobuf-net documentation it indicates attributes are [ProtoContract] and [ProtoMember(i)] instead.
If I want my DTOs to work with both native protbuf-net and ServiceStack's protobuf-net wrapper do I need to add both attributes to every class and property, or will one or the other be sufficient?
ProtoBuf requires a mapping from Properties to numerical indexes, both of the options you've specified are equivalent ways to do this:
[DataContract]
public class Dto
{
[DataMember(Order=i)]
public string PropertyName { get; set; }
}
[ProtoContract]
public class Dto
{
[ProtoMember(i)]
public string PropertyName { get; set; }
}
Related
In the protobuf-net v3 release notes, one of the breaking changes is: non-generic list-like APIs like IList or ICollection are no longer supported; there is a new API for processing custom collection types.
I've been looking through the repo, but haven't been able to figure out the details. Would someone be able to provide an example on how to migrate this data contract to v3?
Here is an example:
[DataContract]
public class Data
{
[DataMember(Order = 1)]
public IList<DataEntry> DataEntries
}
[DataContract]
public class DataEntry
{
[DataMember(Order = 1)]
public string Name;
}
No change is necessary. You are using IList<T>, which is the generic API. The thing that isn't supported is using the old non-generic IList (with no <T>)
I have an ASP.NET Core application which can have components of different types. These types are not know until runtime. I have a set of settings which are in a taxonomy of types, and a top-level settings object that stores a collection of the configured components. E.g.,
public class ServiceSettings
{
List<ComponentSettingsBase> Components { get; set; }
}
public abstract class ComponentSettingsBase
{
}
public class ASettings : ComponentSettingsBase { get; set; }
public class BSettings : ComponentSettingsBase { get; set; }
Using a Json file, I can create the base ServiceSettings object and map it correctly for simple types like strings. When it comes to the collection it just ignores it. I've tried adding type information like Json.NET (Newtonsoft) does for type name handling, but haven't found anywhere to configure how it should be deserialized. I thought that's what they used to use, and there are easy configuration settings for the Json serializer used for Web API communication, but this does not seem to effect the settings/configuration serialization.
Is there a way that I can do this using the built-in settings provider? Or will I need to do something like use the settings provider to point to another file, then use a more fully-fledged Json deserializer to deserialize the settings?
I think the problem here is that you want to map a JSON array to a C# List<T>.
What I would do is to change my code to something like this:
public class ServiceSettings
{
ComponentSettingsBase[] Components { get; set; }
}
I might be wrong, however...
Next thing I would try is to go the other direction and
build an example object model in memory
serialize it to a JSON
see how that JSON looks like to learn the format your environment likes
reproduce what you need in the format you have learned in the previous step
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.
This question already has answers here:
Can I optionally turn off the JsonIgnore attribute at runtime?
(3 answers)
Closed 4 years ago.
I am currently using the same C# DTOs to pull data out of CouchDB, via LoveSeat which I am going to return JSON via an ASP MVC controller.
I am using the NewtonSoft library to seralise my DTOs before sending them down through the controller.
However, as CouchDB also uses NewtonSoft it is also respecting the property level NewtonSoft attributes such as
[JsonIgnore]
[JsonProperty("foo")]
Is there anyway to tell the newtonsoft library to ignore these attributes explicitly? LoveSeat allows me to provide my own implementation of IObjectSerializer, which gives me full control over netwonsofts JsonSerializerSettings. So, can I ignore the attributes by using those settings ?
I ask as the only alternative I can see at this point, is to dupe my DTOs. While not that's not terrible, it isn't great either.
The only other way I can see is to bring in my own version of the Newtonsoft.Json source into my project, with a different assembly name etc etc. But this way madness definitely lies and I will just dupe the DTOs before I go down this road.
I'm not sure if this is what you're after, but from what I understand you're looking for the [JsonIgnore] attribute. Stops properties from being serialized with the rest of the object into to JSON.
[JsonIgnore]
public string Whatever{ get; set; }
One suggestion that you may not like. For best practices, I recommend having two almost identical objects. One specifically for your Data Access Layer (Domain Object) which maps to your DB. And a separate DTO that your apps care about. This way the Domain Object will mostly contain more properties than the DTO and you can separate the concerns.
According to Json.NET documentation
You can add method to your class: public bool ShouldSerialize_________(){...} and fill in the blank with the name of the property you don't want to serialize. If the method returns false, the property will be ignored.
The example from the documentation doesn't want to serialize an employee's manager if the manager is the same employee.
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
// don't serialize the Manager property if an employee is their own manager
return (Manager != this);
}
}
You could put some kind of inhibit setting on your class:
public class DTO
{
[JsonIgnore]
public bool IsWritingToDatabase { get; set; }
public string AlwaysSerialize { get; set; }
public string Optional { get; set; }
public bool ShouldSerializeOptional()
{
return IsWritingToDatabase;
}
}
But, this isn't much simpler than having two objects. So I would recommend doing as #zbugs says, and having separate definitions for API-side and DB-side.
I ended up making all properties I needed to only add attributes to virtual, and overriding them alone in another class, with the relevant newtonsoft attributes.
This allows me to have different serialisation behavior when de-serialising from CouchDB and serialising for a GET, without too much dupe. It is fine, and a bonus, that the two are coupled; any changes in the base i would want anyway.
It would still be nice to know if my original question is possible?
This newtonking.com link helped in a similar situation. It extends the DefaultContractResolver class. To make it work I had to replace
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
with
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
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.