As a builder of this WCF service, you did not have to build the data contract because this service used simple types.. Listing 29-34: Building the Customer type VB Imports System Imports
Trang 1isWSHttpBinding_ICalculator, which is a reference to the<binding>element contained within the
<wsHttpBinding>element:
As demonstrated, the Visual Studio 2008 enhancements for WCF do make the consumption of these
services fairly trivial The next step is to code the consumption of the service interface to the GUI that
was created as one of the first steps
Writing the Consumption Code
The code to consume the interface is quite minimal The end user places a number in each of the two
text boxes provided and clicks the button to call the service to perform the designated operation on the provided numbers Listing 29-31 is the code from the button click event:
Listing 29-31: The button click event to call the service
VB
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Button1.Click
Dim ws As New ServiceReference.CalculatorClient()
Dim result As Integer
result = ws.Add(TextBox1.Text, TextBox2.Text)
Response.Write(result.ToString())
ws.Close()
End Sub
C#
protected void Button1_Click(object sender, EventArgs e)
{
ServiceReference.CalculatorClient ws = new ServiceReference.CalculatorClient();
int result = ws.Add(int.Parse(TextBox1.Text), int.Parse(TextBox2.Text));
Response.Write(result);
ws.Close();
}
This is quite similar to what is done when working with Web references from the XML Web services
world First is an instantiation of the proxy class, as shown with the creation of thesvcobject:
Dim ws As New ServiceReference.CalculatorClient()
Working with thewsobject now, the IntelliSense options provide you with the appropriateAdd(), Sub-tract(),Multiply(), andDivide()methods
As before, the requests and responses are sent over HTTP as SOAP 1.2 This concludes the short tutorial demonstrating how to build your own WCF service using the HTTP protocol and consume this service directly into an ASP.NET application
Trang 2Working with Data Contracts
Thus far, when building the WCF services, the defined data contract has relied upon simple types or
primitive datatypes In the case of the earlier WCF service, a NET type ofIntegerwas exposed, which
in turn was mapped to an XSD type ofint While you may not be able to see the input and output types
defined in the WSDL document provided via the WCF-generated one, they are there These types are
actually exposed through an imported.xsddocument (Calculator.xsdandCalculator1.xsd) This bit
of the WSDL document is presented in Listing 29-32:
Listing 29-32: Imported types in the WSDL document
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/Calculator.svc?xsd=xsd0"
namespace="http://tempuri.org/" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/Calculator.svc?xsd=xsd1"
namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
</xsd:schema>
</wsdl:types>
Typing in the XSD location ofhttp://localhost:51715/WCFService1/Calculator.svc?xsd=xsd0gives
you the input and output parameters of the service For instance, looking at the definition of theAdd()
method, you will see the following bit of code, as shown in Listing 29-33
Listing 29-33: Defining the required types in the XSD
<xs:element name="Add">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="a" type="xs:int" />
<xs:element minOccurs="0" name="b" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="AddResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="AddResult" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
This bit of XML code indicates that there are two required input parameters (aandb) that are
of typeint; in return, the consumer gets an element called<AddResult>, which contains a value of
typeint
As a builder of this WCF service, you did not have to build the data contract because this service used
simple types When using complex types, you have to create a data contract in addition to your service
contract
Trang 3Building a Service with a Data Contract
For an example of working with data contracts, create a new WCF service (another WCF service project) calledWCF_WithDataContract In this case, you still need an interface that defines your service contract, and then another class that implements that interface In addition to these items, you also need another class that defines the data contract
As with the service contract, which makes use of the<ServiceContract()>and the
<Operation-Contract()>attributes, the data contract uses the<DataContract()>and<DataMember()>attributes
To gain access to these attributes, you have to make a reference to theSystem.Runtime.Serialization
namespace in your project and import this namespace into the file
The custom type in this case is aCustomertype, as presented in Listing 29-34
Listing 29-34: Building the Customer type
VB
Imports System
Imports System.ServiceModel
Imports System.Runtime.Serialization
<DataContract()> _
Public Class Customer
<DataMember()> _
Public FirstName As String
<DataMember()> _
Public LastName As String
End Class
<ServiceContract()> _
Public Interface IHelloCustomer
<OperationContract()> _
Function HelloFirstName(ByVal cust As Customer) As String
<OperationContract()> _
Function HelloFullName(ByVal cust As Customer) As String
End Interface
C#
using System.Runtime.Serialization;
using System.ServiceModel;
[DataContract]
public class Customer
{
[DataMember]
public string Firstname;
[DataMember]
public string Lastname;
}
Continued
Trang 4[ServiceContract] IHelloCustomer
public interface IWithContract
{
[OperationContract]
string HelloFirstName(Customer cust);
[OperationContract]
string HelloFullName(Customer cust);
}
Here, you can see that theSystem.Runtime.Serializationnamespace is also imported, and the first
class in the file is the data contract of the service This class, theCustomerclass, has two members:
First-NameandLastName Both of these properties are of typeString You specify a class as a data contract
through the use of the<DataContract()>attribute:
<DataContract()> _
Public Class Customer
‘ Code removed for clarity
End Class
Now, any of the properties contained in the class are also part of the data contract through the use of the
<DataMember()>attribute:
<DataContract()> _
Public Class Customer
<DataMember()> _
Public FirstName As String
<DataMember()> _
Public LastName As String
End Class
Finally, theCustomerobject is used in the interface, as well as the class that implements the
IHelloCus-tomerinterface, as shown in Listing 29-35
Listing 29-35: Implementing the interface
VB
Public Class HelloCustomer
Implements IHelloCustomer
Public Function HelloFirstName(ByVal cust As Customer) As String _
Implements IHelloCustomer.HelloFirstName
Return "Hello " & cust.FirstName End Function
Public Function HelloFullName(ByVal cust As Customer) As String _
Implements IHelloCustomer.HelloFullName
Return "Hello " & cust.FirstName & " " & cust.LastName
Trang 5End Function
End Class
C#
public class HelloCustomer: IHelloCustomer
{
public string HelloFirstName(Customer cust)
{
return "Hello " + cust.Firstname;
}
public string HelloFullName(Customer cust)
{
return "Hello " + cust.Firstname + " " + cust.Lastname;
}
}
Building the Consumer
Now that the service is running and in place, the next step is to build the consumer To begin, build a
new ASP.NET application from Visual Studio 2008 and call the projectHelloWorldConsumer Again,
right-click on the solution and select Add Service Reference from the options provided in the menu
From the Add Service Reference dialog box, add the location of the WSDL file for the service and press
OK This adds the changes to the references and theweb.configfile just as before, enabling you to con-sume the service The following code, as presented in Listing 29-36, shows what is required to concon-sume the service if you are using a Button control to initiate the call
Listing 29-36: Consuming a custom type through a WCF service
VB
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Button1.Click
Dim ws As New ServiceReference.HelloCustomerClient()
Dim myCustomer As New ServiceReference.Customer()
myCustomer.Firstname = "Bill"
myCustomer.Lastname = "Evjen"
Response.Write(ws.HelloFullName(myCustomer))
ws.Close()
End Sub
C#
protected void Button1_Click(object sender, EventArgs e)
{
ServiceReference.HelloCustomerClient ws = new
ServiceReference.HelloCustomerClient();
ServiceReference.Customer myCustomer = new ServiceReference.Customer();
Continued
Trang 6myCustomer.Firstname = "Bill";
myCustomer.Lastname = "Evjen";
Response.Write(ws.HelloFullName(myCustomer));
ws.Close();
}
As a consumer, once you make the reference, you will notice that the service reference provides both
aHelloCustomerClientobject andtheCustomerobject, which was defined through the service’s data
contract
Therefore, the preceding code block just instantiates both of these objects and builds theCustomerobject
before it is passed into theHelloFullName()method provided by the service
Looking at WSDL and the Schema for HelloCustomerService
When you make a reference to theHelloCustomerservice, you will find the following XSD imports in
the WSDL:
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd0"
namespace="http://tempuri.org/" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd1"
namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd2"
namespace="http://schemas.datacontract.org/2004/07/" />
</xsd:schema>
</wsdl:types>
http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd2provides the details on your
Customerobject The code from this file is shown here:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified"
targetNamespace="http://schemas.datacontract.org/2004/07/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://schemas.datacontract.org/2004/07/">
<xs:complexType name="Customer">
<xs:sequence>
<xs:element minOccurs="0" name="Firstname" nillable="true"
type="xs:string" />
<xs:element minOccurs="0" name="Lastname" nillable="true"
type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="Customer" nillable="true" type="tns:Customer" />
</xs:schema>
Trang 7This is an XSD description of theCustomerobject Making a reference to the WSDL includes the XSD
description of theCustomerobject and gives you the ability to create local instances of this object
Using this model, you can easily build your services with your own defined types
Namespaces
Note that the services built in the chapter have no defined namespaces If you looked at the WSDL files that were produced, you would see that the namespace provided ishttp://tempuri.org Obviously, you
do not want to go live with this default namespace Instead, you need to define your own namespace
To accomplish this task, the interface’s<ServiceContract()>attribute enables you to set the
names-pace, as shown here:
<ServiceContract(Namespace:="http://www.lipperweb.com/ns/")> _
Public Interface IHelloCustomer
<OperationContract()> _
Function HelloFirstName(ByVal cust As Customer) As String
<OperationContract()> _
Function HelloFullName(ByVal cust As Customer) As String
End Interface
Here, the<ServiceContract()>attribute uses theNamespaceproperty to provide a namespace
Summar y
This chapter was a whirlwind tour of XML Web services in the NET platform It is definitely a topic that merits an entire book of its own The chapter showed you the power of exposing your data and logic as SOAP and also how to consume these SOAP messages directly in the ASP.NET applications you build
In addition to pointing out the power you have for building and consuming basic Web services, the
chapter spent some time helping you understand caching, performance, the use of SOAP headers, and
more A lot of power is built into this model; every day the Web services model is starting to make
stronger inroads into various enterprise organizations It is becoming more likely that to get at some data
or logic you need for your application, you will employ the tactics presented here
This chapter also looked at one of the newest capabilities provided to the NET Framework world The
.NET Framework 3.5 and WCF are a great combination for building advanced services that take ASP.NET Web services, NET Remoting, Enterprise Services, and MSMQ to the next level
While not exhaustive, this chapter broadly outlined the basics of the framework As you start to dig
deeper in the technology, you will find capabilities that are strong and extensible
Trang 8Developers usually build Web applications in their native language and then, as the audience for
the application expands, they then realize the need to globalize the application Of course, the ideal
is to build the Web application to handle an international audience right from the start — but, in
many cases, this may not be possible because of the extra work it requires
It is good to note that with the ASP.NET 3.5 framework, a considerable effort has been made
to address the internationalization of Web applications You quickly realize that changes to the
API, the addition of capabilities to the server controls, and even Visual Studio itself equip you to
do the extra work required more easily to bring your application to an international audience This
chapter looks at some of the important items to consider when building your Web applications for
the world
Cultures and Regions
The ASP.NET page that is pulled up in an end user’s browser runs under a specific culture and
region setting When building an ASP.NET application or page, the defined culture in which it
runs is dependent upon both a culture and region setting coming from the server in which the
application is run or from a setting applied by the client (the end user) By default, ASP.NET runs
under a culture setting defined by the server
The world is made up of a multitude of cultures, each of which has a language and a set of defined
ways in which it views and consumes numbers, uses currencies, sorts alphabetically, and so on
The NET Framework defines cultures and regions using the Request for Comments 1766 standard
definition (tags for identification of languages) that specifies a language and region using two-letter
codes separated by a dash The following table provides examples of some culture definitions
Trang 9Culture Code Description
Looking at the examples in this table, you can see that four distinct cultures are defined These four
cultures have some similarities and some differences All four cultures speak the same language (English)
For this reason, the language code ofenis used in each culture setting After the language setting comes
the region setting Even though these cultures speak the same language, it is important to distinguish
them further by setting their region (such asUSfor the United States,GBfor the United Kingdom,AU
for Australia, andCAfor Canada) As you are probably well aware, the English language in the United
States is slightly different from the English language that is used in the United Kingdom, and so forth
Beyond language, differences exist in how dates and numerical values are represented This is why
a culture’s language and region are presented together
The differences do not break down by the country only Many times, countries contain more than a single
language and each area has its own preference for notation of dates and other items For example,en-CA
specifies English speakers in Canada Because Canada is not only an English-speaking country, it also
includes the culture setting offr-CAfor French-speaking Canadians
Understanding Culture Types
The culture definition you have just seen is called a specific culture definition This definition is as detailed
as you can possibly get — defining both the language and the region The other type of culture definition
is a neutral culture definition Each specific culture has a specified neutral culture that it is associated
with For instance, the English language cultures shown in the previous table are separate, but they also
all belong to one neutral culture EN (English) The diagram presented in Figure 30-1 displays how these
culture types relate to one another
From this diagram, you can see that many specific cultures belong to a neutral culture Higher in the
hierarchy than the neutral culture is an invariant culture, which is an agnostic culture setting that should
be utilized when passing items (such as dates and numbers) around a network When performing these
kinds of operations, make your back-end data flows devoid of user-specific culture settings Instead,
apply these settings in the business and presentation layers of your applications
Also, pay attention to the neutral culture when working with your applications Invariably, you are going
to build applications with views that are more dependent on a neutral culture rather than on a specific
culture For instance, if you have a Spanish version of your application, you probably make this version
available to all Spanish speakers regardless of their regions In many applications, it will not matter
if the Spanish speaker is from Spain, Mexico, or Argentina In a case where it does make a difference,
use the specific culture settings
Trang 10Invariant Culture
EN (Neutral Culture)
en-US en-GB en-AU en-CA
es -ES
es -MX
es -AR
ES (Neutral Culture)
Figure 30-1
The ASP.NET Threads
When the end user requests an ASP.NET page, this Web page is executed on a thread from the thread
pool The thread has a culture associated with it You can get information about the culture of the
thread programmatically and then check for particular details about that culture This is illustrated in
Listing 30-1
Listing 30-1: Checking the culture of the ASP.NET thread
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim ci As CultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture
Response.Write("<b><u>CURRENT CULTURE’S INFO</u></b>")
Response.Write("<p><b>Culture’s Name:</b> " & ci.Name.ToString() & "<br>")
Continued