4

在面向服务的架构中开发应用程序时定义服务调用原型/签名的最佳实践是什么?

例如,我想创建服务调用来发送电子邮件。

假设我的域层中有以下对象

 [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;}

  }

我应该像这样创建服务方法签名吗

   public bool SendEmail(string from,string to, string subject,string message){//My Logic}}

或者

   public bool SendEmail(Email myEmail){//My Logic}

我倾向于第一个选项。(话虽如此,我知道对象是否比传递整个对象本身更复杂。)

4

6 回答 6

3

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.

于 2012-08-15T19:27:46.193 回答
3

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;}    
}
于 2012-08-15T19:40:21.957 回答
1

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}}
于 2012-08-15T19:18:46.217 回答
0

两个都写怎么样?只是拥有第一个,调用第二个?

于 2012-08-15T19:12:41.930 回答
0

我会将您的Email对象设为 [DataContract] 并使用选项二。我认为您不希望一种服务方法有那么多参数。

于 2012-08-15T19:15:14.550 回答
0

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)

于 2012-08-19T19:15:40.740 回答