Windows Communication Foundation journey Series 4)

Source: Internet
Author: User

6. Define datacontract

When I introduced how to define a servicecontract, I gave an example as follows,CodeAs follows:
[Servicecontract]
Public class bookticket
{
[Operationcontract]
Public bool check (Ticket)
{
Bool flag;
// Logic to check whether the ticket is none;
Return flag;
}
[Operationcontract]
Private bool book (Ticket)
{
// Logic to book the ticket
}
}

In service bookticket, the check and book parameters of the two service methods are of the ticket type. This type is a custom type. According to the requirements of WCF, this type must support serialized operations before it can be passed as a message in the service method.

In. net, except for basic types such as int, long, double, enumeration type, and string type, if a custom type supports serialization, you should mark this type as [serializable] or enable this type to implement the iserializable interface. In WCF, we recommend that you mark datacontractattribute for these types. The method is as follows:
[Datacontract]
Public class ticket
{
Private string m_moviename;

[Datamember]
Public int seatno;
[Datamember]
Public String moviename
{
Get {return m_moviename ;}
Set {m_moviename = value ;}
}
[Datamember]
Private datetime time;
}

[Datamember] indicates the attribute of a member of the datacontract class. Similar to operationcontractattribute in the service class, datamemberattribute has no direct relationship with object access restriction modifiers (public, internal, Private, etc. Even if the member is private, it can still be serialized as long as [datamember] is marked. Although datamemberattribute can be applied to fields and attributes of the type, if it is applied to a static member, WCF ignores the datamemberattribute.

When we label datacontractattribute for a type, serialization is supported only for members explicitly labeled with datamemberattribute. This is quite different from serializableattribute. A type marked with serializableattribute. By default, its internal members, whether public or private, support serialization unless they are members that have been applied nonserializedattribute. Datacontractattribute adopts this explicit annotation method, which enables us to focus more on the definition of service messages. datamemberattribute is labeled only for Service Message members that need to be passed.

If the datamember member in the datacontract class contains generics, the generic type parameters must support serialization, as shown in the following code:
[Datacontract]
Public class mygeneric
{
[Datamember]
T thedata;
}

In the mygeneric class, generic parameter T must support serialization. If this object is instantiated:
Mygeneric initialize bject = new mygeneric ();
Mygeneric customobject = new mygeneric ();

The passed generic parameter of object jsonbject can be serialized because it is of the int basic type. Whether the custom object can be serialized depends on whether the imported generic parameter customtype type supports serialization.

Datacontract is uniquely identified by namespace and name. You can set it in the namespace and name attributes of datacontractattribute. If the name attribute of datacontract is not set, the default name is the defined type name. You can also set the name attribute for datamember. The default name is the defined member name. The following code is used:
Namespace mycompany. orderproc
{
[Datacontract]
Public class purchaseorder
{
// Datamember is named as the default amount;
[Datamember]
Public double amount;

// The default name ship_to will be rewritten for the name attribute. In this case, the datamember name is address;
[Datamember (name = "Address")]
Public String ship_to;
}
// Namespace is the default value:
// Http://schemas.datacontract.org/2004/07/MyCompany.OrderProc
// Its name is "purchaseorder" instead of "myinvoice ".
[Datacontract (name = "purchaseorder")]
Public class myinvoice
{
// Code not shown.
}

// Its name is payment, not mypayment
// Namespace is set to http://schemas.example.com
[Datacontract (name = "Payment ",
Namespace = http://schemas.example.com)]
Public class mypayment
{
// Code not shown.
}
}

// Rewrite the namespace of all datacontract under mycorp. CRM
[Assembly: contractnamespace (
Clrnamespace = "mycorp. CRM ",
Namespace = "http://schemas.example.com/crm")]
Namespace mycorp. CRM
{
// At this time namespace is set to http://schemas.example.com/crm.
// The name is still the default value Customer
[Datacontract]
Public Class Customer
{
// Code not shown.
}
}

Since datacontract will be serialized and deserialized, the order of members in the type is also very important. In datamemberattribute, the Order attribute is provided to set the order of members. The serialization sequence of members in WCF is defined as follows:
1. The default order is in alphabetical order;
2. If the members specify the order through the order attribute and the order value is the same, the Order is in alphabetical order;
3. The order attribute is not specified before the order is specified;
4. If datacontract is in the inheritance system, the membership order of the parent class takes precedence regardless of the order value specified in the subclass.

The following code demonstrates the order of datamember:
[Datacontract]
Public class basetype
{
[Datamember] Public String zebra;
}

[Datacontract]
Public class derivedtype: basetype
{
[Datamember (Order = 0)] Public String bird;
[Datamember (Order = 1)] Public String parrot;
[Datamember] Public String dog;
[Datamember (Order = 3)] Public String antelope;
[Datamember] Public String cat;
[Datamember (Order = 1)] Public String albatross;
}

The serialized XML content is as follows:
<Derivedtype>
<Zebra/>
<CAT/>
<Dog/>
<Bird/>
<Albatross/>
<Parrot/>
<Antelope/>
</Derivedtype>

Because the Member zebra is a parent class member, the first order is at the beginning. Cat and dog do not specify order, so they are listed alphabetically before other members of order are specified. Both parrot and albatross specify the order value as 1. Therefore, they are arranged alphabetically after the bird whose order value is 0.

Determine whether two datacontract are the same. It should be determined based on the namespace and name of datacontract, and the name and order of datamember. For example, the Class Customer and person shown in the following code are actually the same datacontract:
[Datacontract]
Public Class Customer
{
[Datamember]
Public String fullname;

[Datamember]
Public String telephonenumber;
}

[Datacontract (name = "customer")]
Public class person
{
[Datamember (name = "fullname")]
Private string nameofperson;

Private string address;

[Datamember (name = "telephonenumber")]
Private string phonenumber;
}

For example, the classes coords1, coords2, and coords3 shown in the following code are also the same datacontract, while the classes coords4 are different from the first three classes because of their order:
[Datacontract (name = "coordinates")]
Public class coords1
{
[Datamember] public int X;
[Datamember] public int y;
}

[Datacontract (name = "coordinates")]
Public class coords2
{
[Datamember] public int y;
[Datamember] public int X;
}

[Datacontract (name = "coordinates")]
Public class coords3
{
[Datamember (Order = 2)] public int y;
[Datamember (Order = 1)] public int X;
}
[Datacontract (name = "coordinates")]
Public class coords4
{
[Datamember (Order = 1)] public int y;
[Datamember (Order = 2)] public int X;
}

When datacontract is in an inheritance system, note the "polymorphism" of objects. If messages are to be transmitted between the server and the client, dynamic binding of types is often involved. According to regulations, if the message type is subclass type, then the sender cannot transmit the base class type. On the contrary, if the message type is a parent class, the sender can be the parent class or its subclass. From this point of view, the WCF rules are in parallel with the object-oriented thinking. However, the possible problem is that when the message type is defined as the parent class type and the sender transmits its subclasses, the server may be in an "unknown" status for this subclass type, this prevents normal deserialization. Therefore, WCF provides knowntypeattribute for datacontract and sets it to inform the server of possible dynamic binding class types.

For example, if we define three classes:
[Datacontract]
Public class shape {}

[Datacontract (name = "circle")]
Public class circletype: Shape {}

[Datacontract (name = "Triangle")]
Public class triangletype: Shape {}

Then define the shape field in the companylogo class, as shown below:
[Datacontract]
Public class companylogo
{
[Datamember]
Private shape shapeoflogo;
[Datamember]
Private int coloroflogo;
}

In this case, the companylogo class can be serialized because [datacontract] and [datamember] are correctly set, and the shape type also supports serialization. However, if the client sets the value of the shapeoflogo field to circletype or triangletype when calling a companylogo object, a deserialization error occurs, because the server does not know the circletype or triangletype type, it cannot perform a correct match. Therefore, the definition of the companylogo class should be modified as follows:
[Datacontract]
[Knowntype (typeof (circletype)]
[Knowntype (typeof (triangletype)]
Public class companylogo
{
[Datamember]
Private shape shapeoflogo;
[Datamember]
Private int coloroflogo;
}

The implementation of interfaces is the same as that of classes, as shown in the following example:
Public interface icustomerinfo
{
String returncustomername ();
}

[Datacontract (name = "customer")]
Public class customertype: icustomerinfo
{
Public String returncustomername ()
{
Return "No Name ";
}
}

[Datacontract]
[Knowntype (typeof (mermertype)]
Public class purchaseorder
{
[Datamember]
Icustomerinfo buyer;

[Datamember]
Int amount;
}

Because the field of icustomerinfo interface type is defined in the purchaseorder, if this class can be correctly deserialized, you must add the [knowntype (typeof (customertype)] annotation to the class purchaseorder.

Set types are similar. For example, for the hashtable type, all objects stored in it are object objects, but the actual value may be some custom types. In this case, you may need to mark them by knowntype. For example, in the class librarycatalog, The hashtable field thecatalog is defined. This field may be set to book and magazine. If both book and magazine are defined as datacontract, the correct definition of librarycatalog should be as follows:
[Datacontract]
[Knowntype (typeof (book)]
[Knowntype (typeof (magazine)]
Public class librarycatalog
{
[Datamember]
System. Collections. hashtable thecatalog;
}

If a field of the object type is defined in datacontract. Because the object type is a parent class of all types, we need to use knowntype to indicate the types allowed by the client. For example, mathoperationdata:
[Datacontract]
[Knowntype (typeof (INT [])]
Public class mathoperationdata
{
Private object numbervalue;
[Datamember]
Public object numbers
{
Get {return numbervalue ;}
Set {numbervalue = value ;}
}
// [Datamember]
// Public operation;
}

The property numbers belongs to the object type, while knowntype is set to int []. Therefore, acceptable types include integer, integer array, and list type. The following calls are correct:
Static void run ()
{
Mathoperationdata MD = new mathoperationdata ();

Int A = 100;
Md. Numbers =;

Int [] B = new int [100];
Md. Numbers = B;

List C = new list ();
Md. Numbers = C;
}

However, if the number attribute is set to arraylist, an error occurs even if all elements in the arraylist object are int objects:
Static void run ()
{
Mathoperationdata MD = new mathoperationdata ();

Arraylist d = new arraylist ();
Md. Numbers = D;
}

Once a datacontract type is labeled with knowntypeattribute, the scope of this attribute can be applied to its subclass, as shown below:
[Datacontract]
[Knowntype (typeof (circletype)]
[Knowntype (typeof (triangletype)]
Public class mydrawing
{
[Datamember]
Private object shape;
[Datamember]
Private int color;
}

[Datacontract]
Public class doubledrawing: mydrawing
{
[Datamember]
Private object additionalshape;
}

Although doubledrawing is not labeled with knowtypeattribute, its field additionalshape can still be set to circletype or triangletype because its parent class has been set to knowtypeattribute.

Note: knowtypeattribute can mark classes and structures, but cannot mark interfaces. In addition, datacontract cannot mark interfaces, but can only label classes, structures, and enumeration. To use datacontractattribute, datamemberattribute, and knowntypeattribute, you must add system. runtime. serialization of the winfx version.ProgramSet Reference.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.