Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Azure

Service-Orientation with .NET : Decoupled Contract

5/16/2011 6:27:53 PM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
Ultimately, the combination of logic-to-contract and consumer-to-contract is considered to establish the healthiest foundation for achieving balanced loose coupling within and between services. The most effective way of realizing this is by establishing a service contract that is physically independent of both service consumers and its underlying implementation (Figure 1). This is the goal of the Decoupled Contract pattern.
Figure 1. A decoupled service contract is physically separated from other parts of the technology architecture.


By positioning the service contract as a standalone artifact, we force the service implementation to adhere to the contract and we allow for the Contract Centralization pattern to be applied in such a way that service consumers cannot become dependent on the service implementation.

When building services with .NET, there are several ways of accomplishing this, as explored in these next sections.

WSDL-First

Based on the data types we will create message types that are essentially XML schemas tailored for use in specific messages. Thereafter, we will create a WSDL definition that imports these schemas.

Our service will have three operations:

  • GetPerson

  • GetAllPersons

  • UpdatePerson

We need to import that type into a new XML schema, as follows:

Example 1.
<xs:import namespace=
"http://schemas.example.org/enterprise/models/v1"
schemaLocation="Personperson.xsd"/>

We also need to create a namespace that matches the namespace of the imported XML schema:

xmlns:persondata="http://schemas.example.org/
enterprise/models/v1"

Lastly, when we want to use the person type in an element we declare its type like this:

type="persondata:person"

The completed message schema that we place in the PersonServiceMessages.xsd file looks like this:

Example 2.
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:persondata=
"http://schemas.example.org/enterprise/models/v1"
xmlns:tns=
"http://schemas.example.org/enterprise/service/v1"
targetNamespace=
"http://schemas.example.org/enterprise/service/v1">
<xs:importnamespace=
"http://schemas.example.org/enterprise/models/v1"
schemaLocation="Person.xsd"/>
<xs:element name="GetPerson">
<xs:complexType>
<xs:sequence>
<xs:element name="personId"
type="xs:positiveInteger" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetPersonResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="person"
type="persondata:person"
minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetAllPersons">
<xs:complexType>
<xs:sequence/>
</xs:complexType>
</xs:element>
<xs:element name="GetAllPersonsResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="person"
type="persondata:personList"
minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="UpdatePerson">
<xs:complexType>
<xs:sequence>
<xs:element name="updatablePerson"
type="persondata:person"
minOccurs="0" nillable="true" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="UpdatePersonResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="success" type="xs:boolean" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>


After creating the message types, they are imported into the WSDL definition. Using the import statement we showed earlier, the WSDL definition is structured as follows:

Example 3.
<definitions xmlns:tns=
"http://schemas.example.org/enterprise/service/v1"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:personMessages=
"http://schemas.example.org/enterprise/service/v1"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="PersonService"
targetNamespace=
"http://schemas.example.org/enterprise/service/v1"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<wsdl:documentation
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<types>
<xsd:schema>
<xsd:import schemaLocation="PersonServiceMessages.xsd" />
</xsd:schema>
</types>
<message name="getPersonIn">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters"
element="personMessages:GetPerson" />
</message>
<message name="getPersonOut">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters"
element="personMessages:GetPersonResponse" />
</message>
<message name="getAllPersonsIn">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters"
element="personMessages:GetAllPersons" />
</message>
<message name="getAllPersonsOut">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters"
element="personMessages:GetAllPersonsResponse" />
</message>
<message name="updatePersonIn">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters"
element="personMessages:UpdatePerson" />
</message>
<message name="updatePersonOut">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters" element=
"personMessages:UpdatePersonResponse" />
</message>
<portType name="PersonServiceInterface">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<operation name="GetPerson">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<input message="tns:getPersonIn" />
<output message="tns:getPersonOut" />
</operation>
<operation name="GetAllPersons">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<input message="tns:getAllPersonsIn" />
<output message="tns:getAllPersonsOut" />
</operation>
<operation name="UpdatePerson">
<wsdl:documentation xmlns:wsdl=
"http://schemas.xmlsoap.org/wsdl/" />
<input message="tns:updatePersonIn" />
<output message="tns:updatePersonOut" />
</operation>
</portType>
<binding name=
"BasicHttpBinding_PersonServiceInterface
"type="tns:PersonServiceInterface">
<soap:binding transport=
"http://schemas.xmlsoap.org/soap/http" />
<operation name="GetPerson">
<soap:operation soapAction=
"http://schemas.example.org/enterprise/service/v1:
getPersonIn" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="GetAllPersons">
<soap:operation soapAction=
"http://schemas.example.org/enterprise/service/v1:
getAllPersonsIn" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="UpdatePerson">
<soap:operation soapAction=
"http://schemas.example.org/enterprise/service/v1:
updatePersonIn" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
</definitions>


