Wei-Meng Lee - C# 2008 Programmer's Reference

Здесь есть возможность читать онлайн «Wei-Meng Lee - C# 2008 Programmer's Reference» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Indianapolis, Год выпуска: 2009, ISBN: 2009, Издательство: Wiley Publishing, Inc., Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

C# 2008 Programmer's Reference: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «C# 2008 Programmer's Reference»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

C# 2008 Programmers Reference provides a concise and thorough reference on all aspects of the language. Each chapter contains detailed code samples that provide a quick and easy way to understand the key concepts covered.

C# 2008 Programmer's Reference — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «C# 2008 Programmer's Reference», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

client.Close();

}

Calling the WCF service is very similar to consuming an ASMX Web Service — create an instance of the proxy class, call the service's operation, pass in the required parameters, and wait for the result from the service.

Set the Windows Forms application as the startup project, and press F5. A message box appears, displaying 18.

Understanding How WCF Works

Now that you have built your first WCF service, let's take a more detailed look at the innards of WCF.

WCF Communication Protocols

As mentioned earlier, WCF can use a wide variety of transport protocols to transport its messages. Here are just some of the common ones that you can use:

HTTP —Much like the traditional ASMX Web Services

TCP— Much more flexible and efficient than HTTP; more complex to configure (you'll see an example of this later in this chapter)

Named Pipe— Used to communicate with WCF services on the same machine but residing in different processes

MSMQ— Uses queuing technology; inherently asynchronous

The ABCs of WCF

Figure 20-17 shows the ABCs of WCF — address, binding, and contract.

Figure 2017 Address The address that the service is listening at This - фото 468

Figure 20-17

Address— The address that the service is listening at. This indicates where the service can be located and used. The address for a WCF service is dependent on the communication protocol used.

Binding— The type of binding that you will use to communicate with the service. The binding used determines the security requirements for the communication and how clients will connect to the service.

Contract— The contract defines what the service offers. The following sections discuss each of these points in detail.

Addresses and Endpoints

Every WCF service has an address and endpoints in which it listens for incoming connections. Figure 20-18 shows a WCF service with two endpoints exposed. A client wanting to use the service just needs to send messages to the appropriate endpoint.

Figure 2018 The address of a WCF service depends on the protocols used for the - фото 469

Figure 20-18

The address of a WCF service depends on the protocols used for the service. For example, if a WCF service uses the HTTP protocol, then its address may be:

http://:/<\/code><\/p>

https://:&lt;port&gt;/&lt;service&gt;&lt;\/code&gt;&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;https://&lt;server&gt;:&lt;port&gt;/&lt;service&gt;.svc&lt;\/code&gt;&lt;\/p&gt; &lt;p&gt;If a WCF service uses TCP as the protocol, its address is in this format:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;net.tcp://&lt;server&gt;:&lt;port&gt;/&lt;service&gt;&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;For Named Pipes, the address is &lt;code&gt;net.pipe://&lt;server&gt;/&lt;service&gt;&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;A service may have an operation that uses any of the protocols (or all). For example, a service may listen at port 80 (endpoint number 1) using HTTP as well as listen at port 5000 (endpoint number 2) using TCP.&lt;\/p&gt; &lt;div class="title"&gt;Bindings&lt;\/div&gt; &lt;p&gt;The bindings of a WCF not only specify the protocols used but also the security requirements for communication. The following table describes the available bindings:&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Binding&lt;\/th&gt; &lt;th valign="top"&gt;Description&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;BasicHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Most basic; limited security and no transactional support. Compatible with traditional ASMX Web Services.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;WSHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;More advanced HTTP with WSE security.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;WSDualHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Extends &lt;code&gt;WSHttpBinding&lt;\/code&gt;and includes duplex communications.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;WSFederationHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Extends &lt;code&gt;WSHttpBinding&lt;\/code&gt;and includes federation capabilities.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;NetTcpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Used for TCP communication; supports security, transaction, and so on.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;NetNamedPipeBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Used for named pipe communication; supports security, transaction, and so on.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;NetPeerTcpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Supports broadcast communication.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;MexHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Publishes the metadata for the WCF service.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;NetMsmqBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Used for MSMQ.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;MsmqIntegrationBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Used for MSMQ.&lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;p&gt;The bindings of a WCF determine how a client can communicate with the service.&lt;\/p&gt; &lt;p&gt;How to use &lt;code&gt;BasicHttpBinding&lt;\/code&gt;, &lt;code&gt;WSHttpBinding&lt;\/code&gt;, and &lt;code&gt;NetTcpBinding&lt;\/code&gt;bindings is shown later in this chapter.&lt;\/p&gt; &lt;div class="title"&gt;Contracts&lt;\/div&gt; &lt;p&gt;Contracts define what a WCF service offers. The types of available contracts are explained in the following table.&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Contract&lt;\/th&gt; &lt;th valign="top"&gt;Defines&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;Service&lt;\/td&gt; &lt;td valign="top"&gt;All the operations contained in a service.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;Operation&lt;\/td&gt; &lt;td valign="top"&gt;All the methods, parameters, return types, and so on.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;Message&lt;\/td&gt; &lt;td valign="top"&gt;How messages are formatted. For instance, data should be included in SOAP header or SOAP message body, and so on.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;Fault&lt;\/td&gt; &lt;td valign="top"&gt;Faults an operation may return.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;Data&lt;\/td&gt; &lt;td valign="top"&gt;The type of data used and required by the service.&lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;div class="title"&gt; &lt;p&gt;Messaging Patterns&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;Traditional ASMX Web Services use the request/response communication model. This model has some disadvantages. In some cases, the client might want to call the service without waiting for a response from the service. For example, you might want to call a service rapidly to turn on and off a switch and you do not need a response from the service. Using the request/response model, all requests made by the client have to wait for a reply from the service (even if the request does not return a result). The result is unnecessary blocking on the client side, especially if there are many queued requests on the service's end.&lt;\/p&gt; &lt;p&gt;WCF supports three communication models (also known as &lt;em&gt;messaging patterns&lt;\/em&gt; ):&lt;\/p&gt; &lt;p&gt;□ Request/response&lt;\/p&gt; &lt;p&gt;□ One-way (simplex)&lt;\/p&gt; &lt;p&gt;□ Two-way (duplex)&lt;\/p&gt; &lt;p&gt;The one-way messaging pattern allows clients to fire off a request and forget about it; no response is needed from the service. The two-way messaging pattern allows both the service and the client to send and receive messages.&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Hosting Web Services&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;As mentioned earlier, WCF services can be hosted using different forms:&lt;\/p&gt; &lt;p&gt;□ &lt;strong&gt;Web Servers&lt;\/strong&gt;— IIS; similar to Web Services&lt;\/p&gt; &lt;p&gt;□ &lt;strong&gt;Executable&lt;\/strong&gt;— Console application, Windows Forms, WPF, and so on&lt;\/p&gt; &lt;p&gt;□ &lt;strong&gt;Windows Service&lt;\/strong&gt;— Runs in the background&lt;\/p&gt; &lt;p&gt; &lt;strong&gt;□ Windows Activation Service (WAS)&lt;\/strong&gt;— Simpler version of IIS&lt;\/p&gt; &lt;p&gt;In the earlier example, the WCF service is hosted by the WCF Service Host (see Figure 20-19), a utility provided by Visual Studio 2008.&lt;\/p&gt; &lt;img src=#i_470.png" &gt; &lt;p&gt;Figure 20-19&lt;\/p&gt; &lt;cite&gt; &lt;p&gt;If you host a WCF service using an executable or Windows service, that WCF service is said to be self-hosted.&lt;\/p&gt; &lt;\/cite&gt; &lt;div class="title"&gt; &lt;p&gt;Building WCF Services&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;This section explores more sophisticated WCF services that illustrate the various theories presented earlier. Let's start off with creating a WCF that exposes multiple endpoints.&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Exposing Multiple Endpoints&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;A WCF service can expose multiple endpoints. Follow along to build a WCF service that exposes endpoints using two different bindings: &lt;code&gt;WSHttpBinding&lt;\/code&gt;and &lt;code&gt;BasicHttpBinding&lt;\/code&gt;.&lt;\/p&gt; &lt;div class="title"&gt;Creating the WCF Service&lt;\/div&gt; &lt;p&gt;Using Visual Studio 2008, create a new WCF Service Application and name it &lt;code&gt;MultipleEndpointsService&lt;\/code&gt;(see Figure 20-20).&lt;\/p&gt; &lt;img src=#i_471.png" &gt; &lt;p&gt;Figure 20-20&lt;\/p&gt; &lt;cite&gt; &lt;p&gt;In this example, the WCF service is hosted by the ASP.NET Development Server, a web server shipped with Visual Studio 2008. Because the service is hosted by a web server, the &lt;code&gt;NetTcpBinding&lt;\/code&gt;binding is not supported.&lt;\/p&gt; &lt;\/cite&gt; &lt;p&gt;Edit the &lt;code&gt;Web.config&lt;\/code&gt;file by right-clicking it in Solution Explorer and selecting Edit WCF Configuration. (You can also launch the WCF Service Configuration Editor by selecting Tools→WCF Service Configuration Editor.)&lt;\/p&gt; &lt;p&gt;Expand the Endpoints node, and select the first endpoint. Name it WS (see Figure 20-21).&lt;\/p&gt; &lt;img src=#i_472.png" &gt; &lt;p&gt;Figure 20-21&lt;\/p&gt; &lt;p&gt;Right-click on the Endpoints node, and select New Service Endpoint to add a new endpoint to the service (see Figure 20-22).&lt;\/p&gt; &lt;img src=#i_473.png" &gt; &lt;p&gt;Figure 20-22&lt;\/p&gt; &lt;p&gt;Name the new endpoint BASIC, and set its various properties as indicated (see Figure 20-23).&lt;\/p&gt; &lt;img src=#i_474.png" &gt; &lt;p&gt;Figure 20-23 &lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Property&lt;\/th&gt; &lt;th valign="top"&gt;Value&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Address&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;asmx&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Binding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;basicHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Contract&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;MultipleEndpointsService.IService1&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;p&gt;Save and close the &lt;code&gt;Web.config&lt;\/code&gt;file. Build the &lt;code&gt;MultipleEndpointsService&lt;\/code&gt;project.&lt;\/p&gt; &lt;p&gt;The WCF service now has three endpoints as shown in the following table.&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Name&lt;\/th&gt; &lt;th valign="top"&gt;Binding&lt;\/th&gt; &lt;th valign="top"&gt;Description&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;WS&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;wsHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;The &lt;code&gt;wsHttpBinding&lt;\/code&gt;: Uses the &lt;code&gt;WS-*&lt;\/code&gt;protocols. Security is at the message level. Uses additional handshake messaging. Supports reliable session. Messages exchanged between the client and the server are encrypted.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt;[Empty Name]&lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;mexHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Publishes the metadata for the WCF service, allowing clients to retrieve the metadata using a &lt;code&gt;WS-Transfer GET&lt;\/code&gt;request or an &lt;code&gt;HTTP/GET&lt;\/code&gt;request using the &lt;code&gt;?wsdl&lt;\/code&gt;query string. By default, every WCF service created using Visual Studio 2008 has this endpoint to allow clients to request the service's metadata.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;BASIC&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;basicHttpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;The &lt;code&gt;basicHttpBinding&lt;\/code&gt;: Supports old ASMX-style (based on &lt;code&gt;WS-BasicProfile1.1&lt;\/code&gt;) Web Services call. Does not support secure messaging (no WS enhancements). Does not support reliability and ordered delivery. Calls may be lost and the client simply time out. Calls may not be ordered correctly. Security is at the transport layer (SSL, for instance). Allows compatibility with ASMX Web Services and clients.&lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;div class="title"&gt;Creating the Client&lt;\/div&gt; &lt;p&gt;Now add a new project to the current solution so that you can consume the WCF service created. Add a new Windows Forms Application project to the current solution and use its default name, &lt;code&gt;WindowsFormsApplication1&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;Populate the default &lt;code&gt;Form1&lt;\/code&gt;with the two Button controls shown in Figure 20-24.&lt;\/p&gt; &lt;img src=#i_475.png" &gt; &lt;p&gt;Figure 20-24&lt;\/p&gt; &lt;p&gt;Add a Service reference to the &lt;code&gt;WindowsFormApplication1&lt;\/code&gt;project, and click the Discover button to locate the WCF service in your solution. When the service is found, click OK (see Figure 20-25).&lt;\/p&gt; &lt;img src=#i_476.png" &gt; &lt;p&gt;Figure 20-25&lt;\/p&gt; &lt;p&gt;To inform clients of your service, you simply need to inform them of this URL: http://localhost:1039/Service1.svc. Because the WCF service is hosted by the ASP.NET Development server, the port number is dynamically chosen. The port number you will see is likely to be different from that shown.&lt;\/p&gt; &lt;p&gt;Add another service reference to the &lt;code&gt;WindowsFormApplication1&lt;\/code&gt;project. This time, click the Advanced button at the bottom left of the Add Service Reference dialog, and then click the Add Web Reference button at the bottom left of the Service Reference Settings dialog (see Figure 20-26).&lt;\/p&gt; &lt;img src=#i_477.png" &gt; &lt;p&gt;Figure 20-26&lt;\/p&gt; &lt;p&gt;In the Add Web Reference dialog, click the Web services In the This Solution link and click Service1. Use the default name of localhost, and click the Add Reference button to add a web reference to the project (see Figure 20-27).&lt;\/p&gt; &lt;img src=#i_478.png" &gt; &lt;p&gt;Figure 20-27&lt;\/p&gt; &lt;p&gt;Double-click the Use wsHttpBinding button in Form1, and code it as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void btnwsHttpBinding_Click(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ServiceReference1.Service1Client client =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; new ServiceReference1.Service1Client("WS");&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; MessageBox.Show("Using wsHttpBinding: " +&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; client.GetData(5));&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; client.Close();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Double-click the Use basicHttpBinding button, and code it as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void btnBasicHttpBinding_Click(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; localhost.Service1 ws = new localhost.Service1();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; MessageBox.Show("Using basicHttpBinding: " + ws.GetData(6, true));&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Set the &lt;code&gt;WindowsFormApplication1&lt;\/code&gt;project as the startup project, and press F5 to test it. Click both buttons (see Figure 20-28) to access the WCF service using &lt;code&gt;WSHttpBinding&lt;\/code&gt;and &lt;code&gt;BasicHTTPBinding&lt;\/code&gt;.&lt;\/p&gt; &lt;img src=#i_479.png" &gt; &lt;p&gt;Figure 20-28&lt;\/p&gt; &lt;p&gt;This example shows that you can have one WCF service exposed via different endpoints — traditional ASMX Web Service clients can connect to the service using the &lt;code&gt;basicHttpBinding&lt;\/code&gt;binding, while the rest can connect using the &lt;code&gt;wsHttpBinding&lt;\/code&gt;binding.&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Creating Self- Hosted WCF Service&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;So far, all the WCF services you have seen are hosted using either a web server or the WCF Service Host. This section shows how you can host a WCF service right from within a Windows Forms application. This example can also be used with the &lt;code&gt;netTCPBinding&lt;\/code&gt;binding.&lt;\/p&gt; &lt;p&gt;The example application is a simple message server that allows clients to send messages to it. Messages received by the service are displayed in a Windows Form.&lt;\/p&gt; &lt;div class="title"&gt;Creating the WCF Service&lt;\/div&gt; &lt;p&gt;Launch Visual Studio 2008 and create a new Windows Forms Application project. Name the project &lt;code&gt;MessageServer&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;Populate the default &lt;code&gt;Form1&lt;\/code&gt;with a &lt;code&gt;TextBox&lt;\/code&gt;control, and set its &lt;code&gt;MultiLine&lt;\/code&gt;property to &lt;code&gt;true&lt;\/code&gt;(see Figure 20-29).&lt;\/p&gt; &lt;img src=#i_480.png" &gt; &lt;p&gt;Figure 20-29 &lt;\/p&gt; &lt;p&gt;Add a new item to the project. Select the WCF Service template, and name it &lt;code&gt;MessageService.cs&lt;\/code&gt;(see Figure 20-30).&lt;\/p&gt; &lt;img src=#i_481.png" &gt; &lt;p&gt;Figure 20-30&lt;\/p&gt; &lt;p&gt;In the code-behind of &lt;code&gt;Form1&lt;\/code&gt;, import the following namespace:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Declare the following objects:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;public partial class Form1 : Form {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private MessageService service;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private ServiceHost host;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;The &lt;code&gt;ServiceHost&lt;\/code&gt;class is used to host a WCF service. In the &lt;code&gt;Form1_Load&lt;\/code&gt;event handler, code the following:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void Form1_Load(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---host the service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; service = new MessageService(this);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; host = new ServiceHost(service);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; host.Open();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;In the design view of &lt;code&gt;Form1&lt;\/code&gt;, create an event handler for the &lt;code&gt;FormClosing&lt;\/code&gt;event of &lt;code&gt;Form1&lt;\/code&gt;by using the Properties window (see Figure 20-31).&lt;\/p&gt; &lt;img src=#i_482.png" &gt; &lt;p&gt;Figure 20-31&lt;\/p&gt; &lt;p&gt;Code the &lt;code&gt;Form1_FormClosing&lt;\/code&gt;event handler as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void Form1_FormClosing(&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; object sender, FormClosingEventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---end the hosting of the service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; host.Close();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;This code simply ends the hosting of the WCF service when the window is closed.&lt;\/p&gt; &lt;p&gt;Define the &lt;code&gt;DisplayMessage()&lt;\/code&gt;function within the &lt;code&gt;Form1&lt;\/code&gt;class as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;//---display a message on the TextBox control---&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;internal void DisplayMessage(string msg) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; textBox1.Text += msg + Environment.NewLine;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;In the &lt;code&gt;IMessageService.cs&lt;\/code&gt;file, define the operation contract &lt;code&gt;SetMessage&lt;\/code&gt;, highlighted here:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;namespace MessageServer {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; [ServiceContract]&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; public interface IMessageService {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; [OperationContract]&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; void DoWork();&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract(IsOneWay = true)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; void SetMessage(string msg);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; }&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt;&lt;\/p&gt; &lt;cite&gt; &lt;p&gt;The &lt;code&gt;SetMessage()&lt;\/code&gt;operation uses the one-way messaging pattern because clients simply send messages to the sender and do not need to wait for a response from the server.&lt;\/p&gt; &lt;\/cite&gt; &lt;p&gt;This operation allows clients to send a message to the WCF service.&lt;\/p&gt; &lt;p&gt;In the &lt;code&gt;MessageService.cs&lt;\/code&gt;file, add the following highlighted code:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Collections.Generic;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Linq;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Runtime.Serialization;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Text;&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt;namespace MessageServer {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; public class MessageService : IMessageService {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private Form1 hostApp;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; public void DoWork() {}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---constructor---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public MessageService(Form1 hostApp) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---set which host is hosting this service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; this.hostApp = hostApp;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---called by clients sending a message to the service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public void SetMessage(string msg) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---display the message in Form1---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; hostApp.DisplayMessage(msg);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; }&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Notice that the &lt;code&gt;MessageService&lt;\/code&gt;class is prefixed with the &lt;code&gt;[ServiceBehavior]&lt;\/code&gt;attribute. It contains the &lt;code&gt;InstanceContextMode&lt;\/code&gt;property, which is set to &lt;code&gt;Single&lt;\/code&gt;. &lt;\/p&gt; &lt;cite&gt; &lt;div class="title"&gt;Service Behaviors: InstanceContextMode&lt;\/div&gt; &lt;p&gt;When a WCF Service receives a message, the message is dispatched to an object's instance methods:&lt;\/p&gt; &lt;p&gt;□ A single instance of the receiver may be created for &lt;em&gt;all&lt;\/em&gt; clients, or&lt;\/p&gt; &lt;p&gt;□ A single instance of the receiver may be created for &lt;em&gt;each&lt;\/em&gt; client.&lt;\/p&gt; &lt;p&gt;The &lt;code&gt;InstanceContextMode&lt;\/code&gt;property specifies the number of service instances available for handling calls that are contained in incoming messages. It can be one of the following:&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Single&lt;\/code&gt;— Every received message is dispatched to the same object (a singleton).&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Percall&lt;\/code&gt;— Every received message is dispatched to a newly created object. This is the default.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;PerSession&lt;\/code&gt;— Messages received within a session (usually a single sender) are dispatched to the same object.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Shareable&lt;\/code&gt;— Messages received within a session (can be one or more senders) are dispatched to the same object.&lt;\/p&gt; &lt;\/cite&gt; &lt;p&gt;Edit the &lt;code&gt;App.config&lt;\/code&gt;file, using the WCF Service Configuration Editor (you can also select it from Tools→WCF Service Configuration Editor).&lt;\/p&gt; &lt;p&gt;Set the following details for the first endpoint (see Figure 20-32).&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Property&lt;\/th&gt; &lt;th valign="top"&gt;Value&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Address&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;net.tcp://localhost:1234/MessageService&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Binding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;netTcpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;img src=#i_483.png" &gt; &lt;p&gt;Figure 20-32&lt;\/p&gt; &lt;p&gt;Save the file and close the editor.&lt;\/p&gt; &lt;p&gt;Basically, you set the endpoint to use the &lt;code&gt;netTcpbinding&lt;\/code&gt;binding. Examine the &lt;code&gt;App.config&lt;\/code&gt;file now, and you'll see that the following highlighted code has been added:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;configuration&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;services&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;service&lt;/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; behaviorConfiguration="MessageServer.MessageServiceBehavior"&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; name="MessageServer.MessageService"&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;endpoint&lt;/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; address="net.tcp://localhost:l234/MessageService"&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; binding="netTcpBinding" bindingConfiguration=""&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; contract="MessageServer.IMessageService"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;identity&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;dns value="localhost"/&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/identity&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/endpoint&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;endpoint address="mex" binding="mexHttpBinding"&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; contract="IMetadataExchange"/&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;host&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;baseAddresses&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;add&lt;/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; baseAddress="http://localhost:8731/Design_Time_Addresses/MessageServer/MessageService/"/&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/baseAddresses&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/host&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/service&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/services&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/system.serviceModel&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;\/configuration&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Notice the base address contained in the &lt;code&gt;app.config&lt;\/code&gt;file:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;http://localhost:8731/Design_Time_Addresses/MessageServer/MessageService/&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;This is the address that clients can use to add a service reference to your WCF service.&lt;\/p&gt; &lt;p&gt;Press F5 to test the application now. When prompted with the Windows Security Alert dialog, click Unblock (see Figure 20-33).&lt;\/p&gt; &lt;img src=#i_484.png" &gt; &lt;p&gt;Figure 20-33&lt;\/p&gt; &lt;cite&gt; &lt;p&gt;In this example, the WCF service is hosted by the Windows Form application, at port 1234, using the TCP protocol.&lt;\/p&gt; &lt;\/cite&gt; &lt;div class="title"&gt;Creating the Client&lt;\/div&gt; &lt;p&gt;Launch another instance of Visual Studio 2008, and create a new Windows Forms Application project. Name it &lt;code&gt;MessageClient&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;Populate the default &lt;code&gt;Form1&lt;\/code&gt;with the controls shown in Figure 20-34.&lt;\/p&gt; &lt;img src=#i_485.png" &gt; &lt;p&gt;Figure 20-34&lt;\/p&gt; &lt;p&gt;Add a service reference to the WCF service created earlier (see Figure 20-35). Enter the base address URL (http://localhost:8731/Design_Time_Addresses/MessageServer/MessageService) that you have observed in the &lt;code&gt;app.config&lt;\/code&gt;file.&lt;\/p&gt; &lt;img src=#i_486.png" &gt; &lt;p&gt;Figure 20-35&lt;\/p&gt; &lt;p&gt;Switch to the code-behind of &lt;code&gt;Form1&lt;\/code&gt;, and import the following namespace:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Declare the following member variable:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;public partial class Form1 : Form {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ServiceReferencel.MessageServiceClient client;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Double-click the Send button, and code the &lt;code&gt;button1_Click&lt;\/code&gt;event handler as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void btnSend_Click(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; client = new&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; MessageClient.ServiceReference1.MessageServiceClient();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; client.SetMessage(textBox1.Text);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; client.Close();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;That's it! Press F5 and you can now send a message to the server using the WCF service (see Figure 20-36).&lt;\/p&gt; &lt;img src=#i_487.png" &gt; &lt;p&gt;Figure 20-36&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Implementing WCF Callbacks&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;One of the limitations of a traditional ASMX Web Service call lies in its request/response communication model. ASMX Web Services calls are passive and return results only when called upon. For instance, say that a particular cinema operator deploys a Web Service to allow online purchasing of tickets. The cinema's branches have systems that are connected to the Web Service to obtain the latest status of seat allocation and that sell tickets to cinema goers. In this case, the systems have to keep polling the Web Service at regular intervals to obtain the latest seats status. Moreover, it is very likely that a few branches may be booking the same seat(s) at the same time.&lt;\/p&gt; &lt;p&gt;A better approach would be for the Web Service to notify all the branches about the changes in seat status as and when a seat has been reserved. This way, all branches have the latest seat information, and there is no need to poll the Web Service at regular intervals, thereby relieving the Web Service of the additional load. To accomplish this, you need a communication model in which the client is always connected to the service and is notified when an event occurs. Using WCF, this communication model can be implemented by using &lt;em&gt;callbacks.&lt;\/em&gt; A callback allows a service to call back its clients. The roles of the service and the client are now duplicated — the client is also the service, and the service is also the client.&lt;\/p&gt; &lt;p&gt;This section of the chapter leads you through building a WCF ticketing service that allows clients to book tickets. When multiple clients are connected to the service, a seat booked by one client is broadcast to all the connected clients. Figure 20-37 illustrates the flow of the system. It shows four cinema branches using the client to connect to the WCF ticketing service. Once seats are selected (represented by the yellow buttons), a client will click on the Book Seats button to send the reservation to the WCF service. The WCF service will then broadcast the booked seats to all connected clients, which will then set the booked seats in red.&lt;\/p&gt; &lt;img src=#i_488.png" &gt; &lt;p&gt;Figure 20-37&lt;\/p&gt; &lt;div class="title"&gt;Building the Service&lt;\/div&gt; &lt;p&gt;The WCF service that allows clients to book cinema tickets needs to come first. Launch Visual Studio 2008 and create a new WCF Service Library project. Name the project &lt;code&gt;WcfTicketingService&lt;\/code&gt;(see Figure 20-38).&lt;\/p&gt; &lt;img src=#i_489.png" &gt; &lt;p&gt;Figure 20-38&lt;\/p&gt; &lt;cite&gt; &lt;p&gt;In this example, the WCF service will be hosted by the WCF Service Host, a utility provided by Visual Studio 2008.&lt;\/p&gt; &lt;\/cite&gt; &lt;p&gt;In the &lt;code&gt;IService1.cs&lt;\/code&gt;file, define the following service and data contracts:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Collections.Generic;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Linq;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Runtime.Serialization;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Text;&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt;namespace WcfTicketingService {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [ServiceContract(&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Name = "TicketingService",&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Namespace = "http://www.learn2develop.net/",&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; CallbackContract = typeof(ITicketCallBack),&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; SessionMode = SessionMode.Required)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public interface ITicketService {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract(IsOneWay = true)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; void SetSeatStatus(string strSeats);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract(IsOneWay = true)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; void RegisterClient(Guid id);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract(IsOneWay = true)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; void UnRegisterClient(Guid id);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public interface ITicketCallBack {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract(IsOneWay = true)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; void SeatStatus(string message);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---each client connected to the service has a GUID---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [DataContract]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public class Client {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [DataMember]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public Guid id { get; set; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;The &lt;code&gt;ITicketService&lt;\/code&gt;interface defines three operations, which are described in the following table.&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Operation&lt;\/th&gt; &lt;th valign="top"&gt;Description&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;SetSeatStatus&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Allows clients to book seats. Takes in a string containing the seats to be booked.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;RegisterClient&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Registers a client when it connects to the service. Takes in a GUID so that the service can uniquely identify a client.&lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;UnRegisterClient&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt;Unregisters a client when it disconnects from the service. Takes in the client's GUID.&lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;p&gt;The &lt;code&gt;ITicketService&lt;\/code&gt;interface is also prefixed with the &lt;code&gt;[ServiceContract]&lt;\/code&gt;attribute. Specifically, note the &lt;code&gt;CallbackContract&lt;\/code&gt;property, which specifies the interface that defines the callback operation. The &lt;code&gt;SessionMode&lt;\/code&gt;property is set to &lt;code&gt;Required&lt;\/code&gt;, indicating that state must be maintained between the service and client.&lt;\/p&gt; &lt;p&gt;The &lt;code&gt;ITicketCallBack&lt;\/code&gt;interface contains one operation — &lt;code&gt;SeatStatus&lt;\/code&gt;, which allows the service to initiate a callback to the client, thereby updating the client about the latest seat status (that is, which seats have been booked by other clients).&lt;\/p&gt; &lt;p&gt;The &lt;code&gt;Client&lt;\/code&gt;class defines the data contract. It contains the GUID of a client connecting to the service.&lt;\/p&gt; &lt;p&gt;All the operations in these two interfaces are defined as one-way operations. To understand why this is so, assume that all the operations use the default request/response model. When the &lt;code&gt;SetSeatStatus()&lt;\/code&gt;method is called to book seats, it waits for a response from the service. However, the service now invokes the &lt;code&gt;SeatStatus&lt;\/code&gt;callback on the client (the service informs all clients about the seats booked) and waits for a reply from the client. A deadlock occurs because the client is waiting for a response from the service while the service is waiting for a response from the client after invoking the callback. By defining the operations as one-way, the service can invoke the callback on the client without waiting for a reply from the client, preventing a deadlock from happening.&lt;\/p&gt; &lt;p&gt;In the &lt;code&gt;Service1.cs&lt;\/code&gt;file, define the &lt;code&gt;SeatStatus&lt;\/code&gt;class:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Text;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Timers;&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt;namespace WcfTicketingService {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; //...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt; &lt;em&gt;public class SeatStatus {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---a string representing the seats booked by a client---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public string Seats { get; set; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt;}&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;The &lt;code&gt;SeatStatus&lt;\/code&gt;class contains &lt;code&gt;Seats&lt;\/code&gt;, a property for storing the seats booked by a client.&lt;\/p&gt; &lt;p&gt;In the &lt;code&gt;Service1.cs&lt;\/code&gt;file, define the &lt;code&gt;Ticketing&lt;\/code&gt;class that implements the &lt;code&gt;ITicketingService&lt;\/code&gt;service contract:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Collections.Generic;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Linq;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Runtime.Serialization;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Text;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Collections;&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt;namespace WcfTicketingService {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ConcurrencyMode = ConcurrencyMode.Multiple)]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public class Ticketing : ITicketService {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---used for locking---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private object locker = new object();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private SeatStatus _seatStatus = null;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---for storing all the clients connected to the service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private Dictionary&lt;Client, ITicketCallBack&gt; clients =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; new Dictionary&lt;Client, ITicketCallBack&gt;();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public Ticketing() { }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---add a newly connected client to the dictionary---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public void RegisterClient(Guid guid) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ITicketCallBack callback =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; OperationContext.Current.GetCallbackChannel&lt;ITicketCallBack&gt;();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---prevent multiple clients adding at the same time---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; lock (locker) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; clients.Add(new Client { id = guid }, callback);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---unregister a client by removing its GUID from&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; // dictionary---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public void UnRegisterClient(Guid guid) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; var query = from c in clients.Keys&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; where c.id == guid select c;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; clients.Remove(query.First());&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---called by clients when they want to book seats---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public void SetSeatStatus(string strSeats) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; _seatStatus = new SeatStatus {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---stores the seats to be booked by a client---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Seats = strSeats&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; };&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---get all the clients in dictionary---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; var query = (from c in clients&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; select c.Value).ToList();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---create the callback action delegate---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Action&lt;ITicketCallBack&gt; action =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; delegate(ITicketCallBack callback) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---callback to pass the seats booked&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; // by a client to all other clients---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; callback.SeatStatus(_seatStatus.Seats);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; };&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---for each connected client, invoke the callback---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; query.ForEach(action);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Within the &lt;code&gt;Ticketing&lt;\/code&gt;class are the implementations for the three operations defined in the &lt;code&gt;ITicketService&lt;\/code&gt;interface:&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;RegisterClient()&lt;\/code&gt;— Called when clients are connected to the service for the first time. Clients are stored in a generic &lt;code&gt;Dictionary&lt;K,V&gt;&lt;\/code&gt;object. The key used for storing a client is its GUID, and its callback handler is stored as the value.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;UnRegisterClient()&lt;\/code&gt;— Called when a client is disconnected from the service; its entry in the &lt;code&gt;Dictionary&lt;\/code&gt;object is removed.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;SetSeatStatus()&lt;\/code&gt;— Called when clients want to book seats. The seats to be booked are stored in a &lt;code&gt;SeatStatus&lt;\/code&gt;object and then you create an Action delegate to invoke the callback of a client to pass the seats that have been booked by a client. Because all connected clients need to be notified, you invoke the callback for each client.&lt;\/p&gt; &lt;p&gt;The &lt;code&gt;[ServiceBehavior]&lt;\/code&gt;attribute specifies the &lt;code&gt;InstanceContextMode&lt;\/code&gt;to be &lt;code&gt;Single&lt;\/code&gt;and the &lt;code&gt;ConcurrencyMode&lt;\/code&gt;property to be &lt;code&gt;Multiple&lt;\/code&gt;.&lt;\/p&gt; &lt;cite&gt; &lt;div class="title"&gt;Service Behaviors — ConcurrencyMode&lt;\/div&gt; &lt;p&gt;When messages are received by a WCF service, you can set how threads are used to manage all received messages:&lt;\/p&gt; &lt;p&gt;□ One thread can be used to access the receiver object(s) at a time, or&lt;\/p&gt; &lt;p&gt;□ Multiple threads can be used to access the receiver object(s) concurrently.&lt;\/p&gt; &lt;p&gt;How you handle all incoming messages is specified using the &lt;code&gt;ConcurrencyMode&lt;\/code&gt;property of the &lt;code&gt;[ServiceBehavior]&lt;\/code&gt;attribute, which can assume one of the following values:&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Single&lt;\/code&gt;(default) — Only one thread can access the receiver object at a time.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Multiple&lt;\/code&gt;— Multiple threads can access the receiver object(s) concurrently.&lt;\/p&gt; &lt;p&gt;□ &lt;code&gt;Reentrant&lt;\/code&gt;— Only one thread can access the receiver object at a time, but callbacks can reenter that object on another thread.&lt;\/p&gt; &lt;p&gt;When you use the &lt;code&gt;Multiple&lt;\/code&gt;mode on the service, take special care to make sure that threads are synchronized properly and that critical regions are locked when a threading is accessing it.&lt;\/p&gt; &lt;\/cite&gt; &lt;p&gt;For simplicity of demonstration, the following shortcuts are made:&lt;\/p&gt; &lt;p&gt;□ The seats booked by a client are simply broadcast to all connected clients. In real life, they would also be saved in database or array.&lt;\/p&gt; &lt;p&gt;□ When new clients connect to the server, the current seat allocation status (which seats are booked and which are not) is not sent to them.&lt;\/p&gt; &lt;p&gt;Next, double-click on the &lt;code&gt;App.config&lt;\/code&gt;file in Solution Explorer. Change the following highlighted attributes values:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;system.serviceModel&gt;: &lt;services&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;service name="WcfTicketingService.Ticketing"&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; behaviorConfiguration="WcfTicketingService.Service1Behavior"&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;host&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;baseAddresses&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;add&lt;/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; baseAddress="http://localhost:8731/Design_Time_Addresses/WcfTicketingService/Service1/" /&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/baseAddresses&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/host&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;!-- Service Endpoints --&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;!-- Unless fully qualified, address is relative to base address&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; supplied above --&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;endpoint address="" binding="wsHttpBinding"&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; contract="WcfTicketingService.ITicketService"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Right-click on the &lt;code&gt;App.config&lt;\/code&gt;file, and select Edit WCF Configuration. Expand the &lt;code&gt;EndPoints&lt;\/code&gt;node (see Figure 20-39), and select the first &lt;code&gt;[Empty Name]&lt;\/code&gt;node. Set its properties as follows:&lt;\/p&gt; &lt;table&gt; &lt;tr&gt; &lt;th valign="top"&gt;Property&lt;\/th&gt; &lt;th valign="top"&gt;Value&lt;\/th&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Address&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;net.tcp://localhost:5000/TicketingService&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;tr&gt; &lt;td valign="top"&gt; &lt;code&gt;Binding&lt;\/code&gt; &lt;\/td&gt; &lt;td valign="top"&gt; &lt;code&gt;NetTcpBinding&lt;\/code&gt; &lt;\/td&gt; &lt;\/tr&gt; &lt;\/table&gt; &lt;img src=#i_490.png" &gt; &lt;p&gt;Figure 20-39&lt;\/p&gt; &lt;p&gt;TCP is the transport protocol.&lt;\/p&gt; &lt;p&gt;Save the &lt;code&gt;app.config&lt;\/code&gt;file and close the configuration window. Press F5 to debug the service. In the WCF Test Client, you will see something like Figure 20-40. The error icons (represented by the exclamation symbols) are normal.&lt;\/p&gt; &lt;img src=#i_491.png" &gt; &lt;p&gt;Figure 20-40&lt;\/p&gt; &lt;div class="title"&gt;Building the Client&lt;\/div&gt; &lt;p&gt;The WCF service is complete, so it's time to build the client to consume the service. Add a new Windows Forms Application project to the current solution. Name the project &lt;code&gt;Client&lt;\/code&gt;.&lt;\/p&gt; &lt;p&gt;Add a service reference to the ticketing WCF service. In the Add Service Reference dialog, click the Discover button and locate the Ticketing WCF service (see Figure 20-41). Click OK.&lt;\/p&gt; &lt;img src=#i_492.png" &gt; &lt;p&gt;Figure 20-41&lt;\/p&gt; &lt;p&gt;Populate Form1 with the controls shown in Figure 20-42. Set the &lt;code&gt;Size&lt;\/code&gt;property of &lt;code&gt;Form1&lt;\/code&gt;to 477, 387.&lt;\/p&gt; &lt;img src=#i_493.png" &gt; &lt;p&gt;Figure 20-42&lt;\/p&gt; &lt;p&gt;In the code-behind of &lt;code&gt;Form1&lt;\/code&gt;, import the following namespace:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Declare the following constants and objects:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;namespace Client {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public partial class Form1 : Form {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; int ROWS = 10;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; int COLUMNS = 10;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; const int SEAT_WIDTH = 45;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; const int SEAT_HEIGHT = 25;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; const int START_X = 10;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; const int START_Y = 40;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; static Button[,] seatsArray;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private ServiceReference1.TicketingServiceClient _client;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; private Guid _guid = Guid.NewGuid();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;Define the &lt;code&gt;SeatsOccupied()&lt;\/code&gt;static function within the &lt;code&gt;Form1&lt;\/code&gt;class as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;public partial class Form1 : Form {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---set all occupied seats in red---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public static void SeatsOccupied(string strSeatsOccupied) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; string[] seats = strSeatsOccupied.Split(',');&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; for (int i = 0; i &lt; seats.Length - 1; i++) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; string[] xy = seats[i].Split('-');&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Button btn = seatsArray[int.Parse(xy[0]) - 1,&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; int.Parse(xy[1]) - 1];&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.BackColor = Color.Red;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;This function accepts a string containing the seats that are occupied. The format of the string is:&lt;\/p&gt; &lt;p&gt; &lt;em&gt; &lt;code&gt;&lt;column&gt;-&lt;row&gt;,&lt;column&gt;-&lt;row&gt;,...&lt;\/code&gt; &lt;\/em&gt; &lt;\/p&gt; &lt;p&gt;For each seat (represented by the Button control) that is booked, the background color is changed to red.&lt;\/p&gt; &lt;p&gt;Define the &lt;code&gt;SeatStatusCallback&lt;\/code&gt;class and implement the &lt;code&gt;SeatStatus()&lt;\/code&gt;method as defined in the &lt;code&gt;TicketingServiceCallback&lt;\/code&gt;interface (defined in the service):&lt;\/p&gt; &lt;p&gt; &lt;code&gt;namespace Client {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; public partial class Form1 : Form {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; //...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; }&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public class SeatStatusCallback :&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ServiceReference1.TicketingServiceCallback {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public void SeatStatus(string message) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Form1.SeatsOccupied(message);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;The &lt;code&gt;SeatStatus()&lt;\/code&gt;method is invoked when the service calls the client's callback. Here, you call the static &lt;code&gt;SeatsOccupied()&lt;\/code&gt;function to update the seats status.&lt;\/p&gt; &lt;p&gt;Code the &lt;code&gt;Form1_Load&lt;\/code&gt;event handler as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void Form1_Load(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; InstanceContext context =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; new InstanceContext(new SeatStatusCallback());&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; _client = new&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; ServiceReference1.TicketingServiceClient(context);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; _client.RegisterClient(_guid);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---display the seats---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; seatsArray = new Button[COLUMNS, ROWS];&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; for (int r = 0; r &lt; ROWS; r++) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; for (int c = 0; c &lt; ROWS; c++) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; Button btn = new Button();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.Location = new Point(&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; START_X + (SEAT_WIDTH * c),&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; START_Y + (SEAT_HEIGHT * r));&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.Size = new Size(SEAT_WIDTH, SEAT_HEIGHT);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.Text =&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; (c + 1).ToString() + "-" + (r + 1).ToString();&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.BackColor = Color.White;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; seatsArray[c, r] = btn;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; btn.Click += new EventHandler(btn_Click);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; this.Controls.Add(btn);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;These statements basically create an instance of the &lt;code&gt;InstanceContext&lt;\/code&gt;class by passing it an instance of the &lt;code&gt;SeatStatusCallback&lt;\/code&gt;class. Then an instance of the WCF client is created using the constructor that requires an &lt;code&gt;InstanceContext&lt;\/code&gt;object. In addition, the form is dynamically populated with Button controls representing the seats in a cinema. Each Button control's &lt;code&gt;Click&lt;\/code&gt;event is wired to the &lt;code&gt;btn_Click&lt;\/code&gt;event handler.&lt;\/p&gt; &lt;p&gt;Define the &lt;code&gt;btn_Click&lt;\/code&gt;event handler as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;void btn_Click(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; if (((Button)sender).BackColor == Color.White) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ((Button)sender).BackColor = Color.Yellow;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; } else if (((Button)sender).BackColor == Color.Yellow) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; ((Button)sender).BackColor = Color.White;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; }&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;This event handler toggles the color of the seats as users click on the Button controls. White indicates that the seat is available; yellow indicates that the seat has been selected for booking.&lt;\/p&gt; &lt;p&gt;Code the Book Seats button as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void btnBookSeats_Click(object sender, EventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; string seatsToBook = string.Empty;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; for (int r = 0; r &lt; ROWS; r++) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; for (int c = 0; c &lt; ROWS; c++) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; if (seatsArray[c, r].BackColor == Color.Yellow) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; seatsToBook += seatsArray[c, r].Text + ",";&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; //---send to WCF service---&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; _client.SetSeatStatus(seatsToBook);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;To specify the seats that are selected for booking, a string is created to containing the seats to be booked in the following format:&lt;\/p&gt; &lt;p&gt; &lt;em&gt; &lt;code&gt;&lt;column&gt;-&lt;row&gt;,&lt;column&gt;-&lt;row&gt;,...&lt;\/code&gt; &lt;\/em&gt; &lt;\/p&gt; &lt;p&gt;Finally, code the &lt;code&gt;Form1_FormClosing&lt;\/code&gt;event as follows:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;private void Form1_FormClosing(object sender, FormClosingEventArgs e) {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; _client.UnRegisterClient(_guid);&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;div class="title"&gt;Testing the Application&lt;\/div&gt; &lt;p&gt;To test the application, press F5 to debug and launch the service. Once this is done, you can debug the client. Right-click the &lt;code&gt;Client&lt;\/code&gt;project in Solution Explorer, and select Debug→Start New Instance (see Figure 20-43).&lt;\/p&gt; &lt;img src=#i_494.png" &gt; &lt;p&gt;Figure 20-43&lt;\/p&gt; &lt;p&gt;Run a few instances of the client and you can start to book cinema tickets. As one client books the seats, the other clients are automatically updated.&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Calling WCF Services from an AJAX Page&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;Visual Studio 2008 includes the new AJAX-enabled WCF Service template that enables you to consume WCF services, using AJAX. To try it out, use Visual Studio 2008 to create a new ASP.NET Web Application project. Name the project &lt;code&gt;AJAXWCF&lt;\/code&gt;(see Figure 20-44).&lt;\/p&gt; &lt;img src=#i_495.png" &gt; &lt;p&gt;Figure 20-44&lt;\/p&gt; &lt;p&gt;Right-click the project name in Solution Explorer, and select Add New Item (see Figure 20-45).&lt;\/p&gt; &lt;img src=#i_496.png" &gt; &lt;p&gt;Figure 20-45&lt;\/p&gt; &lt;p&gt;Select the AJAX-enabled WCF Service template (see Figure 20-46), name it &lt;code&gt;Service.svc&lt;\/code&gt;, and click Add.&lt;\/p&gt; &lt;img src=#i_497.png" &gt; &lt;p&gt;Figure 20-46&lt;\/p&gt; &lt;p&gt;Notice that Visual Studio 2008 automatically inserts the &lt;code&gt;&lt;system.serviceModel&gt;&lt;\/code&gt;element into the &lt;code&gt;Web.config&lt;\/code&gt;file:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;...&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;system.serviceModel&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;behaviors&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;endpointBehaviors&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;behavior name="ServiceAspNetAjaxBehavior"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;enableWebScript/&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/behavior&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/endpointBehaviors&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/behaviors&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;serviceHostingEnvironment&lt;/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; aspNetCompatibilityEnabled="true" /&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;services&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;service name="Service"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;endpoint address=""&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; behaviorConfiguration="ServiceAspNetAjaxBehavior"&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; binding="webHttpBinding" contract="Service"/&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/service&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/services&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/system.serviceModel&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;\/configuration&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;In the &lt;code&gt;Service.cs&lt;\/code&gt;file located in the App_Code folder, give the service a namespace of " &lt;code&gt;WCFService&lt;\/code&gt;", and code the following &lt;code&gt;GetServerTime()&lt;\/code&gt;method:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Linq;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.Runtime.Serialization;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel.Activation;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;using System.ServiceModel.Web;&lt;\/code&gt; &lt;\/p&gt; &lt;empty-line &gt; &lt;p&gt; &lt;code&gt; &lt;em&gt;[ServiceContract(Namespace = "WCFService")]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;[AspNetCompatibilityRequirements(RequirementsMode =&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; AspNetCompatibilityRequirementsMode.Allowed)]&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;public class Service {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; // Add [WebGet] attribute to use HTTP GET&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; [OperationContract]&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; public void DoWork() {&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; // Add your operation implementation here return;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; }&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; [OperationContract]&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; public DateTime GetServerTime() {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; return DateTime.Now;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;}&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;In the Source view of &lt;code&gt;Default.aspx&lt;\/code&gt;, add the following highlighted code:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;form id="form1" runat="server"&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;div&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;asp:ScriptManager ID="ScriptManager1" runat="server"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;Services&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;asp:ServiceReference Path="~/Service.svc" /&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/Services&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/asp:ScriptManager&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;\/div&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;input id="Button1" type="button" value="Get Server Time"&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; onclick="return Button1_onclick()" /&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;div id="result" /&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;\/form&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;This adds an instance of the &lt;code&gt;&lt;ScriptManager&gt;&lt;\/code&gt;control to the page and references the WCF service ( &lt;code&gt;Service.svc&lt;\/code&gt;). It also adds a Button control to the page.&lt;\/p&gt; &lt;p&gt;Insert the following JavaScript code into &lt;code&gt;Default.aspx&lt;\/code&gt;:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;&lt;body&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;script language="javascript" type="text/javascript"&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; function Button1_onclick() {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; WCFService.Service.GetServerTime(CallBackFunction);&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; function CallBackFunction(result) {&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; $get("result").innerHTML = result;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; }&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;em&gt; &lt;\/script&gt;&lt;\/em&gt; &lt;\/code&gt; &lt;\/p&gt; &lt;p&gt; &lt;code&gt; &lt;form id="form1" runat="server"&gt;&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;The &lt;code&gt;Button1_onclick()&lt;\/code&gt;JavaScript function is invoked when the button on the page is clicked. It calls the WCF service and the returning result is retrieved via the &lt;code&gt;CallBackFunction()&lt;\/code&gt;function.&lt;\/p&gt; &lt;p&gt;Press F5 to debug the application. You can now click the Get Server Time button to obtain the server time without causing a refresh on the web page (see Figure 20-47).&lt;\/p&gt; &lt;img src=#i_498.png" &gt; &lt;p&gt;Figure 20-47&lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Summary&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;This chapter provided an overview of WCF and explained how it differs from traditional ASMX Web Services. It explored the limitations of Web Services today and examined how WCF aims to provide a better way of writing and hosting your services. The various examples shown throughout this chapter afford concrete illustrations of what WCF offers and hopefully provide enough motivations for you to explore this important technology further. &lt;\/p&gt; &lt;div class="title"&gt; &lt;p&gt;Part III&lt;\/p&gt; &lt;p&gt;Appendixes &lt;\/p&gt; &lt;\/div&gt; &lt;div class="title"&gt; &lt;p&gt;Appendix A&lt;\/p&gt; &lt;p&gt;C# Keywords&lt;\/p&gt; &lt;\/div&gt; &lt;p&gt;This appendix lists the various keywords in C# that are predefined and have special meanings for the compiler. It is important to familiarize yourself with these keywords because they cannot be used as identifiers in your program. For example, this is a keyword in C# that is used to refer to the current instance of a class. Hence, this cannot be used as an identifier:&lt;\/p&gt; &lt;p&gt; &lt;code&gt;string this = "Hello, World"; //---error---&lt;\/code&gt; &lt;\/p&gt; &lt;p&gt;To use a keyword as an identifier, you need to prefix the keyword with thЧитать дальше

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «C# 2008 Programmer's Reference»

Представляем Вашему вниманию похожие книги на «C# 2008 Programmer's Reference» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «C# 2008 Programmer's Reference»

Обсуждение, отзывы о книге «C# 2008 Programmer's Reference» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x