C# attributes are a mechanism for declaratively embedding metadata in C# source code. This metadata adds additional meaning to the code that can be retrieved and processed by other programs. In WCF's programming model, service and message contracts are typically defined in this straightforward, declarative manner. Soya reuses this programming model and provides additional SSDL-specific attributes and functionality. On one side this allows developers to define the structure of messages supported by an SSDL contract. On the other side it describes how these messages relate to each other through the use of different protocol frameworks. This attribute-oriented approach makes it possible to specify contract data with very little code yet provides extensive control over the contract when warranted.
In Soya, we have adopted the attribute-oriented programming model for the following reasons:
Where possible, Soya reuses existing WCF attributes to make the transition from WCF to Soya as smooth as possible. For concepts unique to SSDL, however, we had to introduce additional attributes (e.g. message names, message namespaces, protocols ...). The following code shows how messages are defined in Soya using C# attributes:
[SsdlMessageContract] // a Soya attribute public class MsgA { [MessageHeader] public string MyHeader; [MessageBodyMember] public MyData MyBody; } [DataContract] // a WCF attribute public class MyData { [DataMember] public int id; [DataMember] public string code; }
Attributes can take additional property parameters that can be used to override default values and give developers more control over the message data. For example, to explicitly specify the qualified name of the SSDL message element in the code above, one would simply define values for the Name and Namespace properties as shown in the following code fragment:
[SsdlMessageContract(Name="...", Namespace="...")]
From the above examples, Soya infers the following XML Schema code, which is part of the SSDL contract:
<xs:element name="MyHeader" type="xs:string"/> <xs:element name="MyBody" type="s:MyData"/> <xs:complexType name="MyData"> <xs:sequence> <xs:element name="id" type="xs:int"/> <xs:element name="code" type="xs:string"/> </xs:sequence> </xs:complexType>
Additionally, Soya generates the following SSDL message element, which is likewise included in the SSDL contract:
<ssdl:message name="MsgA"> <ssdl:header ref="s:MyHeader"/> <ssdl:body ref="s:MyBody"/> </ssdl:message>
As illustrated in the above examples, Soya reuses attributes defined by WCF wherever possible (e.g. MessageHeader, MessageBodyMember ...). Instead of generating WSDL, however, Soya uses the attribute metadata to create SSDL contracts.
Apart from defining messages supported by an SSDL contract, Soya's programming model may also be used to describe how these messages relate to each other. Soya has been designed to accommodate SSDL's extensible model and provides the necessary hooks to plug in new protocol frameworks. Of the four initial SSDL protocol frameworks, the MEP protocol is the simplest and least sophisticated. It does not demonstrate SSDL's full strength and has primarily been designed for capturing the Message Exchange Patterns defined by WSDL so it can be used as a simple, SOAP-centric language replacement for WSDL. The following lines show how simple MEP protocol interactions can be modeled using Soya's MEP attributes.
[Mep(Style=MepStyle.InOnly)] public void Process(MsgA msg) {} [Mep(Style=MepStyle.InOptionalOut, Out=typeof(MsgC), Fault=typeof(FaultX))] public void Process(MsgB msg) {}
The attribute on the first method declaration defines an in-only MEP in which MsgA represents the incoming message. The second method declaration defines an in-optional-out MEP with MsgB representing the incoming message, MsgC being the outgoing message, and FaultX standing for the optional fault message. From this code, Soya can generate the following SSDL protocol information which captures the messaging behavior in the SSDL contract:
<ssdl:protocol xmlns:mep="urn:ssdl:mep:v1"> <mep:in-only> <ssdl:msgref ref="m:MsgA" direction="in"/> </mep:in-only> <mep:in-optional-out> <ssdl:msgref ref="m:MsgB" direction="in"/> <ssdl:msgref ref="m:MsgC" direction="out"/> <ssdl:msgref ref="m:FaultX" direction="out"/> </mep:in-optional-out> </ssdl:protocol>
These examples show how Soya can use class information and attribute metadata to infer SSDL contracts. The examples also show how little additional code is necessary to create an entire SSDL contract including XML Schema definitions, method and fault declarations, and protocol descriptions.
Compared to WCF, Soya has a more restrictive programming model. This decision has been made deliberately, because we want developers to create truly service- and message-oriented - not RPC-like - applications. As a consequence, Soya enforces a service to have the following properties: