Building the Client
With the WCF service completed, you can now build the client that consumes the service. Using the same solution, add a new Windows Forms Application project, named
Client.
Add a service reference to the WCF ticketing service (in the Add Service Reference dialog, click the Discover button and you should be able to discover the Ticketing WCF service (see
Figure 5). Select it, and then click OK.
 | |
Figure 5. Add Service Reference: Using the Add Service Reference dialog, add a reference to the WCF ticketing service. |
|
 | |
Figure 6. Sample Controls: Populate Form1 with the controls shown in this figure. |
|
|
Next, populate
Form1 with the controls shown in
Figure 6. Set the form's
Size property to
477, 387.
In the code-behind for
Form1, import the namespace shown below, and then declare the following constants and objects:
using System.ServiceModel;
namespace Client
{
public partial class Form1 : Form
{
int ROWS = 10;
int COLUMNS = 10;
const int SEAT_WIDTH = 45;
const int SEAT_HEIGHT = 25;
const int START_X = 10;
const int START_Y = 40;
static Button[,] seatsArray;
private ServiceReference1.TicketingServiceClient _client;
private Guid _guid = Guid.NewGuid();
Define the
SeatsOccupied() static function within the
Form1 class as follows:
public partial class Form1 : Form
{
...
...
...
//---set all occupied seats in red---
public static void SeatsOccupied(string strSeatsOccupied)
{
string[] seats = strSeatsOccupied.Split(',');
for (int i = 0; i < seats.Length - 1; i++)
{
string[] xy = seats[i].Split('-');
Button btn = seatsArray[int.Parse(xy[0]) - 1,
int.Parse(xy[1]) - 1];
btn.BackColor = Color.Red;
}
}
}
The
SeatsOccupied function in the preceding code accepts a string containing the seats that are occupied. You'll see more about that in a minute. The seats themselves will be represented by button controls. Whenever a user books a seat (using the
Button control), the application changes that seat's background color to red (meaning it's reserved).
Define the SeatStatusCallback class and implement the
SeatStatus() method as defined in the
TicketingServiceCallback interface (defined in the service):
namespace Client
{
public partial class Form1 : Form
{
//...
}
public class SeatStatusCallback :
ServiceReference1.TicketingServiceCallback
{
public void SeatStatus(string message)
{
Form1.SeatsOccupied(message);
}
}
}
The client invokes the
SeatStatus() method when the web service calls the client's callback. In this case, you call the static
SeatsOccupied() function to update the seats status.
Code the
Form1_Load event handler as follows:
private void Form1_Load(object sender, EventArgs e)
{
InstanceContext context =
new InstanceContext(new SeatStatusCallback());
_client = new
ServiceReference1.TicketingServiceClient(context);
_client.RegisterClient(_guid);
//---display the seats---
seatsArray = new Button[COLUMNS, ROWS];
for (int r = 0; r < ROWS; r++)
{
for (int c = 0; c < ROWS; c++)
{
Button btn = new Button();
btn.Location = new Point(
START_X + (SEAT_WIDTH * c),
START_Y + (SEAT_HEIGHT * r));
btn.Size = new Size(SEAT_WIDTH, SEAT_HEIGHT);
btn.Text = (c + 1).ToString() + "-" +
(r + 1).ToString();
btn.BackColor = Color.White;
seatsArray[c, r] = btn;
btn.Click += new EventHandler(btn_Click);
this.Controls.Add(btn);
}
}
}
The preceding code basically creates an instance of the InstanceContext class by passing it an instance of the SeatStatusCallback class. It then creates an instance of the WCF client using the constructor (which requires an
InstanceContext object). In addition, it dynamically populates the form with a 10x10 array of Button controls that represent the seats, and wires each Button control's
Click event to the
btn_Click event handler, shown below:
void btn_Click(object sender, EventArgs e)
{
if (((Button)sender).BackColor == Color.White)
{
((Button)sender).BackColor = Color.Yellow;
}
else if (((Button)sender).BackColor == Color.Yellow)
{
((Button)sender).BackColor = Color.White;
}
}
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.
Code the Book Seats button as follows:
private void btnBookSeats_Click(object sender, EventArgs e)
{
string seatsToBook = string.Empty;
for (int r = 0; r < ROWS; r++)
{
for (int c = 0; c < ROWS; c++)
{
if (seatsArray[c, r].BackColor == Color.Yellow)
{
seatsToBook += seatsArray[c, r].Text + ,"";
}
}
}
//---send to WCF service---
_client.SetSeatStatus(seatsToBook);
}
To specify the seats that are selected for booking, create the string containing the seats to be booked in the following format:
<column>-<row>,<column>-<row>,…
Finally, code the
Form1_FormClosing event so it calls the web service to unregister the client, as follows:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_client.UnRegisterClient(_guid);
}
Testing the Application
To test the application, press F5 to debug and launch the service. When it's running, you can debug the client. Right-click on the
Client project in Solution Explorer, and select Debug → Start new instance. (See
Figure 7).
 | |
Figure 7. Launching the Client: To debug an instance of the client, right-click on the client project in Solution Explorer, and select Debug ( Start new instance. |
|
 | |
Figure 8. Real-Time Updates: When one client books seats, all the clients get updated in near real-time. |
|
|
Run a few instances of the client and you can then start to book cinema tickets. Notice that as one client books the seats, the service updates the other clients automatically (see
Figure 8).
That completes the example. You've seen how you to use WCF callbacks to implement a cinema ticketing system, and you have an example you can extend to meet your own needs. Callbacks are advantageous because they allow asynchronous communications between a client and a service, and eliminate the need to constantly poll the service.