Service Implementation


The implementation of the service can be marked with the attribute [ServiceBehavior], as shown with the class RoomReservationService:

  [ServiceBehavior] public class RoomReservationService : IRoomService {    public bool ReserveRoom(RoomReservation roomReservation)    {    // implementation    } } 

The attribute [ServiceBehavior] is used to describe behavior as is offered by WCF services to intercept the code for required functionality as shown in the following table.

Open table as spreadsheet

ServiceBehavior Property

Description

TransactionAutoComleteOnSessionClose

When the current session is finished without error, the transaction is automatically committed. This is similar to the [AutoComplete] attribute that has been discussed with Enterprise Services in Chapter 38.

TransactionIsolationLevel

To define the isolation level of the transaction within the service, the property TransactionIsolationLevel can be set to one value of the IsolationLevel enumeration.

ReleaseServiceInstanceOnTransactionComplete

When the transaction is finished, the instance of the service is recycled.

AutomaticSessionShutdown

If the session should not be closed when the client closes the connection, you can set the property AutomaticSessionShutdown to false. By default, the session is closed.

InstanceContextMode

With the property InstanceContextMode, you can define if stateful or stateless objects should be used. The default setting is InstanceContextMode.PerCall to create a new object with every method call. You can compare this with .NET Remoting well-known SingleCall objects. Other possible settings are PerSession and Single. With both of these settings stateful objects are used. However, with PerSession a new object is created for every client. Single allows sharing the same object with multiple clients.

ConcurrencyMode

Because stateful objects can be used by multiple clients (or multiple threads of a single client), you must pay attention to concurrency issues with such object types. If the property ConcurrencyMode is set to Multiple, multiple threads can access the object, and you have to deal with synchronization. If you set the option to Single, only one thread accesses the object at a time. Here, you don’t have to do synchronization; however, scalability problems can occur with a higher number of clients. For stateless objects, this setting doesn’t have any meaning, as new objects are instantiated with every method call and thus no state is shared.

UseSynchronizationContext

With Windows Forms and WPF members of controls may only be invoked from the creator thread. If the service is hosted in a Windows application, and the service methods invoke control members, set the UseSynchronizationContext to true. This way the service runs in a thread defined by the SynchronizationContext.

IncludeExceptionDetailInFaults

With .NET, errors face up as exceptions. SOAP defines that a SOAP fault is returned to the client in case the server has a problem. For security reasons it’s not a good idea to return details of server side exceptions to the client. Thus, by default exceptions are converted to unknown faults. To return specific faults, throw an exception of type FaultException.

For debugging purposes, it can be very helpful to return the real exception information. This is the case when changing the setting of IncludeExceptionDetailInFaults to true. Here a FaultException<TDetail> is thrown where the original exception contains the detail information.

MaxItemsInObjectGraph

With the property MaxItemsInObjectGraph, you can limit the number of objects that are serialized.

ValidateMustUnderstand

The property ValidateMustUnderstand set to true means that the SOAP headers must be understood (which is the default).

Tip 

Transactions are discussed in Chapter 21, “Transactions.”

To demonstrate a service behavior, the interface IStateService defines a service contract with two operations to set and get state. With a stateful service contract a session is needed. That’s why the SessionMode property of the service contract is set to SessionMode.Required. The service contract also defines methods to initiate and close the session by applying the IsInitiating and IsTerminating properties to the operation contract.

  [ServiceContract(SessionMode=SessionMode.Required)] public interface IStateService {    [OperationContract(IsInitiating=true)]    void Init(int i);    [OperationContract]    void SetState(int i);    [OperationContract]     int GetState();        [OperationContract(IsTerminating=true)]    void Close(); } 

The service contract is implemented by the class StateService. The service implementation defines the InstanceContextMode.PerSession to keep state with the instance.

  [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] public class StateService : IStateService {    int i = 0;    public void Init(int i)     {       this.i = i;    }    public void SetState(int i)    {       this.i = i;    }    public int GetState()    {       return i;    }    public void Close()    {    } } 

The host of the service is a console application as before. The service is started with the Open() method of the ServiceHost class that has the type of the service assigned with the constructor.

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

Now the binding to the address and protocol must be defined. Here, the basicHttpBinding is assigned to the endpoint of the service:

  <?xml version="1.0" encoding="utf-8" ?> <configuration>   <system.serviceModel>     <services>       <service name="Wrox.ProCSharp.WCF.StateService">         <!-- basicHttpBinding does not support sessions -->         <endpoint address="http://localhost:8080/StateService"           binding="basicHttpBinding"           contract="Wrox.ProCSharp.WCF.IStateService" />       </service>     </services>   </system.serviceModel> </configuration> 

If you start the service host with the defined configuration, an exception of type InvalidOperationException is thrown. The error message with the exception gives this error message: “Contract requires Session, but Binding ‘BasicHttpBinding’ doesn’t support it or isn’t configured properly to support it.”

Not all bindings support all services. Because the service contract requires a session with the attribute [ServiceContract(SessionMode=SessionMode.Required)], the host fails because the configured binding does not support sessions.

As soon as you change the configuration to a binding that supports sessions (e.g., the wsHttpBinding), the server starts successful.

 <?xml version="1.0" encoding="utf-8" ?> <configuration>   <system.serviceModel>     <services>       <service name="Wrox.ProCSharp.WCF.StateService">         <endpoint address="http://localhost:8080/StateService"           binding="wsHttpBinding"           contract="Wrox.ProCSharp.WCF.IStateService" />       </service>     </services>   </system.serviceModel> </configuration>

Now a client application can be created. In the previous example, the client application was created by adding a service reference. Instead of adding a service reference, you can also directly access the assembly containing the contract interface, and use the ChannelFactory<TChannel> class to instantiate the channel to connect to the service.

The constructor of the class ChannelFactory<TChannel> accepts the binding configuration and endpoint address. The binding must be compatible to the binding defined with the service host, and the address defined with the EndpointAddress class references the URI of the running service.

The CreateChannel() method creates a channel to connect to the service. Then you can invoke methods of the service, and you can see that the service instance holds state until the Close() method is invoked that has the IsTerminating operation behavior assigned.

  using System; using System.ServiceModel; namespace Wrox.ProCSharp.WCF {    class Program    {       static void Main()       {          WsHttpBinding binding = new WsHttpBinding();          EndpointAddress address =                new EndpointAddress("http://localhost:8080/StateService");          ChannelFactory<IStateService> factory =                new ChannelFactory<IStateService>(binding, address);          IStateService channel = factory.CreateChannel();          channel.Init(1);          Console.WriteLine(channel.GetState());          channel.SetState(2);          Console.WriteLine(channel.GetState());          channel.Close();          factory.Close();       }    } } 

With the implementation of the service, you can apply to the service methods the following properties, with the attribute [OperationBehavior]:

Open table as spreadsheet

OperationBehavior

Description

AutoDisposeParameters

By default all disposable parameters are automatically disposed. If the parameters should not be disposed, you can set the property AutoDisposeParameters to false. Then the sender is responsible to dispose the parameters.

Impersonation

With the Impersonation property, the caller can be impersonated and the method runs with the identity of the caller.

ReleaseInstanceMode

The InstanceContextMode defines the lifetime of the object instance with the service behavior setting. With the operation behavior setting, you can override the setting based on the operation. The RelaseInstanceMode defines an instance release mode with the enumeration ReleaseInstanceMode. The value None uses the instance context mode setting. With the values BeforeCall, AfterCall, and BeforeAndAfterCall you can define recycle times with the operation.

TransactionScopeRequired

With the property TransactionScopeRequired, you can specify if a transaction is required with the operation. If a transaction is required, and the caller already flows a transaction, the same transaction is used. If the caller doesn’t flow a transaction, a new transaction is created.

TransactionAutoComplete

The TransactionAutoComplete property specifies if the transaction should complete automatically. If the TransactionAutoComplete property is set to true, the transaction is aborted if an exception is thrown. The transaction is committed if it is the root transaction and no exception is thrown.




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