Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1373
Chapter 29: Building and Consuming Services
is
WSHttpBinding_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 e vent 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 the
svc
object:
Dim ws As New ServiceReference.CalculatorClient()
Working with the
ws
object now, the IntelliSense options provide you with the appropriate
Add()
,
Sub-
tract()
,
Multiply()
,and
Divide()
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.
1373
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1374
Chapter 29: Building and Consuming Services
Working 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 of
Integer
was exposed, which
in turn was mapped to an XSD type of
int
.Whileyoumaynotbeabletoseetheinputandoutputtypes
defined in the WSDL document provided via the WCF-generated one, they are there. These types are
actually exposed through an imported
.xsd
document (
Calculator.xsd
and
Calculator1.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=" /><xsd:import
schemaLocation="http://localhost:51715/WCFService1/Calculator.svc?xsd=xsd0"
namespace=" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/Calculator.svc?xsd=xsd1"
namespace=" />
</xsd:schema>
</wsdl:types>
Typing in the XSD location of
http://localhost:51715/WCFService1/Calculator.svc?xsd=xsd0
gives
you the input and output parameters of the service. For instance, looking at the definition of the
Add()
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 (
a
and
b
)thatare
of type
int
; in return, the consumer gets an element called <
AddResult
>, which contains a value of
type
int
.
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.
1374
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1375
Chapter 29: Building and Consuming Services
Building a Service with a Data Contract
For an example of working with data contracts, create a new WCF service (another WCF service project)
called
WCF_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 t he 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 the
System.Runtime.Serialization
namespace in your project and import this namespace into the file.
Thecustomtypeinthiscaseisa
Customer
type, 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
1375
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1376
Chapter 29: Building and Consuming Services
[ServiceContract] IHelloCustomer
public interface IWithContract
{
[OperationContract]
string HelloFirstName(Customer cust);
[OperationContract]
string HelloFullName(Customer cust);
}
Here, you can see that the
System.Runtime.Serialization
namespace is also imported, and the first
class in the file is the data contract of the service. This class, the
Customer
class, has two members:
First-
Name
and
LastName
. Both of these properties are of type
String
. 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 o f 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, the
Customer
object is used in the interface, as well as the class that implements the
IHelloCus-
tomer
interface, 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
1376
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1377
Chapter 29: Building and Consuming Services
End 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 project
HelloWorldConsumer
.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 the
web.config
file just as before, enabling you to con-
sume the service. The following code, as presented in Listing 29-36, shows what is required to consume
the service if you are using a Button control to initiate the call.
Listing 29-36: C onsuming 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
1377
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1378
Chapter 29: Building and Consuming Services
myCustomer.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
a
HelloCustomerClient
object andthe
Customer
object, which was defined through the service’s data
contract.
Therefore, the preceding code block just instantiates both of these objects and builds the
Customer
object
before it is passed into the
HelloFullName()
method provided by the service.
Looking at WSDL and the Schema for HelloCustomerService
When you make a reference to the
HelloCustomer
service, you will find the following XSD imports in
the WSDL:
<wsdl:types>
<xsd:schema targetNamespace=" /><xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd0"
namespace=" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd1"
namespace=" />
<xsd:import
schemaLocation="http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd2"
namespace=" />
</xsd:schema>
</wsdl:types>
http://localhost:51715/WCFService1/HelloCustomer.svc?xsd=xsd2
provides the details on your
Customer
object. The code from this file is shown here:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified"
targetNamespace=" />xmlns:xs=" />xmlns:tns=" /><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>
1378
Evjen c29.tex V2 - 01/28/2008 3:53pm Page 1379
Chapter 29: Building and Consuming Services
This is an XSD description of the
Customer
object. Making a reference to the WSDL includes the XSD
description of the
Customer
object 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 is
. 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:=" _
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 the
Namespace
property to provide a namespace.
Summary
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 e xhaustive, 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.
1379
Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1381
Localization
Developers 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.
Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1382
Chapter 30: Localization
Culture Code Description
en-US English language; United States
en-GB English language; United Kingdom (Great Britain)
en-AU English language; Australia
en-CA English language; Canada
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 of
en
is 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 as
US
for the United States,
GB
for the United Kingdom,
AU
for Australia, and
CA
for 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 of
fr-CA
for 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.
1382
Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1383
Chapter 30: Localization
Invariant
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
1383