Simple Service and Client


Before going into the details of WCF let’s start with a simple service. The service is used to reserve meeting rooms.

For a backing store of room reservations, a simple SQL Server database with the table RoomReservation is used. The table and its properties are shown in Figure 40-1. You can download the database together with the samples code of this chapter.

image from book
Figure 40-1

Create a .NET Framework 3.0 WCF Service Library named RoomReservationService with Visual Studio 2005. Add the class RoomReservation with the properties Room, StartDate, EndDate, ContactName, and EventName to map the required data.

  using System; namespace Wrox.ProCSharp.WCF {    public class RoomReservation    {       private string room;       public string Room        {          get { return room; }          set { room = value; }       }       private DateTime startDate;       public DateTime StartDate       {          get { return startDate; }          set { startDate = value; }       }       private DateTime endDate;       public DateTime EndDate       {          get { return endDate; }          set { endDate = value; }       }       private string contactName;       public string ContactName       {          get { return contactName; }          set { contactName = value; }       }       private string eventName;       public string EventName       {          get { return eventName; }          set { eventName = value; }       }    } } 

To read and write data from the database using ADO.NET, add the class RoomReservationData. The method ReserveRoom() writes a room reservation to the database. The method GetReservations() returns an array of room reservations from a specified date range.

Tip 

Reading and writing to the database with ADO.NET is covered in Chapter 25, “Data Access with .NET.”

  using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; namespace Wrox.ProCSharp.WCF {    public class RoomReservationData    {       public void ReserveRoom(RoomReservation roomReservation)       {          SqlConnection connection = new SqlConnection(                Properties.Settings.Default.RoomReservationConnectionString);          SqlCommand command = connection.CreateCommand();          command.CommandText = "INSERT INTO RoomReservations (RoomName, StartDate, " +                "EndDate, Contact, Event) VALUES " +                "(@RoomName, @StartDate, @EndDate, @Contact, @Event)";          command.Parameters.Add("@RoomName", SqlDbType.NVarChar, 50);          command.Parameters.Add("@StartDate", SqlDbType.DateTime);          command.Parameters.Add("@EndDate", SqlDbType.DateTime);          command.Parameters.Add("@Contact", SqlDbType.NVarChar, 50);          command.Parameters.Add("@Event", SqlDbType.NVarChar, 50);          command.Parameters["@RoomName"].Value = roomReservation.Room;          command.Parameters["@StartDate"].Value = roomReservation.StartDate;          command.Parameters["@EndDate"].Value = roomReservation.EndDate;          command.Parameters["@Contact"].Value = roomReservation.ContactName;          command.Parameters["@Event"].Value = roomReservation.EventName;          connection.Open();          try          {             int rows = command.ExecuteNonQuery();          }          finally          {             connection.Close();          }       }       public RoomReservation[] GetReservations(DateTime from, DateTime to)       {          List<RoomReservation> roomReservations = new List<RoomReservation>(10);          SqlConnection connection = new SqlConnection(                Properties.Settings.Default.RoomReservationConnectionString);          SqlCommand command = connection.CreateCommand();          command.CommandText = "SELECT Id, RoomName, StartDate, EndDate, Contact, " +                "Event FROM RoomReservations WHERE " +                "(StartDate > @StartDate) AND (EndDate < @EndDate)";          command.Parameters.Add("@StartDate", SqlDbType.DateTime);          command.Parameters.Add("@EndDate", SqlDbType.DateTime);          command.Parameters["@StartDate"].Value = from;          command.Parameters["@EndDate"].Value = to;          connection.Open();          SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);          while (reader.Read())          {             RoomReservation reservation = new RoomReservation();             reservation.Room = reader.GetString(1);             reservation.StartDate = reader.GetDateTime(2);             reservation.EndDate = reader.GetDateTime(3);             reservation.ContactName = reader.GetString(4);             reservation.EventName = reader.GetString(5);             roomReservations.Add(reservation);          }          reader.Close();          return roomReservations.ToArray();       }    } } 

Now let’s start creating the service.

Service Contract

