官术网_书友最值得收藏!

Defining the contract

Unlike ASP.NET web services, WCF truly promotes a "contract first" design style where developers need to thoughtfully consider how the outside world will interact with their service. There is a clean separation between the interface definition and the actual implementation of the service. When building ASP.NET services, the developer typically takes a code-first approach, where .NET classes are decorated with attributes and exposed as services. In the WCF model, we focus first on the data being shared and what our interface to the outside world should look like (the contract). Only after this critical step is complete does the WCF developer begin to design the actual service implementation logic.

There are actually three different contracts that you may define for a WCF service:

  • Service contract
  • Data contract
  • Fault contract

There's actually a fourth contract type corresponding to the message, but I won't be covering that here. We'll investigate the service and data contract types right now, but save the fault contract for the Throwing custom service faults section in this chapter.

Service contracts

The service contract explains what your service can do. It's built using a .NET interface class and decorated with WCF attributes that identify it as a service contract. A basic service contract looks like this:

[ServiceContract()]
public interface IVendorContract
{
    [OperationContract()]
    void InsertVendor(string vendorId, string vendorName);

    [OperationContract()]
    bool DeleteVendor(string vendorId);
}

Note that the interface has a ServiceContract attribute and that each operation that we wish to expose publicly on our contract has an OperationContract attribute. Each of these metadata attributes has a series of optional parameters that let us explicitly define public characteristics of the service. For instance, we can add the Name and Namespace properties to ServiceContract to better characterize this service in our environment. We can also add a series of properties to OperationContract to control what the operation is named and what the SOAPAction value is set to. Why give an alternate name to a service operation? Consider scenarios where you have an overloaded operation in your WCF service contract and need each WSDL operation to have a unique public name. C# (and .NET) support overloading, but the WSDL standard no longer does. Examples of service contracts are shown as follows:

[ServiceContract(Name="VendorService", Namespace="http://BizTalkSOA/Contracts")]
public interface IVendorContract
{
    [OperationContract(Name="InsertVendor")]
    void InsertVendor(string vendorId, string vendorName);
    [OperationContract(Name="InsertVendorWithContact")]
    void InsertVendor(string vendorId, string vendorName, string vendorContactName);

    [OperationContract(Name="DeleteVendor")]
    bool DeleteVendor(string vendorId);
}

Data contracts

As you can probably imagine, services often need to accept and return comprehensive data entities in addition to simple type parameters. I might want to model a data entity such as customer instead of having a service operation accept 15 inpidual string parameters. Complex data parameters are categorized as data contracts in WCF. Data contracts can be replica of schemas, or we can think of contracts as .NET class representation of schemas. Contracts can have the same level of hierarchy and structure as schemas. A data contract is a .NET class decorated with the DataContract attribute and whose public properties are flagged with DataMember attributes. Public service operation definitions can only include complex types identified as data contracts as illustrated in the following code:

[DataContract()]
public class VendorType
{
    private string vendorId;
    private string vendorName;
    private string vendorContactName;

    [DataMember()]
    public string VendorId
    {
        get { return vendorId; }
        set { vendorId = value; }
    }

    [DataMember()]
    public string VendorName
    {
        get { return vendorName; }
        set { vendorName = value; }
    }

    [DataMember()]
    public string VendorContactName
    {
        get { return vendorContactName; }
        set { vendorContactName = value; }
    }
}

Much like the service contract, the attributes of the data contract allow for more fine-grained control of the entity definition. For instance, we may provide Name and Namespace to DataContract while also adding some useful node ordering and existence attributes to the member elements:

[DataContract(Name="Vendor" Namespace = "http://BizTalkSOA/Types")]
public class VendorType
{
    private string vendorId;
    private string vendorName;
    private string vendorContactName;

    [DataMember(IsRequired=true, Order=0)]
    public string VendorId
    {
        get { return vendorId; }
        set { vendorId = value; }
    }

    [DataMember(IsRequired=true, Order=1)]
    public string VendorName
    {
        get { return vendorName; }
        set { vendorName = value; }
    }

    [DataMember(IsRequired=false, Order=2)]
    public string VendorContactName
    {
        get { return vendorContactName; }
        set { vendorContactName = value; }
    }
}

If you omit the Order property from the DataMember attribute, the nodes are ordered alphabetically, which may not be how you wish to organize your public schema.

主站蜘蛛池模板: 淮南市| 长春市| 龙山县| 和硕县| 阿图什市| 呼图壁县| 麻栗坡县| 兴文县| 淮安市| 安塞县| 美姑县| 保康县| 桐庐县| 柯坪县| 吴川市| 尼勒克县| 阳西县| 灯塔市| 古蔺县| 武宁县| 客服| 云南省| 扎赉特旗| 南乐县| 永善县| 奉贤区| 景德镇市| 台东市| 松溪县| 辰溪县| 万宁市| 荔波县| 定襄县| 浦江县| 丹东市| 天水市| 贵南县| 长宁区| 庄浪县| 双流县| 浦东新区|