What is the best practice to define service call prototype/signature while developing application in service oriented architecture.
For Example I want to create Service call to send email.
Let say I have following object in my domain layer
[datacontract]
public class Email
{
public string To { get; set; }
public string From { get; set; }
public string Message { get; set; }
public string Subject { get; set; }
//I am not going to use this properties in send email method
public string OtherProp1 {get; set;}
public string OtherProp2 {get; set;}
public string OtherProp3 {get; set;}
}
Should I create Service method signature like
public bool SendEmail(string from,string to, string subject,string message){//My Logic}}
Or
public bool SendEmail(Email myEmail){//My Logic}
I am leaning toward first option.(Having said that I know if object is way to complex than it make sense to pass whole object itself.)
Unfortunately, second option is less clear in this case and this is because of your Email class
.
Suppose I am to call your method. You make me pass an instance of the Email
class. I go to the class contract and find 7 properties.
And, how am I supposed to know which parameters are mandatory and which are optional? From the docs? Not a cleanest design if I have to consult the docs to make proper use of the API.
I would rather refactor your Email class to call it EmailRequest
with all these optional parameters removed and then I would create yet another class EmailResponse
if you ever need to use it as a return value of a service.
I too vote for approach #2.
Since you mentioned 'service oriented architecture', you should create a DataContract
to gain full control of what your clients see.
Here, serialization is opt-in, so the 'unused properties' will not be sent over the wire.
Plus, you get other benefits like controlling the order of serialized members, specifying if fields are required or not, custom names, versioning and so on. It just makes things obvious for the clients.
Also, the DataContractSerializer
is supposedly 10% faster than the XmlSerializer
. More details on this blog, though I am not sure if approach #1 (primitive types) would use XmlSerializer
or DataContractSerializer
.
[DataContract(Name="MyEmail", Namespace="http://contoso.org/soa/datacontracts")]
public class Email
{
[DataMember(Name="ToField", IsRequired=true, Order=0]
public string To { get; set; }
[DataMember(Name="FromField", IsRequired=false, Order=1]
public string From { get; set; }
[DataMember(Name="MessageField", IsRequired=true, Order=2]
public string Message { get; set; }
[DataMember(Name="SubjectField", IsRequired=false, Order=3]
public string Subject { get; set; }
public string OtherProp1 {get; set;}
public string OtherProp2 {get; set;}
public string OtherProp3 {get; set;}
}
It's always better to go OOP way. If email class is excessive, try to analyze and define another solution. Like this
public class Email
{
//everything needed for service is extracted in another class
public EmailAddressDetails {get;set}
//I am not going to use this properties in send email method
public string OtherProp1 {get; set;}
public string OtherProp2 {get; set;}
public string OtherProp3 {get; set;}
}
and use service like this
public bool SendEmail(EmailAddressDetails email){//My Logic}}
How about writing both? And simply having the first, call the second?
I would make your Email
object a [DataContract] and go with option two. It's my opinion that you don't want that many parameters for one service method.
One of the important aspects of SOA is the contract so I would really vote against cluttering it with unneeded data and details which will cause it to deteriorate fast(er).
The option offered by channs is pretty good as it concentrates on defining the contract explicitly and in details, but I'd also separate the classes used for contract purposes from the classes used internally to decouple and hide internal implementation details (I explain this in detail in the Edge Component pattern)