The operations offered by the service can be defined by an interface. The interface IRoomService defines the methods ReserveRoom and GetRoomReservations. The service contract is defined with the attribute [ServiceContract]. The operations defined by the service have the attribute [OperationContract] applied.

  using System; using System.ServiceModel; namespace Wrox.ProCSharp.WCF {    [ServiceContract()]    public interface IRoomService    {       [OperationContract]       bool ReserveRoom(RoomReservation roomReservation);       [OperationContract]       RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate);    } } 

The data that is sent across the service is defined by a data contract. Change the class RoomReservation to define a data contract with the attributes [DataContract] and [DataMember].

 [DataContract] public class RoomReservation {    private string room;        [DataMember]    public string Room    {       get { return room; }       set { room = value; }    }    private DateTime startDate;        [DataMember]    public DateTime StartDate    {       get { return startDate; }       set { startDate = value; }    }    private DateTime endDate;        [DataMember]    public DateTime EndDate    {       get { return endDate; }       set { endDate = value; }    }    private string contactName;        [DataMember]    public string ContactName    {       get { return contactName; }       set { contactName = value; }    }    private string eventName;        [DataMember]    public string EventName    {       get { return eventName; }       set { eventName = value; }    } }

Service Implementation

The service class RoomReservationService implements the interface IRoomService. The service is implemented just by invoking the appropriate methods of the RoomReservationData class.

 using System; using System.ServiceModel; namespace Wrox.ProCSharp.WCF {    public class RoomReservationService : IRoomService    {       public bool ReserveRoom(RoomReservation roomReservation)       {          RoomReservationData data = new RoomReservationData();          data.ReserveRoom(roomReservation);          return true;       }       public RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate)       {          RoomReservationData data = new RoomReservationData();          return data.GetReservations(fromDate, toDate);       }    } }

Service Host

With WCF the service can run in any host. You can create a Windows Forms or WPF application for peer-to-peer services, you can create a Windows service, or host the service with Windows Activation Services (WAS). A console application is also good to demonstrate a simple host.

With the service host you must reference the library RoomReservationService. The service is started by instantiating and opening an object of type ServiceHost. This class is defined in the namespace System .ServiceModel. The class RoomReservationService that implements the service is defined in the constructor. Invoking the Open() method starts the listener channel of the service - the service is ready to listen for requests. The Close() method stops the channel.

  using System; using System.ServiceModel; namespace Wrox.ProCSharp.WCF {    class Program    {       internal static ServiceHost myServiceHost = null;       internal static void StartService()       {          myServiceHost = new ServiceHost(typeof(RoomReservationService));          myServiceHost.Open();       }       internal static void StopService()       {          if (myServiceHost.State != CommunicationState.Closed)             myServiceHost.Close();       }       static void Main()       {          StartService();          Console.WriteLine("Server is running. Press return to exit");          Console.ReadLine();          StopService();       }    } } 

The channel that is used by the service for communication and the address of the service can be configured in the application configuration file. The entire WCF configuration is defined with the element <system.serviceModel>. The service is defined with the <service> element. The <service> element contains an <endpoint> element that specifies the contract. The value for the contract is the name of the interface that has the attribute [ServiceContract] assigned, including the namespace of the interface. The attribute binding specifies the binding information to define the protocol that is used by the service. The value wsHttpBinding references a predefined binding for SOAP and the HTTP protocol. With the <host> element the address of the service is specified. The service can be addressed by the URI http://localhost:8080/RoomReservation.

  <?xml version="1.0" encoding="utf-8" ?> <configuration>   <system.serviceModel>     <services>       <service name="Wrox.ProCSharp.WCF.RoomReservationService">         <endpoint contract="Wrox.ProCSharp.WCF.IRoomService" binding="wsHttpBinding"/>         <host>           <baseAddresses>             <add baseAddress="http://localhost:8080/RoomReservation" />           </baseAddresses>         </host>       </service>     </services>   </system.serviceModel> </configuration> 

You can edit the application configuration file with the tool svcconfigeditor.exe (see Figure 40-2).

image from book
Figure 40-2

