3

I am just learning WCF services. I have a method that returns an object I created called GPSPosition. A GPS Position object has a Latitude and a Longitude. The object should never really exist without these properties.. So, I want to have the constructor accept the Lat and Long floats. So when the object is created, the values are set, and can never be invalid (Unset).

But, it's an object of my WCF service. Can as WCF service object, that my calling application uses, have a constructor? If I var position = new GpsPosition{ lat=1, lon=1 }; in my calling code, will the constructor work? Can you have constructors in WCF classes?

I thought they are shared among different languages - so if the service is used by Java, for example, I'm unsure how the constructor will fire. The object structure is shared to the calling app, no? Can you fire .net code in the constructor (And getter and setter methods, for that case)?

And if the constructor isn't usable - is there a way to ensure my object is never invalid? (Must have valid lat/long values between -180 and +180)?

carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
Craig
  • 18,074
  • 38
  • 147
  • 248

1 Answers1

6

The answer will depend on which serialization model your type GpsPosition uses. The two most common ones used in WCF are POCO (plain-old CLR object) and [DataContract]. In the former, the object must have a parameter-less constructor, which goes against your requirement (that the values need to be set once). In the latter, the object constructor is not invoked - instead an uninitialized instance of the type is created, and its members are set via deserialization.

So constructors are not an alternative to validate the objects coming from the wire. What you need to validate the object, instead of the constructor, is a serialization callback, which is invoked when the deserialization is complete. The WCF serializer will call them when the deserialization is done, and there you can check whether the object was properly initialized, and throw an exception otherwise. This blog post has more details on serialization callbacks, and the code below shows one possible implementation for your scenario.

[DataContract]
public class GpsPosition
{
    private float _lat;
    private float _lon;
    private bool _latWasSet;
    private bool _lonWasSet;

    public GpsPosition(float lat, float lon)
    {
        _lat = lat;
        _lon = lon;
    }

    [DataMember]
    public float lat
    {
        get { return _lat; }
        private set
        {
            _lat = value;
            _latWasSet = true;
        }
    }

    [DataMember]
    public float lon
    {
        get { return _lon; }
        private set
        {
            _lon = value;
            _lonWasSet = true;
        }
    }

    [OnDeserialized]
    void OnDeserialized(StreamingContext ctx)
    {
        if (!_latWasSet || _!lonWasSet ||
            _lat < -90 || _lat > 90 ||
            _lon < -180 || _lon > 180)
        {
            throw new InvalidOperationException("Required property is missing");
        }
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • Can you please take a look at this please? http://stackoverflow.com/questions/33752947/unable-to-initialize-member-through-constructor-in-wcf I believe out of all people that I have come across on SO today. Only you can answer it. – SamuraiJack Nov 17 '15 at 10:09