Thursday, January 30, 2014

WCF Tutorial Part-IV

Module 7

Improving WCF Service Quality

All applications have some form of system quality requirements in addition to their functional requirements. These quality requirements include the expected response time for operations, the availability of the application, the number of users or operations that the application must support, and the usability of the application's interface (human interface for a user interface or contract for a service). As your application evolves, you will adjust your design to improve system qualities such as performance to meet the required standard. Maintaining quality for different aspects of a system is frequently a balancing act. In particular, you will often find that the performance requirements are generally in conflict with almost every other requirement of your system. You must handle changes carefully to ensure that your system does not suffer unexpected consequences.
This module explores ways in which you can improve performance and other system qualities by using features provided by Windows® Communication Foundation (WCF).
·         Lesson 1:
·         Managing WCF Service Instances
·        
·         One way to improve system performance is to ensure that you use resources efficiently and reduce the scope for resource contention. In a WCF solution, service instances provide the primary point that you can control to ensure that resources are allocated efficiently and fairly.

Instance Life Cycle Options

To cope with resource contention and multithreading issues, you can configure the service host and specify the instance life cycle by setting the InstanceContextMode property of the ServiceBehavior applied to the service.
There are three different modes available:
·         PerCall. In this mode, each message that is sent to the service from any client causes a new service instance to be created to handle that message. The service instance is disposed of after the message is processed. The next message from any client (even the same client) causes a new instance to be created to handle that message; this new instance is also disposed of after the message is processed.
·         PerSession. In this mode, the ServiceHost maintains a service instance for each client for a specified duration, referred to as a session. When the first message arrives from a particular client a new service instance is created to handle requests from that client. The message is delivered to this service instance. The next message that arrives from the same client is sent to the same service instance as long as the session has not expired. A message from a different client causes a new service instance to be created to process that message and any subsequent messages from that client. When a session expires or is terminated, the service instance is disposed of.
·         Single. In this mode, a single service instance handles all requests from every client. The service instance is created when the service host starts instead of when the first request arrives from a client.
Each of these instance life cycle models has different implications for issues such as maintaining state and multithreading. These issues are explored later in this module.
The default instance life cycle management mode is PerSession.

Additional Reading

For more information about the different instance management modes, see "Sessions, Instancing, and Concurrency" on the MSDN Web site.
For more information how to apply the instance management modes, see "Discover Mighty Instance Management Techniques For Developing WCF Apps" on the MSDN Web site.

Creating a Service Instance Per-Call

Under the per-call (or per-message) service instance life cycle mode, the ServiceHost creates a new service instance for every client request. When a service instance has processed the message, the ServiceHost disposes of that service instance and any data or resources that it uses. A new service instance is created to handle subsequent requests even if the call is from the same client made by using the same proxy as a previous request.
Under this model, there will be as many instances of the service in existence at any one time as there are concurrent calls to the service. The one-to-one relationship between client requests and service instances means that there is only ever one thread active in the instance at any one time; the thread operates on behalf of the single client call with which this service instance is associated.
The ServiceHost disposes of the service instance at the end of the call, so the service cannot maintain internal state for the client between calls. To maintain server-side state between calls, state information must be written to a persistent store such as a database.
The advantages of per-call instance management are:
·         Your service does not have to manage any form of concurrency or multithreading.
·         Your service does not have to maintain state in the event of a session timeout.
·         Your service minimizes memory use and other resources on the host server.
The primary disadvantages of per-call instance management is that it continually creates and destroys service instances that can add a significant processing overhead to the host server.
The following code example shows how to set the instance context mode to PerCall by using the ServiceBehaviorAttribute.
[Visual Basic]
<ServiceBehavior(InstanceContextMode _
    := InstanceContextMode.PerCall)> _
Public Class BankService
    Implements IBank
    ...
End Class

