none
OperationContract parameterized or "request" "response" pattern, development pain and versioning RRS feed

  • Question

  • Hi all,

    Just wanting to bounce thoughts off some folks.

    thinking about operationcontracts and service clients and just trying to resolve the ease of development and versioning trade offs.

    Essentially you can have these kinds of OPS:

    public string DoSomething(string whoareyou, int thingshere, int[] listofthings, string morethings) {...}
    
    vs 
    
    public DoSomethingResponse DoSomething(DoSomethingRequest request) {...}

    These are both valid however from the service developer there is a lot of work involved in creating the Response/Request objects and maintaining them and also there is more lieklyhood that some elements can be NULL... I've tried "IsRequired" but this is really only a serialization check so you only catch it at runtime (less good IMO - but maybe I'm not deep enough into it to realize its benefits).

    Also the client in the first instance can be simpler I think because you can code against your service more naturally HOWEVER (and moving forward I think this is a big deal), the first is NOT really versionable - ie if you add or change a parameter, you need to discard the operation for a new one or make sure all your clients update, second is more version friendly, because the OPERATION doesn't have to change and as long as the REQUEST follows a few rules then only the DataContract needs to be versioned (and I think this is easier - but if you control both client and server do you care as much about this benefit...?):

    eg:

    MyClientFunction(IMyService svc){
    var stuff = svc.GetStuff(4); // can assume this is as local as any other element - blessing and curse? how to handle handle-ible error and or retries on latency...
    }
    
    vs
    NOTE: unless I wrap my services in a "SvcClient" that does this inside of it then I have to do this in my code (and if I mirro the above by wrapping in a ServiceClient<IMyService> somehow... I still have to write ServiceClient<T>... mo' code == mo' pro'lems)
    
    MyClientFunction(IMyService svc){
    var request = new Request(5);
    var response = svc.GetStuff(request);
    }

    Doesn't look like a huge deal, but when you have 100's of parameters to request it makes a big difference (okay 100's is extreme in both cases, but I'm hoping you take my point).

    So any thoughts/guidance on these things?


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -


    • Edited by noJedi Tuesday, May 5, 2015 4:15 PM
    Tuesday, May 5, 2015 4:10 PM

Answers

  • No, Message is actually a concrete class, not an abstract. It is flexible only in that you store the data in a string property of the class. This data can be anything you want, but you can use a property that tells you what kind of message it is, then your consuming method knows how to treat the data that is contained in the data property. I pretty much always put XML in the data property (a Typed DataSet.GetXml()), but it can be anything that serializes to a string (like JSON). It might look something like this (this is only part of what my Message class looks like):

    [DataContract(Namespace = "http://MyCompany")]
    [Serializable]
    public class TheMessage
    {
        #region Properties
        [DataMember]
        public string Label { get; set; }
        [DataMember]
        public DateTime CreatedDatetime { get; set; }
        [DataMember]
        public DateTime SavedDatetime { get; set; }
        [DataMember]
        public Guid Id { get; set; }
        [DataMember]
        public string DataClear { get; set; }
        [DataMember]
        public string DataEncrypted { get; set; }
        #endregion
        
        // Constructor(s)
        
        // Useful Methods
    }
    

    So, you'd do something like this:

    TheMessage msg = new TheMessage();
    msg.Label = "Customer.Order.Request";
    msg.DataClear = MyDataSet.GetXml();
    

    And then use that message object in your service calls.

    You might also want to take a look at my blog post, http://geek-goddess-bonnie.blogspot.com/2012/09/a-generic-wcf-proxy-class.html.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, May 10, 2015 5:16 AM
    Moderator
  • ServiceContracts and OperationContracts are just that ... contracts. Both sides (server and client) have to keep their end of the "bargain". Therefore you should make them as flexible as possible so that you never have to change those Contracts.

    In my WCF services, I have created a Message class that I pass as a parameter in all my OperationContracts (methods). That way, I never break the contract/interface. Even if I had to refactor or add properties (or methods) in my Message class, it still would not break the Contract.

    I'm not sure if this is the answer you're looking for, but I thought I'd throw in my 2 cents, FWIW.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Friday, May 8, 2015 4:56 AM
    Moderator

All replies

  • Yes, but you can choose do not use the svctest client, it just for a test purpose.
    Wednesday, May 6, 2015 7:21 AM
  • Not sure if you are referring to a testclient that is part of the WCF framework (if there is one can you point me at the doco, as I'm not aware of it...) but I'm NOT referring to the WCFTestClient.exe (sorry if that wasn't clear) utility that you can use to test your svc files, I'm talking about a serviceclient wrapper to make your client code more readable.

    eg: say I have a service with this interface

    IService1{
    string DoStuff(){...}
    }

    if I use this (either by generating a client class via svcutil or by sharing the dll between client and service) interface in my client then I get this kind of code

    MyClientFunc(IService1 svc)
    {

    var things = svc.DoStuff();

    }

    which is nice and clean until you factor in things like error handling on the connection which then destroys the nice illusion that the client is service agnostic...

    so you have to then do stuff like:

    string things = "";

    try{
    things = svc.DoStuff();
    }catch(CommunicationsException ex)
    {recoverycodehere...}

    if (!string.IsNullOrEmpty(things)){dostuffwiththingshere...}

    This ruins the illusion that IService1 is just an interface to an implementation UNLESS I create a wrapper around this that is something like:

    class ClientService:IService1... and it implements IService1 and (somewhere?) is built from an actual channel or service factory or something and then passed into my using class... and handles the try/catch around each operation call... why this isn't an option in the svcutil code generation is beyond me... I guess its not always the same way to handle an error...

    I guess the short version of what I want to know can be summed up like this:

    a) how do you handle errors/communication failures without cluttering up your code with all kinds of try/catch/retry rubbish?

    b) how do you create operations keeping things simple, but allowing flexibility for change/versioning?


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -

    Wednesday, May 6, 2015 12:26 PM
  • ServiceContracts and OperationContracts are just that ... contracts. Both sides (server and client) have to keep their end of the "bargain". Therefore you should make them as flexible as possible so that you never have to change those Contracts.

    In my WCF services, I have created a Message class that I pass as a parameter in all my OperationContracts (methods). That way, I never break the contract/interface. Even if I had to refactor or add properties (or methods) in my Message class, it still would not break the Contract.

    I'm not sure if this is the answer you're looking for, but I thought I'd throw in my 2 cents, FWIW.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Friday, May 8, 2015 4:56 AM
    Moderator
  • Interesting... I'd like to see how your method calls look and/or the implementation of your Message class...

    is it something like

    public abstract Message(){}

    or is it something else?

    How do your calls look?

    is it something like

    var m = svcClient.DoStuff(new MessageForDoStuff(thing, otherthing));

    ???

    Thanks for your input


    - sure I'm noJedi but that's no reason to stop trying to make stuff levitate! -

    Sunday, May 10, 2015 3:43 AM
  • No, Message is actually a concrete class, not an abstract. It is flexible only in that you store the data in a string property of the class. This data can be anything you want, but you can use a property that tells you what kind of message it is, then your consuming method knows how to treat the data that is contained in the data property. I pretty much always put XML in the data property (a Typed DataSet.GetXml()), but it can be anything that serializes to a string (like JSON). It might look something like this (this is only part of what my Message class looks like):

    [DataContract(Namespace = "http://MyCompany")]
    [Serializable]
    public class TheMessage
    {
        #region Properties
        [DataMember]
        public string Label { get; set; }
        [DataMember]
        public DateTime CreatedDatetime { get; set; }
        [DataMember]
        public DateTime SavedDatetime { get; set; }
        [DataMember]
        public Guid Id { get; set; }
        [DataMember]
        public string DataClear { get; set; }
        [DataMember]
        public string DataEncrypted { get; set; }
        #endregion
        
        // Constructor(s)
        
        // Useful Methods
    }
    

    So, you'd do something like this:

    TheMessage msg = new TheMessage();
    msg.Label = "Customer.Order.Request";
    msg.DataClear = MyDataSet.GetXml();
    

    And then use that message object in your service calls.

    You might also want to take a look at my blog post, http://geek-goddess-bonnie.blogspot.com/2012/09/a-generic-wcf-proxy-class.html.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, May 10, 2015 5:16 AM
    Moderator
  • Sometimes, after initial development, we have to do versioning due to some reasons, like business needs change, etc.. In that case, what we have to do is to find a way to do version more effectively.

    I've found some articles regarding versioning, hope they can be of a little help.

    Service Versioning

    Best Practices: Data Contract Versioning

    Versioning Windows Communication Foundation Services

    Versioning WCF Services: Part I

    Versioning WCF Services: Part II

    Monday, May 11, 2015 2:37 AM