This question directly in large part to the protobuf-net maintainer(s) but anyone else please comment.
I was trying to serialize a class that contains a property which has an interface type, ie:
[DataContract]
public class SampleDataClass
{
[DataMember(Order=1)]
public int Field1 { get; set; }
[DataMember(Order = 2)]
public IPayload Payload { get; set; }
}
[ProtoContract]
[ProtoInclude(1, typeof(Payload))]
public interface IPayload
{
int Field4 { get; set; }
}
[DataContract]
public class Payload : IPayload
{
[DataMember(Order = 1)]
public int Field4 { get; set; }
}
I have managed to get this to work by changing the source of v1 of protobuf-net.
I did not see any problem with this approach as long as ProtoInclude is defined for the interface.
Clearly to get this to compile I had to allow ProtoContract and ProtoInclude to be decorated on interfaces, plus a few other changes here and there. (note, I would have used DataContract/KnownType however these attributes are also not able to be decorated on interfaces)
Can you please comment on possible shortcomings?
The main glitch I can see is that in terms of payload this moves the data into a sub-message. I have some similar designs around v2 that hopefully get around this, keeping most values in the primary message. For sanity reasons, I mainly had just v2 in mind for this change (since the two implementations would be separate, and v2 has a much better type model).
However, it should be possible to support both modes of use. If you want to send it as a patch for v1 (with the same license etc) I'd happily take a look :)
This is available as a standard feature of v2
Related
I have a server side class which I make available on the client side through a [DataContract]. This class has a readonly field which I'd like to make available through a property. However, I'm unable to do so because it doesn't seem that I'm allowed to add a [DataMember] property without having both get and set.
So - is there a way to have a [DataMember] property without setter?
[DataContract]
class SomeClass
{
private readonly int _id;
public SomeClass() { .. }
[DataMember]
public int Id { get { return _id; } }
[DataMember]
public string SomeString { get; set; }
}
Or will the solution be use the [DataMember] as the field - (like e.g. shown here)? Tried doing this too, but it doesn't seem to care the field is readonly..?
Edit: Is the only way to make a readonly property by hacking it like this? (no - I don't want to do this...)
[DataMember]
public int Id
{
get { return _id; }
private set { /* NOOP */ }
}
Your "server-side" class won't be "made available" to the client, really.
What happens is this: based on the data contract, the client will create a new separate class from the XML schema of the service. It cannot use the server-side class per se!
It will re-create a new class from the XML schema definition, but that schema doesn't contain any of the .NET specific things like visibility or access modifiers - it's just a XML schema, after all. The client-side class will be created in such a way that it has the same "footprint" on the wire - e.g. it serializes into the same XML format, basically.
You cannot "transport" .NET specific know-how about the class through a standard SOAP-based service - after all, all you're passing around are serialized messages - no classes!
Check the "Four tenets of SOA" (defined by Don Box of Microsoft):
Boundaries are explicit
Services are autonomous
Services share schema and contract, not class
Compability is based upon policy
See point #3 - services share schema and contract, not class - you only ever share the interface and XML schema for the data contract - that's all - no .NET classes.
put DataMember attribute on a field not the property.
Remember thought, that WCF does not know encapsulation. Encapsulation is a OOP term, not a SOA term.
That said, remember that the field will be readonly for people using your class - anyone using the service will have full access to the field on their side.
I had some properties in a class in my service layer I wanted to pass over to Silverlight. I didn't want to create a whole new class.
Not really 'recommended', but this seemed the lesser of two evils to pass over the Total property to silverlight (solely for visual databinding).
public class PricingSummary
{
public int TotalItemCount { get; set; } // doesnt ideally belong here but used by top bar when out of store area
public decimal SubTotal { get; set; }
public decimal? Taxes { get; set; }
public decimal Discount { get; set; }
public decimal? ShippingTotal { get; set; }
public decimal Total
{
get
{
return + SubTotal
+ (ShippingTotal ?? 0)
+ (Taxes ?? 0)
- Discount;
}
set
{
throw new ApplicationException("Cannot be set");
}
}
}
There is a way to achieve this. But be warned that it directly violates the following principle cited in this answer:
"3. Services share schema and contract, not class."
If this violation does not concern you, this is what you do:
Move the service and data contracts into a separate (portable) class library. (Let's call this assembly SomeService.Contracts.) This is how you'd define an immutable [DataContract] class:
namespace SomeService.Contracts
{
[DataContract]
public sealed class Foo
{
public Foo(int x)
{
this.x = x;
}
public int X
{
get
{
return x;
}
}
[DataMember] // NB: applied to the backing field, not to the property!
private readonly int x;
}
}
Note that [DataMember] is applied to the backing field, and not to the corresponding read-only property.
Reference the contract assembly from both your service application project (I'll call mine SomeService.Web) and from your client projects (mine is called SomeService.Client). This might result in the following project dependencies inside your solution:
Next, when you add the service reference to your client project, make sure to have the option "reuse types" enabled, and ensure that your contract assembly (SomeService.Contracts) will be included in this:
VoilĂ ! Visual Studio, instead of generating a new Foo type from the service's WSDL schema, will reuse the immutable Foo type from your contract assembly.
One last warning: You've already strayed from the service principles cited in that other answer. But try not to stray any further. You might be tempted to start adding (business) logic to your data contract classes; don't. They should stay as close to dumb data transfer objects (DTOs) as you can manage.
Define the Service contract (Interface) Before implementing the contract using the class.
I have the following base class:
[ProtoContract]
public class Packet
{
[ProtoMember(1)]
public int Id { get; set; }
}
This class will be derived by 10+ other classes. My question is how should I assign ProtoInclude attributes?
Is this a good solution or not?
[ProtoContract]
[ProtoInclude(20, typeof(NotifyClientBalance))]
[ProtoInclude(21, typeof(IsAlive))]
[ProtoInclude(22, typeof(TransactionConfirmation))]
...
public class Packet
{
[ProtoMember(1)]
public int Id { get; set; }
}
Is there a better alternative? How should I assign tags to ProtoInclude? Everything's unclear for me and there's not a good documentation on the matter.
Thanks
P.S.
Is ProtoInclude portable across different platforms? I'm interested in Python in particular.
Thanks again :)
For use within protobuf-net, that approach is fine. The numbers are nice and low, which keeps it efficient.
Inheritance is not part of the protobuf specification, so no this is not portable between platforms - at least, not as inheritance. It is portable in terms of getting the data back. It maps to something like:
message Packet {
optional int id = 1;
optional NotifyClientBalance balance = 20;
// ...
}
message NotifyClientBalance {...}
//...
Or just use Serializer.GetProto<T>() to export the schema as .proto
I have made a weather app that receives information from an api. I have a class like that:
public class Forecast
{
public DateTime date { get; set; }
public string day_name { get; set; }
public string symbol { get; set; }
public int degree { get; set; }
public int degreemax { get; set; }
public int degreemin { get; set; }
public string condition { get; set; }
}
The class helps me to hold data. Also I can hold data with ArrayList, not necessarily class. I know that I should use classes. However, I am wondering which one is more efficient.
Thanks a lot.
In your scenario, anytime I would prefer a class over an ArrayList. The following are the positives I can think of right now
Intellisense - you will have date, etc in intellisnse. Whereas in arraylist you would need to remember on which location you have entered what data
boxing-unboxing - arraylist adds values in object so if you are putting int values, they will be boxed
Multiple Forecasts - If you want to store many Forcasts then it is not possible using arraylist or at least it will be 1 hell of a time for you to maintain it. It can be easily implemented with classes using List<yourClass>
Performance - Class is anytime better performing than ArrayList
More functionality - You can add methods to a class to extend its functionality like some calculations, etc. To have more functionality to ArrayList you would need to create a custom class inheriting from ArrayList and write your functionality there so ultimately you are using a class only.
OOPS concepts - All OOPS concept apply to a class like inheritance hence extending the functionality to other classes, etc. Not possible with ArrayList
Hope this helps.
I personally don't have my entities implement interfaces. For a Task class I wouldn't have ITask that just had the same properties defined on it.
I've seen it done a few times though, so I'm wondering where that advice comes from, and what benefits you get from it.
If you're using an ORM then the argument that says "I can change my data access" is irrelevent, so what other reason is there for doing this?
UPDATE:
A good point was made in the comments about INotifyPropertyChanged. That wasn't my point though - I'm talking about having something like this:
public interface ITask
{
int Id { get; set; }
string Description { get; set; }
}
public class Task : ITask
{
public int Id { get; set; }
public string Description { get; set; }
}
I went down this road once (interfaces for value objects). It was a royal pain in the backside, I recommended against it. The common arguments for it are:
Mocking:
They are value objects. Nought to mock. Plus mocking ends up being a large pain than either writing a builder (in Java) or using the named arguments stuff in C#.
Readonly views:
I must admit I still prefer to make something immutable by default, only making it mutable if absolutely required.
Hidden functionality:
Generally scope has covered this one for me.
The major benefit of this is that it is a way of exposing your entity as a "read-only" version (as long as your interface does not expose setters of course).
We're doing quite a bit of unit testing and so often want to mock out things we're not testing. Although I don't like it, we've ended up using interfaces all over the place because it makes it a lot easier to mock things.
In theory most of the mocking frameworks can mock normal classes too, but in practice this has caused us issues because we sometimes do clever things with reflection and the type of the mocked class isn't the same as the original. So doing:
var myTask = MyIoCProvider.Get<Task>();
var taskType = typeof(myTask);
Was unpredictable. Whereas:
var myTask = MyIoCProvider.Get<ITask>();
var taskType = typeof(myTask);
Gives you as taskType that IS definitely derived from ITask.
So interfaces just give us a way of making our system more mockable.
If you were thinking in terms of using DomainEvents than data structures such as the task really do need to implement an interface
public interface IDomainEvent
{
Guid EventId { get; }
Guid TriggeredByEvent { get; }
DateTime Created { get; }
}
public class OrderCancelledEvent : IDomainEvent
{
Guid EventId { get; set; }
Guid TriggeredByEvent { get; set; }
DateTime Created { get; set; }
// And now for the specific bit
int OrderId { get; set; }
}
Or similarly if you have a common data access layer that may need to take in a standard base class of IEntity but I wouldn't have an interface for each type if it is just a data structure as you describe in your post.
When you are handling Domain Objects that actually expose behaviour you may then want to have an interface for unit testing.
I think some programmers just use interfaces, because they heard interfaces are good so they ended using them everywhere without thinking about actual pros and cons.
Me personally, I never use interfaces for entities that only represent a piece of data like db row for example.
I appear to be having an issue with the following snippet of code in that, when I come to specifying what the Item is (eg CashInHand), the actual type CashInHandPayment is not available because it hasn't been carried across when I generate the proxy class (most likely because it doesn't read in XmlElementAttributes).
Is there any way to force classes such as AccountPayment, CashInHandPayment and CCPayment to be serialized in the proxy class?
[DataContract]
public class Payment
{
[XmlElementAttribute("Account", typeof(AccountPayment))]
[XmlElementAttribute("CashInHand", typeof(CashInHandPayment))]
[XmlElementAttribute("CreditCard", typeof(CCPayment))]
[XmlChoiceIdentifierAttribute("ItemElementName")]
[DataMember]
public object Item { get; set; }
}
[DataContract]
public enum ItemElementName
{
[EnumMember]
Account,
[EnumMember]
CashInHand,
[EnumMember]
CreditCard
}
//This class will not be in the generated proxy class
[DataContract]
public class AccountPayment
{
[DataMember]
public double Amount { get; set; }
}
//classes for CashInHandPayment and CCPayment also created, but not shown.
Forgive me if 'serialize' isn't the correct term to use, if you read the question and find that it isn't, please change it accordingly!
Update - answer mentioned by Simon Svensson:
[KnownType(typeof(AccountPayment))]
[KnownType(typeof(CashInHandPayment))]
[KnownType(typeof(CCPayment))]
[DataContract]
public class Payment
{
[XmlElementAttribute("Account", typeof(AccountPayment))]
[XmlElementAttribute("CashInHand", typeof(CashInHandPayment))]
[XmlElementAttribute("CreditCard", typeof(CCPayment))]
[XmlChoiceIdentifierAttribute("ItemElementName")]
[DataMember]
public object Item { get; set; }
}
Many thanks, Simon!
Uhm. Isnt XmlElementAttribute and XmlChoiceIdentifierAttribute xml serialization, which is a older serialization compared to the DataContractSerializer which reads DataContractAttribute and DataMemberAttribute?
I believe that you should use the KnownTypeAttribute for this, but I have never tried it, nor have I had this scenario in my own code.
Is there any way to force classes such as AccountPayment,
CashInHandPayment and CCPayment to be serialized in the proxy class?
They need to be marked with a [DataContract] attribute, that should be sufficient, I would think.
When svcutil.exe (either launched directly from the command line, or from Visual Studio using Add Service Reference) encounters classes with the [DataContract] attribute on the class and [DataMember] on the properties (or fields), it will create a copy in the proxy for those classes.
Marc
I think specifying DataContract should be sufficient. But, if that isn't working, why not try creating a dummy OperationContract method that uses the class?