• No results found

Data and Message Contracts

In document Windows Azure Prescriptive Guidance (Page 166-176)

catch (Exception ex) {

Console.ForegroundColor = ConsoleColor.Yellow;

Console.Write("Exception: ");

Console.ForegroundColor = defaultColor;

Console.Write(ex.Message);

} } } }

I did not test all the possible combinations of properties for queues and topics so the demo may not work as expected with all the configurations.

Data and Message Contracts

I started defining the data and message contracts for the request and response messages. These two types of contracts have different roles in WCF:

1. Data contracts provide a mechanism to map .NET CLR types that are defined in code and XML Schemas (XSD) defined by the W3C organization (www.w3c.org). Data contracts are published in the service’s metadata, allowing clients to convert the neutral, technology-agnostic representation of the data types to their native representations.

2. Message contracts describe the structure of SOAP messages sent to and from a service and enable you to inspect and control most of the details in the SOAP header and body.

Whereas data contracts enable interoperability through the XML Schema Definition (XSD) standard, message contracts enable you to interoperate with any system that communicates through SOAP. Using message contracts gives you complete control over the SOAP

message sent to and from a service by providing access to the SOAP headers and bodies directly. This allows the use of simple or complex types to define the exact content of the SOAP parts.

Note

In my solution, I created two separate projects called DataContracts and MessageContracts respectively. For your convenience, I included below the code of the classes used to define the Data and Message Contract of the request and response messages.

CalculatorRequest Class

[Serializable]

[XmlType(TypeName = "CalculatorRequest",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

[XmlRoot(ElementName = "CalculatorRequest",

Namespace = http://windowsazure.cat.microsoft.com/samples/servicebus, IsNullable = false)]

[DataContract(Name = "CalculatorRequest",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

public class CalculatorRequest {

#region Private Fields

private OperationList operationList;

#endregion

#region Public Constructors public CalculatorRequest() {

operationList = new OperationList();

}

public CalculatorRequest(OperationList operationList) {

this.operationList = operationList;

}

#endregion

#region Public Properties

[XmlArrayItem("Operation", Type=typeof(Operation), IsNullable = false)]

[DataMember(Order = 1)]

public OperationList Operations {

get {

return operationList;

} set {

} }

#endregion }

[CollectionDataContract(Name = "OperationList", Namespace =

http://windowsazure.cat.microsoft.com/samples/servicebus, ItemName = "Operation")]

public class OperationList : List<Operation>

{ }

[Serializable]

[XmlType(TypeName = "Operation", AnonymousType = true,

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

[DataContract(Name = "Operation",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

public class Operation {

#region Private Fields private string op;

private double operand1;

private double operand2;

#endregion

#region Public Constructors public Operation()

{ }

public Operation(string op,

double operand1, double operand2) {

this.op = op;

this.operand1 = operand1;

this.operand2 = operand2;

}

#endregion

#region Public Properties [XmlElement]

[DataMember(Order = 1)]

public string Operator {

get {

return op;

} set {

op = value;

} }

[XmlElement]

[DataMember(Order = 2)]

public double Operand1 {

get {

return operand1;

} set {

operand1 = value;

} }

[XmlElement]

[DataMember(Order = 3)]

public double Operand2 {

get {

return operand2;

} set {

operand2 = value;

}

#endregion }

CalculatorResponse Class

[Serializable]

[XmlType(TypeName = "CalculatorResponse",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

[XmlRoot(ElementName = "CalculatorResponse",

Namespace = http://windowsazure.cat.microsoft.com/samples/servicebus, IsNullable = false)]

[DataContract(Name = "CalculatorResponse",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

public class CalculatorResponse {

#region Private Fields private string status;

private ResultList resultList;

#endregion

#region Public Constructors public CalculatorResponse() {

status = default(string);

resultList = new ResultList();

}

public CalculatorResponse(string status) {

this.status = status;

resultList = new ResultList();

}

public CalculatorResponse(string status, ResultList resultList) {

this.status = status;

this.resultList = resultList;

}

#endregion

#region Public Properties

[XmlElement]

[DataMember(Order = 1)]

public string Status {

get {

return status;

} set {

status = value;

} }

[XmlArrayItem("Result", Type=typeof(Result), IsNullable=false)]

[DataMember(Order = 2)]

public ResultList Results {

get {

return resultList;

} set {

resultList = value;

} }

#endregion }

[CollectionDataContract(Name = "ResultList", Namespace =

http://windowsazure.cat.microsoft.com/samples/servicebus, ItemName = "Result")]

public class ResultList : List<Result>

{ }

[Serializable]

[XmlType(TypeName = "Result", AnonymousType = true,

[DataContract(Name = "Result",

Namespace = "http://windowsazure.cat.microsoft.com/samples/servicebus")]

public class Result {

#region Private Fields private double value;

private string error;

#endregion

#region Public Constructors public Result()

{

value = default(double);

error = default(string);

}

public Result(double value, string error) {

this.value = value;

this.error = error;

}

#endregion

#region Public Properties [XmlElement]

[DataMember(Order = 1)]

public double Value {

get {

return value;

} set {

this.value = value;

} }

[XmlElement]

[DataMember(Order = 2)]

public string Error

get {

return error;

} set {

error = value;

} }

#endregion }

CalculatorRequestMessage Class

[MessageContract(IsWrapped=false)]

public class CalculatorRequestMessage {

#region Private Fields

private CalculatorRequest calculatorRequest;

#endregion

#region Public Constructors public CalculatorRequestMessage() {

this.calculatorRequest = null;

}

public CalculatorRequestMessage(CalculatorRequest calculatorRequest) {

this.calculatorRequest = calculatorRequest;

}

#endregion

#region Public Properties [MessageBodyMember(Namespace =

"http://windowsazure.cat.microsoft.com/samples/servicebus")]

public CalculatorRequest CalculatorRequest {

get {

return this.calculatorRequest;

} set

this.calculatorRequest = value;

} }

#endregion }

CalculatorResponseMessage Class

[MessageContract(IsWrapped = false)]

public class CalculatorResponseMessage {

#region Private Fields

private CalculatorResponse calculatorResponse;

#endregion

#region Public Constructors

public CalculatorResponseMessage() {

this.calculatorResponse = null;

}

public CalculatorResponseMessage(CalculatorResponse calculatorResponse) {

this.calculatorResponse = calculatorResponse;

}

#endregion

#region Public Properties [MessageBodyMember(Namespace =

"http://windowsazure.cat.microsoft.com/samples/servicebus")]

public CalculatorResponse CalculatorResponse {

get {

return this.calculatorResponse;

} set {

this.calculatorResponse = value;

} }

#endregion }

Indeed, I could have used just data contracts to model messages as message contracts add a degree of complexity. However, by assigning false to the IsWrapped property exposed by the MessageContractAttribute, you specify that the message body won’t be contained in a wrapper element. Typically, the wrapper element of a request message is the name of the operation invoked and it’s defined in the WSDL. Setting the value of the IsWrapped property to false, you can simply select the Body option in both the Inbound BizTalk message body and Outbound WCF message body sections on the Messages tab when configuring a WCF receive location.

Otherwise you should define a Path in the Inbound BizTalk message body section to extract the payload from the inbound message, and specify a template in the Outbound WCF message body section to include the outgoing response message within a wrapper element.

The namespace of the message and data contract classes match those defined by the XML schemas that model the request and response messages in the BizTalk Server application.

See Also

"Using Data Contracts" topic on MSDN.

“Using Message Contracts” topic on MSDN

In document Windows Azure Prescriptive Guidance (Page 166-176)