To summarize, the WSDL definition we created includes:

  • an import of the message schemas

  • definitions of messages (for example, “getPersonIn”) that refer to the imported message schemas

  • the service interface that specifies operations and refers to the declared messages

  • the binding that specifies SOAP operations for the previously specified operations


Now that we have a Web service contract and associated data model designed via the WSDL-first approach, we need to make it part of our development environment so that we can build the corresponding implementation logic.

There are several tools that can be used for this purpose. The three tools we highlight in the upcoming sections are:

  • svcutil

  • WSCF.blue

  • WSCF.classic

Be sure to study the pros and cons of each tool before choosing which to make part of a standard service-oriented design process for Web services.

Generating Service Code Using Svcutil

The svcutil utility can be used to generate code based on an existing WSDL definition. To launch this utility, we need to type the following statement in the Visual Studio command prompt:

Example 4.
svcutil -serializer:datacontractserializer  -namespace:*,
schemas.woodgroove.com.enterprise
PersonService.wsdl AddressType.xsd
GenderType.xsd Person.xsd Pers
onServiceMessages.xsd /l:cs

An abbreviated version of the code that is subsequently generated is shown here:

Example 5.
[System.CodeDom.Compiler.GeneratedCodeAttribute
("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute
(Namespace="http://schemas.example.org/enterprise/service/v1",
ConfigurationName="schemas.example.org.enterprise.
PersonServiceInterface")]

public interface PersonServiceInterface
{
[System.ServiceModel.OperationContractAttribute
(Action="http://schemas.example.org/enterprise/service/v1:getPer-
sonIn", ReplyAction="*")]
[return: System.ServiceModel.MessageParameterAttribute(Name="person")]
schemas.example.org.enterprise.person GetPerson(long personId);
[System.ServiceModel.OperationContractAttribute(Action="http://schemas
.example.org/enterprise/service/v1:getAllPersonsIn", ReplyAction="*")]
[return:System.ServiceModel.MessageParameterAttribute
(Name="person")]
schemas.example.org.enterprise.personList GetAllPersons();
[System.ServiceModel.OperationContractAttribute(Action="http://schemas
.example.org/enterprise/service/v1:updatePersonIn", ReplyAction="*")]
[return:System.ServiceModel.MessageParameterAttribute
(Name="success")]
bool UpdatePerson(schemas.example.org.enterprise.person
updatablePerson);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.
Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute
(Name="person", Namespace="http://schemas.example.org/enterprise/
models/v1")]

public partial class person : object,
System.Runtime.Serialization.IExtensibleDataObject...
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.
Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="addressType"
,Namespace="http://schemas.example.org/enterprise/models/v1")]

public partial class addressType : object, System.Runtime.
Serialization.IextensibleDataObject...
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.
Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="gender-
Type",Namespace="http://schemas.example.org/enterprise/models/v1")]

public enum genderType : int...
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.
Serialization", "4.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute
(Name="personList",
Namespace="http://schemas.example.org/enterprise/models/v1",
ItemName="person")]

public class personList :
System.Collections.Generic.List<schemas.example.org.enterprise.
person>...
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel",
"4.0.0.0")]

public interface PersonServiceInterfaceChannel :
schemas.example.org.enterprise.PersonServiceInterface, System.
ServiceModel.IclientChannel...
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel",
"4.0.0.0")]

public partial class PersonServiceInterfaceClient : System.
ServiceModel.ClientBase<schemas.example.org.enterprise.
PersonServiceInterface>, schemas.example.org.enterprise.
PersonServiceInterface


What we have here consists of an interface for the actual service and classes for message types. This is convenient as it establishes a structure compliant with the service contract (as per logic-to-contract coupling). That the service is generated as an interface makes sense as you would not want to change the generated code in order to implement your service. This further allows you to start writing code to implement the service without having to worry about the code being overwritten if regenerating the service code should become necessary.

The commonly used WCF attributes we should all be familiar with by now are ServiceContract, OperationContract, DataContract, and DataMember.

When your service is ready to be deployed, WCF will allow you to point consumers to the previously created WSDL file rather than an automatically generated WSDL file from WCF (the files will look different). To do this simply add this XML statement to the service configuration file:

<serviceMetadata httpGetEnabled="true"
externalMetadataLocation="\path\personservice.wsdl"/>

Generating WCF Service Code Using WSCF.blue

WSCF.blue is a third party Visual Studio add-in that was created in support of contract-first development. This tool allows you to create WSDL files and generate WCF code from the WSDL markup code. WSCF.blue is a wizard-driven tool and we will therefore be briefly stepping through its screens in this section.

You begin by right-clicking on the PersonServiceMessages.xsd file and choosing the “Create WSDL Interface Description” option (Figure 2).

Figure 2. This command starts a multi-step wizard that guides you through the creation of a WSDL file and also helps you generate service code.

The next set of wizard dialogs are labeled according to steps, as follows:

  • Step 1– The first step lets you specify basic settings, like service name, namespace and documentation (Figure 3).

    Figure 3. The Create a WSDSC Interface Description dialog, Step 1.
  • Step 2– You can add message schemas (other than the ones that are in the file that we right-clicked), as shown in Figure 4. Note that in our particular example we do not need to do carry out this step.

    Figure 4. The Create a WSDSC Interface Description dialog, Step 2.
  • Step 3– You can specify Web service operations, which can also be automatically inferred by the tool (Figure 5).

    Figure 5. The Create a WSDSC Interface Description dialog, Step 3.
  • Step 4– You can determine the message parameters for the individual operations (Figure 6).

    Figure 6. The Create a WSDSC Interface Description dialog, Step 4.
  • Step 5– Here you are presented with a checkbox that allows you to directly move on to a code generation dialog (Figure 7).

    Figure 7. The Create a WSDSC Interface Description dialog, Step 5.

The final dialog will be pre-loaded with the newly created WSDL file and will allow you to choose from generating a client-proxy or a service-stub. For our example, we will be proceeding with the service-stub.

Figure 8. The Code Generation dialog.

The generated code looks familiar, with the exception that the data classes are not serialized using the DataContractSerializer but rather the XmlSerializer. This is deliberate as XmlSerializer supports a wider range of schema constructs.

Example 6.
[System.CodeDom.Compiler.GeneratedCodeAttribute
("System.ServiceModel", "3.0.0.0")] [System.ServiceModel.
ServiceContractAttribute(Namespace="schemas.example.org.enterprise.
service.v1", ConfigurationName="IPersonServiceWCFBlue")]
public interface IPersonServiceWCFBlue
{
// CODEGEN: Generating message contract since the wrapper namespace
(http://schemas.example.org/enterprise/service/v1) of message
GetPersonRequest does not match the default value
(schemas.example.org.enterprise.service.v1) [System.ServiceModel.
OperationContractAttribute(Action="schemas.example.org.enterprise.
service.v1:getPersonIn", ReplyAction="*")] [System.ServiceModel.
XmlSerializerFormatAttribute(SupportFaults=true)]

GetPersonResponse GetPerson(GetPersonRequest request);
// CODEGEN: Generating message contract since the wrapper namespace
(http://schemas.example.org/enterprise/service/v1) of message
GetAllPersonsRequest does not match the default value (schemas.
example.org.enterprise.service.v1) [System.ServiceModel.
OperationContractAttribute(Action="schemas.example.org.enterprise.
service.v1:getAllPersonsIn", ReplyAction="*")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]

GetAllPersonsResponse GetAllPersons(GetAllPersonsRequest request);
// CODEGEN: Generating message contract since the wrapper namespace
(http://schemas.example.org/enterprise/service/v1) of message
UpdatePersonRequest does not match the default value (schemas.
example.org.enterprise.service.v1) [System.ServiceModel.
OperationContractAttribute(Action="schemas.example.org.enterprise.
service.v1:updatePersonIn", ReplyAction="*")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
UpdatePersonResponse UpdatePerson(UpdatePersonRequest request);
}


Generating ASMX Service Code Using WSCF.classic

The WSCF.blue tool has a predecessor called WSCF.classic. This version of the tool is very similar to the current version, but with one big difference: the WSCF.classic tool instead generates ASMX service code. The code generation dialog looks similar to the one in the WSCF.blue but the options are different as shown in Figure 9.

Figure 9. WSCF.classic options.

The generated code is annotated with the familiar WebMethod attribute of ASMX:

Example 7.
Version=0.7.6319.1
#endregion
namespace PersonServiceWCFBlue
{
using System.Diagnostics;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
using System;
using System.Xml.Serialization;
using System.Web;
/// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute
("System.Web.Services", "2.0.50727.4016")] [System.Web.Services.

WebServiceAttribute(Namespace="schemas.example.org.enterprise.
service.v1")] [System.Web.Services.WebServiceBindingAttribute(Name=
"BasicHttpBinding_PersonServiceWCFBlueInterface",
Namespace="schemas.example.org.enterprise.service.v1")]
public partial class BasicHttpBinding_PersonServiceWCFBlueInterface :
System.Web.Services.WebService, IBasicHttpBinding_PersonServiceWCF-
BlueInterface
{public BasicHttpBinding_PersonServiceWCFBlueInterface()
{
}
/// <remarks/>
[System.Web.Services.WebMethodAttribute()] [System.Web.Services.
Protocols.SoapDocumentMethodAttribute("schemas.example.org.
enterprise.service.v1:getPersonIn",
RequestNamespace="http://schemas.example.org/enterprise/service/v1",
ResponseNamespace="http://schemas.example.org/enterprise/service/v1",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.
Wrapped, Binding="BasicHttpBinding_PersonServiceWCFBlueInterface")]
[return: System.Xml.Serialization.XmlElementAttribute("person",
IsNullable=true)]
public virtual person GetPerson([System.Xml.Serialization.
XmlElementAttribute(DataType="positiveInteger", ElementName=
"personId")] string personId)
{throw new System.NotImplementedException();}
/// <remarks/>
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("schemas.
example.org.enterprise.service.v1:getAllPersonsIn",
RequestNamespace="http://schemas.example.org/enterprise/service/v1",
ResponseNamespace="http://schemas.example.org/enterprise/service/v1",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.
Wrapped, Binding="BasicHttpBinding_PersonServiceWCFBlueInterface")]
[return: System.Xml.Serialization.XmlArrayAttribute("person",
IsNullable=true)]
[return:
System.Xml.Serialization.XmlArrayItemAttribute(Namespace="http://
schemas.example.org/enterprise/models/v1", IsNullable=false)]
public virtual person[] GetAllPersons()
{throw new System.NotImplementedException();}
/// <remarks/>
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("schemas.
example.org.enterprise.service.v1:updatePersonIn",
RequestNamespace="http://schemas.example.org/enterprise/service/v1",
ResponseNamespace="http://schemas.example.org/enterprise/service/v1",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.
Wrapped, Binding="BasicHttpBinding_PersonServiceWCFBlueInterface")]
[return: System.Xml.Serialization.XmlElementAttribute("success")]
public virtual bool UpdatePerson([System.Xml.Serialization.
XmlElementAttribute(IsNullable=true, ElementName="updatablePerson")]
person updatablePerson)
{throw new System.NotImplementedException();}
}}


Other -----------------
- Service-Orientation with .NET : Service Loose Coupling
- Service-Orientation with .NET : Service Contracts and Interoperability - Canonical Protocol
- Service-Orientation with .NET : Service Contracts and Interoperability - Data Model Transformation
- Service-Orientation with .NET : Service Contracts and Interoperability - Canonical Schema
- Service-Orientation with .NET : Standardized Service Contract
- Cloud Services with Windows Azure : Windows Azure Storage
- A REST Service in Windows Azure
- Cloud Services with Windows Azure : A Web Service in Windows Azure
- Cloud Services with Windows Azure : Hello World in Windows Azure
- Cloud Services with Windows Azure : Windows Azure Roles
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server