To enable WSDL configuration to be accessed by a client developer, a MEX (Metadata Exchange) binding must be configured. For accessing the metadata, a new behavior is configured with <serviceMetadata httpGetEnabled=”true” />. This behavior allows it to access metadata with an HTTP GET request. This new binding is configured with the services behaviorConfiguration attribute. In addition, with the service, the contract IMetadataExchange is configured.

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <system.serviceModel>     <services>       <service name="Wrox.ProCSharp.WCF.RoomReservationService"           behaviorConfiguration="MyServiceTypeBehaviors">         <endpoint contract="Wrox.ProCSharp.WCF.IRoomService" binding="wsHttpBinding"/>         <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />         <host>           <baseAddresses>             <add baseAddress="http://localhost:8080/RoomReservation" />           </baseAddresses>         </host>       </service>     </services>     <behaviors>       <serviceBehaviors>         <behavior name="MyServiceTypeBehaviors" >           <serviceMetadata httpGetEnabled="true" />         </behavior>       </serviceBehaviors>     </behaviors>   </system.serviceModel> </configuration>

With this configuration the WSDL document can be accessed from the URI http://loalhost:8080/RoomReservation?wsdl as soon the service host is started.

Tip 

WSDL is discussed in Chapter 36, “Web Services with ASP.NET.”

Client

For the client, WCF is flexible again in what application type can be used. The client can be a simple console application as well. However, for reserving rooms, create a Windows Forms application with controls, as shown in Figure 40-3.

image from book
Figure 40-3

Because the service offers a MEX endpoint with the binding mexHttpBinding, and metadata access is enabled with the behavior configuration, you can add a service reference from Visual Studio. The service host must be running before you add a service reference. When you add a service reference, the dialog shown in Figure 40-4 pops up. Enter the link to the service and set the service reference name to RoomReservationService. The service reference name defines the namespace of the generated proxy class.

image from book
Figure 40-4

Adding a service reference adds references to the assemblies System.Runtime.Serialization and System.ServiceModel and a configuration file containing the binding information and the endpoint address to the service:

 <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel>    <bindings>       <wsHttpBinding>         <binding name="WSHttpBinding_IRoomService" closeTimeout="00:01:00"             openTimeout="00:01:00" receiveTimeout="00:10:00"             sendTimeout="00:01:00" bypassProxyOnLocal="false"              transactionFlow="false" hostNameComparisonMode="StrongWildcard"             maxBufferPoolSize="524288" maxReceivedMessageSize="65536"             messageEncoding="Text" textEncoding="utf-8"             useDefaultWebProxy="true" allowCookies="false">           <readerQuotas maxDepth="32" maxStringContentLength="8192"                 maxArrayLength="16384" maxBytesPerRead="4096"                 maxNameTableCharCount="16384" />           <reliableSession ordered="true" inactivityTimeout="00:10:00"                 enabled="false" />           <security mode="Message">              <transport clientCredentialType="Windows" proxyCredentialType="None"                    realm="" />                <message clientCredentialType="Windows" negotiateServiceCredential="true"                      algorithmSuite="Default" establishSecurityContext="true" />           </security>         </binding>       </wsHttpBinding>     </bindings>     <client>       <endpoint address="http://localhost:8080/RoomReservation"             binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IRoomService"             contract="RoomReservationClient.RoomReservationService.IRoomService"             name="WSHttpBinding_IRoomService">         <identity>           <userPrincipalName value="farabove\Chris" />         </identity>       </endpoint>     </client>   </system.serviceModel> </configuration>

From the data contract the class RoomReservation is generated. This class contains all [DataMember] elements of the contract. The class RoomServiceClient is the proxy for the client that contains methods that are defined by the service contract. Using this client you can send a room reservation to the running service.

  private void OnReserveRoom(object sender, EventArgs e) {    RoomReservation reservation = new RoomReservation();    reservation.Room = textRoom.Text;    reservation.EventName = textEvent.Text;    reservation.ContactName = textContact.Text;     reservation.BeginDate = DateTime.Parse(textBeginTime.Text);    reservation.EndDate = DateTime.Parse(textEndTime.Text);    RoomServiceClient client = new RoomServiceClient();    client.ReserveRoom(reservation);    client.Close(); } 

Running both the service and the client, you can add room reservations to the database.

Now let’s get into the details and different options of WCF.




Professional C# 2005 with .NET 3.0
Professional C# 2005 with .NET 3.0
ISBN: 470124725
EAN: N/A
Year: 2007
Pages: 427

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net