[Visual C#]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class BankService : IBank
{
    ...
}

Additional Reading

For more information about the different instance management modes, see "InstanceContextMode Enumeration" on the MSDN Web site.
For more information how to apply the instance management modes, see "Discover Mighty Instance Management Techniques For Developing WCF Apps" on the MSDN Web site.


Creating a Service Instance Per-Client

Under the per-client (or per-session) service instance life cycle mode, the ServiceHost creates a new service instance for every client. This service instance is then associated with that particular client; subsequent requests from the same client are directed to the same service instance until the session terminates. If a client is multithreaded or makes asynchronous calls, multiple threads may execute in the service instance at one time. Therefore, you must ensure that the code in your service is thread-safe.
A service instance that uses the per-session instance life cycle mode retains in-memory state between client requests. After a specified period of inactivity—the session timeout period—the ServiceHost discards the service instance and any state information associated with this service instance. The default session time-out period is 10 minutes. At any one time, there can be potentially as many service instances as there are clients.
The advantage of per-session instance management is that there is a lower overhead from the instance creation/destruction/data access cycle compared to per-call instance life cycle management.
The disadvantages of per-session instance management are as follows:
·         You must be aware of the potential concurrency issues and mitigate them in your service implementation.
·         You must be prepared to handle the effects of a session timeout in both your client code and your service code.
·         Your service instance may be idle between requests but will still use up memory and other resources on the server.
The following code example shows how to set the instance context mode to PerSession by using the ServiceBehaviorAttribute.
[Visual Basic]
<ServiceBehavior(InstanceContextMode _
    := InstanceContextMode.PerSession)> _
Public Class BankService
    Implements IBank
    ...
End Class

[Visual C#]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class BankService : IBank
{
    ...
}
You can also set the ReleaseInstanceMode property of the OperationBehavior attribute for a service operation. This property forces the service host to release a service instance and recycle it before or after an operation that runs as part of a session.

Additional Reading

For more information about the different instance management modes, see "InstanceContextMode Enumeration" on the MSDN Web site.
For more information on how to apply the instance management modes, see "Discover Mighty Instance Management Techniques For Developing WCF Apps" on the MSDN Web site.

 


Creating a Single Service Instance

Under the single (or singleton) service instance life cycle mode, you can pass a service instance to the ServiceHost when you create it or the ServiceHost can create one itself. In either case, there will only ever be a single instance of the service in existence at any one time. The same service instance processes all calls from all clients, so it must be able to handle multiple concurrent calls.
A service instance that follows the single instance life cycle mode will retain in-memory state between requests; this state is accessible to all clients.
The primary advantages of single instance management is that there is a lower overhead from the instance creation/destruction/data access cycle compared to per-call or per-session instance life cycle management.
The disadvantages of single instance management are as follows:
·         You must be aware of the potential concurrency issues and address them in your service implementation.
·         The service instance will be idle between calls but will still use up memory and other resources on the server even when it is inactive.
·         The clients share the same service instance, they all have access to the data stored inside it. This can present a security risk for some applications if clients can not share state or data.
The following code fragment shows how to set the instance context mode to Single by using the ServiceBehaviorAttribute.
[Visual Basic]
<ServiceBehavior(InstanceContextMode _
    := InstanceContextMode.[Single])> _
Public Class BankService
    Implements IBank
    ...
End Class

[Visual C#]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class BankService : IBank
{
    ...
}

Additional Reading

For more information about the different instance management modes, see "InstanceContextMode Enumeration" on the MSDN Web site.
For more information on how to apply the instance management modes, see "Discover Mighty Instance Management Techniques For Developing WCF Apps" on the MSDN Web site.


Requiring Session Capability

Subheading (in Heading 4 style)

You can specify that your service instance should be able to maintain an ongoing relationship with a particular client. This is referred to as a session. You can use the SessionMode attribute of the service contract to indicate that you require, permit, or disallow this sort of session relationship between a client and service instance.
You can specify the SessionMode property for the service and set it to one of the following values:
·         Allowed. You can use the service as part of an ongoing session or use it per-call.
·         NotAllowed. Any attempt to send requests to the service in the context of a session will cause an error.
·         Required. Any attempt to send requests to the service outside the context of a session will cause an error.
If you specify that sessions are Allowed or Required on a single instance service, you can store and access per-client session state based on the OperationContext.Current.SessionId. If your instance management mode is set to PerSession, the same service instance will work with the same client instance all the time. If you specify Single or PerCall, the service instance can still store data for a specific client; it just involves a bit more work. The following table illustrates how the instance context mode interacts with the session mode.
Instance Context mode
Session mode: Required
Session mode: Allowed
Session mode: NotAllowed
PerCall
Each call has a distinct session and InstanceContext.
Each call has a distinct session and InstanceContext.
An exception is thrown.
PerSession
Each channel has a distinct session and InstanceContext.
Each channel has a distinct session and InstanceContext.
An exception is thrown.
Single
All calls share a single session and InstanceContext.
All calls share a single session and InstanceContext.
An exception is thrown.
If your application relies on sessions, you must ensure that the binding used will support them. Similarly, you must ensure that a service that you did not design to be part of an ongoing session rejects attempts to use it in that way. Bindings that support sessions include WSHttpBinding, WSDualHttpBinding, NetTcpBinding, and NetNamedPipeBinding.
The client does not have to do anything special to support a session. The session starts when the client opens a channel that uses a session-aware binding.
The following code fragment shows how to set the service contract to require session support.
[Visual Basic]
<ServiceContract([Namespace] := "http://myuri.org/Simple", _
    SessionMode := SessionMode.Required)> _
Public Interface IBank
   ...
End Interface

[Visual C#]
[ServiceContract(Namespace="http://myuri.org/Simple",
    SessionMode=SessionMode.Required)]
public interface IBank
{
  ...
}

Additional Reading

For more information about WCF sessions, see "WCF sessions, instancing, and reliable messaging".


Demonstration: Instance Management


Lesson 2:
Managing Concurrency Issues
One way to improve performance and throughput is to use multiple threads to access resources concurrently. However, implementing concurrency in a WCF service brings its own set of challenges to address

Concurrency Issues

Using PerSession and Single instancing opens up the potential for thread-based resource contention and deadlocks. Bugs caused by multithreading issues are among the most difficult to diagnose and fix because by their nature they are:
·         Intermittent. It can be very much a matter of the precise timing of a sequence of calls from clients.
·         Difficult to reproduce. It is often difficult to pin down the precise sequence of events or context that caused the bug.
·         Ccorrupt due to concurrent resource access. When you find the effects of a problem, its causes may have occurred some time ago.
You can take two approaches to prevent threading issues:
·         Block concurrent requests and ensure that only a single thread can run in a service instance at any one time. This simplifies the code that you must write; however, response time will increase because potentially concurrent client requests are held in a queue.
·         Protect sensitive resources from concurrent access. This will require you to analyze areas of potential contention and write code to address threading issues.

Additional Reading

For more information about multithreaded programming under the Microsoft® .NET Framework 2.0, see "What Every Dev Must Know About Multithreaded Apps" on the MSDN Web site.


Concurrency in WCF Services

You can set the concurrency behavior of a service by setting the ConcurrencyMode property of the ServiceBehavior attribute. The three possible settings are:
·         Multiple. Any number of threads can be active in the service instance at any one time.
·         Reentrant. Only one thread can be active in the service instance at any one time, but if a caller's thread leaves the service instance by calling out to another service, another calling thread can enter the service instance.
·         Single. Only one caller can access the service instance at one time, even if its thread of execution leaves the service instance.
You will see more about the characteristics of these concurrency modes in the next few topics. The default mode is ConcurrencyMode.Single.
If you decide to use anything other than single-threaded mode, you should protect resources from concurrent access by multiple threads. You can do this by using standard .NET Framework threading mechanisms such as locks, monitors, mutexes, and interlocking.

Additional Reading

For more information about how threading works with the different WCF instance management modes, see "Sessions, Instancing, and Concurrency" on the MSDN Web site.
For more information about how to create and control threads under the .NET Framework, see "Managed Threading" on the MSDN Web site.


Single Threaded Mode

Under the ConcurrencyMode.Single threading mode, only one client request can be active at any one time in a service instance. To fully understand this definition, it is important to distinguish between client calls and threads.
A client call causes the service host to allocate a thread that will then execute the service operation and process the message passed in the call. After that thread comes to the end of the service operation, the service host either destroys it or, more likely, places it back into a thread pool from which the service host can reallocate it to a subsequent call. If there are more callers at any point in time than there are threads available to the service host, the remaining callers will have to wait until a thread becomes free. Potentially, a client request may time out while waiting for a thread to become available.
Setting the ConcurrencyMode.Single threading mode means that the service instance effectively has only one thread. All other calls to the same service instance are queued until the current call ends, even if the current call blocks other callers to make a call to another service (effectively, the current call leaves the service instance for the amount of time that it is in the other service). This means that there is no possibility of any other call that interferes with the state of the service instance before the original call returns to its client.
Single-threaded mode is the safest option because there is no potential for deadlock or contention for resources. However, this mode can have a serious impact on the performance of the overall system because other calls to that service instance may be blocked and the client kept waiting. If you have specified ConcurrencyMode.PerCall instancing, a new instance is created for every call, so your choice of threading mode will not impact service performance. However, if you selected ConcurrencyMode.PerSession or ConcurrencyMode.Single instancing, the service instance will restrict access and potentially slow down the system.
The following code example shows how to set the service behavior to ConcurrencyMode.Single threading mode.
[Visual Basic]
<ServiceBehavior(ConcurrencyMode := ConcurrencyMode.[Single])> _
Public Class BankService
    Implements IBank
   ...
End Class

[Visual C#]
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single)]
public class BankService : IBank
{
   ...
}

Additional Reading

For more information about the effects of the concurrency mode setting, see "ConcurrencyMode Enumeration" on the MSDN Web site.


Reentrant Threaded Mode

Reentrant threading mode is similar in some ways to Single threaded mode. In both cases, only one thread of execution will be active at any one time in the service instance and other calls are queued if a thread is currently active in the instance. The difference comes when the current thread in the service instance makes a call out to another service. At this point, the service host allows the thread associated with the next call on the queue to enter the service instance. When the original thread returns, it rejoins the queue.
Like Single threaded mode, this mode limits the throughput for a particular service instance, but it does not limit throughput as much as Single mode does. Reentrant mode also eases some issues around distributed blocking on callbacks when calling-out to services.
Reentrant mode is not as safe as Single threaded mode because there is some potential for deadlock and corruption that does not exist with Single mode. However, this risk is a lot lower than with true multithreading.
The following code example shows how to set the service behavior to Reentrant threading mode.
[Visual Basic]
<ServiceBehavior(ConcurrencyMode := ConcurrencyMode.Reentrant)> _
Public Class BankService
    Implements IBank
    ...
End Class

[Visual C#]
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
public class BankService : IBank
{
   ...
}

Additional Reading

For more information about the effects of the concurrency mode setting, see "ConcurrencyMode Enumeration" on the MSDN Web site.


Multiple Threaded Mode

Under the ConcurrencyMode.Multiple threading mode, the WCF runtime permits multiple concurrent requests to the same service instance. The only limit to the number of concurrent threads is the number of potential callers and the level of available system resources.
For any type of shared service instance, this threading option will deliver the highest throughput. However, it is also the most dangerous option because there is a lot of potential for deadlock and corruption due to concurrency conflicts. You must ensure that the code that defines the operations for the service uses thread-safe techniques.
The following code fragment shows how to set the service behavior to ConcurrencyMode.Multiple threading mode.
[Visual Basic]
<ServiceBehavior(ConcurrencyMode := ConcurrencyMode.Multiple)> _
Public Class BankService
    Implements IBank
    ...
End Class

[Visual C#]
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class BankService : IBank
{
   ...
}

Additional Reading

For more information about the effects of the concurrency mode setting, see "ConcurrencyMode Enumeration" on the MSDN Web site.

Lesson 3:
Improving WCF Service Quality
This lesson describes other WCF features that you can use to improve system qualities such as availability and some of the issues that surround these features.

Improving Service Quality

Every system architect would like to serve as many clients as possible by using as few resources as possible. System architects deliver strongly on the unwritten non-functional requirement, namely cost. However, any deployed application has a limited set of resources at its disposal; the same applies for the services that constitute the application. Each service is limited in terms of the available processor time, memory, number of database connections. A large number of client calls can cause a large number of service instances to be created (or a large number of threads in service instances). Each instance or thread requires system resources; contention for these resources slows down the services, which slows down the overall system.
As the system slows down in the face of resource contention, all the callers experience poor performance because the system processes their requests more slowly than when the system is lightly loaded. In general terms, there are two solutions to this problem:
·         Buy better hardware to provide more resources that can be shared between the users of the system. This means more cost in terms of hardware, software, and the time spent installing and configuring. This is particularly galling for the stakeholders if the resource subsequently sits idle for large amounts of time as system usage drops.
·         Limit the demands made on the resources. You can restrict the number of calls handled by the system at one time to a number that means that every caller gets a reasonable amount of resources allocated to them. The problem with this approach is that after you hit that number of calls, subsequent calls must either wait or fail. This means that callers who get through experience a good performance level at the expense of callers who do not get through. The latter group can consist of some very unhappy system users! However, the hope is that this is a small subset of callers.

Additional Reading

For more information about the effects of the concurrency mode setting, see "ConcurrencyMode Enumeration" on the MSDN Web site.


Throttling Service Access

You can limit, or throttle, access to a service by setting the following properties of the ServiceThrottling service behavior:
·         MaxConcurrentCalls. This is the maximum number of client calls that are allowed at one time.
·         MaxConcurrentInstances. This is the maximum number of service instances that are allowed at one time.
·         MaxConcurrentSessions. This is the maximum number of sessions that are allowed at any one time.
The basic implications of these settings are relatively straightforward, but you must consider how the settings will work in combination with instancing and threading modes. In some scenarios, the instancing and threading mode settings can supersede the throttling setting. In other scenarios, the throttling setting can supersede the instancing and threading mode settings. The instancing and threading mode settings requires careful analysis, monitoring, and collection of performance data to achieve a good balance of resource usage versus throughput.

Additional Reading

For more information how to set the service throttling behavior values and their effects, see "ServiceThrottlingBehavior Class" on the MSDN Web site.

Throttling, Instance Management, and Threading

The effect of a particular throttling setting varies that depends on the instance mode and threading model specified for a service. The following table shows how the instance mode and throttling settings interact.
Instance Mode
Throttling Impact
Per-call
The number of concurrent client calls is throttled by whichever is the lower of MaxConcurrentCall and MaxConcurrentInstances.
Per-session
The number of concurrent client calls is throttled by the lowest of the three settings.
The number of concurrent sessions and concurrent instances will be the same.
The concurrent call setting is often smaller since sessions (and hence instances) live longer than the calls.
Single
MaxConcurrentInstances is irrelevant.
If a service has Single or Reentrant threading mode set, this will also alter its throttling behavior. If the number of concurrent calls allowed exceeds the number of instances allowed, the number of concurrent calls that the service will handle at one time will be restricted to the number of instances even though they can theoretically be serviced if multiple threading is allowed.
The session limits apply to transport, reliable, and secure sessions.

Additional Reading

For more information about how to apply service throttling settings, see "Discover Mighty Instance Management Techniques For Developing WCF Apps" on the MSDN Web site.


Improving Service Availability and Throughput

During development, it is easy to think of software applications and services as being hosted on a single hardware server (in many development environments, this is precisely how they are hosted). However, many applications and services are deployed to high-capability platforms, which frequently employ the following features:
·         Clustering, which makes multiple servers look like a single server to the client
·         Failover, which ensures that when one server fails the client is serviced by another one
·         Load-balancing, where the client is directed to the server with the lowest load
All these capabilities help deliver highly scalable, and available systems. Software developers must be careful that they do not undermine this type of platform and stop it from working efficiently by doing the following:
·         Holding state in-memory on a particular server.
·         Maintaining an ongoing connection between client and server.
This type of design leads to server-affinity where a client must communicate with the same server all the time regardless of availability or load, so it works against efforts to migrate clients as the server workload increases or decreases.

Additional Reading

For more information about how to cluster, load-balancing, and failover, see "Enabling Highly Available and Scalable Application Services".


Impact of WCF Settings on Load-Balancing and Failover

Sessions or ongoing connections of any form can reduce the ability to perform load-balancing and failover. As a WCF developer, you must consider this when you use the following WCF features:
·         PerSession instance context mode, where the client must talk to the same service instance each time. This mode creates server affinity because there is no cross-machine session management mechanism available such as that found in Microsoft ASP.NET.
·         Transport sessions such as those provided by TCP-based bindings, which require an ongoing connection between the client and the service, unlike Hypertext Transfer Protocol (HTTP)–based bindings, which do not require this ongoing connection.
·         Single instance context mode, which requires careful consideration in this scenario. You must determine which instance all the clients will communicate with and which server hosts it. What happens if that server fails? Also, is there really only one instance of the service or will you end up with one instance per server? If so, is this what you intended?
To avoid this type of problem, consider the following approaches:
·         Use per-call instance management so that it is not possible to store in-memory state between calls.
·         Load or save any client state to or from a common, persistent store such as a clustered database.
·         Use a type of session that keeps its duration short to help minimize server-affinity.

Additional Reading

For more information about WCF services on high-capability platforms, see "Load Balancing" on the MSDN Web site.

Lesson 4:
Improving Data Transfer Throughput
One of the great advantages that Web services have over other distributed communication mechanisms is their use of XML as an encoding, which makes cross-platform interoperability a lot easier. However, the requirement to encode all data in text format reduces the efficiency of the network when it transfers large amounts of binary data and reduces the performance of the systems that process this data. WCF provides several ways to improve throughput for exchanges that involve large amounts of binary data.

Improving Performance for Large Binary Data

Binary data has traditionally been a problem for Simple Object Access Protocol (SOAP) messaging. To form part of a SOAP body, you must convert binary data into base64 encoding, which makes it a lot larger and hence more inefficient to transmit. If there is a large amount of binary data, this also causes problems for the XML parser that trys to process it; XML parsers do not work well with large blocks of text because they usually read it all into memory before parsing it; therefore, they require a lot of memory to process large messages.
WCF offers two alternatives for more efficient transmission of large binary messages:
·         MTOM (Message Transmission Optimization Mechanism) encoding
·         Streaming

Additional Reading

For more information about how to handle large binary data in WCF, see "Large Data and Streaming" on the MSDN Web site.


Understanding MTOM Encoding

Message Transmission Optimization Mechanism (MTOM) is a Word Wide Web Consortium (W3C) standard that evolved from two previous attempts to deal with large binary data in SOAP messages: SOAP with Attachments (SwA) and DIME (Direct Internet Message Encapsulation). MTOM uses the MIME (Multipurpose Internet Mail Extensions) encoding, which is the same protocol that is used to attach binary data to e-mail messages. The MIME protocol defines a message structure that consists of a variable number of parts. There are delimiters between message parts; each one contains information about the type of data that it holds.
Under MTOM, the WCF runtime splits the SOAP message into text and binary parts. The text part becomes a standard SOAP message which occupies the first MIME message part. Any large binary data has its own MIME part so that it can retain an efficient encoding instead of base64. The SOAP message contains references to the binary data that indicate where that data was located in the original message before it was MTOM-encoded. When the MTOM-encoded message arrives at its destination, the WCF runtime can reconstitute the original message from the SOAP message and the binary MIME attachments.

Additional Reading

For more information about MTOM encoding, see "SOAP Message Transmission Optimization Mechanism".


Enabling MTOM Encoding

To enable MTOM encoding for your messages, you must:
·         Set the messageEncoding property of the binding to Mtom.
·         Set the MaxReceivedMessageSize and MaxArrayLength properties of the binding to values larger than the largest message you expect to process.
When you use MTOM encoding, WCF will optimize its handling of binary content:
·         If the binary content of the message is small, the WCF runtime base64-encodes the binary data and places it in the SOAP message body.
·         If the binary content is large, the WCF runtime places it in separate MIME message parts and adds a reference to this MIME part from the SOAP message body. Binary data of approximately 200 bytes or more is deemed to be large.
In both cases, the core message is contained in a SOAP message envelope in a MIME message.


Implementing Streaming

The first thing you must do to support streaming is to define one or more operations on your interface that passes or returns a System.IO.Stream. The operation you choose depends on whether you pass data from client to service or service to client. A service contract can have other operations with normal parameters and return values alongside operations that use streams, but the operations do not necessarily sit well together conceptually.
After you define your contract for passing streamed data, you must select a binding that supports streaming. There are only three preprovided WCF bindings that support streaming:
·         BasicHttpBinding
·         NetTcpBinding
·         NetNamedPipeBinding
Next, you must enable streaming on the binding by setting the TransferMode to Streamed, StreamedRequest, or StreamedResponse. You would use the latter two modes if you only intend to stream data one way through the contact associated with the endpoint such as only from the service to the client. The default transfer mode is Buffered, which supports normal message-based operation.
Finally, you must set the MaxReceivedMessageSize property of the binding to a value larger than the largest message that you expect to process. The default value of this property is 64 kilobytes (KB).

Additional Reading

For more information about how to enable streaming on a service, see "How to: Enable Streaming" on the MSDN Web site.

Stream Handling

One of the key questions when you work with streams is whose responsibility it is to open and close the streams. Good design tends to indicate that the component that opened a stream should be responsible for closing it again. However, that would link the client and the service unnecessarily. The following steps list the sequence and rules for stream handling. Note that the sender of the streamed data can be either the client or the service.
The sequence is as follows:
1.    The sender obtains a .NET Framework I/O stream onto the binary data source. For example, it may open a FileStream.
2.    The sender passes the stream to the receiver. If the service passes data to the client, you will typically pass the stream through a return value from an operation. If the client passes data to the service, the stream is passed as a parameter to the operation.

The sender should not close the stream; the WCF runtime will do this.
3.    The receiver starts to read from the stream representation created by the WCF runtime.
4.    The receiver must close the stream after it finishes with it.
After WCF hands the stream to the receiver, the receiver does not have to execute any more WCF-related user code. On the sender side, WCF will close the stream when the receiver has read all the data.

Additional Reading

For more information about how to enable streaming on a service, see "How to: Enable Streaming" on the MSDN Web site.


Comparing Streaming and MTOM

You have two mechanisms that pass large binary data, so which one should you choose? Consider the following points when you decide between them:
·         For very large binary data, streaming will be faster and more efficient. MTOM will still have to load the data into memory to turn it into a message, which can use a lot of memory or can even be infeasible in some scenarios. On the other hand, streaming links the source and destination; this enables direct transfer. Streaming will start to transfer faster and will have far less memory overhead.
·         For relatively small binary data (but still above the MTOM threshold), MTOM will be more efficient because it lacks the setup overhead of streaming.
·         If you can split the data into multiple blocks, it is usually better to send it as multiple MTOM messages instead of with streaming. However, all the data may not be available when the transfer starts; if this is the case, streaming is the only option.
·         The use of MTOM is largely transparent to the interface and the service implementation. This means that it places minimal restrictions on contract design and binding selection. However, streaming places restrictions on the form of operations in the interface. In fact, you probably want to have streaming operations in their own contracts to support alternative bindings that you configure specifically for streaming.

Additional Reading

For more information about how to handle large binary data in WCF, see "Large Data and Streaming" on the MSDN Web site.


Demonstration: Passing Large Binary Data in WCF

Lab: Improving Service Quality

Scenario

You must determine the best instance management and threading approach for the Contoso, Ltd Clinic Management System. Opinion is divided on whether to have a single service instance or multiple instances. You have been asked to demonstrate some of the issues to the development manager and some of the more technically-aware stakeholders. To do this, you must show how problems such as lost or corrupt data can occur if the wrong option is selected.

Exercise 1: Managing WCF Service Instances

In this exercise, you will replace the appointment service implementation with one that stores appointments on a linked list. You will then set the state management style so that multiple clients can access the appointments and load the service until it clearly demonstrates concurrency issues.
The main tasks for this exercise are as follows:
1.    Start the 6461A-LON-DEV-07 virtual machine and log on as Student.
2.    Replace the Appointment service implementation with one based on an in-memory linked list.
3.    Set the instance context mode to share the appointment data between clients.

Task 1: Start the 6461A-LON-DEV-07 virtual machine and log on as Student

1.    Open the Virtual Server Remote Control Client, and then double-click 6461A-LON-DEV-07.
2.    Log on to 6461A-LON-DEV-07 as Student by using the password Pa$$w0rd.

Task 2: Replace the appointment service implementation with one based on an in-memory linked list

1.    Start Microsoft® Visual Studio® 2008 development system as ADMINISTRATOR.
2.    Open the starter solution ConnectedWCF.sln:
    • If you are using Microsoft Visual Basic® development system, browse to the E:\Labfiles\Starter\VB\InstanceManagement\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
    • If you are using Microsoft Visual C#® development tool, browse to the E:\Labfiles\Starter\CS\InstanceManagement\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
3.    In the AppointmentService project, open the AppointmentServiceLinkedListImplementation file, and then examine the code in this file to see how:
    • The constructor creates an instance of the LinkedListAppointmentHelper class.
    • The CreateAppointment and ListTodaysAppointments methods delegate their functionality to the LinkedListAppointmentHelper instance.
4.    Examine the code in the LinkedListAppointmentHelper class to see how:
    • The CreateAppointment method wraps the Appointment passed in as the parameter in a linked-list wrapper, steps through the linked list to find the end, and appends the wrapped appointment to the list.
    • The ListTodaysAppointments method navigates through the linked list and places any appointments that occur today into a List<Appointment> that it returns.
5.    In the ContosoServicesSelfHostExtConfig project, in the ContosoServicesHost file, in the Main method, locate the TODO 1 comment, and change the service instance type for the Appointment service to com.contoso.AppointmentService.AppointmentServiceLinkedListImplementation.
6.    In the ContosoServicesHost project, open the App.config file in the WCF Service Configuration Editor window, and change the name of the com.contoso.AppointmentService.AppointmentServiceImplementation service implementation to com.contoso.AppointmentService.AppointmentServiceLinkedListImplementation.
7.    Build the 'Connected WCF' solution.
8.    Run the ConnectedWCF solution with debugging.
9.    On the Clinic Administration Client form, on the Create Appointment tab, click Find Slots, and then verify that a list of available slots is displayed. This confirms that the linked list form of the appointment service is running correctly.
10. Stop debugging.

Task 3: Set the instance management style to share the appointment data between clients

1.    In the HighSpeedAppointmentMaker project, open the HighSpeedMainForm file. This form starts multiple client threads, each of which makes calls to the appointment service.

Examine the AddAppointments method that each thread calls. This method creates a proxy for the appointment service and then calls the CreateAppointment operation 20 times. This method reports its progress by asking the appointment service for a list of the current appointments. The method then displays the number of appointments currently reported by the service, together with the number of appointments that this thread has added so far.

If you run this application with 4 threads, you would expect 80 (4 x 20) appointments to be made on the service.
2.    Configure the ConnectedWCF solution so that the ContosoServicesSelfHostExtConfig and HighSpeedAppointmentMaker projects start when you start debugging.
3.    Run the ConnectedWCF solution with debugging.
4.    In the High Speed Appointment Maker window, increase the number of client threads to 4, and then click Go.

Each row shows the results from one thread. Verify that each thread has added 20 appointments. At least one of the values reported by the service should be 80 because that would be the last value reported by the service if it had received all 80 appointment requests. The problem is that the default instance management mode is PerSession, so each client thread gets its own instance of the appointment service which is independent of the other appointment service instances. The appointments made by the other client are not visible to the other threads; therefore, the maximum value that you will see reported is 20.
5.    Stop debugging.
6.    In the AppointmentService project, edit the AppointmentServiceLinkedListImplementation class, and then locate the TODO 2 comment. Add a ServiceBehaviorAttribute to the AppointmentServiceLinkedListImplementation class with its InstanceContextMode property set to InstanceContextMode.Single. All client threads will now access the same instance of the appointment service.
7.    Run the ConnectedWCF solution with debugging.
8.    In the High Speed Appointment Maker window, increase the number of client threads to 4, and then click Go.

Verify that the service reports that it has received 80 appointment requests (at least one of the lines should report 80 appointments).
9.    Stop debugging.
Results: After completing this exercise, you should have seen how to change the instance management mode on your service and what effect this has.

Exercise 1: Answer Key (detailed steps)


Exercise 2: Managing Concurrency Issues

Scenario

You have been asked to demonstrate the problems that can occur from longer-running methods and resource contention. To do this, you must show how corruption can occur if the wrong combination of threading and instance management is selected.
In this exercise, you will intentionally create a threading problem in the linked-list version of the appointment service implementation. You will then modify the threading mode so that multiple clients can access the service without corruption.
The main tasks for this exercise are as follows:
1.    Demonstrate that the service defaults to a safe threading mode.
2.    Show that attempts to speed up the service can lead to corruption due to multithreading.

Task 1: Demonstrate that the service defaults to a safe threading mode

1.    In Microsoft Visual Studio 2008, open the starter ConnectedWCF.sln solution:
    • If you are using Visual Basic, browse to the E:\Labfiles\Starter\VB\Concurrency\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
    • If you are using Visual C#, browse to the E:\Labfiles\Starter\CS\Concurrency\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
2.    In Solution Explorer, in the AppointmentService project, edit the LinkedListAppointmentHelper file, and in the CreateAppointment method, locate the TODO 3 comment. Add a call to the Thread.Sleep method passing a value of 500 milliseconds. Add a Console.WriteLine call before the call to Sleep, and then print the current time (DateTime.Now.ToLongTimeString method) together with the following properties of the appointment parameter:
    • DoctorId
    • PatientId
    • Id
Add a Console.WriteLine call after the call to Sleep, and then print a message that indicates the sleep operation has finished and displays the current time (DateTime.Now.ToLongTimeString method).

The call to Sleep should enable any other thread running in the service to obtain a duplicate place in the linked list and so the service should gradually "lose" appointments.
3.    Run the ConnectedWCF solution with debugging.
4.    In the High Speed Appointment Maker window, increase the number of client threads to 4, and then click Go.

Verify that each thread reports that it has added 20 appointments and that at least one of the values reported by the service is 80. Because the instance context mode is Single, you may expect that the Sleep call you that added would cause corruption as described in step 5.

The reason that there is no corruption is because the default threading mode is Single, so this prevents any other calling thread from accessing the service instance even if an earlier caller is sleeping in the service. However, the price that you pay for this safety is a potential reduction in performance.
5.    Stop debugging.

Task 2: Show that attempts to speed up the service can lead to corruption due to multithreading

1.    In Solution Explorer, in the AppointmentService project, edit the AppointmentServiceLinkedListImplementation file, and then locate the TODO 2 comment. Amend the ServiceBehaviorAttribute and set the ConcurrencyMode property to ConcurrencyMode.Multiple. All client threads will now be able to access the instance of the appointment service at the same time.
2.    Run the ConnectedWCF solution with debugging.
3.    In the High Speed Appointment Maker window, increase the number of client threads to 4, and then click Go.

Verify that each thread reports that it has added 20 appointments but that the values reported by the service are well below 80. As you can see, in an effort to improve performance, this has opened up potential for corruption due to resource contention (in this case the resource is the linked list).
4.    Stop debugging.
Results: After completing this exercise, you should have seen how to control the threading mode of a service.

Exercise 2: Answer Key (detailed steps)


Exercise 3: Throttling Access to a WCF Service

Scenario

The level of load placed on the Contoso Clinic Management System will vary over time as more family practitioners sign up to the service. Additionally, the level of load from the family practitioners will be unpredictable over the course of a week. However, one thing is for certain: when patients stand at the administrator's desk in the practice waiting for their appointment, they will not appreciate the system running slowly. Because you will probably initially deploy the system on a limited amount of hardware, you must explore how effective throttling the number of clients will be in terms of maintaining service performance.
In this exercise, you will investigate how the service throttling setting affects the response time for successful callers and its overall impact on response times and throughput.
The main tasks for this exercise are as follows:
1.    Take an initial measure of the response times.
2.    Determine the effect of throttling on overall response times.
3.    Determine the effect of throttling on successful caller response times.

Task 1: Take an initial measure of the response times

1.    In Microsoft Visual Studio 2008, open the starter ConnectedWCF.sln solution:
    • If you are using Visual Basic, browse to the E:\Labfiles\Starter\VB\Throttling\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
    • If you are using Visual C#, browse to the E:\Labfiles\Starter\CS\Throttling\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
2.    In Solution Explorer, in the HighSpeedAppointmentMaker project, edit the HighSpeedMainForm file. This version of the form times the duration of the calls made by each client thread and provides you with an overall average.

In the AddAppointments method, locate the TODO 4 comment, and then examine the code underneath it. This code takes a timestamp before the calls to the CreateAppointment and ListTodaysAppointments operations and then uses this information to calculate an average timing across the 20 pairs of calls.

Note: Because these timings are taken on the client side, they will include any wait time encountered by the call; for example, they will include the time that the call is blocked if it must wait for a service instance.
3.    Run the ConnectedWCF solution with debugging.
4.    In the High Speed Appointment Maker window, increase the number of client threads to 10, and then click Go.

After all the threads finish running, you will see a dialog box that contains an average value for the call duration across the 10 threads. Make a note of this value, and then click OK.
5.    Stop debugging.

Task 2: Determine the effect of throttling on overall response times

1.    Edit the configuration file for the ContosoServicesSelfHostExtConfig project, add a serviceThrottling element to the HttpMexAndExceptionDetail behavior, and then set the value of MaxConcurrentCalls property to 3.
2.    Run the ConnectedWCF solution with debugging.
3.    In the High Speed Appointment Maker window, increase the number of client threads to 10, and then click Go.

After the threads have run, you will see a dialog box that contains an average value for the call duration across the 10 threads. Make a note of this value, and click then OK.

Compare this value with the one that you recorded in Task 1. Has throttling increased or decreased this overall client-side time?

You should find that setting a throttling value of less than the number of calling threads has increased the average time taken per-call when measured from the client side. This is because calling threads wait for other calling threads to leave a service instance so that the number of concurrent calls drops below 3.
4.    Stop debugging.

Task 3: Determine the effect of throttling on successful caller response times

1.    In Solution Explorer, in the HighSpeedAppointmentMaker project, edit the HighSpeedMainForm file, and in the AddAppointments method, locate the TODO 4 comment. Perform the following steps:
    • Remove the variables startTimestamp and endTimestamp.
    • Replace the call to CreateAppointment with a call to TimedCreateAppointment. This is a form of the CreateAppointment method that times the duration of the call inside the service and returns this duration as a TimeSpan. Assign the return value to a variable named callTime of type TimeSpan.
    • Replace the call to ListTodaysAppointments with a call to TimedListTodaysAppointments. This is a form of the ListTodaysAppointments method that times the duration of the call inside the service and returns this duration as a TimeSpan. Add the return value to the callTime variable.
    • Assign the Milliseconds property of the callTime variable to the millisThisCall variable.
2.    Run the ConnectedWCF solution with debugging.
3.    In the High Speed Appointment Maker window, increase the number of client threads to 10, and then click Go.

After all the threads run, you will see a dialog box that contains an average value for the call duration across the 10 threads. Make a note of this value, and then click OK.

Compare this value with the ones that you recorded in Task 2. This new value should be significantly lower because it is recording the duration of calls on the service-side when there are only 3 concurrent calls. This does not include any wait time.
4.    Stop debugging.
5.    Edit the configuration file for the ContosoServicesSelfHostExtConfig project to change the value of MaxConcurrentCalls to 20.
6.    Save your changes, and then close the WCF Service Configuration Editor window.
7.    Run the ConnectedWCF solution with debugging.
8.    In the High Speed Appointment Maker window, increase the number of client threads to 10, and then click Go.

After all the threads run, you will see a dialog box that contains an average value for the call duration across the 10 threads. Make a note of this value, and then click OK.

Compare this value with the one that you recorded earlier in this task. Has removing throttling increased or decreased this overall service-side time?

You should find that setting the throttling value to more than the number of calling threads has increased the average time taken per-call when measured from the service-side. This is because there are now potentially 10 concurrent calling threads contending for service-side resources at the same time, therefore the call time for each thread will increase.
9.    Stop debugging.
Results: After completing this exercise, you should have seen how to use throttling and how it affects the callers to a service.

Exercise 3: Answer Key (detailed steps)


Exercise 4: Passing Bulk Data between a WCF Client and Service

Scenario

The consultants who use the Contoso Clinic Management System will require access to large amounts of patient data in the form of MRI scan and X-ray images. These files will be far larger than is reasonable to pass as a standard parameter, so they will require some form of special handling.
In this exercise, you will pass large binary data across a WCF service interface by using both MTOM and streaming.
The main tasks for this exercise are as follows:
1.    Add an operation to return an image as a byte array to a WCF service.
2.    Add an endpoint for the contract that uses MTOM encoding.
3.    Add code to the client to call the new operation.
4.    Configure and run the client.
5.    View the raw MTOM messages.
6.    Add a streamed method to the contract.
7.    Change the service-side endpoint to support streaming.
8.    Change the client code to call the new operation.
9.    Configure and run the client.
10. View the raw streamed messages.

Task 1: Add an operation to return an image as a byte array to a WCF service

1.    In Microsoft Visual Studio 2008, open the starter ConnectedWCF.sln solution.
    • If you are using Visual Basic, browse to the E:\Labfiles\Starter\VB\BulkData\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
    • If you are using Visual C#, browse to the E:\Labfiles\Starter\CS\BulkData\ConnectedWCF folder, and then double-click ConnectedWCF.sln.
2.    In Solution Explorer, in the PatientManagementService project, edit the PatientManagementServiceImageContract file, and then locate the TODO 5 comment. Add a WCF operation with the following properties:
    • Name: GetXrayImage
    • Return type: byte[]
    • Parameters: string patientId, string type
3.    Edit the PatientManagementServiceImplementation class, and then locate the TODO 6 comment. Add PatientManagementServiceImageContract to the list of interfaces implemented by the PatientManagementServiceImplementation class.
4.    Implement the GetXrayImage method in the implementation class. This method should perform the following tasks:
    • Call the helper method GetImageAsStream, passing the image type and getting back a memory stream.
    • Convert the memory stream to a byte array and return this from the method.

Task 2: Add an endpoint for the contract that uses MTOM encoding

1.    Edit the configuration of the ContosoServicesSelfHostExtConfig project to add a new endpoint with the following properties:
    • Name: PMIService_WS
    • Address: PatientManagementServiceImages
    • Binding: wsHttpBinding
    • Contract: com.contoso.PatientManagementService.PatientManagementServiceImageContract
2.    Add a new binding configuration of type wsHttpBinding that has the following properties:
    • Name: WebServiceMtomBindingConfig
    • MessageEncoding: Mtom
3.    Apply the WebServiceMtomBindingConfig binding configuration to the PMIService_WS endpoint.
4.    Rebuild the solution.

Task 3: Add code to the client to call the new operation

1.    In Windows Explorer, browse to the ContosoServicesSelfHostExtConfig.exe file at either of the following locations, and then run it as ADMINISTRATOR.
    • If you are using Visual Basic, browse to the E:\Labfiles\Starter\VB\BulkData\ConnectedWCF\ContosoServicesSelfHostExtConfig\bin\Debug folder.
    • If you are using Visual C#, browse to the E:\Labfiles\Starter\CS\BulkData\ConnectedWCF\ContosoServicesSelfHostExtConfig\bin\Debug folder.
2.    In the ConsultantClient project, update the PatientManagementServiceReference.
3.    Close the ContosoServicesSelfHostExtConfig application.
4.    In Solution Explorer, under the ConsultantClient project, edit the ConsultantForm file, and in the GetImageStreamFromBytes method, locate the TODO 7 comment. Replace the existing code in this method with statements that perform the following tasks:
    • Create a new instance of the PatientManagementServiceImageContractClient proxy class.
    • Call the GetXrayImage method on the proxy passing PatientId.Text and typeOfXray as parameters.
    • Create a new MemoryStream by passing the byte array returned from GetXrayImage to the constructor, and then return this MemoryStream instance from the method.
5.    In the GetImage_Click method, locate the TODO 8 comment. Examine the preceding two lines of code, which call the GetImageStreamFromBytes method, and display the contents of the returned imageStream variable. Add a line of code to close the imageStream after it has been displayed.
Note: It is important to close the image stream on the client. In this tasks, the stream is created locally in client code. However, when you use streaming later on, the stream will be created by WCF; you must therefore explicitly close it in the client code.

Task 4: Configure and run the client

1.    Edit the configuration file for the ConsultantClient project and examine the PMIService_WS endpoint. This endpoint already has a binding configuration called PMIService_WS.
2.    Open the PMIService_WS binding configuration, and then perform the following steps:
    • Examine the value of the MessageEncoding and verify that it is already set to Mtom.
    • Set the value of the MaxReceivedMessageSize property to 12000000 (12 million). The X-ray files passed are 6 MB in size, so this should enable WCF to pass them successfully. If this buffer size is smaller than the message, an exception will be thrown.
    • Set the value of the MaxArrayLength under ReaderQuotasProperties to 12000000 (12 million) for the same reason. This allocates more space to process the XML representation of the message.
Note: If this was a production strength application, it is likely that you would split the large file into multiple pieces instead of having a very large buffer size.
3.    Switch to Windows Explorer, and then browse to the E:\LabFiles\logs folder.
4.    In the logs folder, delete the existing messages.svclog file.
5.    Switch to Visual Studio, and then run the ConnectedWCF solution with debugging.
6.    In the Consultant Client window, click the Patient Information tab. On the Patient Information tab, click Chest, and then click Get Image.

You should see an X-ray image displayed on the Patient Information tab.
7.    Stop debugging.

Task 5: View the raw MTOM messages

1.    Start the Microsoft Service Trace Viewer, and then open the E:\LabFiles\logs\messages.svclog file.
2.    In the Service Trace Viewer, in the left pane, click the Message tab, and then click a message with an action of http://contoso.com/ClinicManagementSystem/2007/10/PatientManagementServiceImageContract/GetXrayImage.
Note: You will see each message and response listed twice. This is because the service has been configured to log each message at the message level and the transport level.
3.    In the lower-right pane, click the Message tab, and then examine the Hypertext Transfer Protocol (HTTP) request header. Verify that the WebHeaders element contains a Content-Type element that in turn contains a string that starts with multipart/related;type="application/xop+xml". This confirms that it uses MTOM encoding.
5.    Click the Message tab, and then examine the SOAP message. Scroll down to find the SOAP body and verify that its <s:Body> element contains an empty GetXrayImageResult element. This is because the content is in a separate MIME part.

Task 6: Add a streamed method to the contract

1.    In Solution Explorer, under the PatientManagementService project, edit the PatientManagementServiceImageContract file, and then add a WCF operation with the following properties:
    • Name: StreamXrayImage
    • Return type: Stream
    • Parameters: string patientId, string type
2.    Locate the TODO 9 comment, and then bring the System.IO namespace into scope.
3.    In Solution Explorer, under the PatientManagementService project, edit the PatientManagementServiceImplementation class, and then implement the StreamXrayImage method:
    • Create a string variable named imagePath by concatenating the string literal "..\..\DataFiles\xray_", the type parameter passed into the method, and the string literal ".png".
    • Call the static method OpenRead on the File class, passing the imagePath variable as its parameter. Use the value returned from the OpenRead call as the return value for the StreamXrayImage method.

Task 7: Change the service-side endpoint to support streaming

1.    Edit the configuration of the ContosoServicesSelfHostExtConfig project, and then change the PMIService_WS endpoint. Configure the endpoint as follows:
    • Name: PMIService_TCP
    • Address: PatientManagementServiceImages
    • Binding: netTcpBinding
    • Contract: com.contoso.PatientManagementService.PatientManagementServiceImageContract
2.    Add a new binding configuration of type netTcpBinding, and then configure the binding as follows:
    • Name: NetTcpStreamingBindingConfig
    • TransferMode: Streamed
3.    Apply the NetTcpStreamingBindingConfig binding configuration to the PMIService_TCP endpoint.
4.    Save your changes, and then close the WCF Service Configuration Editor window.
5.    Rebuild the solution.

Task 8: Change the client code to call the new operation

1.    In Windows Explorer, browse to the ContosoServicesSelfHostExtConfig.exe file at either of the following locations, and then run it as ADMINISTRATOR.
    • If you are using Visual Basic, browse to the E:\Labfiles\Starter\VB\BulkData\ConnectedWCF\ContosoServicesSelfHostExtConfig\bin\Debug folder.
    • If you are using Visual C#, browse to the E:\Labfiles\Starter\CS\BulkData\ConnectedWCF\ContosoServicesSelfHostExtConfig\bin\Debug folder.
2.    In the ConsultantClient project, update the PatientManagementServiceReference.
3.    Close the ContosoServicesSelfHostExtConfig application.
4.    In Solution Explorer, in the ConsultantClient project, edit the ConsultantForm file, and then locate the TODO 10 comment. Make the following changes to the code:
    • Create a new instance of the PatientManagementServiceImageContractClient proxy class, passing the value "PMIService_TCP" to its constructor.
    • Call the StreamXrayImage method on the proxy, passing PatientId.Text and typeOfXray as parameters. Use the return value from the StreamXrayImage method call as the return value from the GetImageStream method.
5.    Locate the TODO 11 comment, and then replace the call to GetImageStreamFromBytes with a call to GetImageStream.

Task 9: Configure and run the client

1.    Edit the configuration of the ConsultantClient project.

This file contains a binding configuration called PMIService_TCP.
2.    Modify the PMIService_TCP binding configuration as follows:
    • Examine the value of the TransferMode, and then verify that it is already set to Streamed.
    • Set the value of the MaxReceivedMessageSize property to 12000000 (12 million).
3.    Run the ConnectedWCF solution with debugging.
4.    In the Consultant Client window, click the Patient Information tab. On the Patient Information tab, click Chest, and then click Get Image.

You should see an X-ray image displayed on the Patient Information tab.
5.    Stop debugging.

Task 10: View the raw streamed messages

1.    Switch to the Service Trace Viewer, open the file E:\LabFiles\logs\messages.svclog, and then click Open.
2.    Click the Message tab to display a list of messages passed between the client and the service.
4.    Click the Message tab, and then examine the SOAP message. Scroll down to find the SOAP body and verify that its <s:Body> element contains …stream….
Results: After completing this exercise, you should have seen how to pass bulk binary data between a WCF client and service.

Exercise 4: Answer Key (detailed steps)

4 comments: