Sei sulla pagina 1di 446

O F F I C I A L M I C R O S O F T L E A R N I N G P R O D U C T

10263A
Developing Windows Communication
Foundation Solutions with Microsoft
Visual Studio 2010
Volume 2
ii Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Information in this document, including URL and other Internet Web site references, is subject to change without notice.
Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people,
places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain
name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright
laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be
reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic,
mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft
Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject
matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this
document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.
The names of manufacturers, products, or URLs are provided for informational purposes only and Microsoft makes no
representations and warranties, either expressed, implied, or statutory, regarding these manufacturers or the use of the
products with any Microsoft technologies. The inclusion of a manufacturer or product does not imply endorsement of
Microsoft of the manufacturer or product. Links may be provided to third party sites. Such sites are not under the control of
Microsoft and Microsoft is not responsible for the contents of any linked site or any link contained in a linked site, or any
changes or updates to such sites. Microsoft is not responsible for webcasting or any other form of transmission received from
any linked site. Microsoft is providing these links to you only as a convenience, and the inclusion of any link does not imply
endorsement of Microsoft of the site or the products contained therein.
2010 Microsoft Corporation. All rights reserved.
Microsoft, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or
other countries.
All other trademarks are property of their respective owners.




Product Number: 10263A
Part Number: X17-47396
Released: 08/2010


MICROSOFT LICENSE TERMS
OFFICIAL MICROSOFT LEARNING PRODUCTS - TRAINER EDITION
Pre-Release and Final Release Versions
These license terms are an agreement between Microsoft Corporation and you. Please read them. They apply to the Licensed
Content named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft
updates,
supplements,
Internet-based services, and
support services
for this Licensed Content, unless other terms accompany those items. If so, those terms apply.
By using the Licensed Content, you accept these terms. If you do not accept them, do not use the Licensed
Content.
If you comply with these license terms, you have the rights below.
1. DEFINITIONS.
a. Academic Materials means the printed or electronic documentation such as manuals, workbooks, white papers,
press releases, datasheets, and FAQs which may be included in the Licensed Content.
b. Authorized Learning Center(s) means a Microsoft Certified Partner for Learning Solutions location, an IT
Academy location, or such other entity as Microsoft may designate from time to time.
c. Authorized Training Session(s) means those training sessions authorized by Microsoft and conducted at or
through Authorized Learning Centers by a Trainer providing training to Students solely on Official Microsoft Learning
Products (formerly known as Microsoft Official Curriculum or MOC) and Microsoft Dynamics Learning Products
(formerly know as Microsoft Business Solutions Courseware). Each Authorized Training Session will provide training on
the subject matter of one (1) Course.
d. Course means one of the courses using Licensed Content offered by an Authorized Learning Center during an
Authorized Training Session, each of which provides training on a particular Microsoft technology subject matter.
e. Device(s) means a single computer, device, workstation, terminal, or other digital electronic or analog device.
f. Licensed Content means the materials accompanying these license terms. The Licensed Content may include, but
is not limited to, the following elements: (i) Trainer Content, (ii) Student Content, (iii) classroom setup guide, and (iv)
Software. There are different and separate components of the Licensed Content for each Course.
g. Software means the Virtual Machines and Virtual Hard Disks, or other software applications that may be included
with the Licensed Content.
h. Student(s) means a student duly enrolled for an Authorized Training Session at your location.
i. Student Content means the learning materials accompanying these license terms that are for use by Students and
Trainers during an Authorized Training Session. Student Content may include labs, simulations, and courseware files
for a Course.
j. Trainer(s) means a) a person who is duly certified by Microsoft as a Microsoft Certified Trainer and b) such other
individual as authorized in writing by Microsoft and has been engaged by an Authorized Learning Center to teach or
instruct an Authorized Training Session to Students on its behalf.
k. Trainer Content means the materials accompanying these license terms that are for use by Trainers and Students,
as applicable, solely during an Authorized Training Session. Trainer Content may include Virtual Machines, Virtual Hard
Disks, Microsoft PowerPoint files, instructor notes, and demonstration guides and script files for a Course.
l. Virtual Hard Disks means Microsoft Software that is comprised of virtualized hard disks (such as a base virtual hard
disk or differencing disks) for a Virtual Machine that can be loaded onto a single computer or other device in order to
allow end-users to run multiple operating systems concurrently. For the purposes of these license terms, Virtual Hard
Disks will be considered Trainer Content.
m. Virtual Machine means a virtualized computing experience, created and accessed using Microsoft Virtual PC or
Microsoft Virtual Server software that consists of a virtualized hardware environment, one or more Virtual Hard Disks,

and a configuration file setting the parameters of the virtualized hardware environment (e.g., RAM). For the purposes
of these license terms, Virtual Hard Disks will be considered Trainer Content.
n. you means the Authorized Learning Center or Trainer, as applicable, that has agreed to these license terms.
2. OVERVIEW.
Licensed Content. The Licensed Content includes Software, Academic Materials (online and electronic), Trainer Content,
Student Content, classroom setup guide, and associated media.
License Model. The Licensed Content is licensed on a per copy per Authorized Learning Center location or per Trainer
basis.
3. INSTALLATION AND USE RIGHTS.
a. Authorized Learning Centers and Trainers: For each Authorized Training Session, you may:
i. either install individual copies of the relevant Licensed Content on classroom Devices only for use by Students
enrolled in and the Trainer delivering the Authorized Training Session, provided that the number of copies in use
does not exceed the number of Students enrolled in and the Trainer delivering the Authorized Training Session, OR
ii. install one copy of the relevant Licensed Content on a network server only for access by classroom Devices and
only for use by Students enrolled in and the Trainer delivering the Authorized Training Session, provided that the
number of Devices accessing the Licensed Content on such server does not exceed the number of Students
enrolled in and the Trainer delivering the Authorized Training Session.
iii. and allow the Students enrolled in and the Trainer delivering the Authorized Training Session to use the Licensed
Content that you install in accordance with (ii) or (ii) above during such Authorized Training Session in accordance
with these license terms.
i. Separation of Components. The components of the Licensed Content are licensed as a single unit. You may not
separate the components and install them on different Devices.
ii. Third Party Programs. The Licensed Content may contain third party programs. These license terms will apply to
the use of those third party programs, unless other terms accompany those programs.
b. Trainers:
i. Trainers may Use the Licensed Content that you install or that is installed by an Authorized Learning Center on a
classroom Device to deliver an Authorized Training Session.
ii. Trainers may also Use a copy of the Licensed Content as follows:
A. Licensed Device. The licensed Device is the Device on which you Use the Licensed Content. You may install
and Use one copy of the Licensed Content on the licensed Device solely for your own personal training Use and
for preparation of an Authorized Training Session.
B. Portable Device. You may install another copy on a portable device solely for your own personal training Use
and for preparation of an Authorized Training Session.
4. PRE-RELEASE VERSIONS. If this is a pre-release (beta) version, in addition to the other provisions in this agreement,
these terms also apply:
a. Pre-Release Licensed Content. This Licensed Content is a pre-release version. It may not contain the same
information and/or work the way a final version of the Licensed Content will. We may change it for the final,
commercial version. We also may not release a commercial version. You will clearly and conspicuously inform any
Students who participate in each Authorized Training Session of the foregoing; and, that you or Microsoft are under no
obligation to provide them with any further content, including but not limited to the final released version of the
Licensed Content for the Course.
b. Feedback. If you agree to give feedback about the Licensed Content to Microsoft, you give to Microsoft, without
charge, the right to use, share and commercialize your feedback in any way and for any purpose. You also give to
third parties, without charge, any patent rights needed for their products, technologies and services to use or interface
with any specific parts of a Microsoft software, Licensed Content, or service that includes the feedback. You will not
give feedback that is subject to a license that requires Microsoft to license its software or documentation to third parties
because we include your feedback in them. These rights survive this agreement.
c. Confidential Information. The Licensed Content, including any viewer, user interface, features and documentation
that may be included with the Licensed Content, is confidential and proprietary to Microsoft and its suppliers.

i. Use. For five years after installation of the Licensed Content or its commercial release, whichever is first, you
may not disclose confidential information to third parties. You may disclose confidential information only to
your employees and consultants who need to know the information. You must have written agreements with
them that protect the confidential information at least as much as this agreement.
ii. Survival. Your duty to protect confidential information survives this agreement.
iii. Exclusions. You may disclose confidential information in response to a judicial or governmental order. You
must first give written notice to Microsoft to allow it to seek a protective order or otherwise protect the
information. Confidential information does not include information that
becomes publicly known through no wrongful act;
you received from a third party who did not breach confidentiality obligations to Microsoft or its suppliers;
or
you developed independently.
d. Term. The term of this agreement for pre-release versions is (i) the date which Microsoft informs you is the end date
for using the beta version, or (ii) the commercial release of the final release version of the Licensed Content, whichever
is first (beta term).
e. Use. You will cease using all copies of the beta version upon expiration or termination of the beta term, and will
destroy all copies of same in the possession or under your control and/or in the possession or under the control of any
Trainers who have received copies of the pre-released version.
f. Copies. Microsoft will inform Authorized Learning Centers if they may make copies of the beta version (in either print
and/or CD version) and distribute such copies to Students and/or Trainers. If Microsoft allows such distribution, you
will follow any additional terms that Microsoft provides to you for such copies and distribution.
5. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.
a. Authorized Learning Centers and Trainers:
i. Software.
ii. Virtual Hard Disks. The Licensed Content may contain versions of Microsoft XP, Microsoft Windows Vista,
Windows Server 2003, Windows Server 2008, and Windows 2000 Advanced Server and/or other Microsoft products
which are provided in Virtual Hard Disks.
A. If the Virtual Hard Disks and the labs are launched through the Microsoft Learning Lab Launcher,
then these terms apply:
Time-Sensitive Software. If the Software is not reset, it will stop running based upon the time indicated on the
install of the Virtual Machines (between 30 and 500 days after you install it). You will not receive notice before
it stops running. You may not be able to access data used or information saved with the Virtual Machines
when it stops running and may be forced to reset these Virtual Machines to their original state. You must
remove the Software from the Devices at the end of each Authorized Training Session and reinstall and launch
it prior to the beginning of the next Authorized Training Session.
B. If the Virtual Hard Disks require a product key to launch, then these terms apply:
Microsoft will deactivate the operating system associated with each Virtual Hard Disk. Before installing any
Virtual Hard Disks on classroom Devices for use during an Authorized Training Session, you will obtain from
Microsoft a product key for the operating system software for the Virtual Hard Disks and will activate such
Software with Microsoft using such product key.
C. These terms apply to all Virtual Machines and Virtual Hard Disks:
You may only use the Virtual Machines and Virtual Hard Disks if you comply with the terms and
conditions of this agreement and the following security requirements:
o You may not install Virtual Machines and Virtual Hard Disks on portable Devices or Devices that are
accessible to other networks.
o You must remove Virtual Machines and Virtual Hard Disks from all classroom Devices at the end of each
Authorized Training Session, except those held at Microsoft Certified Partners for Learning Solutions
locations.

o You must remove the differencing drive portions of the Virtual Hard Disks from all classroom Devices at
the end of each Authorized Training Session at Microsoft Certified Partners for Learning Solutions locations.
o You will ensure that the Virtual Machines and Virtual Hard Disks are not copied or downloaded from
Devices on which you installed them.
o You will strictly comply with all Microsoft instructions relating to installation, use, activation and
deactivation, and security of Virtual Machines and Virtual Hard Disks.
o You may not modify the Virtual Machines and Virtual Hard Disks or any contents thereof.
o You may not reproduce or redistribute the Virtual Machines or Virtual Hard Disks.
ii. Classroom Setup Guide. You will assure any Licensed Content installed for use during an Authorized Training
Session will be done in accordance with the classroom set-up guide for the Course.
iii. Media Elements and Templates. You may allow Trainers and Students to use images, clip art, animations,
sounds, music, shapes, video clips and templates provided with the Licensed Content solely in an Authorized
Training Session. If Trainers have their own copy of the Licensed Content, they may use Media Elements for their
personal training use.
iv. iv Evaluation Software. Any Software that is included in the Student Content designated as Evaluation
Software may be used by Students solely for their personal training outside of the Authorized Training Session.
b. Trainers Only:
i. Use of PowerPoint Slide Deck Templates. The Trainer Content may include Microsoft PowerPoint slide decks.
Trainers may use, copy and modify the PowerPoint slide decks only for providing an Authorized Training Session.
If you elect to exercise the foregoing, you will agree or ensure Trainer agrees: (a) that modification of the slide
decks will not constitute creation of obscene or scandalous works, as defined by federal law at the time the work is
created; and (b) to comply with all other terms and conditions of this agreement.
ii. Use of Instructional Components in Trainer Content. For each Authorized Training Session, Trainers may
customize and reproduce, in accordance with the MCT Agreement, those portions of the Licensed Content that are
logically associated with instruction of the Authorized Training Session. If you elect to exercise the foregoing
rights, you agree or ensure the Trainer agrees: (a) that any of these customizations or reproductions will only be
used for providing an Authorized Training Session and (b) to comply with all other terms and conditions of this
agreement.
iii. Academic Materials. If the Licensed Content contains Academic Materials, you may copy and use the Academic
Materials. You may not make any modifications to the Academic Materials and you may not print any book (either
electronic or print version) in its entirety. If you reproduce any Academic Materials, you agree that:
The use of the Academic Materials will be only for your personal reference or training use
You will not republish or post the Academic Materials on any network computer or broadcast in any media;
You will include the Academic Materials original copyright notice, or a copyright notice to Microsofts benefit in
the format provided below:
Form of Notice:
2010 Reprinted for personal reference use only with permission by Microsoft Corporation. All
rights reserved.
Microsoft, Windows, and Windows Server are either registered trademarks or trademarks of
Microsoft Corporation in the US and/or other countries. Other product and company names
mentioned herein may be the trademarks of their respective owners.
6. INTERNET-BASED SERVICES. Microsoft may provide Internet-based services with the Licensed Content. It may change
or cancel them at any time. You may not use these services in any way that could harm them or impair anyone elses use
of them. You may not use the services to try to gain unauthorized access to any service, data, account or network by any
means.
7. SCOPE OF LICENSE. The Licensed Content is licensed, not sold. This agreement only gives you some rights to use the
Licensed Content. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation,
you may use the Licensed Content only as expressly permitted in this agreement. In doing so, you must comply with any
technical limitations in the Licensed Content that only allow you to use it in certain ways. You may not

install more copies of the Licensed Content on classroom Devices than the number of Students and the Trainer in the
Authorized Training Session;
allow more classroom Devices to access the server than the number of Students enrolled in and the Trainer delivering
the Authorized Training Session if the Licensed Content is installed on a network server;
copy or reproduce the Licensed Content to any server or location for further reproduction or distribution;
disclose the results of any benchmark tests of the Licensed Content to any third party without Microsofts prior written
approval;
work around any technical limitations in the Licensed Content;
reverse engineer, decompile or disassemble the Licensed Content, except and only to the extent that applicable law
expressly permits, despite this limitation;
make more copies of the Licensed Content than specified in this agreement or allowed by applicable law, despite this
limitation;
publish the Licensed Content for others to copy;
transfer the Licensed Content, in whole or in part, to a third party;
access or use any Licensed Content for which you (i) are not providing a Course and/or (ii) have not been authorized
by Microsoft to access and use;
rent, lease or lend the Licensed Content; or
use the Licensed Content for commercial hosting services or general business purposes.
Rights to access the server software that may be included with the Licensed Content, including the Virtual Hard Disks
does not give you any right to implement Microsoft patents or other Microsoft intellectual property in software or
devices that may access the server.
8. EXPORT RESTRICTIONS. The Licensed Content is subject to United States export laws and regulations. You must
comply with all domestic and international export laws and regulations that apply to the Licensed Content. These laws
include restrictions on destinations, end users and end use. For additional information, see
www.microsoft.com/exporting.
9. NOT FOR RESALE SOFTWARE/LICENSED CONTENT. You may not sell software or Licensed Content marked as NFR
or Not for Resale.
10. ACADEMIC EDITION. You must be a Qualified Educational User to use Licensed Content marked as Academic Edition
or AE. If you do not know whether you are a Qualified Educational User, visit www.microsoft.com/education or contact
the Microsoft affiliate serving your country.
11. TERMINATION. Without prejudice to any other rights, Microsoft may terminate this agreement if you fail to comply with
the terms and conditions of these license terms. In the event your status as an Authorized Learning Center or Trainer a)
expires, b) is voluntarily terminated by you, and/or c) is terminated by Microsoft, this agreement shall automatically
terminate. Upon any termination of this agreement, you must destroy all copies of the Licensed Content and all of its
component parts.
12. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and
support services that you use, are the entire agreement for the Licensed Content and support services.
13. APPLICABLE LAW.
a. United States. If you acquired the Licensed Content in the United States, Washington state law governs the
interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws
of the state where you live govern all other claims, including claims under state consumer protection laws, unfair
competition laws, and in tort.
b. Outside the United States. If you acquired the Licensed Content in any other country, the laws of that country
apply.
14. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country.
You may also have rights with respect to the party from whom you acquired the Licensed Content. This agreement does
not change your rights under the laws of your country if the laws of your country do not permit it to do so.

15. DISCLAIMER OF WARRANTY. The Licensed Content is licensed as-is. You bear the risk of using it.
Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights
under your local laws which this agreement cannot change. To the extent permitted under your local laws,
Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-
infringement.
16. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND
ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES,
INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
This limitation applies to
anything related to the Licensed Content, software, services, content (including code) on third party Internet sites, or
third party programs; and
claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the
extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or
exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential
or other damages.
Please note: As this Licensed Content is distributed in Quebec, Canada, some of the clauses in this agreement
are provided below in French.
Remarque : Ce le contenu sous licence tant distribu au Qubec, Canada, certaines des clauses dans ce contrat
sont fournies ci-dessous en franais.
EXONRATION DE GARANTIE. Le contenu sous licence vis par une licence est offert tel quel . Toute utilisation de ce
contenu sous licence est votre seule risque et pril. Microsoft naccorde aucune autre garantie expresse. Vous pouvez
bnficier de droits additionnels en vertu du droit local sur la protection dues consommateurs, que ce contrat ne peut modifier.
La ou elles sont permises par le droit locale, les garanties implicites de qualit marchande, dadquation un usage particulier
et dabsence de contrefaon sont exclues.
LIMITATION DES DOMMAGES-INTRTS ET EXCLUSION DE RESPONSABILIT POUR LES DOMMAGES. Vous
pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement hauteur de
5,00 $ US. Vous ne pouvez prtendre aucune indemnisation pour les autres dommages, y compris les dommages spciaux,
indirects ou accessoires et pertes de bnfices.
Cette limitation concerne:
tout ce qui est reli au le contenu sous licence , aux services ou au contenu (y compris le code) figurant sur des sites
Internet tiers ou dans des programmes tiers ; et
les rclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit stricte, de ngligence ou
dune autre faute dans la limite autorise par la loi en vigueur.
Elle sapplique galement, mme si Microsoft connaissait ou devrait connatre lventualit dun tel dommage. Si votre pays
nautorise pas lexclusion ou la limitation de responsabilit pour les dommages indirects, accessoires ou de quelque nature que
ce soit, il se peut que la limitation ou lexclusion ci-dessus ne sappliquera pas votre gard.
EFFET JURIDIQUE. Le prsent contrat dcrit certains droits juridiques. Vous pourriez avoir dautres droits prvus par les lois
de votre pays. Le prsent contrat ne modifie pas les droits que vous confrent les lois de votre pays si celles-ci ne le
permettent pas.
Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010 ix

x Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Acknowledgements
Microsoft Learning would like to acknowledge and thank the following for their contribution towards
developing this title. Their effort at various stages in the development has ensured that you have a good
classroom experience.
Ishai Ram Lead Content Developer
Ishai is the VP Training of SELA Group, responsible for all training-related activities. He has over 18 years
of experience as a professional trainer and consultant on computer software and electronics.
Sasha Goldshtein Content Developer and Subject Matter Expert
Sasha is a Senior Consultant for SELA Group, a Microsoft Visual C# MVP, and the co-author of
Introducing Windows 7 for Developers (Microsoft Press, 2009). He is the author of multiple SELA
courses, speaks at Microsoft conferences, and leads SELAs Performance and Debugging team.
Manu Cohen-Yashar Subject Matter Expert
Manu is a Senior Consultant and Instructor for SELA Group, a Microsoft MCT, and a member of the
Microsoft Metro team. He is an international expert on distributed systems and application security, a
distinguished trainer and courseware author.
Ido Flatow Subject Matter Expert
Ido is a Senior Consultant and Instructor for SELA Group. With over 12 years of experience in developing,
designing and managing information systems, he is one of SELA's most senior consultants on WCF, Entity
Framework, and Web technologies.
Peter Madziak Technical Reviewer
Peter is a SOA (Service-Oriented Architecture) & BPM (Business Process Management) expert for
ObjectSharp. He helps customers implement solutions using technologies such as: Windows
Communication Foundation (WCF), BizTalk Server, Windows Workflow (WF), SQL Service Broker, and
ASP.NET Web Applications.
Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010 xi
Contents
Module 7: Security
Lesson 1: Introduction to Application Security 7-3
Lesson 2: The WCF Security Model 7-10
Lesson 3: Transport and Message Security 7-15
Lesson 4: Authentication and Authorization 7-31
Lesson 5: Claim-Based Identity 7-40
Lab: Implementing WCF Security 7-52
Module 8: Introduction to Advanced Microsoft Windows Communication
Foundation Topics
Lesson 1: The Asynchronous Invocation Pattern 8-3
Lesson 2: Extending WCF 8-11
Lesson 3: Routing 8-46
Lesson 4: Workflow Services 8-62
Lab: Advanced Topics 8-78
Lab Answer Keys

xii Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

Security 7-1
Module 7
Security
Contents:
Lesson 1: Introduction to Application Security 7-3
Lesson 2: The WCF Security Model 7-10
Lesson 3: Transport and Message Security 7-15
Lesson 4: Authentication and Authorization 7-31
Lesson 5: Claim-Based Identity 7-40
Lab: Implementing WCF Security 7-52
7-2 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Module Overview

Security is an essential part of developing services. To protect your data and to maintain its integrity, you
need to apply various security measures. These measures might relate to subjects such as identifying your
users, securing your transport layer, or auditing operations.
Microsoft Windows Communication Foundation (WCF) supports several techniques that you can use to
enhance the security of your service, such as encryption of messages, and validation of client identities
using various identification techniquesfor example, validating a Windows identity). WCF also allows
you to extend some of the techniques to add your own custom implementation.
In this module, you will learn about the various security aspects that you need to apply to your services,
and how WCF can help you use implement some of these aspects.
Security 7-3
Lesson 1
Introduction to Application Security

Securing your application is one of the main factors that improve your application's reliability. If you do
not control who is accessing your application and what operations they can perform with your data, you
risk having your data changed or stolen, and potentially losing the entire reliability of your application.
Implementing security measures in your application does not mean using only client authentication; it
also means including security measures such as data validation and encryption, client authorization, and
auditing out-of-the-ordinary activities.
In this lesson, you will learn about the various aspects of application security, and become familiar with
some security concepts.
Lesson Objectives
After completing this lesson, you will be able to:
Describe the purpose of application security.
Apply security measurements to you application design.
Describe the concepts of identity and credentials, as they pertain to security.
7-4 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Security Requires a Holistic View

Key Points
The security domain is not only about application security. Securing your application is only one part of
creating a secured environment for your systems.
You can view the security field as a hierarchy, where the human factor is at the top, the infrastructure of
your enterprise is at the bottom, and the application is in the middle.
People are the main interface to any system. Your application can be protected behind numerous firewalls
from every possible breach, but eventually a user needs to use the system. If the user enters the wrong
dataintentionally or by an honest mistakeyou system's reliability will be in danger. No magic solution
exists to prevent human factor mistakes and misdoings. You can strive towards security by controlling the
information flow inside your organization, and by applying audit and control measurements to ensure
that even if such an error occurs, it is quickly diagnosed and fixed.
The infrastructure is a more controllable layer. With the use of firewalls, operating system hardening,
Digital Rights Management (DRM), and other technologies, you can limit and control access to your
resources. Unfortunately, infrastructure has its limits. Infrastructure cannot always comprehend what the
application is doing, and it cannot always distinguish between good and malicious data. Therefore, you
cannot rely only on your infrastructure to filter-out malicious requests.
Finally, the application layer usually has more knowledge of the organization's business. Therefore, it is
often the most appropriate layer in which to place security checks that verify the user's intentions, validate
data, and perform other actions to stop users from doing anything they are not supposed to do. You can
never secure your application completely, but with a good security design, you can dramatically reduce
the number of possible attacks and breaches.
Remember that to implement application security, you must ensure that the other domainshuman and
infrastructureare also secured.
Security 7-5
Understanding Application Security Tenets

Key Points
When you design the security solution that you will implement in your service, you will need to review
several aspects of security:
Input Validation. You must validate all of your service's inputs before you use them. Because clients
can sometimes be impersonated, and malicious users might even use a fake client application, you
should not be satisfied with validation performed on the client side. Always make sure to execute
each client-side validation is again on the service side. With that said, you should still validate the
input on the client side, to provide the user with a better user experience (text boxes with invalid data
might be colored in red), to quickly receive feedback when entering invalid data, and to lower the
number of times a service is called with invalid data.
Authentication. You need to make sure that you know who your client is. Using authentication
techniques for client identification is a common way to secure the service's boundary, and to prevent
unknown users from reaching your service.
Authorization. Knowing your client is important, but you also must make sure your client can perform
the action that they requested. Often, different users will have access to certain services and
operations, but not to others. Sometimes even the value of a parameter that is sent to an operation is
valid if sent by a certain client, but not valid when sent by another client. For example, a bank loan
operation can receive values up to $1,000 if requested by a clerk, and up to $100,000 if requested by
a manager.
Cryptography. To protect the content of your data, you will need to encrypt it and make sure no
attacker will be able to get to it or change it. You can protect your data from being changed by
digitally signing it, and encrypt it using symmetric or asymmetrical cryptography.

Note: Do not be tempted to build your own proprietary cryptographic technology. There are
many well-known industry standards, which are already tested and proven in the field.
7-6 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Sensitive Data. You will need to identify which data is sensitive, such as: contact information, credit
card numbers, salaries, and confidential phone numbers. Sensitive information must be handled with
care. You will need to restrict access to it, encrypt it when persisted, and use a secured channel to
transmit it. Most of the previously mentioned aspects (validation, authentication, and cryptography)
serve the purpose of handling sensitive data.
Session Management. If you plan to use sessions to allow your client to perform several related
operations, and you plan to save state information for that session, then you will need to ensure both
your data and your session are secured. A common attack type is client spoofing, where an external
attacker assumes the role of your client and sends requests on its behalf. You will need to ensure that
your session cannot be compromised to prevent such attacks.
Configuration Management. Your application's configuration might contain sensitive datasuch as
server names, database passwords, default values for operationsand other data that you would not
want anyone to obtain. You will need to protect your configuration by applying authorization and
encryption.
Data Manipulation. When a client calls your service, and when your service responds, the message is
sent over the network, where every resourceful malicious user can see and manipulate it. To protect
yourself from these types of threats, you will need to find a way to prevent changes to the data, or at
least be able to detect if changes were made to the data while in transit. Encrypting or digitally
signing the data can help prevent this threat.
Exception Management. When your service throws an exception, it might contain information you do
not want to reveal to the outside world, such as server or database table names. Revealing these
details can help potential attackers gather information on how your application works, and on the
resources it uses. You need to make sure that exceptions (faults) returned by your service contain a
minimal amount of detailonly the detail required for the client to understand what has happened
without revealing the service's inner workings.

Note: For more information about handling exceptions in services, see Module 6, "Testing and
Troubleshooting Microsoft Windows Communication Foundation Services".
Auditing and Logging. Preventing an attack is important, but so is knowing that you were attacked.
You need to audit any failed attempts for using the service, security violations, or any abnormal
situation your service encounters. Auditing will help you determine the identity of the attacker.
You will need to apply these security aspects to your WCF services. Some of these aspects can be handled
by the Microsoft .NET Frameworksuch as configuration encryption and cryptography. Otherssuch as
authentication, authorization, and exception handlingcan be handled using WCF's security mechanisms.
Security 7-7
Introduction to Identities, Authorization, and Authentication

Key Points
Every entity in the organization has an identity. An entity can be a person, an application, a computer, or a
piece of hardware. Each of these entities has an identity that carries with it some information: the entity's
name, the department to which it belongs, its IP address, or any other information that can help you learn
more about that entity. When securing services, a major concern is identifying the people that use your
services.
Some entities only carry one identity, but others, like people, might have multiple identities associated
with different aspects of their work and interaction with applications. For example, network administrators
might have an identity that allows them to use the attendance system to report their work hours, but they
also have additional identities that grants them administrative access to the servers on the network.
Different aspects of work sometimes mean different identities, and people might use their differing
identities depending on the occasion.
Using an identity to confirm identity claims is referred to as authentication. If your service needs to know
who a person is, it will require that person to authenticate himself or herself, and then send their identity
information to the service.
After authentication takes place, the next step is to verify the permissions granted to the identityto
check what this entity can and cannot do. The process of checking permissions is called authorization.

Note: You will learn more about the different ways to authenticate a user in Lesson 3, "Transport and
Message Security", and in Lesson 5, "Claim-Based Identity".
7-8 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Credentials in Different Environments

Key Points
To prove an identity, an authentication process must take place. When you authenticate yourself, you use
some sort of a credential that identifies you. A credential is a set of claims that states who you arefor
example, your user nameand some proof of possession that identifies you as the rightful owner of the
identityfor example, your password. An application can use the credentials to identify you, and decide if
you have proven your identity or not.
There are various types of credential types in applications, just like there are many credentials a person
has in real life. For example, a person can be identified by showing a driver's license, a social security card,
a badge, or even a library card, if the information on the credential is sufficient for the identification.
Credentials on the Internet
You usually identify yourself on the internet using a user name and a password. Although passwords can
be guessed and stolen, this technique is common because of its simplicity, and because sometimes it is
the best that a website can offer to its users.
However, there are better security mechanisms that you can use on the internet, such as a Security Token
Service (STS). An STS is a service that allows you to get a strong claim-based token, and then use it to
prove your identity to different sites. Windows CardSpace is an identity selectoran application that
allows users to manage security tokens from their different STSsthat is capable of calling an STS to
retrieve such a token.

Note: You will learn more STS and Windows CardSpace in Lesson 5, "Claim-Based Identity".
Credentials on the Intranet
In contrast to the Internet, when working in the intranet inside a domain, you can authenticate yourself
using the domain controller that handles all the user names and passwords on the network, such as Active
Security 7-9
Directory Domain Services (AD DS). For example, using the domain's AD DS, you can send your identity
as a Kerberos security token. A service can verify the token with the AD DS to see if the identity is valid.
Another type of identification in the intranet is a smart card that contains digitally signed information
about the user. A smart card identifies the person that holds that card.
Credentials in the Business-to-Business Environment
When your application is identifying itself to another business, the two systems usually do not share the
same domain, and therefore cannot use a domain controller for identification. In business-to-business
(B2B) cases, identification is usually performed in one of two ways:
1. Using a federated security model. In a federated security model, both systems agree on a third-party
identity provider that provides security tokens and an authentication mechanism. Using federated
security allows systems to identify each other's users with the use of an STS (the same STS mentioned
for Internet users).
2. Using an X.509 certificate. An X.509 certificate is a certificate that is issued by a Certificate Authority
(CA) that everyone trusts. With a digitally signed X.509 certificate, you can identify yourself to another
system, and that system will only need to inspect the certificate to see if it is authentic, without
needing to call an external identity service. (Windows operating systems have copies of root CA
certificates that it uses to validate certificates issued by those CAs.)

Note: You might encounter B2B applications that identify each other by a username and a password. This
is not recommended, because passwords can be stolen and even guessed sometimes, thereby putting
your applications at risk. STS security tokens and X.509 certificates are much harder to forge or steal,
because they have several mechanisms that prevent them from being copied. For example, an X.509
certificate can only be used from the domain that is specified in the certificate, and the domain in the
certificate is digitally signed, and cannot be changed.

7-10 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lesson 2
The WCF Security Model

WCF uses a rich and powerful security model to support all kinds of authentication and authorization
techniques. In this lesson, you will learn about the WCF security model, and how you can configure it
appropriately for different scenarios.
Lesson Objectives
After completing this lesson, you will be able to:
Describe the WCF security model structure.
Choose the appropriate security scenario for your services.
Support different client credential types in your services.
Security 7-11
Introduction to the WCF Security Model

Key Points
The WCF security infrastructure handles identity token management for authentication and authorization
purposes, as well as message signing and encryption.
WCF security activation is consistent through bindings. You define a certain security policy by specifying a
security mode or a specific security binding element that corresponds to a security channel.
The security channel is where the security policy is enforced. Only if the security policy is satisfied will the
message move along the message pipeline.
WCF supports various kinds of security binding elements and security channels for secure conversation
patterns and WS-* standards.
You will encounter the commonly used security mechanisms in the following scenarios:
1. Internet. In cases where your services are publicly exposed and consumed by clients over the Internet,
you may want to consider using SSL with a UserName token for the user name and password
validation.
2. Intranet. In cases where your services are exposed inside the enterprise and consumed by clients on
the intranet, you may want to consider using Windows credentials with Kerberos or Microsoft
Windows NT LAN Manager (NTLM).
3. B2B. In cases where your services should be consumed by other business parties outside the
enterprise, you may want to consider a Public Key Infrastructure (PKI) approach that uses certificates.
4. WS-Federation. In cases where your services may be consumed by clients from different sources, you
may want to consider a federated security approach by issuing tokens for different clients, from a
centralized issuer that your services can trustsuch as an STS.
You can define different security patterns, code, and configuration.
The following example shows how you can configure a service endpoint with transport security using
HTTP/Secure (HTTPS) that will accept Windows tokens as client credentials:
7-12 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
<system.serviceModel>
<services>
<service name="CalcService.WCFCalc">
<endpoint
address="https://localhost:8080/Calc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpWithTransportSecurity"
contract="CalcService.ICalc" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpWithTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
You can also configure the binding in code:
[Visual C#]
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Windows;

[Visual Basic]
Dim binding As New BasicHttpBinding()
binding.Security.Mode = BasicHttpSecurityMode.Transport
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Windows
Security 7-13
Features of the WCF Security Model

Key Points
Message encryption is essential for ensuring privacy. Encryption renders the message content unreadable
for other parties. On the other hand, message signing is essential for ensuring integrity. Signing the entire
message means that other parties cannot tamper with its content.
WCF supports WS-Security, which is a standard policy implementation for message signing and
encryption. This makes WCF security implementation interoperable with other technologies that support
this standard.
When using WS-Security to create a secured channel, several security-related messages are exchanged
between the client and service. If the security requirements are satisfied, then the operation invocation
message transmits to the service after being encrypted and signed using the keys negotiated by both
parties. You can observe the security message exchange using WCF message logging.
WCF supports several client credential types, such as Windows, NTLM, UserName (plain text username
and password), and certificates.
You configure the client credentials and the security policy in the endpoint's binding. The certificates'
location, service credentials, and authorization providers are configured using service behaviors.
The following example shows how you can configure the service with a behavior that uses the Microsoft
ASP.NET Membership Provider to authenticate the client, and an endpoint with the WS-HTTP binding that
accepts a UserName token as the client credential type:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MembershipAuthorizationBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider" />
</serviceCredentials>
7-14 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="CalcService.WCFCalc"
behaviorConfiguration="MembershipAuthorizationBehavior">
<endpoint
address=""
binding="wsHttpBinding"
bindingConfiguration="MembershipBinding"
contract="CalcService.ICalc" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MembershipBinding">
<security mode ="Message">
<message clientCredentialType ="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>

Note: The previous example is a configuration file for a service that is hosted in Internet Information
Services (IIS). Therefore, it does not have an explicit address in the configuration file. For more information
about IIS hosting and configuration, see Module 3, "Hosting Microsoft Windows Communication
Foundation Services".

Security 7-15
Lesson 3
Transport and Message Security

One of the fundamentals of securing a service is the ability to create a secure channel that will convey the
message from a client to the service, and vice versa, without letting network sniffers read and understand
the content of the message. With WCF, you can create secure channels in many ways.
In this lesson, you will learn about the various secure channels WCF offers, and you will learn how you can
configure your WCF service to use a secure channel.
Lesson Objectives
After completing this lesson, you will be able to:
Describe the difference between transport and message security.
Use transport security to secure your endpoint.
Use message security to secure your endpoint.
Use a transport with a message credential security channel to secure your endpoint.
7-16 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Transport Security

Key Points
One security aspect that you need to prevent is stealing and changing sensitive data that is sent to and
from your service. One way to build an encrypted channel is to use an encrypting transport protocol. If
you use the HTTP transport, you can encrypt your channel by using the Secure Sockets Layer (SSL)
transport security mechanism, which creates a secured, encrypted transport (HTTPS) that you can use in
your WCF service endpoint.
Using SSL, you can encrypt each message that is sent to and from the service within the specific client
connection. (An SSL connection needs to be opened for each client.) SSL allows you to use a lower level of
security implementation, so you do not have to build your own security mechanism.
If you use a Transmission Control Protocol (TCP) transport, you can also use a secured transportSSL over
TCPwhich uses the Transport Layer Security (TLS) mechanism. (TLS is a security protocol that evolved
from SSL.)
Benefits and Challenges of Transport Security
Using transport security is simple, because you do not have to write special code to implement message
encryption and decryption. The main advantage of transport security is that you gain throughput and
performance, because most transport security handling is done in the operating system. Today, you can
even use hardware accelerators that perform SSL encryption in hardware, which allows faster encryption
than by using an operating system.
Unfortunately, transport security also has a few disadvantages:
1. Point to point. Transport security implements a secured channel between two points (two machines).
When a more complex topology is required, a secure channel might not be possible. For example,
consider the following topology: Service A calls Service B through a proxy. Service B sends the
response directly to Service A: If Service A does not trust the proxy, a secure channel cannot be
established through the proxy.
Security 7-17
2. Exposed data. Because transport security uses point-to-point security, when the message reaches the
server, it is decrypted. In the previous example, Service A calls Service B through the proxy, so in fact
there are two secured channels: between Service A and the proxy, and between the proxy and Service
B. When the encrypted messages reach the proxy, they are decrypted and then re-encrypted before
they are delivered to Service B. If an attacker gains access to the proxy, he will be able to retrieve the
decrypted data.

Note: When you use an HTTPS snifferA tool that shows all the traffic sent over the HTTP/S transports by
creating a proxy between the client and the serviceyou are actually making all your requests pass
through the sniffer's proxy. The messages are captured and logged, and then resent over a new secure
channel to their real target, as shown in the previous example. This is not considered a security violation,
because the sniffer has its own certificate that your client can see and approve before creating the secure
channel.
3. Limited types of client credentials. When you use a secure transport, the service identifies itself to the
client to prevent phishinga malicious service posing as another service. In addition, you can
configure the channel to require the client to authenticate. The client authenticates using the HTTP-
Authenticate header, which supports most of the authentication credentialssuch as Windows and
X.509but does not support custom authentication credentials.

7-18 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
How Secure Sockets Layer Works

Key Points
SSL helps protect your transport by encrypting every request message that is sent by the client, and every
response message sent by the server (service).
Before starting to exchange encrypted messages, the client and the server agree on the encryption
method that will be used, and which encryption key to use.
To start a secured session, the client sends a special request to the server, asking it to start a secured
session (step 1 in the diagram). In return, the server responds by sending its X.509 certificate, which it was
issued by a CA (step 2 in the diagram).
The client receives the certificate, and uses it to validate the server (step 3 in the diagram). X.509
certificates hold information about the server's address, which the client can check to verify that the server
is authentic and not an impersonator. In addition, the certificate also holds information about the issuer of
the certificate, which the client can use to verify that the certificate was issued by a trusted CA, and is not
a fake.
After validating the certificate, the client generates a random symmetric encryption key, places it in a
message, encrypts the message using the server's public key that was supplied with the server's certificate,
and sends it to the server (step 4 in the diagram). Public key encryption can only be decrypted by using
the server's private key, which only the server has. After the server decrypts the message (step 5 in the
diagram), both sides have the symmetric key. They can now start exchanging encrypted messages using
the symmetric key to encrypt the message on one side and decrypt it on the receiving side (step 6 in the
diagram).
SSL uses symmetric encryption for message exchange instead of public key encryption, because public key
encryption is slower than symmetric encryption, and the created message is larger than when created with
a symmetric key encryption.
Security 7-19
Configuring Transport Security

Key Points
Because a service can have many endpoints with different transport types (HTTP, TCP), the transport
security settings are applied at the endpoint level.
Not all bindings use transport security by default. For example, the Basic HTTP binding and the WS-HTTP
binding do not use transport security by default, but the NetTCP binding does.
To set up an endpoint for transport security, you will need to change its binding configuration. The
following example demonstrates changing the security mode of a Basic HTTP binding.
<endpoint
address="https://localhost/MyCalc.svc"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurityBinding"
contract="Samples.ICalculator" />

<binding name="TransportSecurityBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
To change the security settings of a binding, you need to add the security element under the binding's
configuration. To change the security mode, you set the mode attribute to Transportother values will
be discussed later in this module.

Note: Because transport security over HTTP uses SSL (HTTPS), you will need to ensure the address of your
endpoint starts with https://, and not with http://.
7-20 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

Note: The Basic HTTP, WS-HTTP, NetTCP, and NetNamedPipe bindings support transport security. WS-
DualHTTP and NetMSMQ bindings do not support transport security.
In addition to setting the transport security, you can also set the credential types that the client needs to
transfer. In the previous example, the client credentials are set to None, meaning the client does not need
to transfer any credentials. The different client credentials types are described in the following table.
Authentication scheme Description
None This is anonymous authentication. Everyone can access the service.
Basic The client is required to send their user name and password in a Base64-
encoded string. The string is not encrypted, and therefore sending user names
and passwords this way is the same as sending them in clear text. If you use
this scheme, you will also need to set the realm attribute to the name of the
domain against which you are authenticating.
Digest The client is required to send an encrypted user name and password. This
setting requires a domain account, and the service needs to trust that domain.
When the service receives the user name and password, it sends them to the
domain controller for validation. If you use this scheme, you will also need to
set the realm attribute to the name of the domain against which you are
authenticating.
NTLM With NTLM (also called Integrated Windows Authentication,) the client does
not send its password, but rather uses the password to encrypt the user name.
The service sends the response to the domain controller, which validates the
response and returns the users security information. NTLM was used in
Windows NT and Microsoft Windows 2000, and is rarely used today.
Windows With Windows authentication, the client uses the Kerberos security token that
it obtains from a Ticket-Granting Service (TGS). The token is sent to the service,
which in turn sends it to the TGS for validation. This technique has been used
since Windows Server 2003 to authenticate users, and is commonly used on
Microsoft networks.
Certificate The client is required to send an X.509 certificate that the service can validate.
The certificate must be issued by a trusted CA.
Configuring the Service for SSL and TLS
In order to use transport security using either SSL over HTTP or TLS, you will need to configure your
service to use a specific certificate that will be sent to clients requesting access to the service.
If you host your service under IIS or Windows process Activation Service (WAS), IIS will register the
certificate. (You will need to configure IIS to do this see the Additional Reading section for more details.)
If your service is self-hosted within a Windows application or a Windows Service, you will need to specify
the certificate that you wish to use. For the HTTP transport with SSL you can use the utilities HttpCfg.exe
(with Windows Server 2003 and earlier versions), or the netsh (with Windows Vista and later versions) to
attach an SSL certificate to a specific port. The following command shows how to attach a certificate to
port 8000 using the netsh tool. (Line breaks should be replaced with spaces.)
netsh http add sslcert ipport=0.0.0.0:8000
certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6
appid={00112233-4455-6677-8899-AABBCCDDEEFF}
Security 7-21

The certhash value is the thumbprint of your certificate, which you can find by looking at the certificate's
information. The appid value is the globally unique identifier (GUID) of your service host assembly, which
you can find in the AssemblyInfo.cs file.
If your self-hosted service uses a secure TCP transport, you cannot use the utilities mentioned above. You
will need to set the service's certificate in code or in configuration. The following XML fragment shows
how to set the service's certificate in the configuration file.
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<serviceCertificate
storeLocation="LocalMachine"
storeName="My"
findValue="0000000000003ed9cd0c315bbb6dc1c08da5e6"
x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
The same configuration can be applied in code:
[Visual C#]
ServiceHost host = new ServiceHost(typeof(WCFCalc));
host.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"0000000000003ed9cd0c315bbb6dc1c08da5e6");
host.Open();

[Visual Basic]
Dim host As New ServiceHost(GetType(WCFCalc))
host.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"0000000000003ed9cd0c315bbb6dc1c08da5e6")
host.Open()
Question: Why does WS-DualHTTP binding not support transport security?

7-22 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Message Security

Key Points
If you want to use a secure channel but transport security will not workthe message needs to be
encrypted so it cannot be deciphered even if it passes through a proxyyou can use the WCF security
mechanism that allows end-to-end encryption of messages. The WCF Message Security uses the WS-*
security standards such as WS-Security, WS-Trust, and WS-SecureConversation, to create a secure channel
where all messages are encrypted.
Benefits and Challenges of Message Security
WCF's message security provides an end-to-end secure channel, meaning the message is encrypted on
the client side, and decrypted only when it reaches the service. If other servers (such as proxies) receive
the message, they will not be able to decrypt it. This means that you can use message security when you
need to create a secure channel in a complicated topology where transport security is not an acceptable
solution.
WCF message security is extensibleunlike transport security. With message security, you can add custom
security tokens and protocols, and support custom authentication mechanisms.
Although it seems that message security is the best choice, you should be aware that there are some
disadvantages to this solution:
1. Since message security is implemented in WCF (in software) and not in the operating system or in
hardware, it has a higher performance cost than transport security.
2. The security negotiation that is required to create the secure channel involves sending large messages
on the channel, so there might be a noticeable delay when opening such a channel.
3. Secured messages are larger than normal messages, which might result in longer transmission time.

Note: Although the above list refers to messages sent from a client to a service, it also applies to
messages sent from the service to the client.
Security 7-23
Question: How is message security different from transport security?
7-24 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Configuring Message Security on the Server Side

Key Points
To configure an endpoint to use message security, you will need to change the binding configuration of
the endpoint, as demonstrated in the following XML fragment.
<wsHttpBinding>
<binding name="CertMessageSecBinding" >
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security
</binding>
<wsHttpBinding>
In the previous example, the security mode was set to Message, and the client's credential type was set to
Certificate. The authentication types in message security are different from the ones for transport
security. The following table lists the possible authentication schemes.
Authentication
scheme Description
None Anonymous authentication. Everyone can access the service.
Windows Uses the client's Windows credentials to secure the SOAP message.
UserName Requires the client to transfer a user name and password. WCF requires that the
user name and password are transferred in plain text. When using this scheme,
WCF automatically uses transport security.
Certificate Requires the client to send an X.509 certificate that the service can validate.
IssuedToken Requires the client to transfer a custom security token, such as a Security
Assertion Markup Language (SAML) token.
Security 7-25
When you use message security, you need to specify the certificate that the service will use for
authentication. (You cannot use IIS or netsh to register certificates for message security.) To do this, you
need to add the service credentials behavior to your service. The following XML fragment shows how to
set the certificate for your service.
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceCredentials>
<serviceCertificate
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"
findValue="localhost"/>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
To point to a specific certificate, you will need to specify where the certificate is stored, and how to find.
The following table describes the attributes that you need to use to find the certificate:
Attribute Description
storeLocation LocalMachine or CurrentUser. The default value is LocalMachine. You should not
typically set this attribute to CurrentUser, because service certificates are stored at
the machine level, and not for a specific user.
storeName The certificate store to open. Possible values are:
AddressBook. Contains certificates for other users.
AuthRoot. Contains certificates of third-party CAs.
CertificateAuthority. Contains certificates of intermediary CAs.
Disallowed. Contains revoked certificates.
My. Contains personal certificates (default value).
Root. Contains certificates of trusted root CA.
TrustedPeople. Contains certificates of specifically trusted people.
TrustedPublisher. Contains certificates of specifically trusted publishers.
X509FindType Specify which field of the certificate will be searched for the matching value. The
value specified in the findValue attribute must be an exact match to the value in the
field. The possible fields are:
FindByThumbprint
FindBySubjectName
FindBySubjectDistinguishedName (default value)
FindByIssuerName
FindByIssuerDistinguishedName
FindBySerialNumber
FindByTimeValid
FindByTimeNotYetValid
FindByTemplateName
FindByApplicationPolicy
FindByCertificatePolicy
7-26 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Attribute Description
FindByExtension
FindByKeyUsage
FindBySubjectKeyIdentifier
findValue The string value to match.
Because the credentials type for the client was set to Certificate, you need to make sure the service will
be able to validate the client's certificate. By default, a service will validate the certificate if the server can
find the issuer in a trust chain that leads to a root CA. If you know that your client's certificate is not issued
by a trusted CAfor example, if you are working in a development environment where your client's
certificates are self-issuedthen you can change the way your service validates certificates. In the above
example, the certificateValidationMode attribute was set to PeerOrChainTrust. The various types of
validation modes are described in the following table.
Value Description
None The certificate is not validated. Every certificate is acceptable. This setting is not
recommended.
PeerTrust The client's certificate must exist in the trusted people store.
ChainTrust The chain from the certificate's issuer must lead to a root CA.
PeerOrChainTrust Either the certificate is located in the trusted people store, or its issuer is part of a root
CA trust chain.
Custom Allows you to plug-in a custom X509CertificateValidator class.

Note: You can place the service credential configuration in configuration or in code. However, because
certificates are renewed over time and their information might change, it is a best practice to set
credential information in configuration, and not in code.
Security 7-27
Configuring Message Security on the Client Side

Key Points
When your service exposes an endpoint that uses message security with client certificates, and you use the
Add Service Reference tool in Microsoft Visual Studio, the generated client configuration will contain
the appropriate message security settings.

Note: If the service certificate was exposed in the Web Services Description Language (WSDL), the
endpoint settings will also contain the information about the service's certificate, and it can be compared
against the certificate sent by the service upon opening a channel. The following XML fragment shows a
client endpoint configuration that contains the service certificate informationthe encoded value was
shortened for brevity.
<client>
<endpoint
address="http://localhost:8080/CalcService/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalcContract"
contract="CalcService.ICalcContract"
name="WSHttpBinding_ICalcContract">
<identity>
<certificate
encodedValue=
"AwAAAAEAAAAUAAAA7YeDPqrps9YUN/5iBzGpI2fKYRwgAAAAAQAAANQBAAAwggHQMIIBeqADAgECAhDvO+Au9Wg
/tEfoLK0smo6XMA0GCSqGSIb3DQEBBAUAMBYxFDASBgNVBAMTC1Jvb3QgQWdlbmN5MB0yhqS9Jtcz/HQjdGg855s
HbIy1cMLQVo6BdAiqfjEHpbyzLIFAdRvad6l9gHufN2jQ0=" />
</identity>
</endpoint>
</client>

The generated configuration, however, will not include information about which certificate the client
needs to useit is up to you to provide this information.
7-28 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
To supply the client's certificate, you can use either code or configuration. The following example
demonstrates how to use code to find the certificate in the certificate store, and open a secure channel to
the service.
[Visual C#]
CalcClient proxy = new CalcClient();

proxy.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindBySubjectName,
"client.fabrikam.com");

proxy.Add(5,3);

[Visual Basic]
Dim proxy As New CalcClient()

proxy.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindBySubjectName,
"client.fabrikam.com")

proxy.Add(5, 3)
The following example shows how to specify the same certificate in the client's configuration file.
<behaviors>
<endpointBehaviors>
<behavior name="clientCertificate">
<clientCredentials>
<clientCertificate
findValue="client.fabrikam.com"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>

Note: If you specify the client certificate in a configuration file, you will need to apply the endpoint's
behavior to your endpoint configuration by setting the endpoint's behaviorConfiguration attribute to
the name of the endpoint behavior.
By default, the service certificate is validated on the client side according to the ChainTrust validation
mode. There are some occasions when the ChainTrust mode is not suitablefor example, when working
in a development environment where you use self-signed certificates that are not issued by a certified CA.
In such cases, you will need to change the way your service certificate is validated on the client side. To do
so, change the validation mode of the service's certificate in code or in the configuration. The following
two samples show how to change it in both locationsyou can use either of these options.
In the XML configuration file:
<behaviors>
<endpointBehaviors>
Security 7-29
<behavior name="clientCertificate">
<clientCredentials>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
In code:
[Visual C#]
proxy.ClientCredentials.ServiceCertificate.Authentication
.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;

[Visual Basic]
proxy.ClientCredentials.ServiceCertificate.Authentication
.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust

Note: Setting the validation mode to PeerOrChainTrust will require you to add the service's certificate to
the trusted people store. This will allow the certificate to be validated even if it was not issued by a trusted
CA.

Note: Beware of changing the validation mode to None, as then your client will not check the validity of
the service's certificate.
Question: Why is it helpful if the client knows which certificate the service will use for authentication?
7-30 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Transport with Message Credentials Security

Key Points
WCF offers another security mechanism that incorporates both transport security and message security to
create a better secure channel.
The TransportWithMessageCredential security mode uses transport securitywhich offers better
performance and secured transport of messagesand the message-layer security mechanismwhich
supports various credential types that you cannot use with the standard transport security mechanism.
When you use transport with message credential over HTTP, WCF will use HTTPS. Over TCP, WCF will use
TLS similar to the transport security mechanism.
When you use transport with message credentials, you need to apply the same rules as using the
transport security mechanism with SSL certificates. If the certificate is hosted under IIS or WAS, then IIS will
manage the certificate for you. If the service is self-hosted, you will need to use the httpCfg or netsh tools
if the service uses an HTTP endpoint, or specify the certificate yourself in configuration or in code (using
the SetCertificate method) if the service uses a TCP endpoint.
You can use any of the message security client credential types with message credentials transport
UserName, Windows, even custom tokens and SAML.
The following XML fragment demonstrates how to configure your binding to use the
TransportWithMessageCredential security mode.
<wsHttpBinding>
<binding name="WsHttpBinding_ICalculator">
<security mode="TransportWithMessageCredential" >
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
Security 7-31
Lesson 4
Authentication and Authorization

After defining the service endpoints with the security mode and the credential type, you should address
authentication and authorization of the client's identity.
You configure WCF authentication and authorization through service behaviors. WCF contains several
built-in providers and extensibility points to customize these aspects of your service for your needs.
Moreover, WCF authorization supports the .NET role-based security model that uses the IIdentity and
IPrincipal interfaces.
In this lesson, you will learn about the WCF authentication and authorization models, the built-in
providers and extensibility points, and how you can perform authorization enforcement at runtime.
Lesson Objectives
After completing this lesson, you will be able to:
Configure authentication or authorization providers.
Authenticate clients using a built-in or a customized provider.
Authorize clients using a built-in or a customized provider.
7-32 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Configuring Authentication and Authorization Providers

Key Points
When writing secured services, authenticating and authorizing clients is essential. WCF contains built-in
providers that you can use to authenticate and authorize client identities that the client credentials
present.
ASP.NET has a successful infrastructure for identity management, which is based on username and
password credentials. WCF has full support for integrating services with the ASP.NET infrastructure. You
can configure your service to use the ASP.NET Membership Provider for client authentication, and to use
the ASP.NET Role Provider for client authorization.
The following example shows how you can configure the service behavior to use the built-in ASP.NET
Membership and Role providers for client authentication and authorization.
<serviceBehaviors>
<behavior name="SecureCalcBehavior">
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
In intranet scenarios, you would usually authenticate the clients against the domain's AD DS. The
following XML fragment example shows how you can configure the service to authenticate the client
against AD DS with an endpoint that accepts a user name token as the client credential type.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="WindowsAuthorizationBehavior">
<serviceCredentials>
Security 7-33
<userNameAuthentication
userNamePasswordValidationMode="Windows" />
<serviceCertificate
findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="CalcService.WCFCalc"
behaviorConfiguration="WindowsAuthorizationBehavior">
<endpoint
address="http://localhost:8080/Calc"
binding="wsHttpBinding"
bindingConfiguration="UserNameBinding"
contract="CalcService.ICalc" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="UserNameBinding">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
You can configure the same authentication in code, as shown in the following example.
[Visual C#]
ServiceHost host = new ServiceHost(
typeof(WCFCalc),
new Uri("http://localhost:8080/Calc"));

WSHttpBinding httpBinding = new WSHttpBinding(SecurityMode.Message);
httpBinding.Security.Message.ClientCredentialType =
MessageCredentialType.UserName;

host.AddServiceEndpoint(typeof(ICalc), httpBinding, "");

host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode
= UserNamePasswordValidationMode.Windows;

host.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"localhost");

[Visual Basic]
Dim host As New ServiceHost(
GetType(WCFCalc),
New Uri("http://localhost:8080/Calc"))

Dim httpBinding As New WSHttpBinding(SecurityMode.Message)
httpBinding.Security.Message.ClientCredentialType =
MessageCredentialType.UserName
7-34 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

host.AddServiceEndpoint(GetType(ICalc), httpBinding, "")

host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode
= UserNamePasswordValidationMode.Windows

host.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"localhost")
If you use the previous approach, WCF creates the corresponding IIdentity and IPrincipal
implementations, and attaches them to the WCF security context of the thread that handles client
requests for your service. You can access this information in your service code for performing role-based
security, which will be discussed later in this lesson.
Security 7-35
Using Custom Authentication Providers

Key Points
WCF provides you with extensibility points that you can use to plug your custom authentication and
authorization providers and implement your own identity management solution. To do so, you must
either derive from a class or implement an interface that is appropriate for what you need to customize.
For example, for validating username and password or X.509 certificate credentials, you would need to
derive from either UserNamePasswordValidator or X509CertificateValidator, respectively.
The following example shows how you can insert a custom implementation for validating username and
password credentials.
<serviceBehaviors>
<behavior name="SecureCalcBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType=
"ServicesBehaviors.CustomValidators.EqualUsernamePasswordValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
The following code example is the EqualUsernamePasswordValidator class that validates the users
username and password:
[Visual C#]
namespace ServicesBehaviors.CustomValidators
{
public class EqualUsernamePasswordValidator :
UserNamePasswordValidator
{
public override void Validate(string userName,
string password)
7-36 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
{
if (userName != password)
throw new SecurityTokenException("Access denied");
}
}
}

[Visual Basic]
Namespace ServicesBehaviors.CustomValidators
Public Class EqualUsernamePasswordValidator
Inherits UserNamePasswordValidator
Public Overrides Sub Validate(ByVal userName As String,
ByVal password As String)
If userName <> password Then
Throw New SecurityTokenException("Access denied")
End If
End Sub
End Class
End Namespace
Security 7-37
Performing Authorization in Code

Key Points
.NET role-based security is based on the IIdentity and IPrincipal interfaces. The IIdentity implementation
contains information about the client's identity, and the IPrincipal implementation contains information
about the client's roles along with functionality for checking if the client's identity has a certain role.
For example, in cases where you authenticate users using Windows credentials, WCF creates the
corresponding WindowsIdentity and WindowsPrincipal objects, and attaches them to the threads
security context.
You can access the IIdentity and IPrincipal interface implementations from two locations:
WCF Security Context. WCF attaches the identity and principal objects to its security context. The
security context contains information about the various identities that may be presented by the client
credentials.
The following example shows how you can access the client's Windows identity or primary identity
whose type varies according to the client credentials.
[Visual C#]
IIdentity identity =
ServiceSecurityContext.Current.PrimaryIdentity;

WindowsIdentity winIdentity =
ServiceSecurityContext.Current.WindowsIdentity;

[Visual Basic]
Dim identity As IIdentity =
ServiceSecurityContext.Current.PrimaryIdentity

Dim winIdentity As WindowsIdentity =
ServiceSecurityContext.Current.WindowsIdentity
7-38 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
You can access the security context by using either the static property
ServiceSecurityContext.Current, or the security context attached to the current operation context
OperationContext.Current.ServiceSecurityContextboth properties point to the same object.
Thread Principal. WCF attaches the principal to the thread that handles the request.
The following example shows how you can access the principal from your service code.
[Visual C#]
IPrincipal principal = Thread.CurrentPrincipal;

IIdentity identity = principal.Identity;

[Visual Basic]
Dim principal As IPrincipal = Thread.CurrentPrincipal

Dim identity As IIdentity = principal.Identity
Because the identity and principal are available throughout the entire lifetime of your service, you
can use their implementation to authorize the client against specific role requirements. In addition,
you can use the common .NET role-based security model through the PrincipalPermission class
imperatively or declaratively.
To use the PrincipalPermission declaratively, decorate your service operation implementation with
the PrincipalPermissionAttribute, and set against which roles you want to authenticate the
identity. The following code demonstrates using the attribute to allow only Managers (for example,
identities that belong to the Manager role) to use the service operation.
[Visual C#]
[PrincipalPermission(SecurityAction.Demand, Role="Manager")]
public int Add(int a, int b)
{
return a + b;
}

[Visual Basic]
<PrincipalPermission(SecurityAction.Demand, Role:="Manager")>
Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
Implements ICalc.Add
Return a + b
End Function

You can use the SecurityAction enum to demand that the identity belong to a role, and you can also use
it to deny access from specific roles, as shown in the following example:
[Visual C#]
[PrincipalPermission(SecurityAction.Deny, Role="Intern")]
public int Mul(int a, int b)
{
return a * b;
}

[Visual Basic]
<PrincipalPermission(SecurityAction.Deny, Role:="Intern")>
Public Function Mul(ByVal a As Integer, ByVal b As Integer) As Integer
Implements ICalc.Mul
Security 7-39
Return a * b
End Function
You can also use the PrincipalPermission imperatively by creating an instance of the
PrincipalPermission type, and then specifying which roles to check. The following
example shows how to check the Manager role in codethe null parameter means the current identity is
checked.
[Visual C#]
[PrincipalPermission(SecurityAction.Demand, Role="Manager")]
public int Add(int a, int b)
{
PrincipalPermission rolePermission =
new PrincipalPermission(null, "Manager");

rolePermission.Demand();

return a + b;
}

[Visual Basic]
<PrincipalPermission(SecurityAction.Demand, Role:="Manager")>
Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
Implements ICalc.Add

Dim rolePermission As New PrincipalPermission(Nothing, "Manager")

rolePermission.Demand()

Return a + b
End Function
Question: How can role-based security help you secure your services?
7-40 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lesson 5
Claim-Based Identity

WCF maps client credentials that are represented as tokens into identity claims. A claim is basically a piece
of information about the identity, such as a name, email, and social security number.
Clients can present numerous claims about their identity inside the token, thus providing all kind of
information; or the identity might be specific to the claims that are required by the service. On the service
side, the claims presented by the client token are grouped inside a claim set, which holds information
about the issuer, and can be verified.
Claim-based security is helpful for creating a unified authentication and authorization model for your
services, and enabling a single sign on (SSO) user experience.
In scenarios where you apply claim-based security, signing and encrypting the message (and the token)
becomes essential for ensuring integrity and privacy.
In this lesson, you will learn about standards and important concepts for applying claim-based security,
the WCF support for claim-based security, as well as other frameworks and products that you may
consider integrating into your solution.
Lesson Objectives
After completing this lesson, you will be able to:
Implement claim-based security for your services.
Enable federation scenarios for securing your services.
Define claim types that are required by your service.
Security 7-41
Introduction to Claim-Based Identity

Key Points
Claim-based identity revolves around describing the identity information as a set of claims. A claim is
basically a piece of information about the identity, such as name, email, social security number, and
authorized resources.
In the claim-based identity approach, client credentials are represented by a token that contains the set of
claims about the clients identity. In federation scenarios, the token is generated, signed and encrypted by
a certain issuer that the service can trust and use to verify the tokens integrity, such as a trusted STS.
The external issuer responsibility for authenticating clients and providing the necessary information claims
enables an SSO user experience by design. In addition, externalizing this behavior from the application
improves productivity and enhances the application security model.
Federation is a policy standard that is part of the WS-* specifications, making it a rich, powerful, and
interoperable security approach. Furthermore, you can relate federation with multiple identity issuers. WS-
Trust is an example of that; it addresses the problem of authenticating clients from different enterprises
using federation. WS-Trust takes advantage of the fact that these enterprises have a trust relationship
between their two issuers.
When the client wants to access a service from a different enterprise, they request a valid token from their
local issuer, and then access the other enterprise issuer to obtain another token that they can use for
accessing the actual service.
One of the main advantages of this technique is that the service application layer does not need to
implement additional authentication, or preserve an identity data store. The service can publish its claim
type requirements, and in return receive a valid token containing all the relevant information for
determining what the client can do.
Claim-based identity is a generalized approach that we encounter in real life as well. Consider the
following example: When travelers arrive in a foreign country, they need to pass through the immigration
7-42 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
authorities using their passport in order to enter. The passport represents the travelers; identity tokens,
which were issued by the authorities in their home country. The process begins thanks to the fact that the
destination country trusts the authorities from the travelers country of origin. The local destination
authorities do not need to preserve identity information of every potential visitor; it is enough for them to
verify the information claims and the issuer of the passport for authorizing the travelers entrance.
Claim-based identity is a flexible approach where you have full control over the generated token
information. You can include as much information as you need inside the token. This is contrary to normal
credentials, which aren't extensible. Additionally, applications can trust several issuers, which give the
client the ability to choose the issuer that holds the most appropriate identity.

Security 7-43
Using Tokens to Manage Identities

Key Points
When a client application transmits the user's identity, it sends a security token that holds the information
about the user. The security token is a package that contains the set of claims that together form the
identity of the user. For example, the claims of a person can be his or her name, the groups to which he or
she belongs, his or her age, and email address. In addition to the list of claims, a token will contain a
signature that identifies the tokens issuer, and prevents changes to the issued claims.
The token sent by the client is not created by the client; it is created by an STS an identity provider
(software) that issues tokens. The STS uses a repository where all the identities are stored (for example: AD
DS). When a client requests a token, the STS will retrieve the identity from the repository, digitally sign
and encrypt it to prove its integrity, and send it back to the client.
The token issued by the STS is generated using the SAML, which is a standard markup language that can
be interpreted by all the participants that need to read the content of the token.
7-44 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Tokens to Authenticate a Claim-Based Identity

Key Points
When you build a service, you define in the service's security policy the list of claims that your service
requiresfor example: user name, email address, and role memberships. The list of claims and the address
of the STS are exposed through your service's WSDL document. This enables your clients to understand
how they can retrieve a token with those claims from the STS.
When the client wants to call the service, it makes a request to the STS, requesting a token with the claims
that the service requires (diagram step 1). The STS authenticates the client and returns a security token
that contains all the claims required by the service.
The client then sends its request to the service with the token that it received from the STS (diagram step
2).
The service receives the token, validates it using its digital signature, and then uses the claims for its work
(diagram step 3).
Security 7-45
Using Claim-Based Identity with WCF

Key Points
WCF supports claim-based identity using the WS-Federation HTTP binding, which is a specially designed
binding that allows a service to configure the details of the STS and the required claims in the service's
configuration file.
The WS-Federation HTTP binding handles all the cryptography and SAML parsing that are required for
opening a token and reading it. This enables you to access the claims in code without the need to
perform any of these operations yourself.
You can use the System.IdentityModel namespace to access the claims that are sent by a client. The
main type exposed by the System.IdentityModel is the Claim type. Each claim consists of three parts:
Claim Type. The property the claim refers tofor example, Username, Email, or Age. A type can
be a property, but it can also be a file, a database, or any other resource type.
Resource. The value of the claim type (the property)for example: the Username type can have
the value of Bob, and the File type can have a value of vacation.jpg.
Right. The right associated with the claim. There are three rights: Possess (has the property), Write
(has the write right on a resource), or Read (has the read right for a resource).
Claims can be grouped into a ClaimSet, which is a container of claims. In addition to the client's claims,
the ClaimSet class also contains the claims of the identity's issuer. The issuer claims can be accesses using
the ClaimSet.Issuer property.
Client Side
On the client side, the WCF WSFederationHttpBinding class enables you to use identity selectors to
choose an STS. For example, WCF supports the Windows CardSpace identity chooser.
7-46 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Inspecting Claims in Code

Key Points
To access the claims that pass within a message, you can use the AuthorizationContext class that
exposes a collection of the messages claim sets. To retrieve the claims that build up the identity of the
client, you need to iterate through the claim sets, and then iterate each of the claims inside the set, as
demonstrated in the following code.
[Visual C#]
AuthorizationContext ctx =
OperationContext.Current.ServiceSecurityContext.AuthorizationContext;

foreach (ClaimSet claimSet in ctx.ClaimSets)
{
foreach (Claim claim in claimSet)
{
Console.WriteLine(claim.ClaimType);
Console.WriteLine(claim.Resource);
Console.WriteLine(claim.Right);
}
}

[Visual Basic]
Dim ctx As AuthorizationContext =
OperationContext.Current.ServiceSecurityContext.AuthorizationContext

For Each l_claimSet As ClaimSet In ctx.ClaimSets
For Each l_claim As Claim In l_claimSet
Console.WriteLine(l_claim.ClaimType)
Console.WriteLine(l_claim.Resource)
Console.WriteLine(l_claim.Right)
Next l_claim
Next l_claimSet
Security 7-47
You can use the Claim instance to find the value (Resource) of a property (ClaimType) that the client
possesses (Right).
For example, if you have set the security settings to require claims for given name, surname, and email,
then the output of the previous code might look like the following code:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/hash
System.Byte[]
http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
johnd@fabrikam.com
http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
John
http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
Doe
http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty
7-48 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Configuring WS-Federation HTTP Binding

Key Points
WS-Federation HTTP Binding is a built-in WCF binding that you can use to apply federated security for
your services by implementing the WS-Federation standard. The WS-Federation standard describes the
communication between the client and the issuer where the client sends a Request Security Token (RST)
message to the issuer and receives a Request Security Token Response (RSTR) message including the
issued token (according to the client's authenticated identity). Finally, the client can use the issued token
to call the service.
The advantages of WS-Federation have been established throughout this lesson. In summary, with the
help of an external issuer, the service does not need to authenticate the client, but rather just verify the
issued token and perform authorization checks as necessary. In addition, the service application defines its
claim type requirements, and then receives them from an external trusted issuer; the service is not
concerned about managing this information or the identity store.
A common approach when you want your service to support clients from different sourcessuch as
different enterprisesis federated security, which is considered a unified and interoperable security
implementation for your services.
The following example shows how you can define a rather simple form of the WS-Federation HTTP
Binding using the service XML configuration file.
<wsFederationHttpBinding>
<binding name="CalcFederationBinding">
<security>
<message issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion">
<claimTypeRequirements>
<clear/>
<add
claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
<add
claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>
Security 7-49
<add
claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"/>
</claimTypeRequirements>
<issuer address="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self"/>
</message>
</security>
</binding>
</wsFederationHttpBinding>
The example above defines three claim types that are required by the service: email, given name, and
surname. Additionally, there is no specific issuer defined, which means that by default, Windows
CardSpace will be activated on the client side, showing self-issued identity cards for each of the valid
issuers that can satisfy these claim type requirements. Clients can then choose an appropriate issuer,
receive the issued token, and then call the service.
You can also configure a specific location of the issuer's metadata that you intend for the client to use, as
demonstrated in the following XML fragment:
<wsFederationHttpBinding>
<binding name="CalcFederationBinding">
<security>
<message issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion">
<issuerMetadata address="http://localhost:8090/MySTSIssuerService/mex"/>
</message>
</security>
</binding>
</wsFederationHttpBinding>
7-50 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Introduction to Windows Identity Foundation

Key Points
Microsoft Windows Identity Framework (WIF) is a set of technologies and products that provide you with
identity management tools and a programming model for building on-premises software as well as cloud
services. WIF assists you with externalizing identity logic for your applications, thus increasing productivity
and enhancing the service's security.
Building the products and services for implementing a unified claim-based security and STS for your
enterprise was historically complex and difficult until the release of WIF. WIF simplifies the creation of a
STS as well as the interaction with other existing STSs, and resources such as Active Directory Federation
Services (AD FS).
Finally, WIF includes a rich programming model for claim-based identity logic and seamless integration
with services and ASP.NET applications.
The Windows Identity and Access platform contains the following product releases:
Active Directory Federation Services 2.0.
Windows Identity Foundation.
Windows CardSpace 2.0
AD FS 2.0
AD FS 2.0 is an identity provider that enables the use of federated identities and can act as an STS. AD FS
supports various authentication types, such as Kerberos tokens and X.509 certificates, and supports using
various identity stores, such as the AD DS. AD FS supports issuing security tokens using different types of
protocolsfor example WS-Trust, SAML and WS-Federation.

Note: AF DS 2.0 supports both SAML 1.1 and SAML 2.0.
Security 7-51
Windows CardSpace 2.0
Windows CardSpace is an identity selector platform. A Windows CardSpace identity card represents a
user's identity in a simple and friendly manner, very much like your personal social security card. The
identity card installs on the users computer. The card does not include information specifically about the
user identity, but rather the information required for fetching the identity information from the identity
provider.
The original version of Windows CardSpace was released with .NET Framework 3.0. WIF enables using
Windows CardSpace on the client side as well as supplying the infrastructure needed on the server for
building a custom identity provider, or for using an existing one.
7-52 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lab: Implementing WCF Security

Lab Objectives
After completing this lab, you will be able to:
Secure policy implementation for the customer relationship management (CRM) Service.
Configure client security.
Verify security policy.
Introduction
In this lab, you will be securing policy implementation for the CRM service, configuring client security, and
verifying a security policy.
Lab Setup
For this lab, you will use the available virtual machine environment. Before you begin the lab, you must:
Start the 10263A-SVR1 virtual machine, and then log on by using the following credentials:
User name: Administrator
Password: Pa$$w0rd

Note: You can perform tasks in this lab by using either Microsoft Visual Basic or Microsoft Visual C#. If
you are using Visual C#, refer to the steps provided in Section 1 of the lab page. If you are using Visual
Basic, refer to the steps provided in Section 2 of the lab page.
Security 7-53
Lab Scenario

After multiple security breaches, the Fabrikam Information Security (IS) department has devised a new
security policy for all incoming and outgoing communication, as well as new authentication and
authorization requirements. Specifically, security experts identified the CRM service endpointsthat are
exposed to ordinary customers as well as company employeesas vulnerable. You have been tasked with
implementing different security policies for these two endpoints, and the HallState service, which has an
endpoint for customers, for business partners, and for the internal channels within your server farms.
You need to implement security for internal communication using intranet security (Kerberos). You will
secure the external channels using transport security (SSL), or using message security with either username
and password or X.509 credentials. Implementing these security policies to comply with regulation
requirements, while retaining the distinction between the roles and authorization capabilities of different
users, is a top priority.
7-54 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Section 1: Visual C#
Exercise 1: Implementing Security Policy
Task 1: Prepare the IIS for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M07\CS folder, run setup.bat.
3. After the batch completes, press any key in the command window to close it and then close the
Windows Explorer window.
Task 2: Examine how to configure IIS to support HTTPS
1. Open the IIS Manager.
2. Open the Bindings setting for the Default Web Site.
3. In the Site Bindings dialog box, verify that https is included in the bindings list.
4. Verify that the https binding uses the localhost certificate.
5. Close the Internet Information Services (IIS) Manager.
Task 3: Configure the CRM service to use transport security with no other user
credentials
1. Open Microsoft Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M07\CS folder.
3. Build the solution.
4. Locate the CRMService project under the Services\Crm solution folder, and open the web.config
file.
5. In the web.config file, locate the bindings XML element.
6. In the bindings XML element, locate the XML element for basicHttpBinding, and add the following
binding configurations inside it:
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
7. Locate the customer relationship management (CRM) service configuration in the services XML
element of the web.config file.
8. Add an endpoint with the PrivateCrm address, basicHttpBinding, and
TicketingOffice.CrmService.Contracts.IPrivateCrm contract. Set the binding configuration to use
the TransportSecurity binding configuration that you just defined. The resulting endpoint
configuration should look as follows:
<endpoint address="PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
Security 7-55
Task 4: Configure the CRM service to use message security and client credentials
1. In the web.config file, locate the bindings XML element.
2. In the bindings XML element, locate the XML element for ws2007HttpBinding, and then add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
3. Locate the CRM service configuration in the services XML element of the web.config file.
4. In the CRM service configuration, change the InternalCrm endpoint to use the UNMessageSecurity
binding configuration.
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
5. In the CRM service configuration, change the PartnerCrm endpoint to use the CertMessageSecurity
binding configuration.
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
6. In the web.config file, locate the behaviors XML element.
7. In the behaviors XML element, locate the service behavior named StandardBehavior.
8. Add the following XML credentials to the behavior that you have found in the previous step.
<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>

7-56 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Task 5: Configure identity and roles management using the ASP.NET Membership and
Roles providers
1. In the web.config file, locate the behaviors XML element.
2. In the behaviors XML element, locate the service behavior named StandardBehavior.
3. Add the following role management settings XML to the behavior that you found in the previous
step.
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
4. In the behavior configuration, locate the serviceCredentials XML element, and add to it the
following identity management XML.
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>
5. After adding the above XML fragments, the service behavior should resemble the following XML
fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>

<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>

<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>

<serviceDiscovery/>
</behavior>
6. Save the web.config file.
Task 6: Authorize the access to the CRM service using Role Based Security
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Decorate the UpdateCustomer method with the
PrincipalPermission attribute. This opens the CrmService.svc.cs file.
3. Decorate the UpdateCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public void UpdateCustomer(Contracts.Customer newCustomer)

Security 7-57
4. Double-click the comment TODO: Ex1 Decorate the GetCustomerOrders method with the
PrincipalPermission attribute.
5. Decorate the GetCustomerOrders method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Order[] GetCustomerOrders(
Guid customerID, DateTime? fromDate, DateTime? toDate)

6. Double-click the comment TODO: Ex1 Decorate the FindCustomersByCriteria method with the
PrincipalPermission attribute.
7. Decorate the FindCustomersByCriteria method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer[] FindCustomersByCriteria(
CustomerCriteria criteria)

8. Double-click the comment TODO: Ex1 Decorate the FindCustomerByOrder method with the
PrincipalPermission attribute.
9. Decorate the FindCustomerByOrder method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer FindCustomerByOrder(Guid orderID)

10. Double-click the comment TODO: Ex1 Decorate the FindBestCustomers method with the
PrincipalPermission attribute.
11. Decorate the FindBestCustomers method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer[] FindBestCustomers(int numberOfCustomers)

12. Double-click the comment TODO: Ex1 Decorate the DeleteCustomer method with the
PrincipalPermission attribute.
13. Decorate the DeleteCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public void DeleteCustomer(Guid customerID)

14. Double-click the comment TODO: Ex1 Decorate the CreateCustomer method with the
PrincipalPermission attribute.
15. Decorate the CreateCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Guid CreateCustomer(Contracts.Customer newCustomer)

7-58 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Task 7: Use imperative authorization
1. Double-click the comment TODO: Ex1 Add imperative authorization to the DeleteCustomer
method to locate the DeleteCustomer method.
2. In the DeleteCustomer method, replace the TODO comment with the following code that checks the
authorization for the Manager role.
if (Thread.CurrentPrincipal.IsInRole("Managers"))
Manager.DeleteCustomer(customerID);
else
throw new CrmException(StringsResource.UnauthorizedOperation);
Task 8: Log the name of the Identity using the all the CRM methods
1. Double-click the comment TODO: Ex1 Add identity logging to locate the LogUser method.
2. Add the following code to the method:
if ((ServiceSecurityContext.Current != null) &&
(ServiceSecurityContext.Current.PrimaryIdentity != null))
{
StackFrame stackFrame = new StackFrame(1);
string methodName = "CustomerRelationsService." +
stackFrame.GetMethod().Name; // Which method called me

LoggingManager.Logger.Log(
LoggingCategory.Info,
string.Format(
StringsResource.MethodCalledBy,
methodName,
ServiceSecurityContext.Current.PrimaryIdentity.Name));
}
3. Save the CrmService.svc.cs file.
Results: After this exercise, you will have created endpoints for the CRM service that use transport
security and message security, and require client credentialssuch as username and certificate.
In addition, you will have added authorization checksboth imperative and declarativeto the CRM
service, and will have configured the service to use the Microsoft ASP.NET Membership and Roles
provider.
Security 7-59
Exercise 2: Configuring Client
Task 1: Add an endpoint behavior to determine the location of the certificate to send
1. Open the App.config file of the TicketingOffice.UI project.
2. In the App.config file, locate the behaviors XML element.
3. Add the following XML fragment inside the behaviors XML element.
<endpointBehaviors>
<behavior name="CredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>

Note: This CRM service uses a self-issued certificate whose issuer does not belong to a chain trust.
Therefore, you must change the way the service's certificate is validated from its default value of
ChainTrust, to the value of PeerOrChainTrust.
Task 2: Add a binding configuration that will match the security configuration
requirements of the CRM service
1. In the App.config file, locate the bindings XML element.
2. Add the following binding configuration to the bindings XML element.
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
</basicHttpBinding>
3. In the bindings XML element, locate the XML element for ws2007HttpBinding, and add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
7-60 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Task 3: Add client endpoints to consume the CrmService
1. Locate the client XML element in the App.config file.
2. Add the following endpoints to the client XML element:
<endpoint
name="InternalCrm"
address="http://localhost/CrmService/CrmService.svc/InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PartnerCrm"
address="http://localhost/CrmService/CrmService.svc/PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PrivateCRM"
address="https://localhost/CrmService/CrmService.svc/PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm" />
3. Save the App.config file.
Task 4: Add client proxy initialization with username authentication
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Add proxy creation and client authentication code. This
opens the InternalCRMWindow.xaml.cs file in the TicketingOffice.UI project.
3. Delete the content of the CreateCrmServiceProxy method.
4. Place the following code inside the method:
ChannelFactory<ICrmService> factory = new ChannelFactory<ICrmService>
("InternalCrm");
factory.Credentials.UserName.UserName = "Admin";
factory.Credentials.UserName.Password = "Pa$$w0rd";
return factory.CreateChannel();

Note: In real-world applications, avoid hard-coding user credentials into your code.
5. Save the InternalCRMWindow.xaml.cs file.
Results: After this exercise, you will have configured your client application to consume the CrmService
using transport and message security, and you will have configured the client to send a specific
certificate and client authorization information to the service.
Security 7-61
Exercise 3: Verifying Security
Task 1: Configure the CRM Service for message logging
1. Open the CrmService project's web.config file in the Microsoft Windows Communication
Foundation (WCF) Service Configuration Editor.
2. Turn on MessageLogging and Tracing.
3. Configure Message Logging to log entire messages, and to log entire messages at the service level.
4. Save the configuration file.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
Task 2: Deploy the service
1. Create a deployment package for the CrmService project.
2. Open the IIS Manager.
3. Import the package that you have created to the Default Web Site, and name it CrmService.
4. Close the IIS Manager, and return to Visual Studio 2010.
Task 3: Consume the secured service from a client application
1. Set the TicketingOffice.UI project as the startup project.
2. Run the TicketingOffice.UI project.
3. In the client's main window, click the Show customer details (Internal) button.
4. In the InternalCRMWindow window, click the New button.
5. Enter new customer informationfirst name and last name are mandatory.
6. Click the Save button.
7. Click OK to close the operation completion message box.
8. Close the client application.
Task 4: Examine the message logging output
1. Open the Web_messages.svclog from the CrmService project folder.
2. Click the Message tab on the left pane, and review the list of messages that were sent. You can see
the security negotiation that occurred before the business message was sent.
3. In the Message tab, locate the CreateCustomer message.
Select the action, and in the action's description, click the XML tab to see the message that was
sent to the service. Notice that the data is encrypted. (Scroll to the end of the XML to view the
cipher value.)
7-62 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

4. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have configured the CRM service for message logging. In addition,
you will have deployed the service in IIS, run the client application to test the service, and reviewed the
service message logs to see how messages appear when using message security.

Security 7-63
Section 2: Visual Basic
Exercise 1: Implementing Security Policy
Task 1: Prepare the IIS for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M07\VB folder, run setup.bat.
3. After the batch completes, press any key in the command window to close it and then close the
Windows Explorer window.
Task 2: Examine how to configure IIS to support HTTPS
1. Open the IIS Manager.
2. Open the Bindings setting for the Default Web Site.
3. In the Site Bindings dialog box, verify that https is included in the bindings list.
4. Verify that the https binding uses the localhost certificate.
5. Close the Internet Information Services (IIS) Manager.
Task 3: Configure the CRM service to use transport security with no other user
credentials
1. Open Microsoft Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M07\VB folder.
3. Build the solution.
4. Locate the CRMService project under the Services\Crm solution folder, and open the web.config
file.
5. In the web.config file, locate the bindings XML element.
6. In the bindings XML element, locate the XML element for basicHttpBinding, and add the following
binding configurations inside it:
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
7. Locate the customer relationship management (CRM) service configuration in the services XML
element of the web.config file.
8. Add an endpoint with the PrivateCrm address, basicHttpBinding, and
TicketingOffice.CrmService.Contracts.IPrivateCrm contract. Set the binding configuration to use
the TransportSecurity binding configuration that you just defined. The resulting endpoint
configuration should look as follows:
<endpoint address="PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
7-64 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Task 4: Configure the CRM service to use message security and client credentials
1. In the web.config file, locate the bindings XML element.
2. In the bindings XML element, locate the XML element for ws2007HttpBinding, and then add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
3. Locate the CRM service configuration in the services XML element of the web.config file.
4. In the CRM service configuration, change the InternalCrm endpoint to use the UNMessageSecurity
binding configuration.
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
5. In the CRM service configuration, change the PartnerCrm endpoint to use the CertMessageSecurity
binding configuration.
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
6. In the web.config file, locate the behaviors XML element.
7. In the behaviors XML element, locate the service behavior named StandardBehavior.
8. Add the following XML credentials to the behavior that you have found in the previous step.
<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>
Security 7-65
Task 5: Configure identity and roles management using the ASP.NET Membership and
Roles providers
1. In the web.config file, locate the behaviors XML element.
2. In the behaviors XML element, locate the service behavior named StandardBehavior.
3. Add the following role management settings XML to the behavior that you found in the previous
step.
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
4. In the behavior configuration, locate the serviceCredentials XML element, and add to it the
following identity management XML.
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>
5. After adding the above XML fragments, the service behavior should resemble the following XML
fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>

<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>

<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>

<serviceDiscovery/>
</behavior>
6. Save the web.config file.
Task 6: Authorize the access to the CRM service using Role Based Security
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Decorate the UpdateCustomer method with the
PrincipalPermission attribute. This opens the CrmService.svc.vb file.
3. Decorate the UpdateCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Sub UpdateCustomer(ByVal newCustomer As Contracts.Customer) _
Implements ICrmService.UpdateCustomer

7-66 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
4. Double-click the comment TODO: Ex1 Decorate the GetCustomerOrders method with the
PrincipalPermission attribute.
5. Decorate the GetCustomerOrders method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function GetCustomerOrders(ByVal customerID As Guid, _
ByVal fromDate? As Date, ByVal toDate? As Date) _
As Order() Implements ICrmService.GetCustomerOrders

6. Double-click the comment TODO: Ex1 Decorate the FindCustomersByCriteria method with the
PrincipalPermission attribute.
7. Decorate the FindCustomersByCriteria method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindCustomersByCriteria( _
ByVal criteria As CustomerCriteria) As Contracts.Customer() _
Implements ICrmService.FindCustomersByCriteria

8. Double-click the comment TODO: Ex1 Decorate the FindCustomerByOrder method with the
PrincipalPermission attribute.
9. Decorate the FindCustomerByOrder method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindCustomerByOrder(ByVal orderID As Guid) _
As Contracts.Customer Implements ICrmService.FindCustomerByOrder

10. Double-click the comment TODO: Ex1 Decorate the FindBestCustomers method with the
PrincipalPermission attribute.
11. Decorate the FindBestCustomers method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindBestCustomers(ByVal numberOfCustomers As Integer) _
As Contracts.Customer() Implements ICrmService.FindBestCustomers

12. Double-click the comment TODO: Ex1 Decorate the DeleteCustomer method with the
PrincipalPermission attribute.
13. Decorate the DeleteCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Sub DeleteCustomer(ByVal customerID As Guid) _
Implements ICrmService.DeleteCustomer

14. Double-click the comment TODO: Ex1 Decorate the CreateCustomer method with the
PrincipalPermission attribute.
15. Decorate the CreateCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
Security 7-67
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function CreateCustomer( _
ByVal newCustomer As Contracts.Customer) As Guid _
Implements ICrmService.CreateCustomer

Task 7: Use imperative authorization
1. Double-click the comment TODO: Ex1 Add imperative authorization to the DeleteCustomer
method to locate the DeleteCustomer method.
2. In the DeleteCustomer method, replace the TODO comment with the following code that checks the
authorization for the Manager role.
If Thread.CurrentPrincipal.IsInRole("Managers") Then
Manager.DeleteCustomer(customerID)
Else
Throw New CrmException(StringsResource.UnauthorizedOperation)
End If
Task 8: Log the name of the Identity using the all the CRM methods
1. Double-click the comment TODO: Ex1 Add identity logging to locate the LogUser method.
2. Add the following code to the method:
If (ServiceSecurityContext.Current IsNot Nothing) AndAlso
(ServiceSecurityContext.Current.PrimaryIdentity IsNot Nothing) Then
Dim l_stackFrame As New StackFrame(1)
Dim methodName As String = "CustomerRelationsService." &
l_stackFrame.GetMethod().Name ' Which method called me?

LoggingManager.Logger.Log(
LoggingCategory.Info,
String.Format(
StringsResource.MethodCalledBy,
methodName,
ServiceSecurityContext.Current.PrimaryIdentity.Name))
End If
3. Save the CrmService.svc.vb file.
Results: After this exercise, you will have created endpoints for the CRM service that use transport
security and message security, and require client credentialssuch as username and certificate.
In addition, you will have added authorization checksboth imperative and declarativeto the CRM
service, and will have configured the service to use the Microsoft ASP.NET Membership and Roles
provider.
7-68 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 2: Configuring Client
Task 1: Add an endpoint behavior to determine the location of the certificate to send
1. Open the App.config file of the TicketingOffice.UI project.
2. In the App.config file, locate the behaviors XML element.
3. Add the following XML fragment inside the behaviors XML element.
<endpointBehaviors>
<behavior name="CredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>

Note: This CRM service uses a self-issued certificate whose issuer does not belong to a chain trust.
Therefore, you must change the way the service's certificate is validated from its default value of
ChainTrust, to the value of PeerOrChainTrust.
Task 2: Add a binding configuration that will match the security configuration
requirements of the CRM service
1. In the App.config file, locate the bindings XML element.
2. Add the following binding configuration to the bindings XML element.
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
</basicHttpBinding>
3. In the bindings XML element, locate the XML element for ws2007HttpBinding, and add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
Security 7-69
Task 3: Add client endpoints to consume the CrmService
1. Locate the client XML element in the App.config file.
2. Add the following endpoints to the client XML element:
<endpoint
name="InternalCrm"
address="http://localhost/CrmService/CrmService.svc/InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PartnerCrm"
address="http://localhost/CrmService/CrmService.svc/PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PrivateCRM"
address="https://localhost/CrmService/CrmService.svc/PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm" />
3. Save the App.config file.
Task 4: Add client proxy initialization with username authentication
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Add proxy creation and client authentication code. This
opens the InternalCRMWindow.xaml.vb file in the TicketingOffice.UI project.
3. Delete the content of the CreateCrmServiceProxy method.
4. Place the following code inside the method:
Dim factory As New ChannelFactory(Of ICrmService)("InternalCrm")
factory.Credentials.UserName.UserName = "Admin"
factory.Credentials.UserName.Password = "Pa$$w0rd"
Return factory.CreateChannel()

Note: In real-world applications, avoid hard-coding user credentials into your code.
5. Save the InternalCRMWindow.xaml.vb file.
Results: After this exercise, you will have configured your client application to consume the CrmService
using transport and message security, and you will have configured the client to send a specific
certificate and client authorization information to the service.
7-70 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 3: Verifying Security
Task 1: Configure the CRM Service for message logging
1. Open the CrmService project's web.config file in the Microsoft Windows Communication
Foundation (WCF) Service Configuration Editor.
2. Turn on MessageLogging and Tracing.
3. Configure Message Logging to log entire messages, and to log entire messages at the service level.
4. Save the configuration file.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
Task 2: Deploy the service
1. Create a deployment package for the CrmService project.
2. Open the IIS Manager.
3. Import the package that you have created to the Default Web Site, and name it CrmService.
4. Close the IIS Manager, and return to Visual Studio 2010.
Task 3: Consume the secured service from a client application
1. Set the TicketingOffice.UI project as the startup project.
2. Run the TicketingOffice.UI project.
3. In the client's main window, click the Show customer details (Internal) button.
4. In the InternalCRMWindow window, click the New button.
5. Enter new customer informationfirst name and last name are mandatory.
6. Click the Save button.
7. Click OK to close the operation completion message box.
8. Close the client application.
Task 4: Examine the message logging output
1. Open the Web_messages.svclog from the CrmService project folder.
2. Click the Message tab on the left pane, and review the list of messages that were sent. You can see
the security negotiation that occurred before the business message was sent.
3. In the Message tab, locate the CreateCustomer message.
Select the action, and in the action's description, click the XML tab to see the message that was
sent to the service. Notice that the data is encrypted. (Scroll to the end of the XML to view the
cipher value.)
Security 7-71

4. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have configured the CRM service for message logging. In addition,
you will have deployed the service in IIS, run the client application to test the service, and reviewed the
service message logs to see how messages appear when using message security.

7-72 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lab Review

Review Questions
1. What are the steps required to implement message security with username-password credentials?
2. What are the steps required to implement HTTPS transport security?
3. How do you access the identity object in code?
4. Which authentication and authorization providers are shipped with WCF?
5. What is a security negotiation?
Security 7-73
Module Review and Takeaways

Review Questions
1. What are the tenets of application security?
2. What is an identity in the digital world?
3. What are the differences between message and transport security?
4. What types of credentials does WCF support?
5. What is claim-based identity?
Real-World Issues and Scenarios
1. You need to expose a secured service inside your organizational network, which has a local active
directory. Which security configuration will you use?
2. You need to expose a secured service on the Internet for unknown clients. Which security
configuration will you use?
Best Practices
Mention some best practices in the context of your own business situations.


7-74 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010



Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-1
Module 8
Introduction to Advanced Microsoft Windows
Communication Foundation Topics
Contents:
Lesson 1: The Asynchronous Invocation Pattern 8-3
Lesson 2: Extending WCF 8-11
Lesson 3: Routing 8-46
Lesson 4: Workflow Services 8-62
Lab: Advanced Topics 8-78
8-2 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Module Overview

Services have various requirements and deployment needs. In many cases, you will need to extend or
customize your service behavior and implementation to meet specific needsfor example, to apply
advanced error handling, logging, or auditing.
In order to customize your services and the way they behave, it is important to understand the structure
of the service execution runtime, which is based on the dispatcher runtime. The Microsoft Windows
Communication Foundation (WCF) dispatcher runtime has many extensibility points that you can
integrate to alter the way WCF inspects and handles the messages that are sent to the service and
returned by the service.
WCF enables you to use asynchronous patterns on either the client or the service side, in a truly
decoupled form. This can increase your system's throughput and improve your client's user experience.
WCF 4 includes a built-in routing service implementation. You can apply the routing service as a message
broker design, enabling service transparency, load balancing, failover, protocol bridging, and more.
Finally, you can use the Windows Workflow Foundation that ships with convenient modeling tools, and
that tightly integrates with WCF technology to construct reliable long-term services, and to benefit from
state management, persistence, and tracking capabilities
In this module, you will learn how you can extend and customize your service's functionality through the
WCF dispatcher runtime, how to implement asynchronous patterns, and how to apply advanced
communication scenarios and management capabilities using the routing service and the workflow
runtime.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-3
Lesson 1
The Asynchronous Invocation Pattern

The asynchronous pattern is a well-known and commonly used pattern in the design of system execution.
You usually apply the asynchronous pattern when executing long-running operations that are not CPU-
bound, such as accessing the database or calling services across the network.
When applied correctly, the asynchronous pattern should improve the system's throughput. Additionally,
this pattern is commonly used for preventing user interface (UI) blocking in client applications.
WCF (and Service-Oriented Architecture (SOA) in general) use message exchange patterns for interaction
between decoupled systems. As long as the underlying message exchange is preserved, the internal
implementation at one end should not affect the other.
WCF provides you with rich support for applying the asynchronous pattern at each or both ends,
according to your needs. You can choose from three asynchronous patterns:
Client-side asynchrony. You can make asynchronous calls to the service regardless of the message
exchange pattern.
Service-side asynchrony. You can implement the service operation asynchronously regardless of the
message exchange pattern.
One-way message exchange. You can define operations as one-way to apply asynchronous message
exchange. This mode has to match on both the client and service sides.
In this lesson, you will learn how you can apply the asynchronous pattern on either the service side or the
client side.
Lesson Objectives
After completing this lesson, you will be able to:
Determine when to apply the asynchronous pattern.
8-4 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Invoke any service operation asynchronously.
Implement service operations using the asynchronous pattern.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-5
Implementing Asynchronous Clients

Key Points
You can use the client proxy to call the service asynchronously, regardless of the service implementation.
When calling services, you perform input/output (I/O)-bound work. You might want to consider using the
asynchronous pattern to improve the throughput and responsiveness of your client. This is particularly
true if your client has a UI that it can use to prevent UI blocking. You can choose the asynchronous
pattern execution regardless of the service implementation. The service does not know (or care) about
thread management on the client side.
If you wish to call services asynchronously, you can choose from two approaches:
1. <Begin> and <End> asynchronous pattern. Invoke the <Begin> and <End> methods that use the
System.IAsyncResult objects to perform an asynchronous operation.
2. Event-based asynchronous pattern. Subscribe to the event and the call the asynchronous operation;
when the operation completes, the event will be raised.
This pattern is preferred mostly in UI clients, because the resulting event automatically rises on the UI
thread from which the service call executes. This makes the pattern an easy approach for updating
the UI when the service call completes.
The event-based asynchronous pattern is supported as of Microsoft .NET Framework 3.5, and it is not
available when creating client channels using the ChannelFactory class.
The following example demonstrates how you can call a service asynchronously using both patterns.
[Visual C#]
//Call the service asynchronously using <Begin> and <End> methods

CalcServiceClient client = new CalcServiceClient();
client.BeginAdd(1, 2, OnAsyncOperationComplete, client);

static void OnAsyncOperationComplete(IAsyncResult result)
8-6 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
{
CalcServiceClient client = (CalcServiceClient)result.AsyncState;
int addResult = client.EndAdd(result);
}

//Call the service asynchronously using the event-based pattern

CalcServiceClient client = new CalcServiceClient();
client.AddCompleted +=
new EventHandler<AddCompletedEventArgs>(OnAddCompleted);
client.AddAsync(1,2);

static void OnAddCompleted(object sender, AddCompletedEventArgs e)
{
int addResult = e.Result;
}

[Visual Basic]
'Call the service asynchronously using <Begin> and <End> methods

Dim client As New CalcClient()
client.BeginAdd(1, 2, AddressOf OnAsyncOperationComplete, client)

Private Shared Sub OnAsyncOperationComplete(
ByVal result As IAsyncResult)
Dim client As CalcClient = CType(result.AsyncState, CalcClient)
Dim addResult As Integer = client.EndAdd(result)
End Sub

'Call the service asynchronously using the event-based pattern

Dim client As New CalcClient()
AddHandler client.AddCompleted, AddressOf OnAddCompleted
client.AddAsync(1, 2)

Private Shared Sub OnAddCompleted(
ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Dim addResult As Integer = e.Result
End Sub
You must specify when importing the service metadata that you want to create asynchronous operations
in the service contract. To do this, use the Microsoft Visual Studio Add Service Reference dialog box,
click the Advanced button, and select the Generate asynchronous operations check box.
You can also create asynchronous service operations when using the svcutil.exe command-line tool, as
demonstrated in the following code.
svcutil.exe http://localhost:8080/CalcService /async /tcv:Version35
The /async command-line switch specifies that asynchronous operations should be created in addition to
the ordinary synchronous operations, while the /tcv:Version35 switch indicates that the target framework
version is 3.5, so that event-based operations are created as well.
Question: What can your client gain by using asynchronous calls to a service?

Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-7
Creating an Asynchronous Service Contract

Key Points
You can implement service operations using the asynchronous pattern, so that the thread that executes
the service operation is not the same as the thread that accepted the request.
You may see improved throughput and scalability by implementing the asynchronous pattern for your
service operations. You should consider using the pattern if the operation is performing blocking I/O-
bound work, such as database access or calls to other services.
You implement asynchronous service operations by defining the operations using the <Begin> and
<End> methods as well as setting the OperationContract attribute AsyncPattern property to true on
the <Begin> operation.
The following example demonstrates how you can define the Add operation to use the asynchronous
pattern:
[Visual C#]
[ServiceContract]
interface ICalcAsync
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAdd(int a, int b,
AsyncCallback callback, object asyncState);

int EndAdd(IAsyncResult result);
}

[Visual Basic]
<ServiceContract>
Public Interface ICalcAsync
<OperationContract(AsyncPattern := True)>
Function BeginAdd(ByVal a As Integer, ByVal b As Integer,
ByVal callback As AsyncCallback, ByVal asyncState As Object)
8-8 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
As IAsyncResult

Function EndAdd(ByVal result As IAsyncResult) As Integer
End Interface
WCF recognizes the operation as asynchronous according to the AsyncPattern property in the
OperationContact attribute. WCF exposes asynchronous operations in the service metadata as a single
request-reply synchronous operation. Client applications that import the service metadata see only the
single request-reply synchronous operation in the generated contract.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-9
Implementing Asynchronous Services

Key Points
You implement the BeginAdd operation and the EndAdd operation of the service contract by using one
of the asynchronous design pattern implementations. For example, you can use delegates, as shown in the
following example.
[Visual C#]
public IAsyncResult BeginAdd(int a, int b,
AsyncCallback callback, object asyncState)
{
Func<int, int, int> add = (n1, n2) => n1 + n2;

return add.BeginInvoke(a, b, callback, asyncState);
}

public int EndAdd(IAsyncResult ar)
{
System.Runtime.Remoting.Messaging.AsyncResult result =
ar as System.Runtime.Remoting.Messaging.AsyncResult;

return ((Func<int, int, int>)result.AsyncDelegate).EndInvoke(ar);
}

[Visual Basic]
Public Function BeginAdd(ByVal a As Integer, ByVal b As Integer,
ByVal callback As AsyncCallback, ByVal asyncState As Object)
As IAsyncResult Implements ICalc.BeginAdd
Dim add As Func(Of Integer, Integer, Integer) =
Function(n1, n2) n1 + n2

Return add.BeginInvoke(a, b, callback, asyncState)
End Function

8-10 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Public Function EndAdd(ByVal ar As IAsyncResult) As Integer
Implements ICalc.EndAdd
Dim result =
TryCast(ar, System.Runtime.Remoting.Messaging.AsyncResult)

Return (CType(result.AsyncDelegate,
Func(Of Integer, Integer, Integer))).EndInvoke(ar)
End Function
Clients can choose whether to invoke that operation synchronously or asynchronously according to its
needs, but this decision affects only the client. This means that there is decoupled behavior between the
client and service. The client and service's internal implementation and thread management should not
affect the other end.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-11
Lesson 2
Extending WCF

When a WCF service receives a message, the message travels a long way through various parts of the WCF
infrastructure until it reaches the service operation to which it is addressed. Most of the work performed
on the messagesuch as inspecting it, extracting information from it, and deserializing itis performed
by built-in mechanisms of WCF. Nonetheless, you can add you own custom message handling
implementation to different parts of the infrastructure.
Once you gain access to the message, WCF offers you an easy application programming interface (API) to
examine and change the WCF contents, and to store relevant message information that will be used later
on when processing the message in the service's operations.
In this lesson, you will learn how WCF controls the behavior of the service and its components, and how
you can customize this behavior to fit to your needs. You will also learn how you can inspect messages
and save state information using various techniques.
Lesson Objectives
After completing this lesson, you will be able to:
Describe the dispatcher mechanism that is used by WCF.
Describe how WCF uses behaviors to extend dispatchers.
Create custom runtime components that you can attach to dispatchers.
Create custom behaviors for your services, endpoints, contracts, and operations.
Apply custom behaviors using custom attributes and configuration files.
Read and write custom SOAP headers in your messages.
Create extension objects to add custom functionality and state to your service.
8-12 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Behaviors to Extend WCF

Key Points
Messages received by a WCF service have a long distance to pass from the moment they arrive until the
moment they are sent to your service implementation for execution.
After a message arrives at the transport channel, it flows through the channel stack, through the
encoding, and through any other channel stack protocolssuch as a security protocol, or a reliable
messaging protocol. After all the protocols in the channel stack are satisfied with the message, it has a few
more steps to pass before reaching the service implementation. For example, someone has to deserialize
the message to the appropriate common language runtime (CLR) types, and inspect it to determine which
service method to invoke and which service instance to use.

Note: For more information about the channel stack, see Module 2, "Getting Started with Microsoft
Windows Communication Foundation Development".
These decisions and actions are performed by the dispatchers, which are the components responsible for
translating the content of the message to a method invocation. The way the dispatcher is constructed is
defined by behaviorsservice behaviors, endpoint behaviors, contract behaviors, and operation behaviors.
Instancing, serialization, throttling, and authorization are only a few examples of the different behaviors
that control dispatcher operations.

Note: Behaviors define how dispatchers initialize. This is similar to how bindings define how channel
stacks initialize.
You define and configure behaviors using code or configuration. For example, adding the
serviceMetadata element under the serviceBehavior element in the service's configuration file adds the
metadata publishing behavior to your service; the OperationBehavior attribute which you use to
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-13
decorate your service operations allows you to configure the creation of transaction scopes and scope
completion. Each of these behaviors changes the dispatcher's operation.
In addition to using the behaviors that ship with WCF, you can write your own custom behaviors. Using
custom behaviors enables you to add your own message handling logic, and change the way messages
process in the dispatcher. For example, you can change the way errors are handled and logged, or provide
custom message validation.
You can apply custom behaviorsjust like standard behaviorsto your services, endpoints, contracts, and
operations, by using either code or configuration. The ability to extend dispatchers using custom
behaviors is the most important extensibility point in WCF.
8-14 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Responsibilities of WCF Dispatchers

Key Points
WCF dispatchers are divided into several types. Each type is responsible for handling messages in a certain
scope:
Channel scope. Responsible for handling all the messages received by a specific binding type (i.e. a
specific URI and binding configuration).
Endpoint scope. Responsible for handling all the messages directed to a specific endpoint.
Operation scope. Responsible for handling all the messages directed to a specific operation in a
specific endpoint.
Channel Dispatcher
The ChannelDispatcherwhich is created by the service hostlistens to messages on a specific channel,
and associates messages from the channel with specific endpoints, by using the appropriate endpoint
dispatcher.
When a service host opens, it creates a ChannelDispatcher object for every combination of Uniform
Resource Identifier (URI) and binding elementsuch as transfer, encoding, and protocolsto which it
listens. For example, if a host is listening on its base address for service metadata requests, and has two
more endpoints (WS-HTTP and NetTCP), then it will have three channel dispatchers: one channel
dispatcher for the base address, one for the WS-HTTP endpoint, and another for the NetTCP endpoint.

Note: If the service has multiple endpoints that use the same binding and address for different contracts,
the host will create only one channel dispatcher for these endpoints.
Each channel dispatcher contains information about the URI on which it listens, its channel stack, and the
endpoints, represented by EndpointDispatcher objects, that are used by this channel. When the channel
dispatcher receives a message, it passes it across to the endpoint dispatchers of which it contains, to see
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-15
which of them can handle the message. When the matching endpoint dispatcher is found, the channel
dispatcher passes to it the message for processing.
The channel dispatcher is also responsible for various behaviors of the servicesuch as the service's error
handling, throttling, and timeout settings for receiving and sending messages. For example, when the
channel dispatcher receives a message, the message will be transferred to its matching endpoint
dispatcher only if the throttling level has not yet been reached.
Endpoint Dispatcher
The EndpointDispatcher class is responsible for receiving messages that were sent to a specific endpoint,
and then passing them to the appropriate service operation using a DispatchOperation object. The
endpoint dispatcher receives a message from the channel dispatcher, and then checks if the message was
sent to it by checking the To and the Action (operation name) elements that are specified in the message
header. The check is performed by using the AddressFilter and the ContractFilter properties. After the
endpoint dispatcher receives a message for which it is intended, it passes it to its DispatchRuntime
object, which in turn passes the messages to the relevant DispatchOperation object, which is responsible
for invoking the service instance method.
Dispatch Runtime
Each endpoint dispatcher holds a DispatchRuntime object, which is responsible for selecting the right
DispatchOperation object according to the content of the message. In addition to selecting the
DispatchOperation object, the dispatch runtime is also responsible for:
Performing message inspection, using custom message inspectors.
Initializing the service instance context and managing its lifetime.
Applying the role provider and authorization manager on the service instance.
You can extend the dispatch runtime and add your own custom processing by adding message inspectors
and instancing providers to the dispatcher. The extensions that you add to the dispatch runtime will affect
all the messages relating to the endpoint that contains the dispatch runtime. For example, you can use the
dispatch runtime to add custom message validation that ensures messages directed to a specific endpoint
contain a custom SOAP header, or to add a special service instance provider that supplies a pool of service
instances instead of letting the dispatch runtime create new service instances.
Dispatch Operation
The DispatchOperation object is responsible for invoking the service method that is specified in the
message, and then passing to it, the parameters contained in the message. To do so, the
DispatchOperation object performs the following tasks:
1. Acquires the service implementation instance from the dispatch runtime.
2. Deserializes the message to the matching CLR types.
3. Applies parameter inspectors to all the parameters sent to the method.
4. Invokes the method with the appropriate parameters.
5. Serializes the response, and creates the response message object.
You can customize and extend each of those tasks. For example, you can add a custom parameter
inspector that validates CLR data after it was deserialized, to check for irregular values such as string
length, and integer values range. You can also use message inspectors to validate data, but it will be
harder than using parameter inspector, because message inspectors are called when the message is still in
XML format, which require more work to parse and validate specific parts of the message.
8-16 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Extending the dispatch operation allows you to add custom processing to the operation level. It will affect
all the messages sent to a specific operation that is specified in the contract, regardless of the endpoint
through which the message was received.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-17
Service-Side Dispatchers Architecture

Key Points
After a message is received in the channel stack and completes its flow through the protocols, it is
forwarded to the channel dispatcher. The channel dispatcher iterates the endpoint dispatchers to find the
dispatcher that is best suited to handle the message, according to the address and action specified in the
message. If several endpoint dispatchers are found, the channel dispatcher uses the endpoint dispatcher's
FilterPriority property to find the suitable dispatcher to use.

Note: If the channel dispatcher examines the FilterPriority and there is still more than one endpoint that
can handle the message, the channel dispatcher will throw a MultipleFilterMatchException, and the
request will fail.
Once the channel dispatcher finds the endpoint dispatcher and passes it the message, the endpoint
dispatcher passes the message to its dispatch runtime. The dispatch runtime inspects the message, finds
the appropriate dispatch operation according to the action header of the message, and calls it. If there is
no matching dispatch operation, the dispatch runtime searches for a dispatch operation that has the "*"
action; this operation's method will usually receive an untyped Message object that contains the entire
message's content without deserialization.
The dispatch operation deserializes the message, inspects the parameters, acquires the service
implementation object from the dispatch runtime, and then invokes the required method on it.
Both the dispatch runtime and the dispatch operation objects are extensible. Since the dispatch runtime
inspects all the messages under a specific contract, the extensions you add to the dispatch runtime object
apply to all of the contract's operations, while extensions added to the dispatch operation apply only to
that specific operation.
8-18 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

Note: A dispatch runtime object belongs to a specific instance of an endpoint dispatcher. If you want to
extend all the dispatch runtime objects of all the endpoints in your service, you will need to customize all
the endpoint dispatchers. This will be demonstrated later in this lesson.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-19
Client-Side Dispatchers Architecture

Key Points
The dispatcher components mentioned earlier are used on the service side. On the client side, other
components that are responsible for creating and handling messages are sent to the service.
The proxies generated in WCF clients by the Visual Studio Add Service Reference tool, and the dynamic
proxies created by the ChannelFactory<T> class, are responsible for converting method calls and
parameters to outbound messages, and for converting response messages back to return values.
When the client calls an operation (such as a proxy method), the ClientOperation objectwhich is a part
of the proxytakes the parameters that are sent to the method, inspects them, and then serializes the
parameters to a message. After the client operation finishes building the message, it sends it to the
ClientRuntime object, which inspects the message, creates the outgoing channel, and passes the
message to the channel and from there to the service.
You can use the ClientRuntime and the ClientOperation objects to customize your service's behavior.
Customizing the ClientRuntime allows you to modify the behavior of all the operations in the contract
that are exposed by the proxy, while the ClientOperation offers extensibility for a specific operation.
For example, you can build a message inspector that adds a custom SOAP header to all outgoing
messages, and then place this inspector in the MessageInspectors collection of the ClientRuntime object.
8-20 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Matching Runtime Components to WCF Interfaces

Key Points

There are several runtime components that you can create to control the message flow in your service. All
the runtime component interfaces are declared in the System.ServiceModel.Dispatcher namespace,
which is a part of the System.ServiceModel assembly. Some of these interfaces are:
Parameter inspectors. You can use parameter inspectors to check the value of parameters before
invoking the operation's method. You can use parameter inspectors to validate constraints on your
data types, such as maximum length of strings, or the size of arrays. To implement a parameter
inspector, you will need to write a class that implements the IParameterInspector interface. You can
add the parameter inspector component by adding it to the ParameterInspectors collection of the
ClientOperation object (on the client-side) or the DispatchOperation object (on the service-side).
Message formatters. The message formatter allows you to customize how messages deserialize to
parameters, how return values are serialized to messages on the service side, how parameters
serialize to messages, and how response messages deserialize to return values on the client side. If
you want to build a custom message formatter, you can implement either the
IDispatchMessageFormatter or the IClientMessageFormatter. IDispatchMessageFormatter is
required for customizing the service side, and IClientMessageFormatter is required customizing the
client side. You can apply this runtime component by setting the Formatter property of your
DispatchOperation object on the service side, or of the ClientOperation object on the client side.
Message inspectors. You can use message inspectors to validate and extract information that is
contained inside the message sent from clients to the service, and inside messages sent from services
to clientsyou can implement the inspectors on either side client or service. If you want to build
an inspector that you will in the service, you will need to implement the
IDispatchMessageInspector interface. If you want to build an inspector for the client side, you will
need to implement the IClientMessageInspector interface. To use the message inspector runtime
component, add it to the MessageInspectors collection of your DispatchRuntime object on the
service side, or of the ClientRuntime object on the client side.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-21
Operation selectors. You can create custom operation selectors to change the way the dispatch
runtime finds the dispatch operation that can process the incoming message. For example, you
would use a custom operation selector if you wanted the operation selection process to use a
different header than the standard "action" SOAP header. If you want to build a selector for the
service side, you will need to implement the IDispatchOperationSelector interface. If you want to
build a selector for the client side, you will need to implement the IClientOperationSelector
interfaceyou can use the client-side operation selector to map between proxy methods and service
operations. (For example, you would use operation selectors in cases where you need to use a newer
version of a service that had changes to operation names, and you cannot rebuild your service proxy
to reflect those changes.) You can apply this runtime component by setting the OperationSelector
property of your DispatchRuntime object on the service side, or of the ClientRuntime object on
the client side.
Operation invokers. You can change the way the operation invocations translate to method calls by
using the operation invoker runtime component. For example, you can change the orders of
parameters sent to the method, or log each method invocation. The operation invoker runtime
component can only be applied on the service side. To build an operation invoker, you will need to
implement the IOperationInvoker interface, and apply it in your service by setting the Invoker
property of your DispatchOperation object.

Note: Another runtime component is the error handler, which you can create by implementing the
IErrorHandler interface. For more information about error handling and implementing the
IErrorHandler interface, see Module 6, "Testing and Troubleshooting Microsoft Windows
Communication Federation Services".
8-22 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Implementing a Custom Message Inspector

Key Points
One of the runtime components that you can customize and to which you can add your own
implementation, is the message inspector. A message inspector allows you to inspect the messages going
in and out of the service or the client. (You can use a message inspector in both WCF services and in WCF
clients.) By using this type of inspector, you can check a message and even modify it. For example, you
can inspect the message and log a copy of it, or you can create a different message and return it as the
new message to be processed.
To build a message inspector that you can attach to the dispatch runtime object on the service side, you
will need to write a class that implements the IDispatchMessageInspector interface. If you want to build
a message inspector that you can attach to the client runtime object, you will need to implement the
IClientMessageInspector interface.
The following example demonstrates how to implement the IDispatchMessageInspector interface to
build a message inspector for the service side.
[Visual C#]
public class LoggingMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(
ref Message request,
IClientChannel channel,
InstanceContext context)
{
Console.WriteLine(request);
return null;
}

public void BeforeSendReply(ref Message reply,
object correlationState)
{
Console.WriteLine(reply);
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-23
}
}

[Visual Basic]
Public Class LoggingMessageInspector
Implements IDispatchMessageInspector
Public Function AfterReceiveRequest(ByRef request As Message,
ByVal channel As IClientChannel,
ByVal context As InstanceContext) As Object
Implements IDispatchMessageInspector.AfterReceiveRequest
Console.WriteLine(request)
Return Nothing
End Function

Public Sub BeforeSendReply(ByRef reply As Message,
ByVal correlationState As Object)
Implements IDispatchMessageInspector.BeforeSendReply
Console.WriteLine(reply)
End Sub
End Class
The IDispatchMessageInspector declares the following methods:
AfterReceiveRequest. This method is called after the message arrives at the dispatch runtime. You
can use this method to inspect the contents of the message, extract information from it, or change its
contents. The Message object is passed by reference, so you can also supply a new message instance
instead of the original message, which will transfer the new message to the dispatch operation. The
return value of the method is a state object that will be sent to the BeforeSendReply method, thus
allowing you to correlate the work of the two methods.
BeforeSendReply. This method is called after the message is created with the response of the
operation. You can use this method to inspect and change the returned message. This method also
passes the Message object by reference, so you can create a new message instead of the current
message, which will cause the new message to flow down to the channel stack. As mentioned in the
previous paragraph, the correlationState parameter holds the state object that is returned from the
AfterReceiveRequest method.
If you want to build a message inspector for the client side, you will need to implement the
IClientMessageInspector interface. This interface declares similar methods to the
IDispatchMessageInspector:
BeforeSendRequest. This method is called before the message is sent to the service. You can use
this method to inspect, change, or replace the message before it is moved to the channel stack.
AfterReceiveReply. This method is called after the message is received from the service. You can use
this method to inspect, change, or replace the content of the message before it is passed to the
client operation (and from there to the calling method).
Question: When would you need to use a message inspector on the service side?
8-24 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Introduction to Custom Behaviors

Key Points
Extensibility points in the dispatch runtime and the dispatch operations allow you to add custom runtime
components that can handle various tasks, such as message and parameter inspection, custom
serialization and deserialization of messages, and service instance creation.
To build custom runtime components, you need to implement specific interfaces according to the type of
the component that you wish to build. For example, to build a custom runtime component that performs
message inspection, you will need to write a class that implements the IDispatchMessageInspector
interface and add it to the DispatchRuntime object that you want to customize.
After you build the custom runtime components, you will need to decide to which DispatchRuntime and
DispatchOperation you want to attach these components. This must be done at runtime, when your
service host opens. To do this, you will need a custom behavior.
Custom behaviors are the mechanism that allows you to control which runtime components are added to
the various dispatchers. With the use of custom behaviors, you can access the ChannelDispatcher,
EndpointDispatcher, DispatchRuntime, and DispatchOperation objects, and then add runtime
components to them. You can also use custom behaviors to remove existing runtime components from
the dispatchers.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-25
Using the Appropriate Behavior Type

Key Points
When you build a custom behavior, you will need to decide to which scope you want to apply the
behavior. For example, you can build a custom behavior and attach it to a specific endpoint so it will only
apply to the operations of that endpoint, or you can build a custom behavior and attach it to the entire
service so it will apply to all the operations in all the different endpoints exposed by the service.
WCF offers you the following types of behaviors:
Service behaviors. By creating a service behavior and applying it to your service, you can change
the runtime components of all the operations in all the endpoints of your service. For example, if
you want to add a custom error handler runtime component that will handle exceptions from all
the service operations, you will need to add it using a service behavior. Only service behaviors
have access to the channel dispatcher where this runtime component is declared. In addition to
customizing the runtime components, you can also customize the service host itself.
To create a custom service behavior, you will need to implement the IServiceBehavior interface.
You can apply service behaviors to a service by creating the custom behavior as a custom
attribute and then placing it on the service implementation, or by adding the behavior to the
service's behavior configuration in the configuration file.
Endpoint behaviors. You can use endpoint behaviors to apply changes to a specific endpoint and
its operations. Building an endpoint behavior instead of a service behavior is useful if you only
need to customize the runtime components of a specific endpoint. For example, you can take a
message inspector runtime component that performs message logging, create an endpoint
behavior for it, and only apply the behavior to endpoints that allow user access from the Internet.
To create a custom endpoint behavior, you will need to implement the IEndpointBehavior
interface. You cannot apply endpoint behaviors using attributes, because they need to be applied
directly to an endpoint declaration. Endpoint behaviors can be added to the endpoint's behavior
configuration in the configuration file.
8-26 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Contract behaviors. When using a contract behavior, you can apply changes to all the operations
of a specific contract, regardless of the endpoint in which it is declared.
To create a custom contract behavior, you will need to implement the IContractBehavior
interface. You can apply contract behaviors to your contract or service implementation only by
using custom attributes, because there is no contract configuration in the configuration file.
Operation behaviors. You can use an operation behavior to change the runtime components that
will be used for a specific operation, regardless of the endpoint dispatcher through which it was
invoked. For example, you can create a custom operation invoker that logs the duration of time it
took an operation to execute, and then apply it to several operations while testing the service.
To create a custom operation behavior, you will need to implement the IOperationBehavior
interface. Like the contract behavior, operation behaviors can only be attached to an operation
by using custom attributes.
Each of the interfaces mentioned above contains the ApplyDispatchBehavior method, which gives you
access to the dispatchers so you can apply custom runtime components to them.
If you want to customize the runtime components on the client side, you can create an endpoint
behavior, a contract behavior, or an operation behavior. Each of these behaviors contains the
ApplyClientBehavior method, which allows you to gain access to either the client runtime or the client
operation in order to apply the necessary runtime component to them.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-27
Implementing a Custom Service Behavior

Key Points
The following code example demonstrates how to build a custom service behavior that attaches a
message inspector runtime component to every dispatch runtime, and a parameter inspector to every
dispatch operation in the service.
[Visual C#]
public class RequestLoggingServiceBehavior : IServiceBehavior
{
public void AddBindingParameters(
ServiceDescription description,
ServiceHostBase hostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{}


public void ApplyDispatchBehavior(
ServiceDescription description,
ServiceHostBase hostBase)
{
foreach (ChannelDispatcher chDisp in
hostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
{
epDisp.DispatchRuntime.MessageInspectors.Add(
new LoggingMessageInspector());

foreach (DispatchOperation op in
epDisp.DispatchRuntime.Operations)
op.ParameterInspectors.Add(
new LoggingParameterInspector());
}
}
8-28 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
}

public void Validate(ServiceDescription description,
ServiceHostBase hostBase)
{}
}

[Visual Basic]
Public Class RequestLoggingServiceBehavior
Implements IServiceBehavior
Public Sub AddBindingParameters(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase,
ByVal endpoints As Collection(Of ServiceEndpoint),
ByVal bindingParameters As BindingParameterCollection)
Implements IServiceBehavior.AddBindingParameters
End Sub

Public Sub ApplyDispatchBehavior(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase)
Implements IServiceBehavior.ApplyDispatchBehavior
For Each chDisp As ChannelDispatcher
In hostBase.ChannelDispatchers
For Each epDisp As EndpointDispatcher In chDisp.Endpoints
epDisp.DispatchRuntime.MessageInspectors.Add(
New LoggingMessageInspector())

For Each op As DispatchOperation
In epDisp.DispatchRuntime.Operations
op.ParameterInspectors.Add(
New LoggingParameterInspector())
Next op
Next epDisp
Next chDisp
End Sub

Public Sub Validate(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase)
Implements IServiceBehavior.Validate
End Sub
End Class
The custom behavior implements the IServiceBehavior interface. This interface declares the following
methods:
AddBindingParameters. This method allows you to customize the binding elements in the channel
stack, and add binding parameters that you can use to configure custom binding elements. For
example, you can use this method to change the timeout properties of the binding.
ApplyDispatchBehavior. This method allows you to customize the runtime components used by the
channel dispatcher and its related dispatchers. You can use this method to add custom runtime
components to dispatchers.
Validate. This method allows you to verify that you can successfully use the behavior, by inspecting
the host and service settings, such as verifying that the contract's operations support a required fault
contract.
In the ApplyDispatchBehavior method of the IServiceBehavior interface, you have access to the
channel dispatchers by iterating the ChannelDispatchers collection of the ServiceHostBase object. In
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-29
the previous example, notice that the code iterates the EndpointDispatcher collection of each channel,
and adds a message inspector and parameter inspector to each endpoint dispatcher.
Because the service behavior lets you access the service host object, you can change the behavior of all
the channels in the service, thus affecting all the messages that are sent to the service.
Other types of behaviorssuch as the endpoint behavior or the operation behaviorgive you access to
other scopes (the endpoint scope and the operation scope respectively). Therefore, when you want to add
your own custom behavior, start with thinking what the required scope of your behavior is.
The following table lists which behavior type is most suitable to the scope you want to control with the
custom behavior.
Behavior type Message scope
Service behavior All the messages sent to the service
Endpoint behavior All the messages sent to a specific endpoint
Contract behavior All the messages sent to a specific contract in the service, regardless of the
endpoint that exposes it
Operation behavior All the messages sent to a specific service operation
8-30 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Attaching Custom Behaviors in Code

Key Points
A common practice when applying custom behaviors is to use custom attributes. If you write a custom
service behavior, contract behavior, or an operation behavior, you can apply it to your service, contract,
and operation (respectively) by using custom attributes.

Note: You cannot use custom attributes to apply endpoint behaviors. You can only attach endpoint
behaviors to endpoints using the configuration file.
To build your custom behavior so it can be used as a custom attribute, you will need to derive your
custom behavior from the Attribute class. The following example shows how to create a custom service
behavior using a custom attribute.
[Visual C#]
public class RequestLoggingServiceBehavior : Attribute,
IServiceBehavior
{
public void AddBindingParameters(
ServiceDescription description,
ServiceHostBase hostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{}


public void ApplyDispatchBehavior(
ServiceDescription description,
ServiceHostBase hostBase)
{
foreach (ChannelDispatcher chDisp in
hostBase.ChannelDispatchers)
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-31
{
foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
{
epDisp.DispatchRuntime.MessageInspectors.Add(
new LoggingMessageInspector());

foreach (DispatchOperation op in
epDisp.DispatchRuntime.Operations)
op.ParameterInspectors.Add(
new LoggingParameterInspector());
}
}
}

public void Validate(ServiceDescription description,
ServiceHostBase hostBase)
{}
}

[Visual Basic]
Public Class RequestLoggingServiceBehavior Inherits Attribute
Implements IServiceBehavior
Public Sub AddBindingParameters(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase,
ByVal endpoints As Collection(Of ServiceEndpoint),
ByVal bindingParameters As BindingParameterCollection)
Implements IServiceBehavior.AddBindingParameters
End Sub

Public Sub ApplyDispatchBehavior(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase)
Implements IServiceBehavior.ApplyDispatchBehavior
For Each chDisp As ChannelDispatcher
In hostBase.ChannelDispatchers
For Each epDisp As EndpointDispatcher In chDisp.Endpoints
epDisp.DispatchRuntime.MessageInspectors.Add(
New LoggingMessageInspector())

For Each op As DispatchOperation
In epDisp.DispatchRuntime.Operations
op.ParameterInspectors.Add(
New LoggingParameterInspector())
Next op
Next epDisp
Next chDisp
End Sub

Public Sub Validate(
ByVal description As ServiceDescription,
ByVal hostBase As ServiceHostBase)
Implements IServiceBehavior.Validate
End Sub
End Class
The following code demonstrates how to apply the custom behavior to a service implementation.
[Visual C#]
[RequestLoggingServiceBehavior()]
public class Calculator : ICalc
{
8-32 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
. . .
}

[Visual Basic]
<RequestLoggingServiceBehavior()>
Public Class Calculator Implements ICalc
. . .
End Class
You can similarly wrap your service contract and service methods with custom contract behaviors and
operation behaviors.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-33
Attaching Custom Behaviors in the Configuration

Key Points
If you do not want to apply the custom behavior using custom attributes, or if you have built a custom
endpoint behavior that cannot be applied using custom attributes, you can apply the behavior by using
the configuration. To provide the ability to use custom behaviors in configuration files, you will need to
create a class that derives from the BehaviorExtensionElement class.
The following code shows an example of a behavior extension element.
[Visual C#]
class RequestLoggingBehaviorConfigExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(RequestLoggingServiceBehavior); }
}

protected override object CreateBehavior()
{
return new RequestLoggingServiceBehavior();
}
}

[Visual Basic]
Class RequestLoggingBehaviorConfigExtension
Inherits BehaviorExtensionElement
Public Overrides ReadOnly Property BehaviorType() As Type
Get
Return GetType(RequestLoggingServiceBehavior)
End Get
End Property

Protected Overrides Function CreateBehavior() As Object
8-34 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Return New RequestLoggingServiceBehavior()
End Function
End Class
The BehaviorExtensionElement declares two abstract members that you need to override when you
build your custom configuration extension:
1. BehaviorType. You must override this property to return a Type object that represents the type of
the custom behavior this configuration element creates.
2. CreateBehavior. You must override this method to return your custom behavior's instance.
To apply this behavior in the configuration, you will need to introduce this behavior as an XML element.
To do so, you will need to add the newly created type to the extension element of the
system.serviceModel element. The following XML fragment demonstrates how to add the above
configuration extension to the configuration file.
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="RequestLogging"
type="RequestLoggingBehaviorConfigExtension, MyCustomBehaviors, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
Once you have added the behavior extension and set its name and type using the name and the type
attribute, you can use its name to apply the custom behavior in your service's configuration file, or in your
endpoint configuration, depending on the type of custom behavior that you have created.

Note: The type attribute must be set to the full name of the class, including its assembly name, assembly
version, public key, and culture information.
The following XML fragment shows how to apply the custom service behavior in configuration.
<system.serviceModel>
<services>
<service name="Calculator"
behaviorConfiguration="MyServiceBehavior">
. . .
</service>
</services>

<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<RequestLogging/>
</behavior>
</serviceBehaviors>
</behaviors>

<extensions>
<behaviorExtensions>
<add name="RequestLogging"
type="RequestLoggingBehaviorConfigExtension, MyCustomBehaviors,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-35
</extensions>
</system.serviceModel>
8-36 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Introduction to Custom Headers

Key Points
WCF uses the SOAP messaging protocol to construct the XML content of messages sent to the service,
and of messages returned by the service. Each message contains a SOAP envelope element that contains
two child elements: the SOAP header, and the SOAP body. The SOAP body usually contains all the
business-related data that is passed to the service operation, while the SOAP header contains information
that is used by the WCF infrastructure (including binding elements, dispatchers, and runtime
components), such as the session ID, digital signatures, and transaction information. The following XML
fragment is part of a SOAP request message.
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
<soap:Header>
<a:Action>http://www.fabrikam.com/ICalc/Add</a:Action>
<a:MessageID>
urn:uuid:263fcb7e-8b23-4080-98fa-27e9b8a991a2</a:MessageID>
</soap:Header>
<soap:Body>
<Add>
<a>3</a>
<b>5</b>
</Add>
</soap:Body>
</soap:Envelope>
Your service design might require your client to pass additional information that is essential for the
service's work. For example, you might want all your services to receive a parameter with the client's
locale, so you can output fault messages in the correct language. Instead of changing all the contracts in
your service in order to receive this new parameter, you can add the required parameter to the SOAP
header, and extract it when it is required.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-37
You can also place information inside the response message SOAP header if you want to return special
information to the client without including it in every return value that is declared for your service
operations.
WCF provides a simple API for reading and writing custom headers from and to the SOAP header section
of the message.
Question: Why would you need to use custom headers, and not simply add them as an additional
parameter to the operation's parameters?
8-38 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Custom Headers

Key Points
A custom header is usually written into the message before the client sends it to the service, and is usually
read from the message on the service side. You can also write a custom header into the message that
returned from the service, and read it when it reaches the client.
To place a custom header in the message on the client side, you need to gain access to the outgoing
message. To do so, you can use the operation context's OutgoingMessageHeaders collection that gives
you direct access to the headers of the outgoing message, as demonstrated in the following code:
[Visual C#]
CalcClient proxy = new CalcClient();

using (OperationContextScope ocs =
new OperationContextScope(proxy.InnerChannel))
{
MessageHeader header = MessageHeader.CreateHeader(
"UserId",
"http://www.fabrikam.com/",
"6119CF89-B65F-4C08-AB5E-40BF5424F0E2");

OperationContext.Current.OutgoingMessageHeaders.Add(header);
proxy.Sub(1, 3);
}

[Visual Basic]
Dim proxy As New CalcClient()

Using ocs As New OperationContextScope(proxy.InnerChannel)
Dim header As MessageHeader = MessageHeader.CreateHeader(
"UserId",
"http://www.fabrikam.com/",
"6119CF89-B65F-4C08-AB5E-40BF5424F0E2")
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-39

OperationContext.Current.OutgoingMessageHeaders.Add(header)
proxy.Sub(1, 3)
End Using
To add a header to the OutgoingMessageHeaders collection, you start by creating a MessageHeader
object. Because the headers are XML elements, they have a name that is the name of the element, and an
XML namespace to which the name belongs. The third parameter of the CreateHeader method is the
value of the header, which can be any XML-serializable object.

Note: To access the operation context in the client, you will need to use an OperationContextScope
object.
You can use a more type-safe approach by using the MessageHeader<T> class. The following code
demonstrates how to create the exact same header information with the use of type-safe headers.
[Visual C#]
CalcClient proxy = new CalcClient();

using (OperationContextScope ocs =
new OperationContextScope(proxy.InnerChannel))
{
MessageHeader<string> header = new MessageHeader<string>(
"6119CF89-B65F-4C08-AB5E-40BF5424F0E2");
MessageHeader headerBase = header.GetUntypedHeader(
"UserId",
"http://www.fabrikam.com/");

OperationContext.Current.OutgoingMessageHeaders.Add(headerBase);
proxy.Sub(1, 3);
}

[Visual Basic]
Dim proxy As New CalcClient()

Using ocs As New OperationContextScope(proxy.InnerChannel)
Dim header As New MessageHeader(Of String)(
"6119CF89-B65F-4C08-AB5E-40BF5424F0E2")
Dim headerBase As MessageHeader = header.GetUntypedHeader(
"UserId",
"http://www.fabrikam.com/")

OperationContext.Current.OutgoingMessageHeaders.Add(headerBase)
proxy.Sub(1, 3)
End Using
To read the content of the header on the service side, you can use the following code:
[Visual C#]
public class LoggingMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(
ref Message request,
IClientChannel channel,
InstanceContext instanceContext)
{
string userId = OperationContext.Current
.IncomingMessageHeaders.GetHeader<string>(
8-40 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
"UserId",
"http://www.fabrikam.com/");

Console.WriteLine(userId);
return null;
}

public void BeforeSendReply(ref Message reply,
object correlationState)
{
Console.WriteLine(reply);
}
}

[Visual Basic]
Public Class LoggingMessageInspector
Implements IDispatchMessageInspector
Public Function AfterReceiveRequest(ByRef request As Message,
ByVal channel As IClientChannel,
ByVal context As InstanceContext) As Object
Implements IDispatchMessageInspector.AfterReceiveRequest
Dim userId As String = OperationContext.Current
.IncomingMessageHeaders.GetHeader(Of String)(
"UserId",
"http://www.fabrikam.com/")

Console.WriteLine(userId)
Return Nothing
End Function

Public Sub BeforeSendReply(ByRef reply As Message,
ByVal correlationState As Object)
Implements IDispatchMessageInspector.BeforeSendReply
Console.WriteLine(reply)
End Sub
End Class
On the service side, you can use the IncomingMessageHeaders collection of the operation context to
get access to the incoming message headers. The GetHeader<T> generic method allows you to search
the header collection for a specific header according to its name and namespace, and to retrieve its value
once it converts to the required data type.
If you want to add custom headers to the outgoing message, you can do so by adding the headers to the
message in the BeforeSendReply method.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-41
Using IExtension<T> to Extend WCF

Key Points
Another method that you can use to extend various parts of your service is to use the extensible object
pattern that WCF implements. By using the extensible object pattern, you can add new functionality to
your services, operations, and channels.

Note: The extensible object pattern was discussed in Module 3, "Hosting Microsoft Windows
Communication Foundation Services".
The extensibility mechanism in WCF uses the IExtensibleObject<T> interface, which declares an
Extensions property that holds a collection of extension objects. There are several types that implement
this interface and enable extensions to attach to them. An extension object is any type that implements
the IExtension<T> interface. By adding and removing extension objects from the collection, you can
customize the functionality of the extensible objects.
The IExtension<T> interface declares the following methods:
Attach. This method is called when the extension is added to the extensions collection of the
extensible object. You can use this method to apply the required functionality changes.
Detach. This method is called when the extension is removed from the extensions collection. Use this
method to undo the changes that you have made to the extensible object.
The following WCF types implement the IExtensibleObject<T> interface:
ServiceHostBase. This is the base type of the ServiceHost class. Adding extensions to this object
allows you to extend the behavior of your service host.
InstanceContext. This class gives you access to both the service instance that is created at runtime,
and to its containing service host. By adding extensions to the instance context, you can add
functionality that is executed when the instance is created or destroyed.
8-42 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
OperationContext. This class gives you access to all the information regarding the current
operationsuch as the incoming message, and the security identity of the client. By using
extensions, you can modify the behavior of the operation's endpoint dispatcher, examine and modify
message content, and apply other customizations.
IContextChannel. This interface is implemented by the service and client channels. You can add
extensions to the channels to attach custom data to them, in order to be used at some point by
custom behaviors and runtime components. For example, you can create an extension for the service
side that keeps a list of message header (name, namespace and value) that will be added to every
outoing message. Because the channel is accessible from anywhere in the service, any service
operation and runtime component will be able to add headers to the extension object. When a
message is ready to be sent back to the client, a message inspector can take all the headers from the
extension, and place them in the returned message. (You will have to write both the extension object
and the message inspector that uses it..
In addition to adding functionality to the runtime classes by customizing the dispatchers and the host,
you can also use the extensions to hold state information that will be used at some point by runtime
components, or by your service implementation, like the example described for the IContextChannel
extension object.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-43
Accessing Host Extensions

Key Points
You can use extensions to maintain state for different scopes of your service, to configure the behavior of
your service, and to add functionality to various parts of your service. For example, you can create a
service host extension that will perform special processing whenever a host opens or closes.

Note: To see an implementation of a service host extension that adds functionality to the Opened and
Closed events of the service host, see Module 3, "Hosting Microsoft Windows Communication
Foundation Services".
The following example shows an extension that provides a singleton instance of a log manager that can
be accessed from anywhere in the service.
[Visual C#]
public class SingletonLoggerExtension : IExtension<ServiceHostBase>
{
public LogManager Logger { get; private set; }

public SingletonLoggerExtension(string outputLogFile)
{
Logger = new LogManager(outputLogFile);
}

public void LogMessage(string message)
{
Logger.LogMessage(message);
}

public void Attach(ServiceHostBase owner)
{
Logger.Initialize();
}
8-44 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

public void Detach(ServiceHostBase owner)
{
}
}

[Visual Basic]
Public Class SingletonLoggerExtension
Implements IExtension(Of ServiceHostBase)
Private privateLogger As LogManager
Public Property Logger() As LogManager
Get
Return privateLogger
End Get
Private Set(ByVal value As LogManager)
privateLogger = value
End Set
End Property

Public Sub New(ByVal outputLogFile As String)
Logger = New LogManager(outputLogFile)
End Sub

Public Sub LogMessage(ByVal message As String)
Logger.LogMessage(message)
End Sub

Public Sub Attach(ByVal owner As ServiceHostBase)
Implements IExtension(Of ServiceHostBase).Attach
Logger.Initialize()
End Sub

Public Sub Detach(ByVal owner As ServiceHostBase)
Implements IExtension(Of ServiceHostBase).Detach
End Sub
End Class

Note: Using extensions for singletons gives you more flexibility than using the standard singleton design
pattern or static classes, because with extensions, you can also declare singleton objects for scopes other
than the entire service. For example, you can create a singleton extension that you can apply to the
operation context, meaning all the runtime components and the service implementation code share the
same singleton object, while other operation contexts have their own singleton object. This behavior can
be very hard to achieve when using the standard singleton design pattern, or when using static classes.
Once you attach the extension to the host, a logger instance is created and becomes accessible to anyone
who needs it. To add this extension to the service host, you will need to use the service host's Extensions
collection, as demonstrated in the following code.
[Visual C#]
ServiceHost host = new ServiceHost(typeof(Calculator));
host.Extensions.Add(new
SingletonLoggerExtension(@"d:\serviceLogs\calculatorLog.txt"));
host.Open();

[Visual Basic]
Dim host As New ServiceHost(GetType(Calculator))
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-45
host.Extensions.Add(New
SingletonLoggerExtension("d:\serviceLogs\calculatorLog.txt"))
host.Open()
After you add the extension to the host, you can use it anywhere you need inside the service. The
following example shows how to use this extension in a service operation.
[Visual C#]
public class Calculator : ICalc
{
public int Add(int a, int b)
{
ServiceHostBase host = OperationContext.Current.Host;

SingletonLoggerExtension extension =
(SingletonLoggerExtension)host.Extensions.
Find<SingletonLoggerExtension>();

int result = a + b;
extension.LogMessage("a + b = " + result.ToString());

return result;
}
. . .
}

[Visual Basic]
Public Class Calculator Implements ICalc
Public Function Add(ByVal a As Integer, ByVal b As Integer)
As Integer Implements ICalc.Add

Dim host As ServiceHostBase = OperationContext.Current.Host

Dim extension As SingletonLoggerExtension =
CType(host.Extensions
.Find(Of SingletonLoggerExtension)(), SingletonLoggerExtension)

Dim result As Integer = a + b
extension.LogMessage("a + b = " & result.ToString())

Return result
End Function
By using the Find<T> method, you can locate a specific extension inside the extension collection. If you
added several instances of the same extension typefor example if the logger extension is added several
times to create different output filesyou can use the FindAll<T> method that returns a collection of
extension objects.
8-46 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lesson 3
Routing

WCF 4 includes a built-in router service that is represented by the RoutingService class.
The routing service resembles a message broker design that you can use as a centralized faade to
manage communication between the clients and the back-end services. The presence of the router layer
allows you to apply advanced communication scenarios such as load-balancing, fail-over, priority based
delivery, and protocol bridging.
In this lesson, you will learn how you can use the WCF routing service to create a rich and powerful
intermediary layer for your services.
Lesson Objectives
After completing this lesson, you will be able to:
Host and configure the routing service according to your needs.
Support several message exchange patterns.
Define various message filters to be used as part of the routing decision-making process.
Perform protocol bridging where the transport and binding of the client and the back-end service
can differ.
Define endpoint backup lists for providing fail-over solutions.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-47
The Benefits of Routing

Key Points
With the progression of SOA throughout the years, more and more systems are being designed as
services. As more services deploy, and the interaction between services becomes more complex, you
might need to use a message broker design to enable better agility and reliability.
The router service is an implementation of a message brokerit receives request messages from different
clients, and routes each message to the appropriate back-end service. For example, when a person
decides to send a letter to a specific recipient, he or she writes the recipient's address on the envelope and
submits it to the local post office. The post office acts as the router serviceit locates the right recipient,
and delivers the envelope.
A router service makes the location and implementation of your back-end services transparent to your
clients. The client is aware only of the router service's location, in order to get a response. The router
model is a powerful model that enables you to shield your services from the clients by implementing a
centralized location where you can manage all communication as you see fit.
You can implement a load-balancing solution as part of your router service decision-making process. In
the scope of the router service, you can examine the request message and then make decisions according
to the actual message content.
Furthermore, you can implement a failover solution to improve reliability. The router service can continue
routing the message to other services that are able to handle the request, one after another, until the call
succeeds.
Another scenario where you may find a router service beneficial is protocol bridging. Protocol bridging
allows you to define the endpoints of your back-end services in their optimized internal form, and still
expose an endpoint with a more interoperable binding, to clients with different technologies. The bridge
is the router service that enables communication despite the different bindings.
8-48 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Finally, a router service can assist you with service versioning problems. The router service is an
intermediary layer where you can choose to forward the request message to any target service, which
allows you to manage numerous published versions of the services, and route messages appropriately, or
make transformations to resolve version compatibility issues.
Question: How can a routing service help to improve the reliability of a service?
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-49
Introduction to the WCF Routing Service

Key Points
WCF 4 introduces a new built-in router service implementation in the
System.ServiceModel.Routing.RoutingService class, which is located in the
System.ServiceModel.Routing assembly.
The router service is just like any other WCF service that you can host. You define its endpoints and
configure it using a routing configuration, which will be covered later in this chapter. The routing service
implements several interfaces; each reflects a specific message exchange pattern, and whether or not it is
session-aware:
ISimplexDatagramRouter. Reflects a one-way message exchange.
ISimplexSessionRouter. Reflects a one-way message exchange with a session-aware channel.
IRequestReplyRouter. Reflects a request-reply message exchange.
IDuplexSessionRouter. Reflects duplex communication using a callback contract.
The following example demonstrates how you can configure the routing service with an endpoint to
support a request-reply message exchange through the NetTCP Binding.
<system.serviceModel>
<services>
<service name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add
baseAddress="net.tcp://localhost:9021/routingservice/" />
</baseAddresses>
</host>

<endpoint
address="requestReply"
binding="netTcpBinding"
8-50 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
</services>
</system.serviceModel>
When you define the routing service endpoints, you need to determine the type of the contract that you
wish to expose. You should choose to expose all the contracts that represent the appropriate channels
that are used for communicating with the back-end service.
The client sends the request message to the appropriate endpoint of the router service, and the router
service then forwards the request to the matched target service. The routing service determines the target
service by evaluating every message against a set of message filters that represent the routing rules. If
more than one service matches the filters, the message is multicast to all of them if the communication is
one-way or duplex, whereas in request-reply message exchange, only the first service match will be called.
Error Handling
An error in the routing service is a communication or processing error that occurs while trying to deal
with the request message. In cases where the message delivery to the target service works, and a fault
message is returned from the service, this is not identified as an error within the routing service layer, and
the fault message is simply sent back to the client as the reply message.
If an error occurs while trying to communicate with the target servicesuch as a general communication
exception or a timeout exceptionthe routing service falls back to a backup listif one is definedand
resends the message to new targets until one is successful. This will be covered in more detail later in this
module.
Finally, in case of an error, the routing service traces the exception details onto the reply message as a
message property named Exceptions. This allows you to access the details by implementing a message
inspector, and logging the exception, for example.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-51
Configuring Routing Using Message Filters

Key Points
The routing service process of determining the appropriate target services is controlled using message
filters, which represent the routing rules. Message filters are grouped into filter tables, and can be
configured in code or in the application configuration file.
You define each message filter with a name, a certain filter type, and its details, in the routing
configuration filters collection. Then, you use the defined filters as part of a filter table by connecting
filters with client endpoints. If the filter is matched upon a request, the client endpoint that is configured
with that filter is used to call the back-end service.
In addition, you can define different priority levels for a filter entry within the filter table. Filters are
evaluated from the highest priority to the lowest, and once a matching filter is found, the routing service
routes the request and stops processing filters with lower priority.
The following example demonstrates how you can configure the router service with an endpoint and
define a message filter.
[Visual C#]
private static void ConfigureRouterViaCode(ServiceHost host)
{
string routerAddress = "http://localhost:8000/router";
string clientAddress = "http://localhost:8000/calculator";
Binding routerBinding = new BasicHttpBinding();
Binding clientBinding = new BasicHttpBinding();

host.AddServiceEndpoint(
typeof(IRequestReplyRouter), routerBinding, routerAddress);

ContractDescription contract =
ContractDescription.GetContract(typeof(IRequestReplyRouter));

ServiceEndpoint client = new ServiceEndpoint(
8-52 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
contract, clientBinding, new EndpointAddress(clientAddress));

//create a new routing behavior
List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>();
endpointList.Add(client);

RoutingConfiguration routingConfig = new RoutingConfiguration();
routingConfig.FilterTable.Add(
new MatchAllMessageFilter(), endpointList);

RoutingBehavior myRoutingBehavior =
new RoutingBehavior(routingConfig);

host.Description.Behaviors.Add(myRoutingBehavior);
}

[Visual Basic]
Private Shared Sub ConfigureRouterViaCode(ByVal host As ServiceHost)
Dim routerAddress As String = "http://localhost:8000/router"
Dim clientAddress As String = "http://localhost:8000/calculator"
Dim routerBinding As Binding = New BasicHttpBinding()
Dim clientBinding As Binding = New BasicHttpBinding()

host.AddServiceEndpoint(
GetType(IRequestReplyRouter), routerBinding, routerAddress)

Dim contract As ContractDescription =
ContractDescription.GetContract(GetType(IRequestReplyRouter))

Dim client As New ServiceEndpoint(
contract, clientBinding, New EndpointAddress(clientAddress))

'create a new routing behavior
Dim endpointList As New List(Of ServiceEndpoint)()
endpointList.Add(client)

Dim routingConfig As New RoutingConfiguration()
routingConfig.FilterTable.Add(
New MatchAllMessageFilter(), endpointList)

Dim myRoutingBehavior As New RoutingBehavior(routingConfig)

host.Description.Behaviors.Add(myRoutingBehavior)
End Sub


Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-53
Configuring Routing Endpoints and Filters

Key Points
The following XML example demonstrates a simple routing configuration.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UseRouting">
<routing filterTableName="MyFilterTable" />
</behavior>
</serviceBehaviors>
</behaviors>

<routing>
<filters>
<filter name="MatchAllFilter" filterType="MatchAll" />
</filters>
<filterTables>
<filterTable name="MyFilterTable">
<add filterName="MatchAllFilter" endpointName="CalcService" />
</filterTable>
</filterTables>
</routing>

<client>
<endpoint name="CalcService"
address="http://localhost:8080/WCFCalcService"
binding="basicHttpBinding"
contract="*" />
</client>
</system.serviceModel>

As demonstrated in this previous example, you can configure the routing details using the routing
configuration section as part of the system.serviceModel section.
8-54 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
The routing configuration contains the following sections:
Filters. You define the message filters in this section.
Filter Tables. In this section, you define both the message filter tables that contain the desired filters,
and the name of the endpoint that will be used to forward the messages, from the list of endpoints
configured in the client section of the configuration file.
Backup Lists. In this section, you define a list of named client endpoint definitions to be called in case
the primary back-end service fails to execute.
Namespace Table. In this section, you configure namespace definitions that you can use with message
filters based on XPath queries.
In the example above, the configured filter table is attached to the routing service through a service
behavior. The filter table contains a single filter of a MatchAll filter type. This means that every request
message will match this filter, and the related client endpoint will be used to call the back-end service. In
this case, the CalcService client endpoint is used.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-55
Using Custom Filter Types and Content-Based Routing

Key Points
Message filters contain the core logic that is used to determine the target back-end services to which the
request message will be routed. WCF includes a rich set of built-in filter types that you can use:
Action. Filter according to the request's Action SOAP header.
Endpoint Address. Filter according to the request's To header data.
Endpoint Address Prefix. Filter according to the request's To header data prefix.
And. Combine filters that are both required to match.
Custom. Define a custom message filter implementation.
Endpoint Name. Filter according to the name of the service endpoint on which the request arrived.
Match All. Match every incoming request.
XPath. Filter according to an XPath query of the request content.
With XPath-based filters, you can define the XPath query of the entire request message, including the
contents of the message body. This enables content-based routing. In order to be able to process XPath
queries of the message body, you need to enable it in the configuration as follows:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UseRouting">
<routing routeOnHeadersOnly="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
8-56 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Finally, WCF provides you with the ability to implement a custom message filter and a custom message
filter table for applying custom filtering functionality.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-57
Using Routers for Protocol Bridging

Key Points
WCF's routing service includes an implementation for protocol bridging between the clients and the
back-end services. The protocol bridging implementation supports transformations between SOAP
message versions 1.1 and 1.2, with or without WS-Addressing. In addition, the routing service allows you
to use different transport protocols, such as HTTP or Transmission Control Protocol (TCP).
This means that the transport and binding on the client and back-end service are not required to match.
This allows you to design your back-end services with internal communication settings optimized for your
needs, without taking into consideration various clients with different technologies.
For example, you may consider exposing the back-end services using a NetTCP Binding with binary
message encoding for optimization purposes. If a client requires access through HTTP, you can expose a
compatible endpoint in the router service. The client will communicate with the router service, which will
perform the necessary bridging to transmit the message properly to the back-end service.
SOAP message bridging is enabled by default; the following example shows how you can disable it.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UseRouting">
<routing soapProcessingEnabled="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Even though protocol bridging can bridge different bindings, the message exchange pattern always has
to match. For example, you cannot use a request-reply message exchange pattern on the client-side, and
a one-way message exchange pattern on the service-side.
8-58 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Routers to Mask Service Unavailability

Key Points
The routing service provides you with a built-in failover implementation where you can define backup lists
that contain several named client endpoint entries to use if the primary target service fails. Backup lists
enable you to improve your system's reliability seamlessly.
The following XML example demonstrates how you can configure a backup list for a specific filter entry
that is defined in the filter table.
<system.serviceModel>
<routing>
<filters>
<filter name="MatchAllFilter" filterType="MatchAll" />
</filters>
<filterTables>
<filterTable name="MyFilterTable">
<add filterName="MatchAllFilter"
endpointName="CalcService"
backupList="backupEndpointList" />
</filterTable>
</filterTables>
<backupLists>
<backupList name="backupEndpointList">
<add endpointName="CalcService2" />
</backupList>
</backupLists>
</routing>

<client>
<endpoint name="CalcService"
address="http://localhost:8080/WCFCalcService"
binding="basicHttpBinding"
contract="*" />

<endpoint name="CalcService2"
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-59
address="http://localhost:8081/WCFCalcService2"
binding="basicHttpBinding"
contract="*" />
</client>
</system.serviceModel>
In this example, when a request comes in, the MatchAll filter is matched, and the client endpoint
CalcService is used. If there is an error, the next endpoint defined in the backup list is used (CalcService2),
and so onuntil the call succeeds.
8-60 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Routers for Multicast Messaging

Key Points
The routing service supports multicast messaging where multiple services can receive a single incoming
request message simultaneously. Multicast is enabled when a request is matched against numerous
message filters.
Multicast is supported only for one-way and duplex message exchange patterns. When using a request-
reply message exchange pattern, the first match will be usedthere is no practical reason for multiple
service invocations if the client needs a single reply to be returned.
The following XML example demonstrates a scenario where multicast will be used.
<system.serviceModel>
<routing>
<filters>
<filter name="MatchAllFilter" filterType="MatchAll" />
</filters>
<filterTables>
<filterTable name="MyFilterTable">
<add filterName="MatchAllFilter"
endpointName="CalcService" />

<add filterName="MatchAllFilter"
endpointName="CalcService2" />
</filterTable>
</filterTables>
</routing>

<client>
<endpoint name="CalcService"
address="http://localhost:8080/WCFCalcService"
binding="basicHttpBinding"
contract="*" />

<endpoint name="CalcService2"
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-61
address="http://localhost:8081/WCFCalcService2"
binding="basicHttpBinding"
contract="*" />
</client>
</system.serviceModel>
In this example, there will be two matching filters for every given request. In case the message exchange
pattern is one-way or duplex, both client endpoints CalcService and CalcService2 will receive the message.
8-62 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lesson 4
Workflow Services

In this lesson, you will learn about the fundamentals of the Windows Workflow Foundation. You will also
learn how Workflow Services combine the Windows Workflow Foundation and WCF services. A Workflow
Service is a WCF service that is implemented as a workflow.
Lesson Objectives
After completing this lesson, you will be able to:
Design and implement a Workflow Service.
Define a WCF service using a visual designer.
Correlate client calls to specific workflow instances.
Consume a WCF service from within a workflow.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-63
Introduction to Workflow Foundation

Key Points
Declarative programmingas opposed to imperative programmingdeals with the "What" instead of the
"How". Consider the following code segments, and compare their imperative and declarative nature:
Imperative
[Visual C#]
static void Main(string[] args)
{
Console.WriteLine("Hello");
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine("World");
}

[Visual Basic]
Shared Sub Main(ByVal args() As String)
Console.WriteLine("Hello")
Thread.Sleep(TimeSpan.FromSeconds(5))
Console.WriteLine("World")
End Sub
Declarative (using XAML)
<Activity x:Class="DeclarativeXamlHelloWorld.Workflow"
xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Sequence>
<WriteLine Text="Hello" />
<Delay Duration="[TimeSpan.FromSeconds(5)]" />
<WriteLine Text="World" />
</Sequence>

8-64 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
</Activity>
Code behind
[Visual C#]
static void Main(string[] args)
{
WorkflowInvoker.Invoke(new Workflow1());
}

[Visual Basic]
Shared Sub Main(ByVal args() As String)
WorkflowInvoker.Invoke(New Workflow1())
End Sub
Declarative (XAML in a visual designer)

Notice that the imperative code tells the computer how to do the task by calling the Console.WriteLine
method, and instructing it to write "Hello" to the console, asking the current thread to sleep for five
seconds, and then calling the Console class again. The XAML code describes a sequence of activities that
in turn, describe what to do in each activity. Each activity knows how to execute its task, but this is not
reflected in your code.
XAML is a way to describe object graphs. You can write the same workflow using Microsoft Visual C#:
Declarative (using code)
[Visual C#]
static void Main(string[] args)
{
Sequence s = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Hello"
},
new Delay
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-65
{
Duration = TimeSpan.FromSeconds(5)
},
new WriteLine
{
Text = "World"
}
}
};
WorkflowInvoker wfInvoker = new WorkflowInvoker(s);
wfInvoker.Invoke();
}

[Visual Basic]
Shared Sub Main(ByVal args() As String)
Dim s As Sequence = New Sequence()

s.Activities.Add(
New WriteLine With {.Text = "Hello"})

s.Activities.Add(
New Delay With {.Duration = TimeSpan.FromSeconds(5)})

s.Activities.Add(
New WriteLine With {.Text = "World"})

Dim wfInvoker As New WorkflowInvoker(s)
wfInvoker.Invoke()
End Sub
The WorkflowInvoker class accepts an activity, and invokes it when told to.
Declarative programming provides many advantages. It is much easier to tell the computer what to do
instead of instructing it with many low-level details regarding the way to execute a task. High-level
constructssuch as a workflowdecouple the business logic from the execution engine.
When using workflow declarative programming, activities become the language building block. A
workflow is built from a collection of activities, and each of them may contain additional activities.
Programming a Model of a Business Process
Software design is about modeling. As a software architect and designer, you take the real worldthe
problem domainand create a model of this world in your application. Next, you use this model to
provide the solution. For example, in object-oriented design, you define a set of classes and subclasses as
the foundation for your applicationthis is the model. The instantiation of these classes and the
interaction between them in your code provides the specific solution. When dealing with business
processes, workflow activities are the building blocks that describe the model. As a software designer, you
define your custom activities. Combining them with the predefined activities, you create a model, or a
domain specific language (DSL). As a business domain expert, you can take these activities and develop
your business workflows.
Persistence and Tracking for Long-Running Applications
As a business applications architect, you probably concern yourself with software qualities such as high
availability, redundancy, scalability and system health monitoring. Windows Workflow 4 provides some of
these abilities by enabling workflow instances to be persisted to a database. Once a workflow instance is
persisted, it can be removed from the host memory leaving more resources for other running instances.
Future eventssuch as calling to a persistent workflow instancewill wake up the workflow instance by
8-66 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
desterilizing its state from the database. This may happen days and weeks after the workflow instance has
fall to sleep, and even can take place in another host process on another machine. This provides the basis
for handling long-running workflows with all good software architecture and design abilities.
To track the status of your workflow instances without the need to call them (and thus reload them if they
are persisted), Windows Workflow 4 provides a Workflow Tracking facility. The Workflow Tracking
infrastructure emits tracking records in various occasions, such as when a workflow instance starts or
completes. You can issue your own custom tracking record from your custom activity. This will enable you
to provide business-related information. Tracking participants can subscribe to get tracking records,
process them, and if needed, store them in a file or database. Workflow 4 comes with pre-defined Event
Tracing for Windows (ETW) tracking participant, allowing the administrator to view the current status of
all executing workflows.
Program Visualization Using the Workflow Designer
The workflow designer main area is your workflow canvas. You drag and drop onto it activities from the
toolbox. You connect lines and enter text in activity text boxes to visually program your business process.
You can define variables, change activity properties, and navigate the activities tree.
The idea is to build your domain-specific language by developing custom activities that enable modeling
the problem domain. Because you will use those activities as visual elements, you should provide their
look and behavior by creating a custom activity designer. Besides extending the workflow visual language,
you can also host the workflow designer in your application with a set of custom and predefined activities.
This provides a truly visual language for a problem domain expert. Your application becomes a host for
workflows that will be developed in the field.
Narrow the Gap Between the Business and the Code
Most software designs are built in layers. In the low-level layer, you can find the classes and methods that
deal with the "How"these are the workers that know how to perform the low-level tasks such as reading
from a file or updating a table. The higher-level code deals with management and orchestration.
In Workflow Foundation, activities represent the workersthey call the low-level code to fulfill the specific
task, while the workflow instance is the management layer, the orchestrator. Because the orchestration
and the management are built in a visual language by domain experts, the gap between the business and
the code is much smaller. Even if as a developer you build the workflow, a domain expert can view and
understand it. C# code, on the other hand, cannot be understood by anyone who is not a C# developer.
Question: Why do workflow instances need to be persisted?
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-67
Introduction to Workflow Services

Key Points
Workflow Services is the outcome of combining WCF with Workflow Foundation. Using Workflow
Services, workflows can be exposed as a service and consume other services. Because most services expose
high-level interfaces (contracts), it is reasonable to implement a contract using a workflow. WCF provides
the contract, Workflow Foundation provides the process, and together we have a WCF contract for a
business logic process, a service that implements a process with a well-defined communication protocols
that WCF supports.
When you inspect a service contract, you do not really know which message you should call first, what the
correct message sequence is, and how messages are related to each other. The workflow defines the
protocol, and is ready to accept messages according to that protocol.
You can mark the Receive activity with the CanCreateInstance Boolean property. This will bring a new
workflow instance to life. Additional calls to the same workflow instance will continue the protocol, until
you reach the end of the workflow.
Workflow Foundation is a good foundation for long-running processes. Workflow Services provides a
long-running service with the ability to persist its state in a persistence database, and a mechanism to
load it automatically whenever a service method is called.
A business process is usually built upon many smaller business processes. For example, a shopping
transaction may include calls to inventory service, to a payment service, to a fraud detection service, and
to a shipment service. A workflow can orchestrate this kind of business process.
You can host Workflow Services in any workflow host that also provides WCF hosting, but Windows
Server AppFabric is the best host available for Workflow Services.
8-68 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Creating Workflow Services with Visual Studio 2010

Key Points
You can add messaging activities to any workflow, but it is much easier to start your Workflow Service
project by selecting the WCF Workflow Service Application project template under the Microsoft Visual
Basic or Visual C# Workflow or WCF templates in Visual Studio 2010. If you need to create a workflow
service library, you will also find a project template for that. Visual Studio 2010 will generate the workflow
declarative XAML file for you, as well as the App.config configuration file.
After creating the project, you will have a Sequence activity named Sequential Service that implements a
ReceiveAndSendReply composite activity.

The Visual Studio 2010 designer toolbox contains the Messaging category. This category provides
activities such as Send, Receive, SendAndReceiveReply, ReceiveAndSendReply, and other messaging-
related activities.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-69

When you start the project under Visual Studio 2010 debugger, Visual Studio 2010 hosts the workflow in
an ASP.NET Development Server, and runs the default WCF Test Client.
8-70 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Implementing a Workflow Service

Key Points
After inserting a Receive activity into your workflow, you need to define its contract. Currently, Workflow
Foundation 4 does not provide a way to use an existing contract from a Web Services Description
Language (WSDL) file or a contract assembly (.NET interface). You need to define the contract using the
Workflow Foundation designer.
You can also edit the .xamlx file in the XML code view, by right-clicking on the Workflow.xaml file in the
Solution Explorer window, and then choosing View Code from the context menu.

The ServiceContractName property is the nameincluding the XML namespaceof the service contract.
The OperationName property is name of the current operationif you defined a contract using a .NET
interface, this is the same as the name of the interface method. Clicking on the ellipsis () button next to
the Content property opens the message Content Definition dialog box. The content information you
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-71
input in the content definition is the same as the parameters of the interface method if you defined a
contract using a .NET interface.

In the Content Definition dialog box, you have two choices:
Use the Message content definition. You provide a variable that will hold the incoming message data.
The Message type should be the variable type, or a base class of it. If you choose a base class, you
need to provide all possible derived types in the KnownTypes collection.
Use parameter list. You can have one or more parameters. You can map each parameter to a
workflow variable.


Note: Workflow variables are like programming language variableseach variable has type, holds data,
and has a scope.
Notice that the CanCreateInstance property in the Properties window is set to true. This means that
when a call is made to the service, a new workflow instance should be created. Although this is not the
first activity in the workflow, the workflow will run from its first activity. The Workflow Foundation
infrastructure creates a new workflow when the CanCreateInstance property is set to true, and there is
no suitable existing instance to handle the call. How the infrastructure decides when to use an existing
workflow instance will be discussed in the following slides.
8-72 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using the Workflow Services Messaging Activities

Key Points
The basic messaging activities provide the ability to listen for and accept WCF incoming messages, to
send a reply as a response to an incoming message, to call a service, and to wait for a reply from a service
that you called. In many cases, you will use Send and Receive in a sequence. For these cases, there are two
Visual Studio templates: ReceiveAndSendReply, and SendAndReceiveReply.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-73
Declaring Workflow Service Contracts

Key Points
The service contract is specified declaratively in the properties of the Receive and Send activities. You
need to define the contract using the workflow designer (see the previous slides). You can also edit the
.xamlx file in the XML code view:
<Receive DisplayName="ReceiveRequest" OperationName="GetData"
ServiceContractName="contract:IService" CanCreateInstance="True">
. . .
<ReceiveMessageContent>
<p:OutArgument x:TypeArguments="x:Int32">[data]</p:OutArgument>
</ReceiveMessageContent>
</Receive>

<SendReply Request="{x:Reference Name=__ReferenceID0}"
DisplayName="SendResponse">
<SendMessageContent>
<p:InArgument x:TypeArguments="x:String">[data.ToString()]</p:InArgument>
</SendMessageContent>
</SendReply>
When you add a service reference to your Workflow Foundation project using the Visual Studio 2010 Add
Service Reference dialog box, Visual Studio 2010 generates custom activities for each of the service
operations. For example, the following screen capture shows a GetData service operation that became
available once a service reference was added to the project:

To consume the service, simply drag and drop the custom activity onto your workflow design surface.
8-74 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Using Message Correlation

Key Points
When a new message arrives, the Workflow Foundation infrastructure needs to know how to dispatch this
messagefor example, to which activity of which workflow instance the message should be delivered. The
operation name defines the target activity, but the identity of the instance is not a trivial part of the
message. We need a well-known protocol between the client (caller) and the workflow host that will
define when to create a new instance, and when to deliver the message to an existing instance. This
protocol provides the Workflow Foundation infrastructure the missing piece of information for
performing the correlation between the incoming message and the target instance.
Correlation means that the client provides a piece of data that the Workflow Foundation infrastructure
uses to dispatch the message to the correct workflow instance, bringing this instance back from
persistence storage, if necessary.
There are two methods of correlation: context-based and content-based. When using context-based
correlation, the workflow infrastructure puts a unique ID that represents the workflow instance in the
header of the response message. When the same client calls the workflow instance again, this unique ID is
passed in the incoming message header, providing to the workflow infrastructure the information
necessary to call the existing workflow instance. When using an HTTP binding, the context can be put
inside a cookie, which is automatically sent back to the server with each request. The following XML
fragment is an example of a context message header.
<Context xmlns="http://schemas.microsoft.com/ws/2006/05/context">
<Property name="instanceId">
52e6ca00-a33b-40b0-8ea3-8df9433ae884</Property>
</Context>
WCF provides a set of context bindings that handle the workflow instance context information. These
bindings are the WS-HTTP Context Binding, NetTCP Context Binding, and BasicHTTP Context Binding.
They are the same bindings as the pre-defined, non-context-aware WS-HTTP Binding, NetTCP Binding,
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-75
and BasicHTTP Binding, with the addition of the context binding element that performs the context
manipulation.
Content-based correlation is performed by referring to a part of the message body as an instance
identifier. For example, if you pass a userID as a parameter to each service operation invocation, you can
use an XPath expression that refers to the message body element that contains the userID parameter, and
the infrastructure will use this value as the correlation identifier.
You do not need to write the XPath expression manually. The workflow designer provides a dialog box
that allows you to choose the parameter from the message signature, and then converts it to an XPath
expression on your behalf.
Constructing XPath using message parameters

XPath Queries after being converted

The dialog box in the first screen shot allows you to choose the parameter that holds the unique value
representing the current workflow instance. The result of this action is shown in the second dialog box.
The Key value key1 has the XPath expression that will be used to extract the correlation value from the
WCF message body.
Because content-based correlation is not based on a session, it can be used to correlate calls that come
from different clients at different times. For example, a specific instance of a shopping cart workflow
process can receive messages from different user sessions, and from different client machines.
8-76 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Hosting Workflow Services in AppFabric

Key Points
Windows Server AppFabric was designed to host both WCF services and Workflow Foundation services,
using Internet Information Services (IIS) and Windows Process Activation Service (WAS) as its
infrastructure.

Note: For more information about Windows Server AppFabric as a host of WCF services and as a
monitoring environment, see Module 3, "Hosting Microsoft Windows Communication Foundation
Services ".
AppFabric can monitor Workflow Foundation services using the same Dashboard tool that is used for
monitoring WCF services. With the AppFabric Dashboard, you can monitor various aspects of your
Workflow Foundation services, including:
Persisted workflow instances. This view displays running and suspended persisted instances,
enabling you to: identify services with the most suspended instances, resume a suspended
instance, and identify durable Workflow Foundation services that have the current highest
demand.
Workflow instance history. This view shows a historic overview of all workflow instance
activations, failures, and completions, over a specified period of time. You can use this view to
identify Workflow Foundation services that: have high demand, have the most instance failures,
and instances that are recoverable and those that are not.
Using AppFabric, you can also configure the Workflow Foundation persistence and tracking, and view
persisted and tracked instances, as shown in the following screen shot.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-77

8-78 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lab: Advanced Topics

Lab Objectives
After completing this lab, you will be able to:
Use message inspectors and behaviors.
Attach and access host extensions.
Configure and use routing.
Implement asynchronous invocation.
Implement workflow services.
Introduction
In this lab, you will be using message inspectors and behaviors, attaching and accessing host extensions,
configuring and using routing, implementing asynchronous invocation, and implementing workflow
services.
Lab Setup
For this lab, you will use the available virtual machine environment. Before you begin the lab, you must:
Start the 10263A-SVR1 virtual machine, and then log on by using the following credentials:
User name: Administrator
Password: Pa$$w0rd

Note: You can perform tasks in this lab by using either Microsoft Visual Basic or Microsoft Visual C#. If
you are using Visual C#, refer to the steps provided in Section 1 of the lab page. If you are using Visual
Basic, refer to the steps provided in Section 2 of the lab page.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-79
Lab Scenario

The business operations of Fabrikam have been carefully examined by consultants for Litware Inc., a large
investment company. The consultants have identified a set of new business requirements that you must
implement as a condition for their involvement with Fabrikam.
The ticketing bridge that you created converts request response messaging into One-Way calls. The
consultant noticed that there is a tight coupling between the bridge and the ticketing service. The bridge
that you created implements the Ticketing contract. The consultant argued that a bridge is a messaging
infrastructure, and it should not be bound to a business contract.
You have been tasked with creating a different bridge. It should be simple, agile, and not bound to any
business contract. Minor changes in the ticketing service are allowed. The consultant advised you to use
custom headers, behaviors, and message inspectors to fulfill the task. The bridge will be entitled "Http
Bridge", because it forwards messages without any dependency on their content.
To scale up and address the rise of concurrent requests, you should modify the Pricing service so that it
caches pricing rules that it retrieves from the database. You should store the cached rules in the service
host extension collection.
One of the customer's feedbacks was that pricing for VIP users is not as fast as was promised. A new
instance of the pricing service was created, especially for these customers. You have been asked to use the
built-in message routing introduced in WCF 4 to establish a content-based load balancer that will route
VIP customer requests to the special service.
When customers pay with credit cards, you have been asked to use Workflow Foundation to ensure that
three different requests are sent: Init, Authorize, and Execute.
Finally, in view of customer complaints, you are requested to support asynchronous operations in the
HallState service, which reports the current condition of the event hall.
8-80 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Section 1: Visual C#
Exercise 1: Using Message Inspectors and Behaviors
The main tasks for this exercise are as follows:
1. Open the starter solution
2. Add the new bridge and message forwarder contracts
3. Write the implementation of the HTTP Bridge contract
4. Create a message inspector
5. Create a custom behavior as an attribute
6. Use the custom behavior attribute
7. Implement the callback channel
8. Configure the SimpleServiceHost for message logging
9. Use the client application to call the HTTP Bridge service
10. Use the SvcTraceViewer utility
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M08\CS folder, run setup.bat.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M08\CS folder.
Task 2: Add the new bridge and message forwarder contracts
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Add code to the IBridge interface which handles all
incoming messages. This opens the TicketingServiceContracts.cs file.
3. Add the following code to the interface IBridge.
[OperationContract(Action="*", ReplyAction="*")]
Message ProcessMessage(Message message);
4. Double-click the comment TODO: Ex1 Add code to the IBridgeCallBack interface which
handles all incoming messages. This locates the IBridgeCallback interface.
5. Add the following code to the interface IBridgeCallBack.
[OperationContract(IsOneWay=true, Action="*")]
void ProcessResult(Message message);
6. Double-click the comment TODO: Ex1 Add code to the IBridgeOneWayForwarder interface
which handles all incoming messages to locate the IBridgeOneWayForwarder interface.
7. Add the following code to the interface IBridgeOneWayForwarder.
[OperationContract(IsOneWay=true, Action="*")]
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-81
void ProcessMessage(Message message);
8. Save the TicketingServiceContracts.cs file.
Task 3: Write the implementation of the HTTP Bridge contract
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HttpBridge ProcessMessage method.
This opens the HttpBridgeService.svc.cs file.
3. Replace the content of the try block in the ProcessMessage method in class HttpBridge, with the
following code:
// Create a proxy to QueuedTicketingGeneralService
prox = QueuedTicketingGeneralProxyFactory.GetProxy(false);

AutoResetEvent arrived = new AutoResetEvent(false);
// Create a MessagePackage with a wait handle to wait on
//until a response arrives (on another channel)
MessagePackage pack = new MessagePackage()
{MessageArrived = arrived };
MessageCache.Current.SetMessagePack(callId, pack);

//Put the callID inside a header
var header = new MessageHeader<Guid>(callId);
var headerBase = header.GetUntypedHeader(
"CallID", "http://Fabrikam.com");

// Write the header inside the message received from the client.
IncommingMessage.Headers.Add(headerBase);

//Send the message (the original message + the new header)
//to the ticketing service (One-Way)
//Call the ticketing service via MSMQ channel on another thread.
Action<IBridgeOneWayForwarder> del = (
p => p.ProcessMessage(IncommingMessage));
del.BeginInvoke(prox, null, null);

//Wait until result arrives
arrived.WaitOne();

// Clone the message before sending it back
result = MessageCache.Current.GetResponse(callId).Clone();
// Clear the callID header so it will not arrive back to the client.
result.Headers.RemoveAll("CallID", "http://Fabrikam.com");
// Clear the message cache
MessageCache.Current.ClearMessagePack(callId);

return result;
4. Save the HttpBridgeService.svc.cs file.
Task 4: Create a message inspector
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultMessageInspector
AfterReceiveRequest Method. This opens the MessageInspectors.cs file.
3. Replace the content of AfterReceiveRequest method in class
HandleBridgeResultMessageInspector, with the following code:
8-82 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
if (request.Headers.FindHeader("CallID", "http://Fabrikam.com") > 0)
{
var callId = request.Headers.GetHeader<Guid>
("CallID", "http://Fabrikam.com");
var MessageResultPackage =
MessageCache.Current.GetMessagePack(callId);
if (MessageResultPackage != null)
{
//Save the message in the appropriate ResultPackage.
//The message will be forwarded to the client.
MessageResultPackage.Response = buffer;

//Notify a message has arrived.
//When converting Request Response to one way the bridge
//waits on this handle.
MessageResultPackage.MessageArrived.Set();
}
}
return null;
4. Save the MessageInspectors.cs file.
Task 5: Create a custom behavior as an attribute
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultAttribute
ApplyDispatchBehavior method. This opens the ServiceBehaviors.cs file.
3. Add the following code to ApplyDispatchBehavior method:
foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
{
epDisp.DispatchRuntime.MessageInspectors.Add(
new HandleBridgeResultMessageInspector());
}
}
4. Save the ServiceBehaviors.cs file.
Task 6: Use the custom behavior attribute
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Decorate the HttpBridgeCallBack class with the
HandleBridgeResult attribute. This opens the HttpBridgeCallBack.svc.cs file.
3. Decorate the HttpBridgeCallBack class with the HandleBridgeResult attribute. The resulting class
declaration should resemble the following code:
[HandleBridgeResult]
public class HttpBridgeCallBack : IBridgeCallBack
4. Save the HttpBridgeCallBack.svc.cs file.
Task 7: Implement the callback channel
1. Examine the content of the task list.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-83
2. Double-click the comment TODO: Ex1 Implement the QueuedTicketingGeneralService
ProcessMessage method. This opens the QueuedTicketingGeneralService.svc.cs file.
3. Add the following code to ProcessMessage method:
IBridgeCallBack prox;
Message response;

if (request.Headers.FindHeader("CallID", "http://Fabrikam.com") <= 0)
throw new TicketingException(StringsResource.CallIDNotFound);

Guid callId = request.Headers.GetHeader<Guid>(
"CallID", "http://Fabrikam.com");

//Forward the message to the R.R ticketing service.
IRequestChannel ticketingChannel = TicketingRequestChannelFactory.GetProxy();

response = ticketingChannel.Request(request);

//Send the message back to the bridge and then back to the client
prox = HttpBridgeCallBackChannelFactory.GetProxy(false);
using (OperationContextScope scope =
new OperationContextScope(prox as IContextChannel))
{
InjectCallIDHeader(callId);
prox.ProcessResult(response);
}
4. Save the QueuedTicketingGeneralService.svc.cs file.
Task 8: Configure the SimpleServiceHost for message logging
1. In the WCF Service Configuration Editor, open the SimpleServiceHost project's App.config file.
2. Turn on MessageLogging and Tracing.
3. Configure Message Logging to log entire messages, and to log messages at the service level.
4. Save the configuration file.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
6. If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
Task 9: Use the client application to call the HTTP Bridge service
1. Build and run the SimpleServiceHost project without debugging.
2. Start the TicketingOffice.UI client.
3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to view which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
8. When an operation completion message displays, click OK, and then close all the client application
windows.
9. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
8-84 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Task 10: Use the SvcTraceViewer utility
1. Open the Host solution folder from the Solution Explorer window.
2. Double-click the app_messages.svclog file to open it with the Microsoft Service Trace Viewer.
3. If an Error Report window opens, click OK. (This window might display if the file is still opened for
writing by the service host.)
4. On the left Message tab, select the last OrderTicket message. (You might need to expand the width
of the Action column to see the entire string.)
5. In the activity's information (the right side of the window), click the Message tab, and then search for
the CallID SOAP header this is the header that was placed by the message inspector.
6. Close the Microsoft Service Trace Viewer ,and return to Visual Studio 2010.
Results: After this exercise, you will have created a new Bridge contract and implemented it in a service,
created a message inspector and a custom inspector, and used the client application to consume the
service.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-85
Exercise 2: Attaching and Accessing Host Extensions
The main tasks for this exercise are as follows:
1. Create a host extension
2. Attach the extension to the host and use it
Task 1: Create a host extension
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Attach method. This
opens the CacheHostExtension.cs file.
3. Add the following code to the Attach method.
HostCache = HttpRuntime.Cache;
owner.Closed += new EventHandler(owner_Closed);
owner.Faulted += new EventHandler(owner_Faulted);
4. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Detach method to
locate the Detach method.
5. Add the following code to the Detach method.
HostCache = null;
owner.Closed -= owner_Closed;
owner.Faulted -= owner_Faulted;
6. Save the CacheHostExtension.cs file.
Task 2: Attach the extension to the host and use it
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the hosting manager.
This opens the HostingManager.cs file.
3. Add the following code to the CreateHosts method after the TODO comment:
Hosts[item.Name].Extensions.Add(new CacheHostExtension());
4. Save the HostingManager.cs file.
5. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the pricing service host
factory. This opens the PricingServiceHostFactory.cs file.
6. Add the following code to the CreateServiceHost method after the TODO comment.
host.Extensions.Add(new CacheHostExtension());
7. Save the PricingServiceHostFactory.cs file.
8. Double-click the comment TODO: Ex2 Update the code to use the host extension caching. This
opens the PricingService.svc.cs file.
9. Replace the Line rules = GetRulesFromService(policyName); with the following code:
//Look in the rules cache (plugged as a host extension) for the rule
string cacheKey = policyName + DateTime.Today.ToString();
CacheHostExtension cacheHost =
(CacheHostExtension)
(OperationContext.Current.Host.Extensions.Find<CacheHostExtension>());
8-86 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

if (cacheHost != null)
rules = cacheHost.GetItem(cacheKey) as PricingRule[];

//If there are no rules in the cache call the pricing rules service
if (rules == null)
{
rules = GetRulesFromService(policyName);

//put the rules in the cache for future use.
if ((rules != null) && (rules.Count() > 0))
cacheHost.SetItem(cacheKey, rules, DateTime.Today.AddDays(1));
}
10. Save the PricingService.svc.cs file.
Results: After this exercise, you will have created a host extension, attached the extension to the host, and
accessed the extension in the Pricing service.

Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-87
Exercise 3: Configuring and Using Routing
The main tasks for this exercise are as follows:
1. Create the endpoints to be used by the router
2. Add routing configuration
3. Create a routing behavior
4. Host the Routing Service
5. Use the client application to call the Routing service
Task 1: Create the endpoints to be used by the router
1. In the SimpleServiceHost project App.config file, locate the client section.
2. Add the following endpoints to the end of the client section:
<endpoint name="PricingRouterEP"
address="http://localhost:6000/RoutingService/"
binding="basicHttpBinding"
contract="TicketingOffice.Pricing.Contracts.IPricingService" />
<endpoint name="PricingNormalEP"
address="http://localhost:5005/TicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="VipPricingEP"
address="http://localhost:50051/VipTicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="DeadDestination"
address="http://localhost:9999/TicketesPricing"
binding="ws2007HttpBinding" contract="*" />
Task 2: Add routing configuration
1. In the SimpleServiceHost project App.config file, locate the routing section.
2. Add the following filter definitions to the routing element:
<namespaceTable>
<add prefix="pricing" namespace="http://Fabrikam.com"/>
</namespaceTable>

<filters>
<!--Filter according to the policyName parameter sent to the pricing service-->
<filter name="VipPricing"
filterType="XPath"
filterData="//pricing:policyName = 'Vip'"/>
<filter name="NormalPricing"
filterType="XPath"
filterData="//pricing:policyName != 'Vip'"/>
</filters>
3. Add the filter table definitions in the routing section after the filters element that you have added.
<filterTables>
<!-- Set up the Routing Service's Message Filter Table -->
<filterTable name="PricingFilterTable">
<add filterName="VipPricing"
endpointName="VipPricingEP" />
<add filterName="NormalPricing"
endpointName="DeadDestination"
8-88 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
backupList="backupEndpointList"/>
</filterTable>
</filterTables>
4. Add a backup list in the routing section after the filterTables element that you have added.
<!-- Create the backup endpoint list -->
<backupLists>
<!-- Add an endpoint list that contains the backup destination -->
<backupList name="backupEndpointList">
<add endpointName="PricingNormalEP" />
</backupList>
</backupLists>
Task 3: Create a routing behavior
1. In the SimpleServiceHost project App.config file, locate the serviceBehaviors section.
2. Add the following behavior configuration in the serviceBehaviors configuration section:
<!-- Set up the Routing Behavior -->
<behavior name="routingConfiguration">
<routing
filterTableName="PricingFilterTable"
routeOnHeadersOnly="false" />
<serviceDebug
includeExceptionDetailInFaults="true"/>
</behavior>
Task 4: Host the Routing Service
1. In the SimpleServiceHost project App.config file, locate the services section.
2. Add the following service configuration in the services section:
<service behaviorConfiguration="routingConfiguration"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6000/RoutingService/" />
</baseAddresses>
</host>
<!-- Create the Routing Service endpoint -->
<endpoint
address=""
binding="basicHttpBinding"
name="RoutingServiceEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
3. Save the App.config file.
4. Examine the content of the task list.
5. Double-click the comment TODO: Ex3 Add ServiceTypeResolver to the collection. This opens
the HostingManager.cs file.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-89
6. Add the following element to the ServiceTypeResolver collection initialization:
{"System.ServiceModel.Routing.RoutingService",typeof(System.ServiceModel.Routing.RoutingS
ervice)},
7. After adding the previous code, the ServiceTypeResolver definition should resemble the following
code:
static Dictionary<string, Type> ServiceTypeResolver = new Dictionary<string, Type>()
{
// TODO: Ex3 - Add ServiceTypeResolver to the collection
{"System.ServiceModel.Routing.RoutingService",
typeof(System.ServiceModel.Routing.RoutingService)},
{"TicketingOffice.CrmService.CustomerRelationsService",
typeof(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
typeof(CurrencyExchangeService)},
{"TicketingOffice.HallStateService.ReservationsService",
typeof(ReservationsService)},
{"TicketingOffice.PaymentService.TicketsPaymentService",
typeof(TicketsPaymentService)},
{"TicketingOffice.PricingService.TicketsPricingService",
typeof(TicketsPricingService)},
{"TicketingOffice.PricingService.VipPricingService",
typeof(VipPricingService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
typeof(TicketingPricingRulesService)},
{"TicketingOffice.ShowsService.ShowsAndEventsService",
typeof(ShowsAndEventsService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
typeof(GeneralTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingService",
typeof(QueuedTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingGeneralService",
typeof(QueuedTicketingGeneralService)},
{"TicketingOffice.Bridge.TicketingBridge",
typeof(TicketingBridge)},
{"TicketingOffice.Bridge.TicketingBridgeCallBack",
typeof(TicketingBridgeCallBack)},
{"TicketingOffice.Bridge.HttpBridge",
typeof(HttpBridge)},
{"TicketingOffice.Bridge.HttpBridgeCallBack",
typeof(HttpBridgeCallBack)},
{"TicketingOffice.PricingBrokerService.DiscoveryProxyService",
typeof(DiscoveryProxyService)}
};
8. Save the HostingManager.cs file.
Task 5: Use the client application to call the Routing service
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex3 call the pricing routing service. This opens the
OrderTicketWindow.xaml.cs file.
3. Add the following code to the BackgroundTicketOrderWork method, after the TODO comment:
CalculateTicketsPrice(e, parameters);
4. Save the OrderTicketWindow.xaml.cs file.
5. Build and run the SimpleServiceHost project without debugging.
8-90 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
6. Start the TicketingOffice.UI client.
7. In the client's main window, click the Order a ticket button.
8. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
9. From the shows list, select Othello, and from the events list, select the first event in the list.
10. Click the Get hall state button to view which seats are available.
11. Select two available seats, and then click the Order button.
12. When an operation completion message displays, verify that the price is 400 (200 per seat).
13. Click OK, select two other available seats, select the "VIP" check box, and then click the Order button.
14. When an operation completion message displays, verify that the price is 360 (400 minus a 10 percent
discount for VIP customers).
15. Click OK, and then close all the client application windows.
16. Switch to the SimpleServiceHost console window, and examine the console output. Notice that the
VIP Pricing service was called.
17. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Results: After this exercise, you will have created the endpoints to be used by the routing service, added
routing configuration to the routing service, and called the routing service using a client application.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-91
Exercise 4: Implementing Asynchronous Invocation
The main tasks for this exercise are as follows:
1. Use the Asynchronous pattern on the Client
2. Implement and use the Asynchronous pattern on the service
3. Test the Asynchronous client and service
Task 1: Use the Asynchronous pattern on the Client
1. Run the SimpleServiceHost project without debugging.
2. Leave the service host console running, and return to Visual Studio 2010.
3. In the TicketingOffice.UI project, in the Client solution folder, locate the
HallStateServiceReference service reference.
4. Right-click the HallStateServiceReference service reference, and then select Configure Service
Reference.
5. In the Service Reference Settings dialog box, select the Generate asynchronous operations check
box, and then click OK.
6. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
7. Examine the content of the task list.
8. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous client
call. This opens the OrderTicketWindow.xaml.cs file.
9. Add the following code in the AsyncType.ClientAsync switch section, between the TODO comment
and the break statement:
HallStateServiceClient asyncClientProxy = new
HallStateServiceClient("WS2007HttpBinding_IHallStateService");
asyncClientProxy.BeginGetHallState(
SelectedEvent.EventID, GetHallStateCallback, asyncClientProxy);
10. Add the following method to the OrderTicketWindow class, after the GetHallState method:
void GetHallStateCallback(IAsyncResult ar)
{
SeatIndex[] seats;
seats = ((HallStateServiceClient)ar.AsyncState).EndGetHallState(ar);
this.Dispatcher.Invoke(
new Action(() => {ShowAvailableSeats(seats);}));
}
11. Save the OrderTicketWindow.xaml.cs file.
Task 2: Implement and use the Asynchronous pattern on the service
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex4 - Add the IAsyncHallStateService service contract. This
opens the HallStateContract.cs file.
3. Add the following contract code.
[ServiceContract(Namespace = "http://Fabrikam.com")]
public interface IAsyncHallStateService
{
[OperationContract(AsyncPattern=true, Name="GetHallStateAsync")]
8-92 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
IAsyncResult BeginGetHallState(
Guid eventID, AsyncCallback callback, object state);

SeatIndex[] EndGetHallState(IAsyncResult ar);

[OperationContract(AsyncPattern=true, Name="FindTheaterAsync")]
IAsyncResult BeginFindTheater(
string name, int? theaterID,
AsyncCallback callback, object state);

Theater EndFindTheater(IAsyncResult ar);
}
4. Save the HallStateContract.cs file.
5. Double-click the comment TODO: Ex4 Implement the IAsyncHallStateService interface. This
opens the HallStateService.svc.cs file.
6. Make the ReservationsService class implement the IAsyncHallStateService interface. The result
class declaration should resemble the following code.
[ServiceBehavior(
InstanceContextMode=InstanceContextMode.Single,
Namespace = "http://Fabrikam.com")]
public class ReservationsService :
IHallStateService, IReservationService,
IHallManagementService, IAsyncHallStateService
7. Double-click the comment TODO: Ex4 Add IAsyncHallStateService contract implementation.
8. Add the following implementation of the IAsyncHallStateService interface to the
ReservationsService class, after the TODO comment:
public IAsyncResult BeginGetHallState(
Guid eventID, AsyncCallback callback, object state)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"BeginGetHallState",
Thread.CurrentThread.ManagedThreadId));

return manager.BeginGetHallState(eventID, callback, state);
}

public SeatIndex[] EndGetHallState(IAsyncResult ar)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"EndGetHallState",
Thread.CurrentThread.ManagedThreadId));
return manager.EndGetHallState(ar);
}

public IAsyncResult BeginFindTheater(
string name, int? theaterID, AsyncCallback callback, object state)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"BeginFindTheater",
Thread.CurrentThread.ManagedThreadId));
return manager.BeginFindTheater(name, callback, state);
}

Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-93
public Theater EndFindTheater(IAsyncResult ar)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"EndFindTheater",
Thread.CurrentThread.ManagedThreadId));
return manager.EndFindTheater(ar);
}
9. Save the HallStateService.svc.cs file.
10. In the SimpleServiceHost project App.config file, locate the service configuration section of the
TicketingOffice.HallStateService.ReservationsService service.
11. Add an endpoint to the service, with the AsyncHallState address, ws2007HttpBinding binding, and
the TicketingOffice. HallState.contracts.IAsyncHallStateService contract. Set the binding
configuration to use the NoSecurity binding configuration. The resulting endpoint configuration
should look as follows:
<endpoint
address="AsyncHallState"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.HallState.Contracts.IAsyncHallStateService"></endpoint>
12. Save the App.config file.
13. Run the SimpleServiceHost project without debugging.
14. Leave the service host console running, and return to Visual Studio 2010.
15. In the Client solution folder, in the TicketingOffice.UI project, locate the
HallStateServiceReference service reference .
16. Right-click the HallStateServiceREference service reference, and then select Update Service
Reference.
17. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous service
operation. This opens the OrderTicketWindow.xaml.cs file.
18. Add the following code in the AsyncType.ServiceAsync switch section, between the TODO
comment and the break statement:
AsyncHallStateServiceClient asyncServiceProxy = new
AsyncHallStateServiceClient(
"WS2007HttpBinding_IAsyncHallStateService");
seats = asyncServiceProxy.GetHallStateAsync(SelectedEvent.EventID);
ShowAvailableSeats(seats);
19. Save the OrderTicketWindow.xaml.cs file.
Task 3: Test the Asynchronous client and service
1. Run the TicketingOffice.UI client.
2. In the client's main window, click the Order a ticket button.
3. In the OrderTicketWindow window, open the shows list, select Othello, and then from the events list,
select the first event in the list.
4. Click the Get hall state (Async client) button to view which seats are available. Examine the service
host console application outputyou should see the log message Running GetHallState on thread.
8-94 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
5. Return to the OrderTicketWindow window in the client application, and then click the Get hall state
(Async service) button. Examine the service host console application outputyou should see the log
messages Running BeginGetHallState on thread , and Running EndGetHallState on thread .
6. Close all the client application windows.
7. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Results: After this exercise, you will have implemented and used the asynchronous pattern in both the
client and the service.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-95
Exercise 5: Implementing Workflow Services
The main tasks for this exercise are as follows:
1. Open the workflow service project
2. Add activities to the workflow
3. Deploy the CreditCardPayment service to AppFabric using a deployment package
4. Test the CreditCardPayment workflow service
Task 1: Open the workflow service project
1. Open the CreditPayment.xamlx file in the CreditCardPaymentService project.
2. Verify that an empty workflow appears with a single sequence activity, and that the display name of
the activity is Credit Service.
Task 2: Add activities to the workflow
1. Add a ReceiveAndSendReply activity from the Messaging group into the sequence activity.
2. Rename the Receive activity to InitPayment.
3. Drag an InvokeMethod activity from the Primitives group to between the Receive and the
SendReplyToReceive activities.
4. In the new InvokeMethod activity, open the Properties window.
5. In the TargetObject property, type the following:
New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
6. In the MethodName property, type the following: IsPaymentTypeEnabled
7. In the Result property type the following: CreditEnabled
8. Click the ellipses () button in the Parameters collection text box to open the Parameters dialog
box, and complete the first row, and then click OK.
In the Direction column, select In.
In the Type column, select Browse for Types.
In the Type Name text box, type PaymentType, select the PaymentType from the tree, and
then click OK.
In the Value column, enter PaymentType.CreditCard.
Click OK to close the Parameters dialog box.
9. The workflow should display as follows:

8-96 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

10. In the Receive activity, open the Properties window.
11. Select the CanCreateInstance check box.
12. In the ServiceContractName, type: {http://Fabrikam.com/}ICreditCardPaymentService
13. In the SendReplyToReceive activity, open the Properties window.
14. In the Properties window, click the ellipse () button in the Content field to open the Content
Definition dialog box.
15. In the Content Definition window, select Parameters.
16. Set the content to the following values:
Name: Results
Type: Boolean
Value: CreditEnabled
17. Click OK to close the Content Definition dialog box.
18. Add an If activity from the ControlFlow group after the sequence activity.
19. In the If Activity, open the Properties window.
20. In the Condition property, type CreditEnabled.
21. Add a ReceiveAndSendReply activity from the Messaging group into the Then area of the If
activity.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-97
22. Add a Receive activity from the Messaging group, and drag it before the Receive activity that is
already inside the Then area of the If activity. Set the new activity OperationName to
ProvidePaymentDetails, and set the DisplayName to ProvidePaymentDetails.
23. Set the DisplayName of the second Receive activity inside the Then activity to PerformPayment,
and set the OperationName to PerformPayment.
24. Update the display name of the SendReplyToReceive activity in the Then activity to
SendReplyToPerformPayment.
25. In both Receive activities, change the ServiceContractName to
{http://Fabrikam.com/}ICreditCardPaymentService.
26. Right-click the ProvidePaymentDetails activity, select Properties, and set the Content property as
follows:
Name Type Assign To
OrderID Guid OrderID
CustomerID Guid PayingCustomerID
Amount Double Amount
CreditCardNumber String CreditCard

Note: After browsing for a parameter type, some types may appear with their full namespace. For
example, Guid might display as System.Guid.
27. Right-click the SendReplyToPerformPayment activity, and then select Properties.
28. Set the content property as follows:
Name Type Value
PaymentResult Payment PaymentResult
29. Click OK to close the Content Definition dialog box.
30. Add an InvokeMethod activity from the Primitives group between the PerformPayment activity
and the SendReplyToPerformPayment activity.
31. In the InvokeMethod activity, set the properties.
TargetObject: New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
MethodName: PayForOrder
Result: PaymentResult
8-98 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
32. In the Properties window, in the Parameters field, click the ellipses () button, add the following
parameters, and then click OK:
Direction Type Value
In Guid OrderID
In Guid PayingCustomerID
In Double Amount
In PaymentType PaymentType.CreditCard
In String CreditCard
33. Save the CreditPayment.xamlx file.
34. Rebuild the project.
Task 3: Deploy the CreditCardPayment service to AppFabric using a deployment
package
1. Create a Deployment package for the CreditCardPaymentService project.
2. Open the IIS Manager.
3. Import the package that you have created to the Default Web Site, and name it
FabrikamTicketingCreditPayment.
4. Close the IIS Manager.
Task 4: Test the CreditCardPayment workflow service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
2. Add the CreditPayment service, using the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx.
3. Call the InitPayment operation to test the workflow service.
4. After receiving a response, close the Windows Communication Foundation (WCF) Test Client.
5. Open the IIS Manager
6. In the IIS console, open AppFabric Dashboard.
7. Examine the WF Instance History section, and notice that the CreditPayment.xamlx is activated.
8. Close the IIS Manager.
Results: After this exercise, you will have created a workflow service that executes the process of credit
card payment, and then tested it.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-99
Section 2: Visual Basic
Exercise 1: Using Message Inspectors and Behaviors
The main tasks for this exercise are as follows:
1. Open the starter solution
2. Add the new bridge and message forwarder contracts
3. Write the implementation of the HTTP Bridge contract
4. Create a message inspector
5. Create a custom behavior as an attribute
6. Use the custom behavior attribute
7. Implement the callback channel
8. Configure the SimpleServiceHost for message logging
9. Use the client application to call the HTTP Bridge service
10. Use the SvcTraceViewer utility
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M08\VB folder, run setup.bat.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M08\VB folder.
Task 2: Add the new bridge and message forwarder contracts
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Add code to the IBridge interface which handles all
incoming messages. This opens the TicketingServiceContracts.vb file.
3. Add the following code to the interface IBridge.
<OperationContract(Action:="*", ReplyAction:="*")>
Function ProcessMessage(ByVal message As Message) As Message
4. Double-click the comment TODO: Ex1 Add code to the IBridgeCallBack interface which
handles all incoming messages. This locates the IBridgeCallback interface.
5. Add the following code to the interface IBridgeCallBack.
<OperationContract(IsOneWay := True, Action := "*")>
Sub ProcessResult(ByVal message As Message)
6. Double-click the comment TODO: Ex1 Add code to the IBridgeOneWayForwarder interface
which handles all incoming messages to locate the IBridgeOneWayForwarder interface.
7. Add the following code to the interface IBridgeOneWayForwarder.
<OperationContract(IsOneWay := True, Action := "*")>
8-100 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Sub ProcessMessage(ByVal message As Message)
8. Save the TicketingServiceContracts.vb file.
Task 3: Write the implementation of the HTTP Bridge contract
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HttpBridge ProcessMessage method.
This opens the HttpBridgeService.svc.vb file.
3. Change the method declaration so it will implement the IBridge interface.
Public Function ProcessMessage(ByVal IncommingMessage As Message) _
As Message Implements IBridge.ProcessMessage
4. Replace the content of the Try block in the ProcessMessage method in class HttpBridge, with the
following code:
' Create a proxy to QueuedTicketingGeneralService
prox = QueuedTicketingGeneralProxyFactory.GetProxy(False)
Dim arrived As New AutoResetEvent(False)
' Create a MessagePackage with a wait handle to wait on
'until a response arrives (on another channel)
Dim pack As New MessagePackage() With {.MessageArrived = arrived}
MessageCache.Current.SetMessagePack(callId, pack)

'Put the callID inside a header
Dim header = New MessageHeader(Of Guid)(callId)
Dim headerBase = header.GetUntypedHeader("CallID",
"http://Fabrikam.com")

' Write the header inside the message received from the client.
IncommingMessage.Headers.Add(headerBase)

'Send the message (the original message + the new header)
'to the ticketing service (One-Way)
'Call the ticketing service via MSMQ channel on another thread.
Dim del As Action(Of IBridgeOneWayForwarder) = (Sub(p) _
p.ProcessMessage(IncommingMessage))
del.BeginInvoke(prox, Nothing, Nothing)

'Wait until result arrives
arrived.WaitOne()

' Clone the message before sending it back
result = MessageCache.Current.GetResponse(callId).Clone()
' Clear the callID header so it will not arrive back to the client.
result.Headers.RemoveAll("CallID", "http://Fabrikam.com")
' Clear the message cache
MessageCache.Current.ClearMessagePack(callId)

Return result
5. Save the HttpBridgeService.svc.vb file.
Task 4: Create a message inspector
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultMessageInspector
AfterReceiveRequest Method. This opens the MessageInspectors.vb file.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-101
3. Replace the content of AfterReceiveRequest method in class
HandleBridgeResultMessageInspector, with the following code:
Dim buffer As MessageBuffer = request.CreateBufferedCopy(Integer.MaxValue)
If request.Headers.FindHeader("CallID", "http://Fabrikam.com") _
> 0 Then
Dim callId = request.Headers.GetHeader(Of Guid)(
"CallID",
"http://Fabrikam.com")
Dim MessageResultPackage =
MessageCache.Current.GetMessagePack(callId)
If MessageResultPackage IsNot Nothing Then
'Save the message in the appropriate ResultPackage.
'The message will be forwarded to the client.
MessageResultPackage.Response = buffer

'Notify a message has arrived.
'When converting Request Response to one way the bridge
'waits on this handle.
MessageResultPackage.MessageArrived.Set()
End If
End If
Return Nothing
4. Save the MessageInspectors.vb file.
Task 5: Create a custom behavior as an attribute
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultAttribute
ApplyDispatchBehavior method. This opens the ServiceBehaviors.vb file.
3. Add the following code to ApplyDispatchBehavior method:
For Each chDisp As ChannelDispatcher In
serviceHostBase.ChannelDispatchers
For Each epDisp As EndpointDispatcher In chDisp.Endpoints
epDisp.DispatchRuntime.MessageInspectors.Add(
New HandleBridgeResultMessageInspector())
Next epDisp
Next chDisp
4. Save the ServiceBehaviors.vb file.
Task 6: Use the custom behavior attribute
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Decorate the HttpBridgeCallBack class with the
HandleBridgeResult attribute. This opens the HttpBridgeCallBack.svc.vb file.
3. Decorate the HttpBridgeCallBack class with the HandleBridgeResult attribute. The resulting class
declaration should resemble the following code:
<HandleBridgeResult>
Public Class HttpBridgeCallBack
Implements IBridgeCallBack
4. Change the method declaration so it will implement the IBridgeCallBack interface.

8-102 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Public Sub ProcessResult(ByVal l_message As Message) _
Implements IBridgeCallBack.ProcessResult
5. Save the HttpBridgeCallBack.svc.vb file.
Task 7: Implement the callback channel
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex1 Implement the QueuedTicketingGeneralService
ProcessMessage method. This opens the QueuedTicketingGeneralService.svc.vb file.
3. Change the method declaration so it will implement the IBridgeOneWayForwarder interface.
Public Sub ProcessMessage(ByVal request As Message) _
Implements IBridgeOneWayForwarder.ProcessMessage
4. Add the following code to ProcessMessage method:
Dim prox As IBridgeCallBack
Dim response As Message

If request.Headers.FindHeader("CallID", "http://Fabrikam.com") _
<= 0 Then
Throw New TicketingException(StringsResource.CallIDNotFound)
End If

Dim callId As Guid = request.Headers.GetHeader(Of Guid)(
"CallID", "http://Fabrikam.com")

'Forward the message to the R.R ticketing service.
Dim ticketingChannel As IRequestChannel =
TicketingRequestChannelFactory.GetProxy()

response = ticketingChannel.Request(request)

'Send the message back to the bridge and then back to the client
prox = HttpBridgeCallBackChannelFactory.GetProxy(False)
Using scope As New OperationContextScope(
TryCast(prox, IContextChannel))
InjectCallIDHeader(callId)
prox.ProcessResult(response)
End Using
5. Save the QueuedTicketingGeneralService.svc.vb file.
Task 8: Configure the SimpleServiceHost for message logging
1. In the WCF Service Configuration Editor, open the SimpleServiceHost project's App.config file.
2. Turn on MessageLogging and Tracing.
3. Configure Message Logging to log entire messages, and to log messages at the service level.
4. Save the configuration file.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
6. If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
Task 9: Use the client application to call the HTTP Bridge service
1. Build and run the SimpleServiceHost project without debugging.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-103
2. Start the TicketingOffice.UI client.
3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to view which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
8. When an operation completion message displays, click OK, and then close all the client application
windows.
9. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Task 10: Use the SvcTraceViewer utility
1. Open the Host solution folder from the Solution Explorer window.
2. Double-click the app_messages.svclog file to open it with the Microsoft Service Trace Viewer.
3. If an Error Report window opens, click OK. (This window might display if the file is still opened for
writing by the service host.)
4. On the left Message tab, select the last OrderTicket message. (You might need to expand the width
of the Action column to see the entire string.)
5. In the activity's information (the right side of the window), click the Message tab, and then search for
the CallID SOAP header this is the header that was placed by the message inspector.
6. Close the Microsoft Service Trace Viewer ,and return to Visual Studio 2010.
Results: After this exercise, you will have created a new Bridge contract and implemented it in a service,
created a message inspector and a custom inspector, and used the client application to consume the
service.

8-104 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 2: Attaching and Accessing Host Extensions
The main tasks for this exercise are as follows:
1. Create a host extension
2. Attach the extension to the host and use it
Task 1: Create a host extension
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Attach method. This
opens the CacheHostExtension.vb file.
3. Add the following code to the Attach method.
HostCache = HttpRuntime.Cache
AddHandler owner.Closed, AddressOf owner_Closed
AddHandler owner.Faulted, AddressOf owner_Faulted
4. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Detach method to
locate the Detach method.
5. Add the following code to the Detach method.
HostCache = Nothing
RemoveHandler owner.Closed, AddressOf owner_Closed
RemoveHandler owner.Faulted, AddressOf owner_Faulted
6. Save the CacheHostExtension.vb file.
Task 2: Attach the extension to the host and use it
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the hosting manager.
This opens the HostingManager.vb file.
3. Add the following code to the CreateHosts method after the TODO comment:
Hosts(item.Name).Extensions.Add(New CacheHostExtension())
4. Save the HostingManager.vb file.
5. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the pricing service host
factory. This opens the PricingServiceHostFactory.vb file.
6. Add the following code to the CreateServiceHost method after the TODO comment.
host.Extensions.Add(New CacheHostExtension())
7. Save the PricingServiceHostFactory.vb file.
8. Double-click the comment TODO: Ex2 Update the code to use the host extension caching. This
opens the PricingService.svc.vb file.
9. Replace the Line rules = GetRulesFromService(policyName) with the following code:
'Look in the rules cache (plugged as a host extension) for the rule
Dim cacheKey As String = policyName & Date.Today.ToString()
Dim cacheHost As CacheHostExtension =
CType(OperationContext.Current.Host.Extensions.
Find(Of CacheHostExtension)(), CacheHostExtension)
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-105

If cacheHost IsNot Nothing Then
rules = TryCast(cacheHost.GetItem(cacheKey), PricingRule())
End If

'If there are no rules in the cache call the pricing rules service
If rules Is Nothing Then
rules = GetRulesFromService(policyName)

'put the rules in the cache for future use.
If (rules IsNot Nothing) AndAlso (rules.Count() > 0) Then
cacheHost.SetItem(cacheKey, rules, Date.Today.AddDays(1))
End If
End If
10. Save the PricingService.svc.vb file.
Results: After this exercise, you will have created a host extension, attached the extension to the host, and
accessed the extension in the Pricing service.
8-106 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 3: Configuring and Using Routing
The main tasks for this exercise are as follows:
1. Create the endpoints to be used by the router
2. Add routing configuration
3. Create a routing behavior
4. Host the Routing Service
5. Use the client application to call the Routing service
Task 1: Create the endpoints to be used by the router
1. In the SimpleServiceHost project App.config file, locate the client section.
2. Add the following endpoints to the end of the client section:
<endpoint name="PricingRouterEP"
address="http://localhost:6000/RoutingService/"
binding="basicHttpBinding"
contract="TicketingOffice.Pricing.Contracts.IPricingService" />
<endpoint name="PricingNormalEP"
address="http://localhost:5005/TicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="VipPricingEP"
address="http://localhost:50051/VipTicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="DeadDestination"
address="http://localhost:9999/TicketesPricing"
binding="ws2007HttpBinding" contract="*" />
Task 2: Add routing configuration
1. In the SimpleServiceHost project App.config file, locate the routing section.
2. Add the following filter definitions to the routing element:
<namespaceTable>
<add prefix="pricing" namespace="http://Fabrikam.com"/>
</namespaceTable>

<filters>
<!--Filter according to the policyName parameter sent to the pricing service-->
<filter name="VipPricing"
filterType="XPath"
filterData="//pricing:policyName = 'Vip'"/>
<filter name="NormalPricing"
filterType="XPath"
filterData="//pricing:policyName != 'Vip'"/>
</filters>
3. Add the filter table definitions in the routing section after the filters element that you have added.
<filterTables>
<!-- Set up the Routing Service's Message Filter Table -->
<filterTable name="PricingFilterTable">
<add filterName="VipPricing"
endpointName="VipPricingEP" />
<add filterName="NormalPricing"
endpointName="DeadDestination"
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-107
backupList="backupEndpointList"/>
</filterTable>
</filterTables>
4. Add a backup list in the routing section after the filterTables element that you have added.
<!-- Create the backup endpoint list -->
<backupLists>
<!-- Add an endpoint list that contains the backup destination -->
<backupList name="backupEndpointList">
<add endpointName="PricingNormalEP" />
</backupList>
</backupLists>
Task 3: Create a routing behavior
1. In the SimpleServiceHost project App.config file, locate the serviceBehaviors section.
2. Add the following behavior configuration in the serviceBehaviors configuration section:
<!-- Set up the Routing Behavior -->
<behavior name="routingConfiguration">
<routing
filterTableName="PricingFilterTable"
routeOnHeadersOnly="false" />
<serviceDebug
includeExceptionDetailInFaults="true"/>
</behavior>
Task 4: Host the Routing Service
1. In the SimpleServiceHost project App.config file, locate the services section.
2. Add the following service configuration in the services section:
<service behaviorConfiguration="routingConfiguration"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6000/RoutingService/" />
</baseAddresses>
</host>
<!-- Create the Routing Service endpoint -->
<endpoint
address=""
binding="basicHttpBinding"
name="RoutingServiceEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
3. Save the App.config file.
4. Examine the content of the task list.
5. Double-click the comment TODO: Ex3 Add ServiceTypeResolver to the collection. This opens
the HostingManager.vb file.
6. Add the following element to the ServiceTypeResolver collection initialization:
{"System.ServiceModel.Routing.RoutingService",GetType(
System.ServiceModel.Routing.RoutingService)},
8-108 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
7. After adding the previous code, the ServiceTypeResolver definition should resemble the following
code:
Private Shared ServiceTypeResolver As New Dictionary(Of String, Type)() From {
{"System.ServiceModel.Routing.RoutingService",
GetType(System.ServiceModel.Routing.RoutingService)},
{"TicketingOffice.CrmService.CustomerRelationsService",
GetType(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
GetType(CurrencyExchangeService)},
{"TicketingOffice.HallStateService.ReservationsService",
GetType(ReservationsService)},
{"TicketingOffice.PaymentService.TicketsPaymentService",
GetType(TicketsPaymentService)},
{"TicketingOffice.PricingService.TicketsPricingService",
GetType(TicketsPricingService)}, {"TicketingOffice.PricingService.VipPricingService",
GetType(VipPricingService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
GetType(TicketingPricingRulesService)},
{"TicketingOffice.ShowsService.ShowsAndEventsService",
GetType(ShowsAndEventsService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
GetType(GeneralTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingService",
GetType(QueuedTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingGeneralService",
GetType(QueuedTicketingGeneralService)}, {"TicketingOffice.Bridge.TicketingBridge",
GetType(TicketingBridge)}, {"TicketingOffice.Bridge.TicketingBridgeCallBack",
GetType(TicketingBridgeCallBack)}, {"TicketingOffice.Bridge.HttpBridge",
GetType(HttpBridge)},
{"TicketingOffice.Bridge.HttpBridgeCallBack",
GetType(HttpBridgeCallBack)},
{"TicketingOffice.PricingBrokerService.DiscoveryProxyService",
GetType(DiscoveryProxyService)}}
8. Save the HostingManager.vb file.
Task 5: Use the client application to call the Routing service
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex3 call the pricing routing service. This opens the
OrderTicketWindow.xaml.vb file.
3. Add the following code to the BackgroundTicketOrderWork method, after the TODO comment:
CalculateTicketsPrice(e, parameters)
4. Save the OrderTicketWindow.xaml.vb file.
5. Build and run the SimpleServiceHost project without debugging.
6. Start the TicketingOffice.UI client.
7. In the client's main window, click the Order a ticket button.
8. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
9. From the shows list, select Othello, and from the events list, select the first event in the list.
10. Click the Get hall state button to view which seats are available.
11. Select two available seats, and then click the Order button.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-109
12. When an operation completion message displays, verify that the price is 400 (200 per seat).
13. Click OK, select two other available seats, select the "VIP" check box, and then click the Order button.
14. When an operation completion message displays, verify that the price is 360 (400 minus a 10 percent
discount for VIP customers).
15. Click OK, and then close all the client application windows.
16. Switch to the SimpleServiceHost console window, and examine the console output. Notice that the
VIP Pricing service was called.
17. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Results: After this exercise, you will have created the endpoints to be used by the routing service, added
routing configuration to the routing service, and called the routing service using a client application.
8-110 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 4: Implementing Asynchronous Invocation
The main tasks for this exercise are as follows:
1. Use the Asynchronous pattern on the Client
2. Implement and use the Asynchronous pattern on the service
3. Test the Asynchronous client and service
Task 1: Use the Asynchronous pattern on the Client
1. Run the SimpleServiceHost project without debugging.
2. Leave the service host console running, and return to Visual Studio 2010.
3. In the TicketingOffice.UI project, in the Client solution folder, locate the
HallStateServiceReference service reference.
4. Right-click the HallStateServiceReference service reference, and then select Configure Service
Reference.
5. In the Service Reference Settings dialog box, select the Generate asynchronous operations check
box, and then click OK.
6. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
7. Examine the content of the task list.
8. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous client
call. This opens the OrderTicketWindow.xaml.vb file.
9. Add the following code in the AsyncType.ClientAsync Select section, between the TODO comment
and the next Case statement:
Dim asyncClientProxy As New _
HallStateServiceClient("WS2007HttpBinding_IHallStateService")
asyncClientProxy.BeginGetHallState(SelectedEvent.EventID,
AddressOf GetHallStateCallback, asyncClientProxy)
10. Add the following method to the OrderTicketWindow class, after the GetHallState method:
Private Sub GetHallStateCallback(ByVal ar As IAsyncResult)
Dim seats() As SeatIndex
seats =
(CType(ar.AsyncState, HallStateServiceClient)).EndGetHallState(ar)
Me.Dispatcher.Invoke(New Action(Sub() ShowAvailableSeats(seats)))
End Sub
11. Save the OrderTicketWindow.xaml.vb file.
Task 2: Implement and use the Asynchronous pattern on the service
1. Examine the content of the task list.
2. Double-click the comment TODO: Ex4 - Add the IAsyncHallStateService service contract. This
opens the HallStateContract.vb file.
3. Add the following contract code.
<ServiceContract(Namespace := "http://Fabrikam.com")>
Public Interface IAsyncHallStateService

<OperationContract(AsyncPattern := True,
Name := "GetHallStateAsync")>
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-111
Function BeginGetHallState(ByVal eventID As Guid,
ByVal callback As AsyncCallback, ByVal state As Object) _
As IAsyncResult

Function EndGetHallState(ByVal ar As IAsyncResult) As SeatIndex()


<OperationContract(AsyncPattern := True,
Name := "FindTheaterAsync")>
Function BeginFindTheater(ByVal name As String,
ByVal theaterID? As Integer, ByVal callback As AsyncCallback,
ByVal state As Object) As IAsyncResult

Function EndFindTheater(ByVal ar As IAsyncResult) As Theater
End Interface
4. Save the HallStateContract.vb file.
5. Double-click the comment TODO: Ex4 Implement the IAsyncHallStateService interface. This
opens the HallStateService.svc.vb file.
6. Make the ReservationsService class implement the IAsyncHallStateService interface. The result
class declaration should resemble the following code.
<ServiceBehavior(InstanceContextMode := InstanceContextMode.Single,
Namespace := "http://Fabrikam.com")>
Public Class ReservationsService : Implements _
IHallStateService, IReservationService,
IHallManagementService, IAsyncHallStateService
7. Double-click the comment TODO: Ex4 Add IAsyncHallStateService contract implementation.
8. Add the following implementation of the IAsyncHallStateService interface to the
ReservationsService class, after the TODO comment:
Public Function BeginGetHallState(ByVal eventID As Guid,
ByVal callback As AsyncCallback, ByVal state As Object) _
As IAsyncResult Implements IAsyncHallStateService.BeginGetHallState
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "BeginGetHallState",
Thread.CurrentThread.ManagedThreadId))

Return manager.BeginGetHallState(eventID, callback, state)
End Function

Public Function EndGetHallState(ByVal ar As IAsyncResult) _
As SeatIndex() Implements IAsyncHallStateService.EndGetHallState
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "EndGetHallState",
Thread.CurrentThread.ManagedThreadId))
Return manager.EndGetHallState(ar)
End Function

Public Function BeginFindTheater(ByVal name As String,
ByVal theaterID? As Integer, ByVal callback As AsyncCallback,
ByVal state As Object) As IAsyncResult _
Implements IAsyncHallStateService.BeginFindTheater
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "BeginFindTheater",
Thread.CurrentThread.ManagedThreadId))

Return manager.BeginFindTheater(name, callback, state)
End Function
8-112 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010

Public Function EndFindTheater(ByVal ar As IAsyncResult) As Theater _
Implements IAsyncHallStateService.EndFindTheater
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "EndFindTheater",
Thread.CurrentThread.ManagedThreadId))

Return manager.EndFindTheater(ar)
End Function
9. Save the HallStateService.svc.vb file.
10. In the SimpleServiceHost project App.config file, locate the service configuration section of the
TicketingOffice.HallStateService.ReservationsService service.
11. Add an endpoint to the service, with the AsyncHallState address, ws2007HttpBinding binding, and
the TicketingOffice. HallState.contracts.IAsyncHallStateService contract. Set the binding
configuration to use the NoSecurity binding configuration. The resulting endpoint configuration
should look as follows:
<endpoint
address="AsyncHallState"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.HallState.Contracts.IAsyncHallStateService"></endpoint>
12. Save the App.config file.
13. Run the SimpleServiceHost project without debugging.
14. Leave the service host console running, and return to Visual Studio 2010.
15. In the Client solution folder, in the TicketingOffice.UI project, locate the
HallStateServiceReference service reference .
16. Right-click the HallStateServiceREference service reference, and then select Update Service
Reference.
17. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous service
operation. This opens the OrderTicketWindow.xaml.vb file.
18. Add the following code in the AsyncType.ServiceAsync Select section, between the TODO comment
and the end of the section:
Dim asyncServiceProxy As New AsyncHallStateServiceClient(
"WS2007HttpBinding_IAsyncHallStateService")
seats = asyncServiceProxy.GetHallStateAsync(SelectedEvent.EventID)
ShowAvailableSeats(seats)
19. Save the OrderTicketWindow.xaml.vb file.
Task 3: Test the Asynchronous client and service
1. Run the TicketingOffice.UI client.
2. In the client's main window, click the Order a ticket button.
3. In the OrderTicketWindow window, open the shows list, select Othello, and then from the events list,
select the first event in the list.
4. Click the Get hall state (Async client) button to view which seats are available. Examine the service
host console application outputyou should see the log message Running GetHallState on thread.
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-113
5. Return to the OrderTicketWindow window in the client application, and then click the Get hall state
(Async service) button. Examine the service host console application outputyou should see the log
messages Running BeginGetHallState on thread , and Running EndGetHallState on thread .
6. Close all the client application windows.
7. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Results: After this exercise, you will have implemented and used the asynchronous pattern in both the
client and the service.
8-114 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Exercise 5: Implementing Workflow Services
The main tasks for this exercise are as follows:
1. Open the workflow service project
2. Add activities to the workflow
3. Deploy the CreditCardPayment service to AppFabric using a deployment package
4. Test the CreditCardPayment workflow service
Task 1: Open the workflow service project
1. Open the CreditPayment.xamlx file in the CreditCardPaymentService project.
2. Verify that an empty workflow appears with a single sequence activity, and that the display name of
the activity is Credit Service.
Task 2: Add activities to the workflow
1. Add a ReceiveAndSendReply activity from the Messaging group into the sequence activity.
2. Rename the Receive activity to InitPayment.
3. Drag an InvokeMethod activity from the Primitives group to between the Receive and the
SendReplyToReceive activities.
4. In the new InvokeMethod activity, open the Properties window.
5. In the TargetObject property, type the following:
New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
6. In the MethodName property, type the following: IsPaymentTypeEnabled
7. In the Result property type the following: CreditEnabled
8. Click the ellipses () button in the Parameters collection text box to open the Parameters dialog
box, and complete the first row, and then click OK.
In the Direction column, select In.
In the Type column, select Browse for Types.
In the Type Name text box, type PaymentType, select the PaymentType from the tree, and
then click OK.
In the Value column, enter PaymentType.CreditCard.
Click OK to close the Parameters dialog box.
9. The workflow should display as follows:
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-115

10. In the Receive activity, open the Properties window.
11. Select the CanCreateInstance check box.
12. In the ServiceContractName, type: {http://Fabrikam.com/}ICreditCardPaymentService
13. In the SendReplyToReceive activity, open the Properties window.
14. In the Properties window, click the ellipse () button in the Content field to open the Content
Definition dialog box.
15. In the Content Definition window, select Parameters.
16. Set the content to the following values:
Name: Results
Type: Boolean
Value: CreditEnabled
17. Click OK to close the Content Definition dialog box.
18. Add an If activity from the ControlFlow group after the sequence activity.
19. In the If Activity, open the Properties window.
20. In the Condition property, type CreditEnabled.
21. Add a ReceiveAndSendReply activity from the Messaging group into the Then area of the If
activity.
8-116 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
22. Add a Receive activity from the Messaging group, and drag it before the Receive activity that is
already inside the Then area of the If activity. Set the new activity OperationName to
ProvidePaymentDetails, and set the DisplayName to ProvidePaymentDetails.
23. Set the DisplayName of the second Receive activity inside the Then activity to PerformPayment,
and set the OperationName to PerformPayment.
24. Update the display name of the SendReplyToReceive activity in the Then activity to
SendReplyToPerformPayment.
25. In both Receive activities, change the ServiceContractName to
{http://Fabrikam.com/}ICreditCardPaymentService.
26. Right-click the ProvidePaymentDetails activity, select Properties, and set the Content property as
follows:
Name Type Assign To
OrderID Guid OrderID
CustomerID Guid PayingCustomerID
Amount Double Amount
CreditCardNumber String CreditCard

Note: After browsing for a parameter type, some types may appear with their full namespace. For
example, Guid might display as System.Guid.
27. Right-click the SendReplyToPerformPayment activity, and then select Properties.
28. Set the content property as follows:
Name Type Value
PaymentResult Payment PaymentResult
29. Click OK to close the Content Definition dialog box.
30. Add an InvokeMethod activity from the Primitives group between the PerformPayment activity
and the SendReplyToPerformPayment activity.
31. In the InvokeMethod activity, set the properties.
TargetObject: New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
MethodName: PayForOrder
Result: PaymentResult
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-117
32. In the Properties window, in the Parameters field, click the ellipses () button, add the following
parameters, and then click OK:
Direction Type Value
In Guid OrderID
In Guid PayingCustomerID
In Double Amount
In PaymentType PaymentType.CreditCard
In String CreditCard
33. Save the CreditPayment.xamlx file.
34. Rebuild the project.
Task 3: Deploy the CreditCardPayment service to AppFabric using a deployment
package
1. Create a Deployment package for the CreditCardPaymentService project.
2. Open the IIS Manager.
3. Import the package that you have created to the Default Web Site, and name it
FabrikamTicketingCreditPayment.
4. Close the IIS Manager.
Task 4: Test the CreditCardPayment workflow service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
2. Add the CreditPayment service, using the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx.
3. Call the InitPayment operation to test the workflow service.
4. After receiving a response, close the Windows Communication Foundation (WCF) Test Client.
5. Open the IIS Manager
6. In the IIS console, open AppFabric Dashboard.
7. Examine the WF Instance History section, and notice that the CreditPayment.xamlx is activated.
8. Close the IIS Manager.
Results: After this exercise, you will have created a workflow service that executes the process of credit
card payment, and then tested it.

8-118 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Lab Review

Review Questions
1. How can you attach a custom message inspector to a service?
2. What are the common scenarios for using a host extension?
3. What are the steps that are required to implement the asynchronous pattern on the service-side and
on the client-side?
4. How can a router improve the reliability and agility of a service?
5. What Workflow Foundation activities can you use to implement a Workflow Service?
Introduction to Advanced Microsoft Windows Communication Foundation Topics 8-119
Module Review and Takeaways

Review Questions
1. What kind of information should be contained in custom headers?
2. What are the advantages of Workflow Services for WCF services implementation?
3. What are dispatchers?
4. What is the scenario in which the asynchronous pattern on the server can improve the service
throughput?
5. What interface must host extensions implement?
8-120 Developing Windows Communication Foundation Solutions with Microsoft Visual Studio 2010
Course Evaluation

Your evaluation of this course will help Microsoft understand the quality of your learning experience.
Please work with your training provider to access the course evaluation form.
Microsoft will keep your answers to this survey private and confidential and will use your responses to
improve your future learning experience. Your open and honest feedback is valuable and appreciated.

Lab 1: Service-Oriented Architecture L1-1
Module 1: Service-Oriented Architecture
Lab 1: Service-Oriented Architecture
Section 1: Visual C#
Exercise 1: Practicing the SOA Tenets
Task 1: Prepare Internet Information Services (IIS) for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M01\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M01\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
Task 2: Open the starter solution
1. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M01\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M01\CS folder, click the
TicketingOffice.sln file and then click Open.
3. Build the solution.
From the Build menu, select Build Solution.
Task 3: Test the Pricing service, using the WcfTestClient utility
1. Run the SimpleServiceHost project to start all the services.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, and then select Debug, and
then select Start New Instance.
2. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
3. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
L1-2 Lab 1: Service-Oriented Architecture


4. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.

5. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
6. Close the WcfTestClient utility.
Task 4: Service autonomy Change service location
1. Switch to Visual Studio 2010, where the TicketingOffice solution is already open.
2. Open the containing folder of the Lab_1_Helper project.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Helpers solution folder.
Right-click the Lab_1_Helper project, and then select Open Folder in Windows Explorer.
3. Run the Lab_1_Helper service from the Bin\Debug folder.
In the Lab_1_Helper folder, enter the Bin\Debug folder.
Double-click the Lab_1_Helper.exe file.
Lab 1: Service-Oriented Architecture L1-3

Note: The ports used by this service are random. You can see the ports the service uses in the
Console window of the service. For example, the screen capture shown below, shows that the
Lab_1_Helper service uses the 9855 port for its HTTP address and 9856 for its Net.TCP address.

4. Write down the port number used for the HTTP address.
5. Change the SimpleServiceHost project configuration file to use the new service instance.
Switch to Visual Studio 2010, where the TicketingOffice solution is open.
In the Solution Explorer window, open the SimpleServiceHost project from the Host solution
folder.
Double-click the App.config file in the SimpleServiceHost project.
Locate the endpoint element named CurrencyExchangeEP - it should be under
<system.serviceModel><client>, as demonstrated in the following code:
<endpoint name="CurrencyExchangeEP"
address="http://localhost:5002/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
Change the port number in the address attribute to the port that you have written down from
step 4. For example, if you have written down 9855, the configuration would look as follows:
<endpoint name="CurrencyExchangeEP"
address="http://localhost:9855/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
6. Save the App.config file.
In the File menu, click Save App.config.
7. Close the SimpleServiceHost console, and start a new instance of it.
In the Debug menu, click Stop Debugging.
In the Solution Explorer window, open the Host solution folder.
Right-click the SimpleServiceHost project, select Debug, and then select Start New Instance.
8. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
L1-4 Lab 1: Service-Oriented Architecture

Double-click the WcfTestClient shortcut.
9. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
10. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
11. Click Invoke, and if a security warning appears, click OK.
12. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
13. Close the WcfTestClient utility.
14. Close the Lab_1_Helper console window.
15. Close the SimpleServiceHost console.
16. Change the port number of CurrencyExchangeEP back to the original value of 5002, and save the
file.
Switch to Visual Studio 2010, where the TicketingOffice solution is open.
In the Solution Explorer window, open the SimpleServiceHost project from the Host solution
folder.
Double-click the App.config file in the SimpleServiceHost project.
Locate the endpoint element named CurrencyExchangeEP - it should be under
<system.serviceModel><client>.
Change the port number in the address attribute to 5002, as demonstrated in the following
code.
<endpoint name="CurrencyExchangeEP"
address="http://localhost:5002/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
In the File menu, click Save App.config.
Task 5: Services share contract Add reference to a contract-only assembly
1. In the EventsFeed project, add a reference to the HallStateContract project.
In the Solution Explorer window, open the Services solution folder, and then open the Shows
solution folder.
In the Shows solution folder, right-click the EventsFeed project and then click Add Reference.
Lab 1: Service-Oriented Architecture L1-5
In the Add Reference dialog box, click the Projects tab, select the HallStateContract project,
and then click OK.
Task 6: Explicit boundaries Call the HallState service to get information about a theater
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
Double-click the comment TODO: Ex1 Create a method that calls the FindTheater
operation of the HallState service. This opens the EventsFeed.svc.cs file.
2. Add a GetTheater method that calls the HallState's FindTheater operation and returns the
appropriate Theater object.
Add the following method code inside the EventsFeed class.
/// <summary>
/// Call the hallstate service to get details about the theater.
/// </summary>
/// <param name="theaterID"></param>
/// <returns></returns>
public Theater GetTheater(int theaterID)
{
var cache = OperationContext.Current.Host.Extensions.
Find<ServerStateHostExtension>();

if (!cache.StateData.ContainsKey(theaterID.ToString()))
{
var chf = new ChannelFactory<IHallStateService>(
"HallStateEP");
IHallStateService prox = null;

try
{
prox = chf.CreateChannel();
var res = prox.FindTheater(string.Empty, theaterID);
if (res != null)
cache.StateData.Add(theaterID.ToString(), res);
return res;
}
catch (Exception ex)
{
LoggingManager.Logger.Log(
LoggingCategory.Error, ex.Message);
throw new FaultException<HallStateException>
(new HallStateException(
string.Format(
StringsResource.HallNotFound, theaterID), ex));
}
finally
{
var channel = prox as ICommunicationObject;
if ((channel != null) &&
(channel.State == CommunicationState.Opened))
channel.Close();
}
}
return (Theater)cache.StateData[theaterID.ToString()];
}
L1-6 Lab 1: Service-Oriented Architecture


Note: Notice the call to the service is written inside a try catch block.
3. Add a using statement for the TicketingOffice.HallState.Contracts namespace in the
EventsFeed.svc.cs file.
In the task, double-click the comment TODO: Ex1 Add a using statement for the HallState
contract.
Replace the comment with the following using statement:
using TicketingOffice.HallState.Contracts;
4. Change the PresentEvent method in the EventsFeed class to build the show's information using the
GetTheater method.
In the task, double-click the comment TODO: Ex1 Construct event information including
theater information to locate the PresentEvent method.
Delete the content of the PresentEvent method, and replace it with the following code:
var theater = GetTheater(ev.TheaterID);
StringBuilder sb = new StringBuilder();
sb.Append(string.Format("<br/> {0} : {1}", "Date", ev.Date));
sb.Append(string.Format("<br/> {0} : {1}", "Price", ev.ListPrice));
sb.Append(string.Format("<br/> {0} : {1}", "Name", ev.ShowDetails.Title));
sb.Append(string.Format("<br/> {0} : {1}", "Time", ev.StartTime));
sb.Append(string.Format("<br/> {0} : {1}", "State", ev.State));
if (theater != null)
sb.Append(string.Format("<br/> {0} : {1} {2} {3}", "Location", theater.Name,
theater.City, theater.Country));
return sb.ToString();
5. Save the EventsFeed.svc.cs file.
In the File menu, click Save EventsFeed.svc.cs.
6. Build the EventsFeed project.
Open the Build menu, and then click Build EventsFeed.
Results: After this exercise, you will have moved a service to a different address, added a reference to a
contract-only assembly, and called a service from another service.
Exercise 2: Implementing Service Agility and Scalability
Task 1: Create multiple instances of the pricing rule service
1. Run the SimpleServiceHost project to start all the services.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
2. Start three instances of the PricingRules service by running the Lab_1_Helper project three times.
In the Solution Explorer window, open the Helpers solution folder.
Right-click the Lab_1_Helper project, and select Open Folder in Windows Explorer.
In the project's folder, enter the Bin\Debug folder.
Lab 1: Service-Oriented Architecture L1-7
Double-click the file named Lab_1_Helper.exe three times, so the service will have three running
instances.
3. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
4. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu and then select the Add Service option.
In the Add Service dialog box enter the address http://localhost:5005/, and then click OK.
Task 2: Locate the PricingRules service using a dynamic discovery proxy
1. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.
2. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
3. Click Invoke three more times, and if a security warning appears, click OK.
4. Open the SimpleServiceHost console window and observe the logs written when the PricingRules
services was called. You will see that each call used a different address that matches one of the
running instances of the service.
5. Close the WcfTestClient utility.
6. Close the SimpleServiceHost console.
7. Close all Lab_1_Helper windows.
Results: After this exercise, you will have used dynamic discovery proxy to call a new instance of a
service.
Exercise 3: Interoperate with Other SOA Technologies
Task 1: Create a WCF proxy to the ASMX CurrencyExchange service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
Double-click the comment TODO: Ex3 Call the Buy operation of the CurrencyExchange
ASMX Web service. This opens the CurrencyExchangeProxy.cs file.
2. Delete the content of the else clause.
L1-8 Lab 1: Service-Oriented Architecture

In the Buy method, delete the content of the else clause (comment and return 0 command).
After deleting the code, the method's try block should look as follows:
try
{
if (!UseAsmx)
{
// Call the WCF service
currencyProx = currencyChf.CreateChannel();
return currencyProx.Buy(currency, amount);
}
else
{
}
}
3. Add the following code inside the else clause to call the ASMX Web service:
currencyAsmxProx = currencyAsmxChf.CreateChannel();
return currencyAsmxProx.Buy(currency, amount);
4. Double-click the comment TODO: Ex3 Call the Sell operation of the CurrencyExchange ASMX
Web service to get to the Sell method.
5. In the Sell method, delete the content of the else clause.
In the Sell method, delete the content of the else clause (comment and return 0 command).
After deleting the code, the method's try block should look as follows:
try
{
if (!UseAsmx)
{
// Call the WCF service
currencyProx = currencyChf.CreateChannel();
return currencyProx.Sell(currency, amount);
}
else
{
}
}
6. Add the following code inside the else clause to call the ASMX Web service:
currencyAsmxProx = currencyAsmxChf.CreateChannel();
return currencyAsmxProx.Sell(currency, amount);
7. Save the CurrencyExchangeProxy.cs file.
In the File menu, click Save CurrencyExchangeProxy.cs.
Task 2: Configure the CurrencyExchangeProxy service to use the ASMX service instead of
the WCF service
1. In the Solution Explorer window, open the Host solution folder.
2. Open the SimpleServiceHost project from the Host folder, and double-click the App.config file.
3. Locate the appSettings element, and add the following XML fragment:
<add key="UseAsmx" value="true"/>
Lab 1: Service-Oriented Architecture L1-9
4. Save the App.config file.
In the File menu, click Save App.config.
Task 3: Call the ASMX CurrencyExchange service
1. In the Solution Explorer window, open the Services folder, open the CurrencyExchange folder. And
then open the CurrencyExchangeAsmxWebService project.
2. Open the CurrencyExchangeService.asmx.cs file.
In the CurrencyExchangeAsmxWebService project, double-click the
CurrencyExchangeService.asmx file.
3. Locate the Buy method in the CurrencyExchangeService class, and place a breakpoint inside the
method.
Locate the Buy method inside the CurrencyExchangeService class.
Place the cursor on the return statement in the method, and press the F9 key, or select Toggle
Breakpoint from the Debug menu.
4. Build the solution, and run the SimpleServiceHost project to start all the services.
From the Build menu, select Build Solution.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
5. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
6. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
7. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.
8. Return to Visual Studio 2010. If a message displays asking you to allow attaching to the w3wp.exe
process (the process that is running IIS), click the Attach button.
9. Verify that the application breaks inside the CurrencyExchangeService class (the ASMX service
implementation).
L1-10 Lab 1: Service-Oriented Architecture

10. Continue to run the application and watch the result. (If you wait more than a minute there might be
a timeout exception).
If you get a timeout exception, close the test tool, then return to Visual Studio 2010, then select
Terminate All from the Debug menu, and then rerun the task beginning with step 4.
11. Close the WcfTestClient utility.
12. Stop debugging the SimpleServiceHost project
Switch to Visual Studio 2010, and in the Debug menu, select Stop Debugging.
Results: After this exercise, you will have consumed an ASMX web service from a WCF service.
Exercise 4: Using REST Services
Task 1: Present the events feed in the browser
1. Run the SimpleServiceHost project to start all the services.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
2. Open a browser to http://localhost:5015/eventfeed.
Click Start, and then click Internet Explorer.
In the address bar, enter the address http://localhost:5015/eventfeed, and then press ENTER.
3. Verify that a feed populated with events displays.
Task 2: Query on the feed according to show name, and present the events of a
particular show
1. Browse to http://localhost:5015/eventfeed/GreatShow.
2. Verify that the feed displays the results.
Task 3: Query on the feed according to show name and the events dates
1. Add date parameters (from and to) to the URL.
Browse to the same address followed with /GreatShow/date/dd-MM-YYYY/DD-MM-YYYY.
For example: http://localhost:5015/eventfeed/GreatShow/date/1-1-2000/1-1-2100
2. Verify that the feed displays the results.
Results: After this exercise, you will have used REST calls to get shows and events information from a
WCF service.
Lab 1: Service-Oriented Architecture L1-11
Module 1: Service-Oriented Architecture
Lab 1: Service-Oriented Architecture
Section 2: Visual Basic
Exercise 1: Practicing the SOA Tenets
Task 1: Prepare Internet Information Services (IIS) for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M01\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M01\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
Task 2: Open the starter solution
1. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M01\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M01\VB folder, click the
TicketingOffice.sln file, and then click Open.
3. Build the solution.
From the Build menu, select Build Solution.
Task 3: Test the Pricing service, using the WcfTestClient utility
1. Run the SimpleServiceHost project to start all the services.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, and then select Debug, and
then select Start New Instance.
2. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
3. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
L1-12 Lab 1: Service-Oriented Architecture


4. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.

5. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
6. Close the WcfTestClient utility.
Task 4: Service autonomy Change service location
1. Switch to Visual Studio 2010, where the TicketingOffice solution is already open.
2. Open the containing folder of the Lab_1_Helper project.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Helpers solution folder.
Right-click the Lab_1_Helper project, and then select Open Folder in Windows Explorer.
3. Run the Lab_1_Helper service from the Bin\Debug folder.
In the Lab_1_Helper folder, enter the Bin\Debug folder.
Double-click the Lab_1_Helper.exe file.
Lab 1: Service-Oriented Architecture L1-13

Note: The ports used by this service are random. You can see the ports the service uses in the
Console window of the service. For example, the screen capture shown below, shows that the
Lab_1_Helper service uses the 9855 port for its HTTP address and 9856 for its Net.TCP address.


4. Write down the port number used for the HTTP address.
5. Change the SimpleServiceHost project configuration file to use the new service instance.
Switch to Visual Studio 2010, where the TicketingOffice solution is open.
In the Solution Explorer window, open the SimpleServiceHost project from the Host solution
folder.
Double-click the App.config file in the SimpleServiceHost project.
Locate the endpoint element named CurrencyExchangeEP - it should be under
<system.serviceModel><client>, as demonstrated in the following code.
<endpoint name="CurrencyExchangeEP"
address="http://localhost:5002/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
Change the port number in the address attribute to the port that you have written down from
step 4. For example, if you have written down 9855, the configuration would look as follows:
<endpoint name="CurrencyExchangeEP"
address="http://localhost:9855/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
6. Save the App.config file.
In the File menu, click Save App.config.
7. Close the SimpleServiceHost console, and start a new instance of it.
In the Debug menu, click Stop Debugging.
In the Solution Explorer window open the Host solution folder.
Right-click the SimpleServiceHost project, select Debug, and then select Start New Instance.
8. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
L1-14 Lab 1: Service-Oriented Architecture

Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
9. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK
10. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
11. Click Invoke, and if a security warning appears, click OK.
12. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
13. Close the WcfTestClient utility.
14. Close the Lab_1_Helper console window.
15. Close the SimpleServiceHost console.
16. Change the port number of CurrencyExchangeEP back to the original value of 5002, and save the
file.
Switch to Visual Studio 2010, where the TicketingOffice solution is open.
In the Solution Explorer window, open the SimpleServiceHost project from the Host solution
folder.
Double-click the App.config file in the SimpleServiceHost project.
Locate the endpoint element named CurrencyExchangeEP - it should be under
<system.serviceModel><client>.
Change the port number in the address attribute to 5002, as demonstrated in the following
code.
<endpoint name="CurrencyExchangeEP"
address="http://localhost:5002/Exchange"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CurrencyExchange.Contract.IExchangeService">
</endpoint>
In the File menu, click Save App.config.
Task 5: Services share contract Add reference to a contract only assembly
1. In the EventsFeed project, add a reference to the HallStateContract project.
In the Solution Explorer window, open the Services solution folder, and then open the Shows
solution folder.
In the Shows solution folder, right-click the EventsFeed project, and then click Add Reference.
Lab 1: Service-Oriented Architecture L1-15
In the Add Reference dialog box, click the Projects tab, select the HallStateContract project,
and then click OK.
Task 6: Explicit boundaries Call the HallState service to get information about a theater
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
Double-click the comment TODO: Ex1 Create a method that calls the FindTheater
operation of the HallState service. This opens the EventsFeed.svc.vb file.
2. Add a GetTheater method that calls the HallState's FindTheater operation and returns the
appropriate Theater object.
Add the following method code inside the EventsFeed class.
''' <summary>
''' Call the hallstate service to get details about the theater.
''' </summary>
''' <param name="theaterID"></param>
''' <returns></returns>
Public Function GetTheater(ByVal theaterID As Integer) As Theater
Dim cache = OperationContext.Current.Host.Extensions.Find(
Of ServerStateHostExtension)()
If Not cache.StateData.ContainsKey(theaterID.ToString()) Then
Dim chf = New ChannelFactory(Of _
IHallStateService)("HallStateEP")
Dim prox As IHallStateService = Nothing
Try
prox = chf.CreateChannel()
Dim res = prox.FindTheater(String.Empty, theaterID)
If res IsNot Nothing Then
cache.StateData.Add(theaterID.ToString(), res)
End If
Return res
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message)
Throw New FaultException(Of HallStateException)(
New HallStateException(String.Format(
StringsResource.HallNotFound, theaterID), ex))
Finally
Dim channel = TryCast(prox, ICommunicationObject)
If (channel IsNot Nothing) AndAlso
(channel.State = CommunicationState.Opened) Then
channel.Close()
End If
End Try
End If

Return CType(cache.StateData(theaterID.ToString()), Theater)
End Function

Note: Notice the call to the service is written inside a Try Catch block.
3. Add an imports statement for the TicketingOffice.HallState.Contracts namespace in the
EventsFeed.svc.vb file.
In the task, double-click the comment TODO: Ex1 Add an imports statement for the
HallState contract.
L1-16 Lab 1: Service-Oriented Architecture

Replace the comment with the following imports statements:
Imports TicketingOffice.HallState.Contracts
4. Change the PresentEvent method in the EventsFeed class to build the show's information using the
GetTheater method.
In the task, double-click the comment TODO: Ex1 Construct event information including
theater information to locate the PresentEvent method.
Delete the content of the PresentEvent method, and replace it with the following code:
Dim l_theater = GetTheater(ev.TheaterID)
Dim sb As New StringBuilder()
sb.Append(String.Format("<br/> {0} : {1}", "Date", ev.Date))
sb.Append(String.Format("<br/> {0} : {1}", "Price", ev.ListPrice))
sb.Append(String.Format("<br/> {0} : {1}", "Name",
ev.ShowDetails.Title))
sb.Append(String.Format("<br/> {0} : {1}", "Time", ev.StartTime))
sb.Append(String.Format("<br/> {0} : {1}", "State", ev.State))
If l_theater IsNot Nothing Then
sb.Append(String.Format("<br/> {0} : {1} {2} {3}", "Location",
l_theater.Name, l_theater.City, l_theater.Country))
End If
Return sb.ToString()
5. Save the EventsFeed.svc.vb file.
In the File menu, click Save EventsFeed.svc.vb.
6. Build the EventsFeed project.
Open the Build menu, and then click Build EventsFeed.
Results: After this exercise, you will have moved a service to a different address, added a reference to a
contract-only assembly, and called a service from another service.
Exercise 2: Implementing Service Agility and Scalability
Task 1: Create multiple instances of the pricing rule service
1. Run the SimpleServiceHost project to start all the services.
In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
2. Start three instances of the PricingRules service by running the Lab_1_Helper project three times.
In the Solution Explorer window, open the Helpers solution folder.
Right-click the Lab_1_Helper project, and select Open Folder in Windows Explorer.
In the project's folder, enter the Bin\Debug folder.
Double-click the file named Lab_1_Helper.exe three times so the service will have three running
instances.
3. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Lab 1: Service-Oriented Architecture L1-17
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
4. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
Task 2: Locate the PricingRules service using a dynamic discovery proxy
1. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.
2. Validate that the response value is 95. (The exchange rate is 1.0, but there is 5 percent commission.)
3. Click Invoke three more times, and if a security warning appears, click OK.
4. Open the SimpleServiceHost console window, and observe the logs written when the PricingRules
services was called. You will see that each call used a different address that matches one of the
running instances of the service.
5. Close the WcfTestClient utility.
6. Close the SimpleServiceHost console.
7. Close all Lab_1_Helper windows.
Results: After this exercise, you will have used dynamic discovery proxy to call a new instance of a
service.
Exercise 3: Interoperate with Other SOA Technologies
Task 1: Create a WCF proxy to the ASMX CurrencyExchange service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
Double-click the comment TODO: Ex3 Call the Buy operation of the CurrencyExchange
ASMX Web service. This opens the CurrencyExchangeProxy.vb file.
2. Delete the content of the Else clause.
In the Buy method, delete the content of the Else clause (comment and Return 0 command).
After deleting the code, the method's Try block should look as follows:
Try
If Not UseAsmx Then
' Call the WCF service
currencyProx = currencyChf.CreateChannel()
Return currencyProx.Buy(currency, amount)
L1-18 Lab 1: Service-Oriented Architecture

Else
End If
3. Add the following code inside the Else clause to call the ASMX Web service:
currencyAsmxProx = currencyAsmxChf.CreateChannel()
Return currencyAsmxProx.Buy(currency, amount)
4. Double-click the comment TODO: Ex3 Call the Sell operation of the CurrencyExchange ASMX
Web service to get to the Sell method.
5. In the Sell method, delete the content of the Else clause.
In the Sell method, delete the content of the Else clause (comment and Return 0 command).
After deleting the code, the method's Try block should look as follows:
Try
If Not UseAsmx Then
' Call the WCF service
currencyProx = currencyChf.CreateChannel()
Return currencyProx.Sell(currency, amount)
Else
End If
6. Add the following code inside the Else clause to call the ASMX Web service:
currencyAsmxProx = currencyAsmxChf.CreateChannel()
Return currencyAsmxProx.Sell(currency, amount)
7. Save the CurrencyExchangeProxy.vb file.
In the File menu, click Save CurrencyExchangeProxy.vb.
Task 2: Configure the CurrencyExchangeProxy service to use the ASMX service instead of
the WCF service
1. In the Solution Explorer window, open the Host solution folder.
2. Open the SimpleServiceHost project from the Host folder, and double-click the App.config file.
3. Locate the appSettings element, and add the following XML fragment:
<add key="UseAsmx" value="true"/>
4. Save the App.config file.
In the File menu, click Save App.config.
Task 3: Call the ASMX CurrencyExchange service
1. In the Solution Explorer window, open the Services folder, open the CurrencyExchange folder. And
then open the CurrencyExchangeAsmxWebService project.
2. Open the CurrencyExchangeService.asmx.vb file.
In the CurrencyExchangeAsmxWebService project, double-click the
CurrencyExchangeService.asmx file.
3. Locate the Buy method in the CurrencyExchangeService class, and place a breakpoint inside the
method.
Locate the Buy method inside the CurrencyExchangeService class.
Lab 1: Service-Oriented Architecture L1-19
Place the cursor on the Return statement in the method, and press the F9 key, or select Toggle
Breakpoint from the Debug menu.
4. Build the solution, and run the SimpleServiceHost project to start all the services.
From the Build menu, select Build Solution.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
5. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
6. Add the Pricing service, using the address http://localhost:5005/.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5005/, and then click OK.
7. Call the CalculatePrice operation to test the service.
In the My Service Projects tree, double-click the CalculatePrice operation.
Fill in the following data in the Request property page:
policyName: Not_Normal
listPrice: 100
numberOfTickets: 1
currency: Dollar (this is the default value)
Click Invoke, and if a security warning appears, click OK.
8. Return to Visual Studio 2010. If a message displays asking you to allow attaching to the w3wp.exe
process (the process that is running IIS), click the Attach button.
9. Verify that the application breaks inside the CurrencyExchangeService class (the ASMX service
implementation).
10. Continue to run the application and watch the result. (If you wait more than a minute there might be
a timeout exception).
If you get a timeout exception, close the test tool, then return to Visual Studio 2010, then select
Terminate All from the Debug menu, and then rerun the task beginning with step 4.
11. Close the WcfTestClient utility.
12. Stop debugging the SimpleServiceHost project
Switch to Visual Studio 2010, and in the Debug menu, select Stop Debugging.
Results: After this exercise, you will have consumed an ASMX web service from a WCF service.
Exercise 4: Using REST Services
Task 1: Present the events feed in the browser
1. Run the SimpleServiceHost project to start all the services.
L1-20 Lab 1: Service-Oriented Architecture

In the View menu, select the Solution Explorer option.
In the Solution Explorer window, open the Host solution folder.
Under the Host folder, right-click the SimpleServiceHost project, select Debug, and then select
Start New Instance.
2. Open a browser to http://localhost:5015/eventfeed.
Click Start, and then click Internet Explorer.
In the address bar, enter the address http://localhost:5015/eventfeed and then press ENTER .
3. Verify that a feed populated with events displays.
Task 2: Query on the feed according to show name, and present the events of a
particular show
1. Browse to http://localhost:5015/eventfeed/GreatShow.
2. Verify that the feed displays the results.
Task 3: Query on the feed according to show name and the events dates
1. Add date parameters (from and to) to the URL.
Browse to the same address followed with /GreatShow/date/dd-MM-YYYY/DD-MM-YYYY.
For example: http://localhost:5015/eventfeed/GreatShow/date/1-1-2000/1-1-2100
2. Verify that the feed displays the results.
Results: After this exercise, you will have used REST calls to get shows and events information from a
WCF service.

Lab 2: Service Development Life Cycle L2-1
Module 2: Getting Started with Microsoft Windows Configuration
Foundation Development
Lab 2: Service Development Life Cycle
Section 1: Visual C#
Exercise 1: Defining Service and Data Contracts
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M02\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M02\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command prompt window to close it, and then close
the Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M02\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog, move to the D:\LabFiles\Starter\M02\CS folder, click the
TicketingOffice.sln file and click Open.
Task 2: Define the service contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex1 - Decorate service contract and service operations, to
open the PaymentContract.cs file.
3. Add the following attributes in the code:
Decorate the interface with a ServiceContract attribute and set the contract's namespace to
http://www.fabrikam.com.
Decorate each of the interface's methods with an OperationContract attribute.
The complete code should resemble the following code example:
[ServiceContract(Namespace="http://www.fabrikam.com")]
public interface IPaymentService
{
[OperationContract]
Payment PayForOrder(
Guid orderID,
Guid payingCustomerID,
L2-2 Lab 2: Service Development Life Cycle

double amount,
PaymentType methodOfPayment,
string creditCardNumber);

[OperationContract]
Payment Refund(long paymentID, Guid customerID);

[OperationContract]
Payment[] FindPayments(PaymentCriteria criteria);

[OperationContract]
Payment FindPayment(long paymentID);
}
4. Save the change made to the PaymentContract.cs file.
From the File menu, select Save PaymentContract.cs.
Task 3: Define the data contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex1 - Define the Payment Data Contract to open the
Payment.cs file.
3. Add the following attributes in the code:
Decorate the Payment class with the DataContract attributes.
Decorate each property of the class, excluding the MethodOfPaymentID property, with the
DataMember attribute.
The class should resemble the following code example:
[DataContract(Namespace="http://www.fabrikam.com")]
public class Payment
{
[DataMember]
public long ID { get; set; }

[DataMember]
public double Amount { get; set; }

[DataMember]
public DateTime Date { get; set; }

[DataMember]
public Guid CustomerID { get; set; }

[DataMember]
public PaymentType MethodOfPayment
{
get
{
return (PaymentType)Enum.ToObject(
typeof(PaymentType), MethodOfPaymentID);
}
set
{
MethodOfPaymentID = (int)value;
}
Lab 2: Service Development Life Cycle L2-3
}

[DataMember]
public Guid OrderID { get; set; }

//reflect the MethodOfPayment as an integer
public int MethodOfPaymentID { get; set; }

}
4. Save the change made to the Payment.cs file.
From the File menu, select Save Payment.cs.
5. Double-click the comment TODO: Ex1 - Define the PaymentCriteria Data Contract, to open the
PaymentCriteria.cs file.
6. Add the following attributes in the code:
Decorate the PaymentCriteria class with the DataContract attributes.
Decorate each property of the class with the DataMember attribute.
The class should resemble the following code example:
[DataContract(Namespace="http://www.fabrikam.com")]
public class PaymentCriteria
{
[DataMember]
public Guid? OrderID { get; set; }

[DataMember]
public DateTime? FromDate { get; set; }

[DataMember]
public DateTime? ToDate { get; set; }

[DataMember]
public Guid? PayingCustomerID { get; set; }

[DataMember]
public double? Amount { get; set; }
}
7. Save the change made to the PaymentCriteria.cs file.
From the File menu, select Save PaymentCriteria.cs.
Results: After this exercise, you will have defined a contract for the payment service.
Exercise 2: Creating a Service Implementation
Task 1: Create a new WCF service application for the payment service under the
payment service folder
1. In the Solution Explorer window, open the Services solution folder, open the Payment solution
folder, and then add a new WCF Service Application for the payment service project and name the
project PaymentService.
Select View, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
L2-4 Lab 2: Service Development Life Cycle

Under the Services folder, right-click the Payment solution folder, select Add, and then select
New Project.
In the Add New Project dialog box, select WCF from the Visual C# installed templates tree.
From the WCF projects, select the WCF Service Application, set the name of the project to
PaymentService, and then click OK.
The following screen shot shows where you can find the Windows Communication Foundation (WCF)
Service Application project.


2. In the project properties of the newly created project set the default namespace to
TicketingOffice.PaymentService.
Right-click the newly created project, and then select Properties.
In the PaymentService properties window, under the Application tab, change the Default
namespace field to TicketingOffice.PaymentService.
Save the properties by clicking File, and then clicking Save Selected Items.
Close the properties window.

3. Delete the generated files Service1.svc and IService1.cs from the newly created project.

Note: Deleting the Service1.svc file will also delete the Service1.svc.cs file.
Task 2: Add references
1. Add a reference to the CrmContract, PaymentContract, PaymentLogic, TicketingContract, and
TicketingOffice.Commonprojects.
In the Solution Explorer, right-click the PaymentService project (the project that you created in
task 1), and then select Add Reference.
Lab 2: Service Development Life Cycle L2-5
In the Add Reference dialog box, click the Projects tab, select the following projects and click
OK: CrmContract, PaymentContract, PaymentLogic, TicketingContract, and
TicketingOffice.Common.

Note: To add a reference to multiple projects, press and hold the CTRL key while selecting the projects
from the projects list.
Task 3: Add a new WCF service
1. Add a new WCF Service item to the PaymentService project, and name it
TicketsPaymentService.svc.
In the Solution Explorer window, right-click the PaymentService project (the project that you
created in task 1), then select Add, and then select New Item.
In the Add New Item dialog box, in the Visual C# installed templates tree, click the Web folder,
and then select WCF Service from the items list.
Set the name of the new item to TicketsPaymentService.svc, and then click Add.

2. Delete the auto generated file ITicketsPaymentService.cs from the PaymentService project.
3. Open the class TicketsPaymentService. (Double-click the TicketsPaymentService.svc file to open
the class's implementation.)
4. Delete the ITicketsPaymentService interface name and the DoWork method from the class's code.
The class should resemble the following code example:
public class TicketsPaymentService
{
}
5. Add the following using statements to the top of the file:
using TicketingOffice.PaymentService.Contracts;
using TicketingOffice.PaymentService.BusinessLogic;
using TicketingOffice.TicketingService.Contracts;
using TicketingOffice.CrmService.Contracts;
using TicketingOffice.Common.Helpers;
using TicketingOffice.Common.Properties;
6. Have the TicketsPaymentService class implement the IPaymentService contract.
public class TicketsPaymentService : IPaymentService
{
}

Note: Do not try to compile the project, since you have yet to enter the interface implementation code to
the class.
Task 4: Implement the service
1. Decorate the TicketsPaymentService class with the following ServiceBehavior attribute:
L2-6 Lab 2: Service Development Life Cycle

[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode=ConcurrencyMode.Multiple)]
public class TicketsPaymentService : IPaymentService
{

}
2. Add the following private variables to the class:
IPaymentManager manager = new PaymentManager();
ChannelFactory<ITicketingService> ticketingChf;
ChannelFactory<ICrmBase> crmChf;
3. Implement the IPaymentService interface by adding code to the TicketsPaymentService class for
each of the interface's methods: PayForOrder, Refund, FindPayments, and FindPayment.

Note: The service implementation is consuming the CRM service and the Ticketing service to validate the
customer and the order. A proxy is created using a ChannelFactory to minimize the size of the auto-
generated code.
Implement the PayForOrder method.
/// <summary>
/// Pay for a specific order.
/// </summary>
/// <param name="orderID"></param>
/// <param name="payingCustomerID"></param>
/// <param name="amount"></param>
/// <param name="methodOfPayment"></param>
/// <param name="creditCardNumber"></param>
public Payment PayForOrder(
Guid orderID,
Guid payingCustomerID,
double amount,
PaymentType methodOfPayment,
string creditCardNumber)
{
ITicketingService orderProx = null;
ICrmBase crmProx = null;

#region Validate Order
// Contact the ticketing service to ensure that
// the order exist.
lock (this)
{
if (ticketingChf == null)
ticketingChf = new
ChannelFactory<ITicketingService>("TicketingEP");
}

try
{
orderProx = ticketingChf.CreateChannel();
var order = orderProx.FindOrder(orderID);
if (order == null)
throw new NullReferenceException(StringsResource.NullOrder);

//It is always possible to pay less (the order will not be
//approved) but it should not be possible to pay more
Lab 2: Service Development Life Cycle L2-7
//than required.
if (order.TotalPrice < amount)
throw new PaymentException(StringsResource.AmountTooLarge);
}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message);
throw new PaymentException(
StringsResource.FailedToContactTicketing + " " + ex.Message,
ex);
}
finally
{
var channel = orderProx as ICommunicationObject;
if ((channel != null) &&
(channel.State == CommunicationState.Opened))
channel.Close();
}
#endregion

#region Validate Customer
// Contact the Crm service to ensure the customer exists.
// The payment service is using a certificate to identify
// against the crm service.
lock (this)
{
if (crmChf == null)
crmChf = new ChannelFactory<ICrmBase>("CrmEP");
}

try
{
crmProx = crmChf.CreateChannel();
var customer = crmProx.GetCustomerByID(payingCustomerID);
if (customer == null)
throw new NullReferenceException(StringsResource.NullCustomer);
}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message);
throw new PaymentException(
string.Format(
StringsResource.CustomerNotFound,
payingCustomerID),
ex);
}
finally
{
var channel = crmProx as ICommunicationObject;
if ((channel != null) &&
(channel.State == CommunicationState.Opened))
channel.Close();
}

#endregion

var res = manager.PayForOrder(
orderID,
payingCustomerID,
amount,
methodOfPayment,
creditCardNumber);

return res;
L2-8 Lab 2: Service Development Life Cycle

}
Implement the Refund method.
/// <summary>
/// Refund by creating another payment item with negative amount.
/// </summary>
/// <param name="paymentID"></param>
/// <param name="customerID"></param>
public Payment Refund(long paymentID, Guid customerID)
{
ICrmBase crmProx = null;

#region Validate Customer
//Contact the Crm service to ensure the customer exists.
lock (this)
{
if (crmChf == null)
crmChf = new ChannelFactory<ICrmBase>("CrmEP");
}

try
{
crmProx = crmChf.CreateChannel();
var customer = crmProx.GetCustomerByID(customerID);
if (customer == null)
throw new
NullReferenceException(StringsResource.NullCustomer);
}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message);
throw new PaymentException(
string.Format(StringsResource.CustomerNotFound, customerID),
ex);
}
finally
{
var channel = crmProx as ICommunicationObject;
if ((channel != null) &&
(channel.State == CommunicationState.Opened))
channel.Close();
}
#endregion

return manager.Refund(paymentID, customerID);
}
Implement the FindPayments method.
/// <summary>
/// Find payments items according to PaymentCriteria
/// </summary>
/// <param name="criteria"></param>
public Payment[] FindPayments(PaymentCriteria criteria)
{
return manager.FindPayments(criteria);
}
Implement the FindPayment method.
/// <summary>
Lab 2: Service Development Life Cycle L2-9
/// Find a payment item according to its ID
/// </summary>
/// <param name="paymentID"></param>
public Payment FindPayment(long paymentID)
{
return manager.FindPayment(paymentID);
}
4. Save the changes made to the TicketsPaymentService.svc.cs file.
From the File menu, select Save TicketsPaymentService.svc.cs.
Results: After this exercise, you will have written an implementation for the payment service.
Exercise 3: Configuring the Service
Task 1: Delete the entire auto-generated configuration
1. Open the web.config file from the PaymentService project.
2. Delete the entire <system.serviceModel> element and its content. The web.config should look like
the following XML:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Task 2: Configure the service
1. Add the following Entity Framework (EF) connection string inside the <configuration> section of the
web.config file:
<connectionStrings>
<add name="TicketingOfficePaymentEntities"
connectionString="metadata=res://*/PaymentModel.csdl|res://*/PaymentModel.ssdl|res://*/P
aymentModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
2. Add the following services configuration section inside the <configuration> section of the
web.config file:
L2-10 Lab 2: Service Development Life Cycle

<system.serviceModel>
<services>
<service
name="TicketingOffice.PaymentService.TicketsPaymentService"
behaviorConfiguration="StandardBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5004"/>
</baseAddresses>
</host>
<endpoint address="TicketsPayment1"
binding="basicHttpBinding"
contract="TicketingOffice.PaymentService.Contracts.IPaymentService">
</endpoint>
</service>
</services>

<behaviors>
<serviceBehaviors>
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
3. Save the web.config file.
From the File menu, select Save web.config.
Task 3: Use the Visual Studio testing WCF host to host the service
1. Insert a new payment record to the database, using Microsoft SQL Server 2008 Management
Studio, and write down the new ID given to the record.
Click Start, click All Programs, click Microsoft SQL Server 2008, and then click SQL Server
Management Studio.
In the Connect to Server dialog box, enter .\SQLEXPRESS in the Server name field (leave all
other fields with their default values), and then click Connect.

Note: The dot (.) in ".\SQLEXPRESS" is a part of the server's name.
Create a new query window by selecting File, selecting New, and then selecting Query with
Current Connection.
In the new query window, place the following SQL statements, and then press F5 (or select
Query, and then select Execute).
INSERT INTO [TicketingOffice].[PaymentsData].[Payments]
([Amount]
,[Date]
,[MethodOfPayment]
,[OrderID]
,[CustomerID])
VALUES
(100
,1/1/2010
,1
,'00000000-0000-0000-0000-0000000000000000'
Lab 2: Service Development Life Cycle L2-11
,'00000000-0000-0000-0000-0000000000000000')

SELECT @@IDENTITY
Write down the ID (number) shown in the Results window. This ID will be used in the next task.


2. Return to Visual Studio 2010. Right-click the TicketsPaymentService.svc file in the
PaymentService project, and then select Set As Start Page.
3. Right-click the PaymentService project, and then select Debug->Start New Instance. The Visual
Studio 2010 WCF Test Client utility will open, and you will be able to see the hosted service.
Task 4: Test the service using WcfTestClient.exe
1. Test the FindPayment operation of the Payment service using the ID that you wrote down in the
previous task.
Open the service projects tree in the WCF Test Client utility and double-click the FindPayment
operation.
Enter the ID of the payment that you created in task 3, step 1, in the Value cell of the
FindPayment's Request parameters, and then click Invoke.
If a security warning appears, click OK.
L2-12 Lab 2: Service Development Life Cycle


2. Return to Visual Studio and stop debugging.
Return to Visual Studio, open the Debug menu, and then select Stop Debugging.
Results: After this exercise, you will have written a configuration file, and hosted the service using the
Visual Studio test host.
Exercise 4: Consuming the Service Using Channel Factories
Task 1: Call the Payment service using the ChannelFactory<T> type
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex4 - Call the PayForOrder operation of the Payment service
to open the TicketingService.svc.cs file.
3. Use the ChannelFactory<T> type inside the region "Call the payment service" to create a channel
and call the PayForOrder operation of the Payment service.
#region call the payment service

lock (this)
{
if (paymentChf == null)
paymentChf = new ChannelFactory<IPaymentService>("PaymentEP");
}

try
{
paymentProx = paymentChf.CreateChannel();
paymentConfirmation = paymentProx.PayForOrder(
orderID,
payingCustomerID,
amount,
methodOfPayment,
creditCard);

}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message);
Lab 2: Service Development Life Cycle L2-13
throw new TicketingException(
StringsResource.FailedToContactPayment + " " + ex.Message, ex);
}
finally
{
var channel = paymentProx as ICommunicationObject;
if ((channel != null) &&
(channel.State == CommunicationState.Opened))
channel.Close();
}
#endregion
4. Save the TicketingService.svc.cs file.
From the File menu, select Save TicketingService.svc.cs.
Results: After this exercise, you will have created a proxy to the service using a channel factory.
Exercise 5: Consuming the Service Using a Service Reference
Task 1: Host all the services using the simple service host provided
1. Open the SimpleServiceHost project from the Host solution folder and add a reference to the
PaymentService project.
In the Solution Explorer, open the Host solution folder, right-click the SimpleServiceHost
project, and then select Add Reference.
In the Add Reference dialog box, click the Projects tab, select the PaymentService project, and
then click OK.
2. In the Task List window, double-click the comment TODO: Ex5 Host the Payment service, to
open the HostingManager.cs file.
3. Add the payment service information to the dictionary that holds the list of services to host.
In the HostingManager.cs file, locate the static field named ServiceTypeResolver, which is of
type Dictionary<string, Type>.
In the dictionary's collection initializer add the following code:
{"TicketingOffice.PaymentService.TicketsPaymentService",
typeof(TicketingOffice.PaymentService.TicketsPaymentService)}
After adding the Payment service initializer, the dictionary's initialization should resemble the
following code:
static Dictionary<string, Type> ServiceTypeResolver = new Dictionary<string, Type>()
{
{"TicketingOffice.CrmService.CustomerRelationsService",
typeof(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
typeof(CurrencyExchangeService)},

{"TicketingOffice.PricingService.TicketsPricingService", typeof(TicketsPricingService)},

{"TicketingOffice.ShowsService.ShowsAndEventsService", typeof(ShowsAndEventsService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
typeof(TicketingPricingRulesService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
typeof(GeneralTicketingService)},

// TODO: Ex5 - Host the Payment service
L2-14 Lab 2: Service Development Life Cycle

{"TicketingOffice.PaymentService.TicketsPaymentService",
typeof(TicketingOffice.PaymentService.TicketsPaymentService)}

};
4. Save the HostingManager.cs file.
From the File menu, select Save HostingManager.cs.
5. Right-click the SimpleServiceHost project, and then select Set as StartUp Project.
6. Build the solution.
From the Build menu, click Build Solution.
7. Open the Debug menu, and then select Start Without Debugging.
Task 2: Add a service reference to the payment service in the provided client application
1. In the Solution Explorer, open the Client solution folder, right-click the TicketingOffice.UI project,
and then select Add Service Reference.
2. Add a service reference to the running PaymentService, using the address http://localhost:5004.
Set the namespace of the service reference to PaymentServiceReference.
In the Add Service Reference dialog box, enter the address http://localhost:5004 in the
Address field, and then click Go.
After the payment service is added to the Services tree, enter the namespace
PaymentServiceReference in the Namespace field, and then click OK.

3. Build the project TicketingOffice.UI and verify that there are no errors.
Select the TicketingOffice.UI from Solution Explorer by clicking the project.
In the Build menu, select Build TicketingOffice.UI.
Lab 2: Service Development Life Cycle L2-15
Task 3: Consume the Payment service from the client
1. In the Task List window, double-click the comment TODO: Ex5 Call the PayForOrder operation of
the Payment service. The task is located in the btnPayment_Click method.
2. Place the following code inside the btnPayment_Click method, to allow the user to send the
payment request to the service.
double amount;

if (double.TryParse(txtPaymentAmount.Text, out amount))
{
if (amount > 0)
{
// Call the payment service
PaymentServiceReference.IPaymentService proxy = new
PaymentServiceReference.PaymentServiceClient();
proxy.PayForOrder(
SelectedOrder.ID,
SelectedCustomer.ID,
amount,
SelectedPaymentType,
txtCreditCardNo.Text);

// Reload the payments of the selected order
ShowPaymentsForOrder(SelectedOrder);
}
else
{
MessageBox.Show(
Properties.Resources.PayTicketWindow_NewPayment_NotPositive);
}
}
else
{
MessageBox.Show(
Properties.Resources.PayTicketWindow_NewPayment_NotDouble);
}
3. In the Task List window, double-click the comment TODO: Ex5 Call the Refund operation of the
Payment service. The task is located in the btnRefund_Click method.
4. Place the following code inside the btnRefund_Click method:
PaymentServiceReference.IPaymentService proxy = new
PaymentServiceReference.PaymentServiceClient();

proxy.Refund(SelectedPayment.ID, SelectedPayment.CustomerID);
5. In the Task List window, double-click the comment TODO: Ex5 Call the FindPayments operation
of the Payment service. The task is located in the ShowPaymentsForOrder method.
6. Place the following code inside the ShowPaymentsForOrder method:
if (order == null)
lstPayments.ItemsSource = null;
else
{
PaymentServiceReference.IPaymentService proxy = new
PaymentServiceReference.PaymentServiceClient();
lstPayments.ItemsSource = proxy.FindPayments(
new PaymentCriteria() { OrderID = order.ID });
L2-16 Lab 2: Service Development Life Cycle

}
7. Save the PayTicketWindow.xaml.cs file.
From the File menu, select Save PayTicketWindow.xaml.cs.
8. Build the solution.
From the Build menu, select Build Solution.
Task 4: Verify that the service is functioning in a correct manner
1. Make sure the service host is still running
If the service host that you have run in task 1 is closed, repeat task 1, steps 5 to 7.
2. Right-click the TicketingOffice.UI project, select Debug, and then select Start new instance.
3. In the client's main window click the Pay for a ticket button.
4. In the payment window, open the Select the customer drop-down list, and then select Hanson,
Mark.
5. From the Select the order list, select the first order, and then enter the following payment data:
Amount: 100
Type: Credit Card
Card No.: 12345678
6. Click the Approve Payment button.
7. After the service operation completes, you should see the payment information in the payments list
as 100 In CreditCard.
Results: After this exercise, you will have created a proxy to the service using the Add Service
Reference tool in Visual Studio.

Lab 2: Service Development Life Cycle L2-17
Module 2: Getting Started with Microsoft Windows Configuration
Foundation Development
Lab 2: Service Development Life Cycle
Section 2: Visual Basic
Exercise 1: Defining Service and Data Contracts
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M02\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M02\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command prompt window to close it, and then close
the Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M02\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog, move to the D:\LabFiles\Starter\M02\VB folder, click the
TicketingOffice.sln file and click Open.
Task 2: Define the service contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex1 - Decorate service contract and service
operations, to open the PaymentContract.vb file.
3. Add the following attributes in the code:
Decorate the interface with a ServiceContract attribute and set the contract's namespace to
http://www.fabrikam.com.
Decorate each of the interface's methods with an OperationContract attribute.
The complete code should resemble the following code example:
<ServiceContract(Namespace := "http://www.fabrikam.com")>
Public Interface IPaymentService
<OperationContract>
Function PayForOrder(
ByVal orderID As Guid, ByVal payingCustomerID As Guid,
ByVal amount As Double, ByVal methodOfPayment As PaymentType,
ByVal creditCardNumber As String) As Payment
L2-18 Lab 2: Service Development Life Cycle


<OperationContract>
Function Refund(
ByVal paymentID As Long, ByVal customerID As Guid) As Payment

<OperationContract>
Function FindPayments(
ByVal criteria As PaymentCriteria) As Payment()

<OperationContract>
Function FindPayment(ByVal paymentID As Long) As Payment
End Interface
4. Save the change made to the PaymentContract.vb file.
From the File menu, select Save PaymentContract.vb.
Task 3: Define the data contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex1 - Define the Payment Data Contract to open the
Payment.vb file.
3. Add the following attributes in the code:
Decorate the Payment class with the DataContract attributes.
Decorate each property of the class, excluding the MethodOfPaymentID property, with the
DataMember attribute.
The class should resemble the following code example:
<DataContract(Namespace := "http://www.fabrikam.com")>
Public Class Payment
<DataMember>
Public Property ID() As Long

<DataMember>
Public Property Amount() As Double

<DataMember>
Public Property [Date]() As Date

<DataMember>
Public Property CustomerID() As Guid

<DataMember>
Public Property MethodOfPayment() As PaymentType
Get
Return CType(System.Enum.ToObject(GetType(PaymentType),
MethodOfPaymentID), PaymentType)
End Get
Set(ByVal value As PaymentType)
MethodOfPaymentID = CInt(Fix(value))
End Set
End Property

<DataMember>
Public Property OrderID() As Guid

'reflect the MethodOfPayment as an integer
Public Property MethodOfPaymentID() As Integer
End Class
4. Save the change made to the Payment.vb file.
Lab 2: Service Development Life Cycle L2-19
From the File menu, select Save Payment.vb.
5. Double-click the comment TODO: Ex1 - Define the PaymentCriteria Data Contract, to open the
PaymentCriteria.vb file.
6. Add the following attributes in the code:
Decorate the PaymentCriteria class with the DataContract attributes.
Decorate each property of the class with the DataMember attribute.
The class should resemble the following code example:
<DataContract(Namespace := "http://www.fabrikam.com")>
Public Class PaymentCriteria
<DataMember>
Public Property OrderID() As Guid?

<DataMember>
Public Property FromDate() As Date?

<DataMember>
Public Property ToDate() As Date?

<DataMember>
Public Property PayingCustomerID() As Guid?

<DataMember>
Public Property Amount() As Double?
End Class
7. Save the change made to the PaymentCriteria.vb file.
From the File menu, select Save PaymentCriteria.vb.
Results: After this exercise, you will have defined a contract for the payment service.
Exercise 2: Creating a Service Implementation
Task 1: Create a new WCF service application for the payment service under the
payment service folder
1. In the Solution Explorer window, open the Services solution folder, open the Payment solution
folder, and then add a new WCF Service Application for the payment service project and name the
project PaymentService.
Select View, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
Under the Services folder, right-click the Payment solution folder, select Add, and then select
New Project.
In the Add New Project dialog box, select Other Languages from the installed templates tree,
then select Visual Basic, and then select WCF.
From the WCF projects, select the WCF Service Application, set the name of the project to
PaymentService, and then click OK.
The following screen shot shows where you can find the Windows Communication Foundation
(WCF) Service Application project.
L2-20 Lab 2: Service Development Life Cycle


2. In the project properties of the newly created project set the root namespace to
TicketingOffice.PaymentService.
Right-click the newly created project, and then select Properties.
In the PaymentService properties window, under the Application tab, change the Root
namespace field to TicketingOffice.PaymentService.
Save the properties by clicking File, and then clicking Save Selected Items.
Close the properties window.
3. Delete the generated files Service1.svc and IService1.vb from the newly created project.

Note: Deleting the Service1.svc file will also delete the Service1.svc.vb file.
Task 2: Add references
1. Add a reference to the CrmContract, PaymentContract, PaymentLogic, TicketingContract, and
TicketingOffice.Common projects.
In the Solution Explorer, right-click the PaymentService project (the project that you created in
task 1), and then select Add Reference.
In the Add Reference dialog box, click the Projects tab, select the following projects and click
OK: CrmContract, PaymentContract, PaymentLogic, TicketingContract, and
TicketingOffice.Common.

Note: To add a reference to multiple projects, press and hold the CTRL key while selecting the projects
from the projects list.
Task 3: Add a new WCF service
1. Add a new WCF Service item to the PaymentService project, and name it
TicketsPaymentService.svc.
Lab 2: Service Development Life Cycle L2-21
In the Solution Explorer window, right-click the PaymentService project (the project that you
created in task 1), then select Add, and then select New Item.
In the Add New Item dialog box, in the Visual Basic installed templates tree, click the Web
folder, and then select WCF Service from the items list.
Set the name of the new item to TicketsPaymentService.svc, and then click Add.
2. Delete the auto generated file ITicketsPaymentService.vb from the PaymentService project.
3. Open the class TicketsPaymentService. (Double-click the TicketsPaymentService.svc file to open
the class's implementation.)
4. Delete the ITicketsPaymentService interface name and the DoWork method from the class's code.
The class should resemble the following code example:
Public Class TicketsPaymentService
End Class
5. Add the following Imports statements to the top of the file:
Imports TicketingOffice.PaymentService.Contracts
Imports TicketingOffice.PaymentService.BusinessLogic
Imports TicketingOffice.TicketingService.Contracts
Imports TicketingOffice.CrmService.Contracts
Imports TicketingOffice.Common.Helpers
Imports TicketingOffice.Common.Properties
6. Have the TicketsPaymentService class implement the IPaymentService contract.
Public Class TicketsPaymentService
Implements IPaymentService
End Class

Note: Do not try to compile the project, since you have yet to enter the interface implementation code to
the class.
Task 4: Implement the service
1. Decorate the TicketsPaymentService class with the following ServiceBehavior attribute:
<ServiceBehavior(
InstanceContextMode := InstanceContextMode.Single,
ConcurrencyMode := ConcurrencyMode.Multiple)>
Public Class TicketsPaymentService
Implements IPaymentService
End Class
2. Add the following private variables to the class:
Private manager As IPaymentManager = New PaymentManager()
Private ticketingChf As ChannelFactory(Of ITicketingService)
Private crmChf As ChannelFactory(Of ICrmBase)
3. Implement the IPaymentService interface by adding code to the TicketsPaymentService class for
each of the interface's methods: PayForOrder, Refund, FindPayments, and FindPayment.
L2-22 Lab 2: Service Development Life Cycle


Note: The service implementation is consuming the CRM service and the Ticketing service to validate the
customer and the order. A proxy is created using a ChannelFactory to minimize the size of the auto-
generated code.
Implement the PayForOrder method.
''' <summary>
''' Pay for a specific order.
''' </summary>
''' <param name="orderID"></param>
''' <param name="payingCustomerID"></param>
''' <param name="amount"></param>
''' <param name="methodOfPayment"></param>
''' <param name="creditCardNumber"></param>
Public Function PayForOrder(ByVal orderID As Guid, ByVal payingCustomerID As Guid, ByVal
amount As Double, ByVal methodOfPayment As PaymentType, ByVal creditCardNumber As
String) As Payment Implements IPaymentService.PayForOrder
Dim orderProx As ITicketingService = Nothing
Dim crmProx As ICrmBase = Nothing

' Contact the ticketing service to ensure that
' the order exist.
SyncLock Me
If ticketingChf Is Nothing Then
ticketingChf = New ChannelFactory(Of _
ITicketingService)("TicketingEP")
End If
End SyncLock

Try
orderProx = ticketingChf.CreateChannel()
Dim order = orderProx.FindOrder(orderID)
If order Is Nothing Then
Throw New NullReferenceException(StringsResource.NullOrder)
End If

'It is always possible to pay less (the order will not be
'approved) but it should not be possible to pay more
'than required.
If order.TotalPrice < amount Then
Throw New PaymentException(StringsResource.AmountTooLarge)
End If
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message)
Throw New PaymentException(
StringsResource.FailedToContactTicketing & " " &
ex.Message, ex)
Finally
Dim channel = TryCast(orderProx, ICommunicationObject)
If (channel IsNot Nothing) AndAlso
(channel.State = CommunicationState.Opened) Then
channel.Close()
End If
End Try
' Contact the Crm service to ensure the customer exists.
' The payment service is using a certificate to identify
' against the crm service.
SyncLock Me
If crmChf Is Nothing Then
crmChf = New ChannelFactory(Of ICrmBase)("CrmEP")
End If
End SyncLock

Lab 2: Service Development Life Cycle L2-23
Try
crmProx = crmChf.CreateChannel()
Dim customer = crmProx.GetCustomerByID(payingCustomerID)
If customer Is Nothing Then
Throw New NullReferenceException(StringsResource.NullCustomer)
End If
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message)
Throw New PaymentException(String.Format(
StringsResource.CustomerNotFound, payingCustomerID), ex)
Finally
Dim channel = TryCast(crmProx, ICommunicationObject)
If (channel IsNot Nothing) AndAlso
(channel.State = CommunicationState.Opened) Then
channel.Close()
End If
End Try

Dim res = manager.PayForOrder(orderID, payingCustomerID,
amount, methodOfPayment, creditCardNumber)

Return res
End Function
Implement the Refund method.
''' <summary>
''' Refund by creating another payment item with negative amount.
''' </summary>
''' <param name="paymentID"></param>
''' <param name="customerID"></param>
Public Function Refund(
ByVal paymentID As Long, ByVal customerID As Guid) As Payment _
Implements IPaymentService.Refund
Dim crmProx As ICrmBase = Nothing
'Contact the Crm service to ensure the customer exists.
SyncLock Me
If crmChf Is Nothing Then
crmChf = New ChannelFactory(Of ICrmBase)("CrmEP")
End If
End SyncLock

Try
crmProx = crmChf.CreateChannel()
Dim customer = crmProx.GetCustomerByID(customerID)
If customer Is Nothing Then
Throw New NullReferenceException(StringsResource.NullCustomer)
End If
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message)
Throw New PaymentException(String.Format(
StringsResource.CustomerNotFound, customerID), ex)
Finally
Dim channel = TryCast(crmProx, ICommunicationObject)
If (channel IsNot Nothing) AndAlso
(channel.State = CommunicationState.Opened) Then
channel.Close()
End If
End Try

Return manager.Refund(paymentID, customerID)
End Function
L2-24 Lab 2: Service Development Life Cycle

Implement the FindPayments method.
''' <summary>
''' Find payments items according to PaymentCriteria
''' </summary>
''' <param name="criteria"></param>
Public Function FindPayments(ByVal criteria As PaymentCriteria) _
As Payment() Implements IPaymentService.FindPayments
Return manager.FindPayments(criteria)
End Function
Implement the FindPayment method.
''' <summary>
''' Find a payment item according to its ID
''' </summary>
''' <param name="paymentID"></param>
Public Function FindPayment(ByVal paymentID As Long) _
As Payment Implements IPaymentService.FindPayment
Return manager.FindPayment(paymentID)
End Function
4. Save the changes made to the TicketsPaymentService.svc.vb file.
From the File menu, select Save TicketsPaymentService.svc.vb.
Results: After this exercise, you will have written an implementation for the payment service.
Exercise 3: Configuring the Service
Task 1: Delete the entire auto-generated configuration
1. Open the web.config file from the PaymentService project.
2. Delete the entire <system.serviceModel> element and its content. The web.config should look like
the following XML:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" strict="false"
explicit="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Task 2: Configure the service
1. Add the following Entity Framework (EF) connection string inside the <configuration> section of the
web.config file:
<connectionStrings>
<add name="TicketingOfficePaymentEntities"
connectionString="metadata=res://*/PaymentModel.csdl|res://*/PaymentModel.ssdl|res://*/P
aymentModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
Lab 2: Service Development Life Cycle L2-25
2. Add the following services configuration section inside the <configuration> section of the
web.config file:
<system.serviceModel>
<services>
<service
name="TicketingOffice.PaymentService.TicketsPaymentService"
behaviorConfiguration="StandardBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5004"/>
</baseAddresses>
</host>
<endpoint address="TicketsPayment1"
binding="basicHttpBinding"
contract="TicketingOffice.PaymentService.Contracts.IPaymentService">
</endpoint>
</service>
</services>

<behaviors>
<serviceBehaviors>
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
3. Save the web.config file.
From the File menu, select Save web.config.
Task 3: Use the Visual Studio testing WCF host to host the service
1. Insert a new payment record to the database, using Microsoft SQL Server 2008 Management
Studio, and write down the new ID given to the record.
Click Start, click All Programs, click Microsoft SQL Server 2008, and then click SQL Server
Management Studio.
In the Connect to Server dialog box, enter .\SQLEXPRESS in the Server name field (leave all
other fields with their default values), and then click Connect.

Note: The dot (.) in ".\SQLEXPRESS" is a part of the server's name.
Create a new query window by selecting File, selecting New, and then selecting Query with
Current Connection.
In the new query window, place the following SQL statements, and then press F5 (or select
Query, and then select Execute).
INSERT INTO [TicketingOffice].[PaymentsData].[Payments]
([Amount]
,[Date]
,[MethodOfPayment]
,[OrderID]
,[CustomerID])
VALUES
(100
,1/1/2010
,1
,'00000000-0000-0000-0000-0000000000000000'
,'00000000-0000-0000-0000-0000000000000000')

L2-26 Lab 2: Service Development Life Cycle

SELECT @@IDENTITY
Write down the ID (number) shown in the Results window. This ID will be used in the next task.

2. Return to Visual Studio 2010. Right-click the TicketsPaymentService.svc file in the
PaymentService project, and then select Set As Start Page.
3. Right-click the PaymentService project, and then select Debug->Start New Instance. The Visual
Studio 2010 WCF Test Client utility will open, and you will be able to see the hosted service.
Task 4: Test the service using WcfTestClient.exe
1. Test the FindPayment operation of the Payment service using the ID that you wrote down in the
previous task.
Open the service projects tree in the WCF Test Client utility and double-click the FindPayment
operation.
Enter the ID of the payment that you created in task 3, step 1, in the Value cell of the
FindPayment's Request parameters, and then click Invoke.
If a security warning appears, click OK.

Lab 2: Service Development Life Cycle L2-27
2. Return to Visual Studio and stop debugging.
Return to Visual Studio, open the Debug menu, and then select Stop Debugging.
Results: After this exercise, you will have written a configuration file, and hosted the service using the
Visual Studio test host.
Exercise 4: Consuming the Service Using Channel Factories
Task 1: Call the Payment service using the ChannelFactory(Of T) type
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change the selection to Comments.
2. Double-click the comment TODO: Ex4 - Call the PayForOrder operation of the Payment service
to open the TicketingService.svc.vb file.
3. Use the ChannelFactory(Of T) type to create a channel and call the PayForOrder operation of the
Payment service.
SyncLock Me
If paymentChf Is Nothing Then
paymentChf = New ChannelFactory(Of IPaymentService)("PaymentEP")
End If
End SyncLock

Try
paymentProx = paymentChf.CreateChannel()
paymentConfirmation = paymentProx.PayForOrder(orderID,
payingCustomerID, amount, methodOfPayment, creditCard)

Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.Message)
Throw New TicketingException(
StringsResource.FailedToContactPayment & " " & ex.Message, ex)
Finally
Dim channel = TryCast(paymentProx, ICommunicationObject)
If (channel IsNot Nothing) AndAlso
(channel.State = CommunicationState.Opened) Then
channel.Close()
End If
End Try
4. Save the TicketingService.svc.vb file.
From the File menu, select Save TicketingService.svc.vb.
Results: After this exercise, you will have created a proxy to the service using a channel factory.
Exercise 5: Consuming the Service Using a Service Reference
Task 1: Host all the services using the simple service host provided
1. Open the SimpleServiceHost project from the Host solution folder and add a reference to the
PaymentService project.
In the Solution Explorer, open the Host solution folder, right-click the SimpleServiceHost
project, and then select Add Reference.
In the Add Reference dialog box, click the Projects tab, select the PaymentService project, and
then click OK.
L2-28 Lab 2: Service Development Life Cycle

2. In the Task List window, double-click the comment TODO: Ex5 Host the Payment service, to
open the HostingManager.vb file.
3. Add the payment service information to the dictionary that holds the list of services to host.
In the HostingManager.vb file, locate the static field named ServiceTypeResolver, which is of
type Dictionary(Of string, Type).
In the dictionary's collection initializer add the following code:
{"TicketingOffice.PaymentService.TicketsPaymentService",
GetType(TicketingOffice.PaymentService.TicketsPaymentService)}
After adding the Payment service initializer, the dictionary's initialization should resemble the
following code:
Private Shared ServiceTypeResolver As New Dictionary(Of String, Type)() From {
{"TicketingOffice.CrmService.CustomerRelationsService",
GetType(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
GetType(CurrencyExchangeService)},
{"TicketingOffice.PricingService.TicketsPricingService",
GetType(TicketsPricingService)},
{"TicketingOffice.ShowsService.ShowsAndEventsService",
GetType(ShowsAndEventsService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
GetType(TicketingPricingRulesService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
GetType(GeneralTicketingService)},
{"TicketingOffice.PaymentService.TicketsPaymentService",
GetType(TicketingOffice.PaymentService.TicketsPaymentService)}}
4. Save the HostingManager.vb file.
From the File menu, select Save HostingManager.vb.
5. Right-click the SimpleServiceHost project, and then select Set as StartUp Project.
6. Build the solution.
From the Build menu, click Build Solution.
7. Open the Debug menu, and then select Start Without Debugging.
Task 2: Add a service reference to the payment service in the provided client application
1. In the Solution Explorer, open the Client solution folder, right-click the TicketingOffice.UI project,
and then select Add Service Reference.
2. Add a service reference to the running PaymentService, using the address http://localhost:5004.
Set the namespace of the service reference to PaymentServiceReference.
In the Add Service Reference dialog box, enter the address http://localhost:5004 in the
Address field, and then click Go.
After the payment service is added to the Services tree, enter the namespace
PaymentServiceReference in the Namespace field, and then click OK.
Lab 2: Service Development Life Cycle L2-29

3. Build the project TicketingOffice.UI and verify that there are no errors.
Select the TicketingOffice.UI from Solution Explorer by clicking the project.
In the Build menu, select Build TicketingOffice.UI.
Task 3: Consume the Payment service from the client
1. In the Task List window, double-click the comment TODO: Ex5 Call the PayForOrder operation of
the Payment service. The task is located in the btnPayment_Click method.
2. Place the following code inside the btnPayment_Click method, to allow the user to send the
payment request to the service.
Dim amount As Double

If Double.TryParse(txtPaymentAmount.Text, amount) Then
If amount > 0 Then
' Call the payment service
Dim proxy As PaymentServiceReference.IPaymentService =
New PaymentServiceReference.PaymentServiceClient()

proxy.PayForOrder(
SelectedOrder.ID, SelectedCustomer.ID, amount,
SelectedPaymentType, txtCreditCardNo.Text)

' Reload the payments of the selected order
ShowPaymentsForOrder(SelectedOrder)
Else
MessageBox.Show(
Properties.Resources.PayTicketWindow_NewPayment_NotPositive)
End If
Else
MessageBox.Show(
Properties.Resources.PayTicketWindow_NewPayment_NotDouble)
End If
L2-30 Lab 2: Service Development Life Cycle

3. In the Task List window, double-click the comment TODO: Ex5 Call the Refund operation of the
Payment service. The task is located in the btnRefund_Click method.
4. Place the following code inside the btnRefund_Click method:
Dim proxy As PaymentServiceReference.IPaymentService =
New PaymentServiceReference.PaymentServiceClient()
proxy.Refund(SelectedPayment.ID, SelectedPayment.CustomerID)
5. In the Task List window, double-click the comment TODO: Ex5 Call the FindPayments operation
of the Payment service. The task is located in the ShowPaymentsForOrder method.
6. Place the following code inside the ShowPaymentsForOrder method:
If order Is Nothing Then
lstPayments.ItemsSource = Nothing
Else
Dim proxy As PaymentServiceReference.IPaymentService =
New PaymentServiceReference.PaymentServiceClient()
lstPayments.ItemsSource = proxy.FindPayments(
New PaymentCriteria() With {.OrderID = order.ID})
End If
7. Save the PayTicketWindow.xaml.vb file.
From the File menu, select Save PayTicketWindow.xaml.vb.
8. Build the solution.
From the Build menu, select Build Solution.
Task 4: Verify that the service is functioning in a correct manner
1. Make sure the service host is still running
If the service host that you have run in task 1 is closed, repeat task 1, steps 5 to 7.
2. Right-click the TicketingOffice.UI project, select Debug, and then select Start new instance.
3. In the client's main window click the Pay for a ticket button.
4. In the payment window, open the Select the customer drop-down list, and then select Hanson,
Mark.
5. From the Select the order list, select the first order, and then enter the following payment data:
Amount: 100
Type: Credit Card
Card No.: 12345678
6. Click the Approve Payment button.
7. After the service operation completes, you should see the payment information in the payments list
as 100 In CreditCard.
Results: After this exercise, you will have created a proxy to the service using the Add Service
Reference tool in Visual Studio.


Lab 3: Hosting Windows Communication Foundation Services L3-1
Module 3: Hosting Microsoft Windows Communication
Foundation Services
Lab 3: Hosting Windows Communication
Foundation Services
Section 1: Visual C#
Exercise 1: Using Windows Server AppFabric
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M03\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M03\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command prompt window to close it, and then close
the Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M03\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M03\CS folder, click the
TicketingOffice.sln file, and then click Open.
6. Build the solution.
From the Build menu, select Build Solution.
Task 2: Deploy the CrmService service to IIS (built on WAS) using a deployment package
1. Create a deployment package for the CrmService service.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
Open the Crm solution folder, right-click the CrmService project, and then select Build
Deployment Package.
2. Open the Internet Information Services (IIS) Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import to the Default Web Site the package that you have created, and name it
FabrikamTicketingCrm.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
L3-2 Lab 3: Hosting Windows Communication Foundation Services

In the Actions pane (the right pane), expand the Deploy tab, and then select Import
Application.
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M03\CS\Services\Crm\CrmService\obj\Debug\Package\CrmService.zip
In the Select the Contents of the Package step of the wizard, click Next.
In the Enter Application Package Information step of the wizard, set the Application Path to
FabrikamTicketingCrm, and then click Next.
If a message displays asking whether to run the application in the default .NET 4.0 application
pool, click Yes.
In the Installation Progress and Summary step of the wizard, wait for the process to complete,
and then click Finish.
4. Close the IIS Manager.
Task 3: Test the CrmService service using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address
http://localhost/FabrikamTicketingCrm/CrmService.svc.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCrm/CrmService.svc, and then click OK.
3. Call the GetCustomerByID operation of the ICrmService contract to test the service.
In the My Service Projects tree, open the ICrmService operations list, and double-click the
GetCustomerByID operation.
Click Invoke, and if a security warning appears, click OK.
Validate that the response value is null, without an exception.


4. Close the WcfTestClient utility.

Lab 3: Hosting Windows Communication Foundation Services L3-3
Task 4: Add a TCP endpoint
1. Open the CrmService project's configuration file.
Return to Visual Studio 2010, open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
In the CrmService project, double-click the web.config file.
2. Locate the CrmService service configuration in the services section of the web.config file.
In the web.config file, under the configuration XML element, locate the services section that is
inside the system.serviceModel section.
In the services section, locate the service XML element that has the name attribute with the
value of TicketingOffice.CrmService.CustomerRelationsService.
3. Add a TCP endpoint with the NoSecurity binding configuration:
<endpoint
address=""
binding="netTcpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
4. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
5. Verify that the Default Web Site in IIS has a TCP binding.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the Actions pane (the right pane), under Edit Site, click Bindings.
In the Site Bindings dialog box, verify that there is a net.tcp binding.
Click the Close button to close the Site Bindings dialog box.

6. Enable the net.tcp protocol for the FabrikamTicketingCrm web application.
On the Connections pane (the left pane), expand the Default Web Site, and then click the
FabrikamTicketingCrm application.
In the Actions pane (the right pane), under Manage Application, click the Advanced Settings.
In the Advanced Settings dialog box, under Behavior, in the Enabled Protocols box, enter
http, net.tcp, and then click OK.
L3-4 Lab 3: Hosting Windows Communication Foundation Services

7. Redeploy the CrmService service to IIS using a deployment package.
Repeat the steps in Task 2 of this exercise.
If an Overwrite Existing Files step displays in the wizard, select "Yes, delete all extra files and
folders on the destination that are not in the application package", and then click Next.
8. Close the IIS Manager.
Task 5: Test the CrmService service TCP endpoint, using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address
http://localhost/FabrikamTicketingCrm/CrmService.svc.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCrm/CrmService.svc, and then click OK.
3. Call the GetCustomerByID operation using the TCP endpoint to test the service.
In the My Service Projects tree, double-click the GetCustomerByID operation under
ICrmService (NetTcpBinding_ICrmService).
Click Invoke, and if a security warning appears, click OK.
4. Validate that the response value is null, without an exception. Do not close the WcfTestClient.

Task 6: Verify the service runtime behavior using the AppFabric Dashboard
1. Call the CrmService service five times.
Lab 3: Hosting Windows Communication Foundation Services L3-5
In the WcfTestClient, click Invoke five times.
2. Close the WcfTestClient utility.
3. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
4. Open the Windows Server AppFabric Dashboard in the IIS console.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
Under AppFabric, double-click AppFabric Dashboard.

5. Use the Dashboard to monitor the FabrikamTicketingCrm service.

6. Close the IIS Manager.
Results: After this exercise, you will have hosted a service using IIS, and used the AppFabric Dashboard
to monitor the service.
Exercise 2: Using Windows Services
Task 1: Create a new Windows Service
1. Create a new Windows Service project in the host solution folder, with the name
TicketingWindowsService.
L3-6 Lab 3: Hosting Windows Communication Foundation Services

Return to Visual Studio 2010, open the View menu, and then select Solution Explorer.
Right-click the Host solution folder, then select Add, and then select New Project.
In the Add New Project dialog box, in the Installed Templates tree, select Visual C#, and then
select Windows.
Select the Windows Service template.
In the Name text box, enter TicketingWindowsService.
In the Location text box, enter D:\LabFiles\Starter\M03\CS\Host and click OK.
2. Rename the generated service name to TicketingOfficeWindowsService.cs.
In the TicketingWindowsService project, Right-click Service1.cs, and then select Rename.
Rename the file TicketingOfficeWindowsService.cs, and then press Enter.
In the popup window, click Yes.
3. Create a Service Installer.
Right-click the designer surface, and then select Add Installer.
Right-click serviceProcessInstaller1 in the designer surface, and then select Properties.
In the Properties panel, set the Account property to LocalSystem.
Right-click serviceInstaller1 in the designer surface, and then select Properties.
Set the ServiceName property to TicketingOfficeService, and the Description property to
Ticketing Office Host.
4. Save the ProjectInstaller.cs file.
From the File menu, select Save ProjectInstaller.cs.
5. Add all the .cs and .config files from the D:\LabFiles\Starter\M03\CS\FilesToImport folder to the
TicketingWindowsService project.
Open the View menu, and select Solution Explorer.
Open the Host solution folder, right-click the TicketingWindowsService project, then select
Add, and then select Existing Item.
In the Add Existing Item dialog box, open the D:\LabFiles\Starter\M03\CS\FilesToImport
folder.
Set the combo box to show All Files.
Select all the files in the folder (App.config, HostingException.cs, and HostingManager.cs),
and then click Add.
6. Add a reference to assemblies System.Configuration, System.Data.Entity, System.IdentityModel,
System.Runtime.Serialization, System.Security and System.ServiceModel.
Right-click TicketingWindowsService project, and then select Add Reference.
In the Add Reference dialog box, click the .NET tab.
Select the following assemblies, and then click OK: System.Configuration, System.Data.Entity,
System.IdentityModel, System.Runtime.Serialization, System.Security, and
System.ServiceModel,.
Lab 3: Hosting Windows Communication Foundation Services L3-7
7. Add a reference to select projects ClientNotification, ClientNotificationContract, CrmContract,
CrmService, CurrencyExchangeContract, CurrencyExchangeWcfService, HallStateContract,
HallStateService, PaymentContract, PaymentService, PricingContract, PricingRulesService,
PricingService, ShowsContract, TicketingContract, TicketingOffice.Common, and
TicketingService.
Right-click TicketingWindowsService project, and then select Add Reference.
In the Add Reference dialog box, click the Projects tab, select the following projects, and click
then OK: ClientNotification, ClientNotificationContract, CrmContract, CrmService,
CurrencyExchangeContract, CurrencyExchangeWcfService, HallStateContract,
HallStateService, PaymentContract, PaymentService, PricingContract, PricingRulesService,
PricingService, ShowsContract, TicketingContract, TicketingOffice.Common, and
TicketingService.
8. Replace the OnStart and OnStop methods of the TicketingOfficeWindowsService class with the
following code example.
Right-click TicketingOfficeWindowsService.cs, and select View Code.
Replace the OnStart and OnStop method with the following code.
protected override void OnStart(string[] args)
{
HostingManager.CreateHosts();
HostingManager.StartHosts();
}

protected override void OnStop()
{
try
{
HostingManager.StopHost(null);
}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Error, ex.ToString());
}
finally
{
LoggingManager.Logger.Flush();
}
}
9. Add the following namespace to TicketingOfficeWindowsService class.
using TicketingOffice.WindowsServiceHost;
using TicketingOffice.Common.Helpers;
10. Save the TicketingOfficeWindowsService.cs file.
From the File menu, select Save TicketingOfficeWindowsService.cs.
Task 2: Host the new Windows Service
1. Examine the content of the task list.
From the View menu, select the Task List option.
L3-8 Lab 3: Hosting Windows Communication Foundation Services

In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double click the comment TODO: Ex2 Implement CreateHosts function in the Hosting
Manager. This opens the HostingManager.cs file.
3. Replace the CreateHosts method and its content with the following code:
public static void CreateHosts()
{
LoggingManager.Logger.Log(LoggingCategory.Info,
StringsResource.CreateHosts);

var cfg = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None).GetSectionGroup(
"system.serviceModel");

var servicesConfig = cfg.Sections["services"] as ServicesSection;

if (servicesConfig == null)
throw new HostingException(
StringsResource.SevicesToHostNotFound);

foreach (ServiceElement item in servicesConfig.Services)
{
try
{
Hosts[item.Name] = new
ServiceHost(ServiceTypeResolver[item.Name]);
Hosts[item.Name].Extensions.Add(new
ServerStateHostExtension());
Hosts[item.Name].Extensions.Add(new CacheHostExtension());
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.HostCreated, item.Name));

Hosts[item.Name].Faulted += new
EventHandler(HostingManager_Faulted);
}
catch (Exception ex)
{
LoggingManager.Logger.Log(LoggingCategory.Warning,
string.Format(
StringsResource.HostCreationFailed, item.Name,
ex.ToString()));
EventLog.WriteEntry(
"TicketingWindowsService", ex.ToString(),
EventLogEntryType.Error);
}
}
}

Note: The CreateHosts method reads the services configuration section, and creates a new
ServiceHost for each discovered service. The CreateHosts method configures each host and
adds extensions to it.
4. Double click the comment TODO: Ex2 Implement StartHosts function in the Hosting Manager.
This opens the HostingManager.cs file.
5. Replace the StartHosts method and its content with the following code:
Lab 3: Hosting Windows Communication Foundation Services L3-9
public static void StartHosts()
{
ServiceHost err = null;
StringBuilder sb = new StringBuilder();
LoggingManager.Logger.Log(LoggingCategory.Info,
StringsResource.StatrtHosts);
foreach (ServiceHost host in Hosts.Values)
{
try
{
err = host;
host.Open();

if (host.State == CommunicationState.Opened)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.HostStarted,
host.Description.Name));

foreach (var dispatcher in host.ChannelDispatchers)
{
if ((dispatcher.Listener != null) &&
(dispatcher.Listener.Uri != null))
sb.AppendLine(
string.Format(
StringsResource.ListentingAt,
dispatcher.Listener.Uri.AbsoluteUri));
}
LoggingManager.Logger.Log(
LoggingCategory.Info, sb.ToString());
sb.Clear();
}
}
catch (Exception ex)
{
LoggingManager.Logger.Log(
LoggingCategory.Warning,
string.Format(
StringsResource.HostStartFailed,
err.Description.Name, ex.ToString()));

EventLog.WriteEntry(
"TicketingWindowsService", ex.ToString(),
EventLogEntryType.Error);
}
}
}

Note: The StartHosts method iterates through all the newly created hosts and opens them. If one host
fails to open, it will not stop the others from opening.
Task 3: Install the service
1. Open the TicketingWindowsService project properties window.
Right-click TicketingWindowsService project, and select Properties.
2. Under the Application tab, set the target framework to .Net Framework 4.
3. In the Target Framework Change dialog box, click Yes.
L3-10 Lab 3: Hosting Windows Communication Foundation Services

4. If a Save Files dialog box appears, click Yes.
5. Build the project.
In the Solution Explorer window, right-click the TicketingWindowsService project, and then
select Build.
6. Open a Visual Studio 2010 command prompt.
Click Start, then click All Programs, then click Microsoft Visual Studio 2010, then click Visual
Studio Tools, and then click Visual Studio Command Prompt (2010).
7. Install the TicketingWindows Service using the command prompt.
In a command prompt window, type the following code, and then press ENTER: installutil -i
d:\LabFiles\Starter\M03\CS\Host\TicketingWindowsService\bin\Debug\TicketingWindows
Service.exe
8. Close the Visual Studio 2010 command prompt.
Task 4: Start the new Windows Service
1. Open the Services Microsoft Management Console (MMC) snap-in, and identify the new
TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Locate the TicketingOfficeService service in the services list.

2. Right-click TicketingOfficeService in the services list, and then click Properties.
3. Change the LogOn settings to the Administrator account, using the password Pa$$w0rd.
Click the Log On tab.
Select the This Account option.
Lab 3: Hosting Windows Communication Foundation Services L3-11
In the This account text box, type Administrator.
In the Password text box, type Pa$$w0rd.
In the Confirm Password text box, type Pa$$w0rd, and then click OK.
If a message box displays, click OK.
4. Start the TicketingOfficeService service.
Right-click the TicketingOfficeService service, and then select Start.
5. Close the Service window.
6. Verify that the service is running by checking that ports 5001-5006 are open and listening.
Click Start, then click All Programs, then click Microsoft Visual Studio 2010, then click Visual
Studio Tools, and then click Visual Studio Command Prompt (2010).
In a command line window, type netstat a.
Verify that you see ports 5001-5006, and that their state is LISTENING


Results: After this exercise, you will have hosted services using a Windows Service.
Exercise 3: Hosting Services in a Windows Application
Task 1: Create a service host for the notification service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Host this form as a service to open the
ServiceNotificationWindow.xaml.cs file.
3. Add the following code at the beginning of the btnListen_Click method.
_host = new ServiceHost(this);
_host.Open();

Note: The implementation class for the service is the actual form, thus the host is opened for a singleton
objectthere is only one form.
L3-12 Lab 3: Hosting Windows Communication Foundation Services

Task 2: Add the client implementation of the INotification interface
1. Double click the comment TODO: Ex3 Implement IClientNotification MessageArrived method
to locate the MessageArrived method.
2. Add the following method to the MessageArrived method:
_messages.Add(message);
3. Save the ServiceNotificationWindow.xaml.cs file.
From the File menu, select Save ServiceNotificationWindow.xaml.cs.
Task 3: Add the WCF service configuration for the notification service
1. Open the App.config configuration file of the TicketingOffice.UI project
In the Solution Explorer window, open the TicketingOffice.UI project from the Client solution
folder.
In the TicketingOffice.UI project, double-click the App.config file.
2. Add a Services section with on one service under the system.serviceModel section, using the
following XML:
<services>
<service name="TicketingOffice.UI.ServiceNotificationWindow">
<host>
<baseAddresses>
<add baseAddress=
"http://localhost:8733/TicketingOffice/ClientNotification"/>
</baseAddresses>
</host>

<endpoint binding="basicHttpBinding"
contract="TicketingOffice.ClientNotification.Contract.IClientNotification"/>
</service>
</services>

Results: After this exercise, you will have hosted a service under a Windows Presentation Foundation
(WPF) window application.
Exercise 4: Using Performance Counters for Service Monitoring
Task 1: Enable all performance counters in the TicketingWindowsService configuration
file
1. Open the App.config configuration file of the TicketingWindowsService Service.
In the Solution Explorer window, open the TicketingWindowsService project from the Host
solution folder.
In the TicketingWindowsService project,double-click the App.config file.
2. Add the following diagnostics element section under the system.serviceModel.
Lab 3: Hosting Windows Communication Foundation Services L3-13
<diagnostics performanceCounters="All" />
Task 2: Restart the service
1. Stop the TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Right-click TicketingOfficeService, and then click Stop.
2. Keep the Services management window open, and switch to Visual Studio 2010.
3. Build the TicketingWindowsService project.
Right-click TicketingWindowsService project, and select Build.
4. Restart the service.
Return to the Services management window.
Right-click TicketingOfficeService, and then click Start.
5. Close the Service window.
Task 3: Use Windows Performance Monitor (perfmon.exe)
1. Open the Window Performance Monitor.
Click Start, then select Administrative Tools, and then select Performance Monitor
2. In the Performance Monitor window, select Performance, then select Monitoring Tools, and then
select Performance Monitor.
3. Right-click the graph. and select Add Counters.
4. under Available counters, expand ServiceModelService 4.0.0.0.
5. Select the Calls Duration and Calls Per Second performance counters.
6. Under Instances of Selected object, select the instance that starts with
CustomerRelationsService@http://localhost:5001/, click Add, and then click OK.
L3-14 Lab 3: Hosting Windows Communication Foundation Services


7. Leave the Performance Monitor running, and do not close the window.
Task 4: Examine the counters
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address http://localhost:5001.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
3. In the Add Service dialog box, enter the address http://localhost:5001, and then click OK.
4. Call the GetCustomerByID operation using the WS2007HttpBinding endpoint to test the service.
In the My Service Projects tree, under ICrmService (WS2007HttpBinding_ICrmService),
double-click the GetCustomerByID operation.
Click Invoke five times, and if a security warning appears, click OK.
5. Close the WcfTestClient utility, and return to the Performance Monitor.
6. Examine the graph of the Calls Per Second counter.
7. Stop the TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Right-click TicketingOfficeService, and then click Stop.
Lab 3: Hosting Windows Communication Foundation Services L3-15
Results: After this exercise, you will have enabled performance counter on your service, and used the
Performance Monitor to monitor several Windows Communication Foundation (WCF) performance
counters.


L3-16 Lab 3: Hosting Windows Communication Foundation Services

Module 3: Hosting Microsoft Windows Communication
Foundation Services
Lab 3: Hosting Windows Communication
Foundation Services
Section 2: Visual Basic
Exercise 1: Using Windows Server AppFabric
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M03\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M03\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command prompt window to close it, and then close
the Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M03\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M03\VB folder, click the
TicketingOffice.sln file, and then click Open.
6. Build the solution.
From the Build menu, select Build Solution.
Task 2: Deploy the CrmService service to IIS (built on WAS) using a deployment package
1. Create a deployment package for the CrmService service.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
Open the Crm solution folder, right-click the CrmService project, and then select Build
Deployment Package.
2. Open the Internet Information Services (IIS) Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import to the Default Web Site the package that you have created, and name it
FabrikamTicketingCrm.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the Actions pane (the right pane), expand the Deploy tab, and then select Import
Application.
Lab 3: Hosting Windows Communication Foundation Services L3-17
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M03\VB\Services\Crm\CrmService\obj\Debug\Package\CrmService.zip
In the Select the Contents of the Package step of the wizard, click Next.
In the Enter Application Package Information step of the wizard, set the Application Path to
FabrikamTicketingCrm, and then click Next.
If a message displays asking whether to run the application in the default .NET 4.0 application
pool, click Yes.
In the Installation Progress and Summary step of the wizard, wait for the process to complete,
and then click Finish.
4. Close the IIS Manager.
Task 3: Test the CrmService service using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address
http://localhost/FabrikamTicketingCrm/CrmService.svc.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCrm/CrmService.svc, and then click OK.
3. Call the GetCustomerByID operation of the ICrmService contract to test the service.
In the My Service Projects tree, open the ICrmService operations list, and double-click the
GetCustomerByID operation.
Click Invoke, and if a security warning appears, click OK.
Validate that the response value is null, without an exception.

4. Close the WcfTestClient utility.
Task 4: Add a TCP endpoint
1. Open the CrmService project's configuration file.
Return to Visual Studio 2010, open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
In the CrmService project, double-click the web.config file.
L3-18 Lab 3: Hosting Windows Communication Foundation Services

2. Locate the CrmService service configuration in the services section of the web.config file.
In the web.config file, under the configuration XML element, locate the services section that is
inside the system.serviceModel section.
In the services section, locate the service XML element that has the name attribute with the
value of TicketingOffice.CrmService.CustomerRelationsService.
3. Add a TCP endpoint with the NoSecurity binding configuration:
<endpoint
address=""
binding="netTcpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
4. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
5. Verify that the Default Web Site in IIS has a TCP binding.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the Actions pane (the right pane), under Edit Site, click Bindings.
In the Site Bindings dialog box, verify that there is a net.tcp binding.
Click the Close button to close the Site Bindings dialog box.

6. Enable the net.tcp protocol for the FabrikamTicketingCrm web application.
On the Connections pane (the left pane), expand the Default Web Site, and then click the
FabrikamTicketingCrm application.
In the Actions pane (the right pane), under Manage Application, click the Advanced Settings.
In the Advanced Settings dialog box, under Behavior, in the Enabled Protocols box, enter
http, net.tcp, and then click OK.
7. Redeploy the CrmService service to IIS using a deployment package.
Repeat the steps in Task 2 of this exercise.
If an Overwrite Existing Files step displays in the wizard, select "Yes, delete all extra files and
folders on the destination that are not in the application package", and then click Next.
8. Close the IIS Manager.
Lab 3: Hosting Windows Communication Foundation Services L3-19
Task 5: Test the CrmService service TCP endpoint, using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address
http://localhost/FabrikamTicketingCrm/CrmService.svc.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCrm/CrmService.svc, and then click OK.
3. Call the GetCustomerByID operation using the TCP endpoint to test the service.
In the My Service Projects tree, double-click the GetCustomerByID operation under
ICrmService (NetTcpBinding_ICrmService).
Click Invoke, and if a security warning appears, click OK.
4. Validate that the response value is null, without an exception. Do not close the WcfTestClient.

Task 6: Verify the service runtime behavior using the AppFabric Dashboard
1. Call the CrmService service five times.
In the WcfTestClient, click Invoke five times.
2. Close the WcfTestClient utility.
3. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
4. Open the Windows Server AppFabric Dashboard in the IIS console.
L3-20 Lab 3: Hosting Windows Communication Foundation Services

From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
Under AppFabric, double-click AppFabric Dashboard.

5. Use the Dashboard to monitor the FabrikamTicketingCrm service.

6. Close the IIS Manager.

Results: After this exercise, you will have hosted a service using IIS, and used the AppFabric Dashboard
to monitor the service.
Exercise 2: Using Windows Services
Task 1: Create a new Windows Service
1. Create a new Windows Service project in the host solution folder, with the name
TicketingWindowsService.
Return to Visual Studio 2010, open the View menu, and then select Solution Explorer.
Right-click the Host solution folder, then select Add, and then select New Project.
In the Add New Project dialog box, in the Installed Templates tree, select Other Languages,
then select Visual Basic, and then select Windows.
Select the Windows Service template.
In the Name text box, enter TicketingWindowsService.
In the Location text box, enter D:\LabFiles\Starter\M03\VB\Host and click OK.
2. Rename the generated service name to TicketingOfficeWindowsService.vb.
Lab 3: Hosting Windows Communication Foundation Services L3-21
In the TicketingWindowsService project, Right-click Service1.vb, and then select Rename.
Rename the file TicketingOfficeWindowsService.vb, and then press Enter.
In the popup window, click Yes.
3. Create a Service Installer.
Right-click the designer surface, and then select Add Installer.
Right-click serviceProcessInstaller1 in the designer surface, and then select Properties.
In the Properties panel, set the Account property to LocalSystem.
Right-click serviceInstaller1 in the designer surface, and then select Properties.
Set the ServiceName property to TicketingOfficeService, and the Description property to
Ticketing Office Host.
4. Save the ProjectInstaller.vb file.
From the File menu, select Save ProjectInstaller.vb.
5. Add all the .vb and .config files from the D:\LabFiles\Starter\M03\VB\FilesToImport folder to the
TicketingWindowsService project.
Open the View menu, and select Solution Explorer.
Open the Host solution folder, right-click the TicketingWindowsService project, then select
Add, and then select Existing Item.
In the Add Existing Item dialog box, open the D:\LabFiles\Starter\M03\VB\FilesToImport
folder.
Set the combo box to show All Files.
Select all the files in the folder (App.config, HostingException.vb, and HostingManager.vb),
and then click Add.
6. Add a reference to assemblies System.Configuration, System.Data.Entity, System.IdentityModel,
System.Runtime.Serialization, System.Security and System.ServiceModel.
Right-click TicketingWindowsService project, and then select Add Reference.
In the Add Reference dialog box, click the .NET tab.
Select the following assemblies, and then click OK: System.Configuration, System.Data.Entity,
System.IdentityModel, System.Runtime.Serialization, System.Security, and
System.ServiceModel,.
7. Add a reference to select projects ClientNotification, ClientNotificationContract, CrmContract,
CrmService, CurrencyExchangeContract, CurrencyExchangeWcfService, HallStateContract,
HallStateService, PaymentContract, PaymentService, PricingContract, PricingRulesService,
PricingService, ShowsContract, TicketingContract, TicketingOffice.Common, and
TicketingService.
Right-click TicketingWindowsService project, and then select Add Reference.
In the Add Reference dialog box, click the Projects tab, select the following projects, and click
then OK: ClientNotification, ClientNotificationContract, CrmContract, CrmService,
CurrencyExchangeContract, CurrencyExchangeWcfService, HallStateContract,
HallStateService, PaymentContract, PaymentService, PricingContract, PricingRulesService,
PricingService, ShowsContract, TicketingContract, TicketingOffice.Common, and
TicketingService.
8. Replace the OnStart and OnStop methods of the TicketingOfficeWindowsService class with the
following code example.
Right-click TicketingOfficeWindowsService.vb, and select View Code.
Replace the OnStart and OnStop method with the following code.
L3-22 Lab 3: Hosting Windows Communication Foundation Services

Protected Overrides Sub OnStart(ByVal args() As String)
HostingManager.CreateHosts()
HostingManager.StartHosts()
End Sub

Protected Overrides Sub OnStop()
Try
HostingManager.StopHost(Nothing)
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Error, ex.ToString())
Finally
LoggingManager.Logger.Flush()
End Try
End Sub
9. Add the following namespace to TicketingOfficeWindowsService class.
Imports TicketingWindowsService.TicketingOffice.WindowsServiceHost
Imports TicketingOffice.Common.Helpers
10. Save the TicketingOfficeWindowsService.vb file.
From the File menu, select Save TicketingOfficeWindowsService.vb.
Task 2: Host the new Windows Service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double click the comment TODO: Ex2 Implement CreateHosts function in the Hosting
Manager. This opens the HostingManager.vb file.
3. Replace the CreateHosts method and its content with the following code:
Public Shared Sub CreateHosts()
' TODO: Ex2 Implement CreateHosts function in the Hosting Manager
LoggingManager.Logger.Log(
LoggingCategory.Info, StringsResource.CreateHosts)
Dim cfg = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None).GetSectionGroup(
"system.serviceModel")

Dim servicesConfig = TryCast(
cfg.Sections("services"), ServicesSection)

If servicesConfig Is Nothing Then
Throw New HostingException(StringsResource.SevicesToHostNotFound)
End If

For Each item As ServiceElement In servicesConfig.Services
Try
Hosts(item.Name) = New ServiceHost(ServiceTypeResolver(
item.Name))
Hosts(item.Name).Extensions.Add(New ServerStateHostExtension())
Hosts(item.Name).Extensions.Add(New CacheHostExtension())
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.HostCreated, item.Name))
AddHandler Hosts(item.Name).Faulted, AddressOf _
Lab 3: Hosting Windows Communication Foundation Services L3-23
HostingManager_Faulted
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Warning,
String.Format(StringsResource.HostCreationFailed, item.Name,
ex.ToString()))
EventLog.WriteEntry("TicketingWindowsService", ex.ToString(),
EventLogEntryType.Error)
End Try
Next item
End Sub

Note: The CreateHosts method reads the services configuration section, and creates a new
ServiceHost for each discovered service. The CreateHosts method configures each host and
adds extensions to it.
4. Double click the comment TODO: Ex2 Implement StartHosts function in the Hosting Manager.
This opens the HostingManager.vb file.
5. Replace the StartHosts method and its content with the following code:
Public Shared Sub StartHosts()
' TODO: Ex2 Implement StartHosts function in the Hosting Manager

Dim err As ServiceHost = Nothing
Dim sb As New StringBuilder()
LoggingManager.Logger.Log(LoggingCategory.Info,
StringsResource.StatrtHosts)
For Each host As ServiceHost In Hosts.Values
Try
err = host
host.Open()

If host.State = CommunicationState.Opened Then
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.HostStarted,
host.Description.Name))
For Each l_dispatcher In host.ChannelDispatchers
If (l_dispatcher.Listener IsNot Nothing) AndAlso
(l_dispatcher.Listener.Uri IsNot Nothing) Then
sb.AppendLine(String.Format(StringsResource.ListentingAt,
l_dispatcher.Listener.Uri.AbsoluteUri))
End If
Next l_dispatcher
LoggingManager.Logger.Log(LoggingCategory.Info, sb.ToString())
sb.Clear()
End If
Catch ex As Exception
LoggingManager.Logger.Log(LoggingCategory.Warning,
String.Format(StringsResource.HostStartFailed,
err.Description.Name, ex.ToString()))

EventLog.WriteEntry("TicketingWindowsService", ex.ToString(),
EventLogEntryType.Error)
End Try
Next host
End Sub

Note: The StartHosts method iterates through all the newly created hosts and opens them. If one host
fails to open, it will not stop the others from opening.
L3-24 Lab 3: Hosting Windows Communication Foundation Services

Task 3: Install the service
1. Open the TicketingWindowsService project properties window.
Right-click TicketingWindowsService project, and select Properties.
2. Under the Compile tab, click the Advanced Compile Options button, then in the Advanced
Compiler Settings dialog box set the target framework to .Net Framework 4, and then click OK.
3. In the Target Framework Change dialog box, click Yes.
4. If a Save Files dialog box appears, click Yes.
5. Build the project.
In the Solution Explorer window, right-click the TicketingWindowsService project, and then
select Build.
6. Open a Visual Studio 2010 command prompt.
Click Start, then click All Programs, then click Microsoft Visual Studio 2010, then click Visual
Studio Tools, and then click Visual Studio Command Prompt (2010).
7. Install the TicketingWindows Service using the command prompt.
In a command prompt window, type the following code, and then press ENTER: installutil -i
d:\LabFiles\Starter\M03\VB\Host\TicketingWindowsService\bin\Debug\TicketingWindow
sService.exe
8. Close the Visual Studio 2010 command prompt.
Task 4: Start the new Windows Service
1. Open the Services Microsoft Management Console (MMC) snap-in, and identify the new
TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Locate the TicketingOfficeService service in the services list.

Lab 3: Hosting Windows Communication Foundation Services L3-25

2. Right-click TicketingOfficeService in the services list, and then click Properties.
3. Change the LogOn settings to the Administrator account, using the password Pa$$w0rd.
Click the Log On tab.
Select the This Account option.
In the This account text box, type Administrator.
In the Password text box, type Pa$$w0rd.
In the Confirm Password text box, type Pa$$w0rd, and then click OK.
If a message box displays, click OK.
4. Start the TicketingOfficeService service.
Right-click the TicketingOfficeService service, and then select Start.
5. Close the Service window.
6. Verify that the service is running by checking that ports 5001-5006 are open and listening.
Click Start, then click All Programs, then click Microsoft Visual Studio 2010, then click Visual
Studio Tools, and then click Visual Studio Command Prompt (2010).
In a command line window, type netstat a.
Verify that you see ports 5001-5006, and that their state is LISTENING
L3-26 Lab 3: Hosting Windows Communication Foundation Services



Results: After this exercise, you will have hosted services using a Windows Service.
Exercise 3: Hosting Services in a Windows Application
Task 1: Create a service host for the notification service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Host this form as a service to open the
ServiceNotificationWindow.xaml.vb file.
3. Add the following code at the beginning of the btnListen_Click method.
_host = New ServiceHost(Me)
_host.Open()

Note: The implementation class for the service is the actual form, thus the host is opened for a singleton
objectthere is only one form.
Task 2: Add the client implementation of the INotification interface
1. Double click the comment TODO: Ex3 Implement IClientNotification MessageArrived method
to locate the MessageArrived method.
2. Add the following method to the MessageArrived method:
_messages.Add(message)
3. Save the ServiceNotificationWindow.xaml.vb file.
From the File menu, select Save ServiceNotificationWindow.xaml.vb.
Task 3: Add the WCF service configuration for the notification service
1. Open the App.config configuration file of the TicketingOffice.UI project
Lab 3: Hosting Windows Communication Foundation Services L3-27
In the Solution Explorer window, open the TicketingOffice.UI project from the Client solution
folder.
In the TicketingOffice.UI project, double-click the App.config file.
2. Add a Services section with on one service under the system.serviceModel section, using the
following XML:
<services>
<service name="TicketingOffice.UI.ServiceNotificationWindow">
<host>
<baseAddresses>
<add baseAddress=
"http://localhost:8733/TicketingOffice/ClientNotification"/>
</baseAddresses>
</host>

<endpoint binding="basicHttpBinding"
contract="TicketingOffice.ClientNotification.Contract.IClientNotification"/>
</service>
</services>

Results: After this exercise, you will have hosted a service under a Windows Presentation Foundation
(WPF) window application.
Exercise 4: Using Performance Counters for Service Monitoring
Task 1: Enable all performance counters in the TicketingWindowsService configuration
file
1. Open the App.config configuration file of the TicketingWindowsService Service.
In the Solution Explorer window, open the TicketingWindowsService project from the Host
solution folder.
In the TicketingWindowsService project,double-click the App.config file.
2. Add the following diagnostics element section under the system.serviceModel.
<diagnostics performanceCounters="All" />
Task 2: Restart the service
1. Stop the TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Right-click TicketingOfficeService, and then click Stop.
2. Keep the Services management window open, and switch to Visual Studio 2010.
3. Build the TicketingWindowsService project.
Right-click TicketingWindowsService project, and select Build.
4. Restart the service.
Return to the Services management window.
Right-click TicketingOfficeService, and then click Start.
L3-28 Lab 3: Hosting Windows Communication Foundation Services

5. Close the Service window.
Task 3: Use Windows Performance Monitor (perfmon.exe)
1. Open the Window Performance Monitor.
Click Start, then select Administrative Tools, and then select Performance Monitor
2. In the Performance Monitor window, select Performance, then select Monitoring Tools, and then
select Performance Monitor.
3. Right-click the graph. and select Add Counters.
4. under Available counters, expand ServiceModelService 4.0.0.0.
5. Select the Calls Duration and Calls Per Second performance counters.
6. Under Instances of Selected object, select the instance that starts with
CustomerRelationsService@http://localhost:5001/, click Add, and then click OK.

7. Leave the Performance Monitor running, and do not close the window.
Task 4: Examine the counters
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CrmService service, using the address http://localhost:5001.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
3. In the Add Service dialog box, enter the address http://localhost:5001, and then click OK.
4. Call the GetCustomerByID operation using the WS2007HttpBinding endpoint to test the service.
Lab 3: Hosting Windows Communication Foundation Services L3-29
In the My Service Projects tree, under ICrmService (WS2007HttpBinding_ICrmService),
double-click the GetCustomerByID operation.
Click Invoke five times, and if a security warning appears, click OK.
5. Close the WcfTestClient utility, and return to the Performance Monitor.
6. Examine the graph of the Calls Per Second counter.
7. Stop the TicketingOfficeService service.
Click Start, then select Administrative Tools, and then select Services.
Right-click TicketingOfficeService, and then click Stop.
Results: After this exercise, you will have enabled performance counter on your service, and used the
Performance Monitor to monitor several Windows Communication Foundation (WCF) performance
counters.


L3-30 Lab 3: Hosting Windows Communication Foundation Services


Lab 4: Contract Design and Implementation L4-1
Module 4: Defining and Implementing Microsoft Windows
Communication Foundation Contracts
Lab 4: Contract Design and Implementation
Section 1: Visual C#
Exercise 1: Creating Service Contracts
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
3. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M04\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M04\CS folder, click the
TicketingOffice.sln file, and then click Open.
4. Build the solution.
From the Build menu, select Build Solution.
Task 2: Build a service contract for the Shows service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the IShowsService interface with
ServiceContract attribute. This opens the ShowsContract.cs file.
3. Decorate the interface IShowsService with the ServiceContract attribute. Give the service contract
the XML namespace http://Fabrikam.com.
[ServiceContract(Namespace="http://Fabrikam.com")]
public interface IShowsService
4. Decorate all the methods in the interface IShowsService with the OperationContract attribute. The
resulting code should resemble the following code example:
[OperationContract]
Show[] FindShowsByCriteria(ShowCriteria criteria);

[OperationContract]
Show FindShowByID(int showID);

[OperationContract]
int CreateShow(Show newShow);

[OperationContract]
void UpdateShow(Show newShow);

[OperationContract]
L4-2 Lab 4: Contract Design and Implementation

void DeleteShow(int showID);

[OperationContract]
Event[] FindEventsByCrireria(EventCriteria criteria);

[OperationContract]
Event FindEventByID(Guid eventID);

[OperationContract]
Guid CreateEvent(Event newEvent);

[OperationContract]
void UpdateEvent(Event newEvent);

[OperationContract]
void DeleteEvent(Guid EventID);

[OperationContract]
ListPriceRecord[] ShowPrices(EventCriteria criteria);
5. Save the ShowContract.cs file.
From the File menu, select Save ShowContract.cs.
Task 3: Create three client notification service contracts
1. Locate the IClientNotification.cs file under the ClientNotifications project.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the ClientNotifications solution folder.
From the ClientNotificationContract project, open IClientNotification.cs.
2. Decorate the interfaces IClientNotification, INotificationManager, and
IRegisterForDuplexNotification, with the ServiceContract attribute. Give the service contract the
XML namespace http://Fabrikam.com.
[ServiceContract(Namespace="http://Fabrikam.com")]
3. Decorate all the methods in the interfaces IClientNotification,INotificationManager, and
IRegisterForDuplexNotification, with the OperationContract attribute, and set the attribute for
one-way messaging.
[OperationContract(IsOneWay=true)]
4. Define the IClientNotification type as a callback interface for the IRegisterForDuplexNotification
contract.
Set the CallbackContract property of the ServiceContract attribute that decorates the
IRegisterForDuplexNotification interface to the type of IClientNotification.
[ServiceContract(Namespace = "http://Fabrikam.com",
CallbackContract=typeof(IClientNotification))]
public interface IRegisterForDuplexNotification
5. After editing the IClientNotification.cs file, its content should resemble the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
Lab 4: Contract Design and Implementation L4-3

namespace TicketingOffice.ClientNotification.Contract
{
/// <summary>
/// The contract implemented by the client to enable
/// notifications reception
/// </summary>
[ServiceContract(Namespace = "http://Fabrikam.com")]
public interface IClientNotification
{
[OperationContract(IsOneWay=true)]
void MessageArrived(TicketingMessage message);
}

/// <summary>
/// Register a client for notifications
/// </summary>
[ServiceContract(Namespace = "http://Fabrikam.com")]
public interface INotificationManager
{
[OperationContract(IsOneWay=true)]
void Register(
string clientUri, NotificationTypes notificationType);
}


/// <summary>
/// Register a client for notifications using a duplex channel
/// </summary>
[ServiceContract(Namespace = "http://Fabrikam.com",
CallbackContract=typeof(IClientNotification))]
public interface IRegisterForDuplexNotification
{
[OperationContract(IsOneWay = true)]
void RegisterCallback(NotificationTypes notificationType);
}
}
6. Save the IClientNotification.cs file.
From the File menu, select Save IClientNotification.cs.
Results: After this exercise, you will have created a service contract for the Shows service.
Exercise 2: Creating Data Contracts
Task 1: Create a data contract for the Shows service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO : Ex2 - Decorate the Show class with the DataContract
attribute. This opens the Show.cs file.
3. Decorate the Show class with the DataContract attribute. Give the data contract the XML namespace
http://Fabrikam.com.
[DataContract(Namespace="http://Fabrikam.com")]
public class Show
4. Decorate all the properties in the Show class with the DataMember attribute.
L4-4 Lab 4: Contract Design and Implementation

[DataMember]
5. Add a using directive for the System.Runtime.Serialization namespace to the using section of the
Show class.
using System.Runtime.Serialization;

Note: To use the DataContract and DataMember attributes, make sure you have a reference to
the System.Runtime.Serialization assembly.
6. After editing the Show.cs file, its content should resemble the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace TicketingOffice.ShowsService.Contracts
{

/// <summary>
/// Data contract for show
/// </summary>
[DataContract(Namespace="http://Fabrikam.com")]
public class Show
{
[DataMember]
public int ShowID { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Category { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public Uri DetailsLink { get; set; }
[DataMember]
public Uri Preview { get; set; }
[DataMember]
public string Cast { get; set; }
[DataMember]
public TimeSpan Duration { get; set; }
[DataMember]
public Event[] Events { get; set; }
[DataMember]
public byte[] Logo { get; set; }
}
}

Lab 4: Contract Design and Implementation L4-5
7. Save the Show.cs file.
From the File menu, select Save Show.cs.
Task 2: Handle data contract that contains an inheritance hierarchy
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO : Ex2 - Decorate the TicketingMessage class with the
KnownType attribute for each of the derived types. This opens the Messages.cs file.
3. Decorate the TicketingMessage class with the KnownType attribute for each of the derived types,
ShowMessage, EventMessage, OrderMessage, PaymentMessage, PricingRuleMessage, and
CrmMessage.
[KnownType(typeof(ShowMessage))]
[KnownType(typeof(EventMessage))]
[KnownType(typeof(OrderMessage))]
[KnownType(typeof(PaymentMessage))]
[KnownType(typeof(PricingRuleMessage))]
[KnownType(typeof(CrmMessage))]
[DataContract(Namespace = "http://Fabrikam.com")]
public class TicketingMessage
4. Save the Messages.cs file.
From the File menu, select Save Messages.cs.
Task 3: Create a fault contract for the shows service
1. Locate the ShowsContract.cs file under the ShowsContract project.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, then open the Shows
solution folder, and then open the Contracts solution folder.
From the ShowsContract project, open ShowsContract.cs.
2. Decorate the CreateEvent method in the IShowsService interface with a
FaultContract(typeof(ShowExceptionInfo)) attribute.
[OperationContract]
[FaultContract(typeof(ShowExceptionInfo))]
Guid CreateEvent(Event newEvent);
3. Save the ShowsContract.cs file.
From the File menu, select Save ShowsContract.cs.
Task 4: Remove cyclic reference prior to serialization
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double click the comment TODO : Ex2 - Assure no cyclic reference is returned through the
service operation. This opens the ShowsService.svc.cs file.
L4-6 Lab 4: Contract Design and Implementation

3. Verify that the class ShowsAndEventsService implements the IShowsService (the contracts you
defined before).
4. Add the following code to the FindShowsByCriteria method, before the return statement in order
to remove cyclic reference in the data contract.
foreach (Show show in result)
{
foreach (Event anEvent in show.Events)
anEvent.ShowDetails = null;
}

Note: Data contract serialization supports cyclic references but a special configuration is required. In this
case, there is no business need for a cyclic reference.
5. After updating the FindShowsByCriteria method, its content should resemble the following code:
public Show[] FindShowsByCriteria(ShowCriteria criteria)
{
// Clear the loop reference between show and event to solve
// serialization issues.
// DataContract serialization does support loop reference but
// there is no business need to use it here.
var result = showsManager.FindShows(criteria);

foreach (Show show in result)
{
foreach (Event anEvent in show.Events)
anEvent.ShowDetails = null;
}

return result;
}
6. Save the ShowsService.svc.cs file.
From the File menu, select Save ShowsService.svc.cs.
Results: After this exercise you will have built a data contract for the shows service. The contract
contains complex data classes that must be serialized into messages. In addition, you will have declared
a fault contract for the Shows service's operations, and removed a cyclic reference from the service's
implementation.
Exercise 3: Implementing Message Exchange
Task 1: Configure the Shows service to allow metadata exposure
1. Open Services solution folder, then open the Shows solution folder, then open the ShowsService
project and open the web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Shows
solution folder.
From the Shows solution folder, open ShowsService, and then open the web.config file.
2. In the web.config file, locate the behaviors section.
In the web.config file, under the configuration XML element, locate the behaviors section that
is under the system.serviceModel section.
Lab 4: Contract Design and Implementation L4-7
3. Add the following section inside the StandardBehavior behavior.
<serviceMetadata httpGetEnabled="True" />
Task 2: Examine the Shows service WSDL document
1. Browse the ShowsService.svc file.
In ShowsService project, right-click the ShowsService.svc file, and then select View in Browser.
2. Click on the WSDL link.
In the browser window, click the link http://localhost:5007/ShowsService.svc?wsdl.
3. Navigate to the location written in the wsdl:import element that displays at the top of the XML.
In the shown XML, look for the element named wsdl:import.
Copy the value of the location attribute to the address bar, and press ENTER. The address should
be http://localhost:5007/ShowsService.svc?wsdl=wsdl0.
4. Navigate to the schema location written in the first xsd:import element that displays at the top of
the XML, under the xsd:schema that is under the wsdl:types element.
In the following screen shot, locate the element named wsdl:types.
Inside the wsdl:types, under the xsd:schema, locate the first xsd:import element.
Copy the value of the schemaLocation attribute to the address bar, and then press ENTER. The
address should be http://localhost:5007/ShowsService.svc?xsd=xsd0.

L4-8 Lab 4: Contract Design and Implementation

5. Examine the complex type elements that describe the data contracts used in the Shows service.
6. Close the browser, and return to Visual Studio 2010.
Task 3: Configure the Shows Service for message logging
1. Open the ShowsService project's Web.config in the WCF Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor utility, open the File menu, then select Open, and
then select Config File.
In the Open dialog box, navigate to
D:\LabFiles\Starter\M04\CS\Services\Shows\ShowsService folder.
Select the Web.config file, and then click Open.
2. Turn on MessageLogging.
In the Configuration tree, click the Diagnostics node.
Turn the MessageLogging on by clicking the Enable MessageLogging.
3. Configure MessageLogging to log entire messages.
In the Configuration tree, open the Diagnostics node, and then select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True. Leave all other settings
as they are.
4. Save the Configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor, and return to Visual Studio 2010.
If a reload confirmation message appears when you are switching back to Visual Studio 2010,
click Yes.
6. Locate the ASP.NET Development Server in the system tray and stop it.
In the system tray (bottom-right side of the window), locate the ASP.NET Development Server
icon.
Right-click the icon, and then select Stop.

If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
7. Browse the ShowsService.svc file to restart the service host.
Lab 4: Contract Design and Implementation L4-9
In the ShowsService project, right-click the ShowsService.svc file, and then select View in
Browser.
8. Close the browser.
Task 4: Test the Shows service, using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start. and then click Computer.
Open drive D. and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the Shows service, using the address http://localhost:5007/ShowsService.svc.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5007/ShowsService.svc, and
then click OK.
3. Invoke the CreateShow operation to test the service.
In the My Service Projects tree, double-click the CreateShow operation.
Fill the following parameters in the Request grid:
Cast: Limor Henig
Category: Comedy
Description: A comedy by William Shakespeare
ShowID: 100
Title: A Midsummer Night's Dream
Click Invoke, and if a security warning appears, click OK.
4. Click the XML tab, and look at the XML representation of the request and the response.
5. Close the WcfTestClient utility.
Task 5: Examine the message logging output
1. Open the ShowsService project's folder.
Return to Visual Studio 2010, and in the Solution Explorer window, open the Services solution
folder .
In the Services solution folder, open the Shows solution folder, right-click the ShowsService
project, and then select Open Folder in Windows Explorer.
2. Close Visual Studio 2010, and return to the Windows Explorer window where the ShowsService
project's folder is already open.
3. In the ShowsService project folder, open Web_messages.svclog .
Double-click the Web_messages.svclog file. This opens the with the Microsoft Service Trace
Viewer tool.
If an Error Report window displays, click OK. (This window displays because the file is currently
opened for writing by the Shows service.)
4. Click the Message tab on the left pane, and look at the list of messages that were sent to the service.
L4-10 Lab 4: Contract Design and Implementation

5. Locate the CreateShow and CreateShowResponse messages. (You might need to expand the Action
column to see the entire action name.)
Scroll down to find the actions labeled http://Fabrikam.com/IShowsService/CreateShow, and
http://Fabrikam.com/IShowsService/CreateShowResponse.
6. Select the CreateShow message, on the right side under the Description list, click the Message tab,
and examine the content of the message.
7. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have exposed the Shows service using a Web Services Description
Language (WSDL) document, examined the WSDL document, tested the service, and examined the
message output using the Service Trace Viewer utility.


Lab 4: Contract Design and Implementation L4-11
Module 4: Defining and Implementing Microsoft Windows
Communication Foundation Contracts
Lab 4: Contract Design and Implementation
Section 2: Visual Basic
Exercise 1: Creating Service Contracts
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
3. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M04\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M04\VB folder, click the
TicketingOffice.sln file, and then click Open.
4. Build the solution.
From the Build menu, select Build Solution.
Task 2: Build a service contract for the Shows service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the IShowsService interface with
ServiceContract attribute. This opens the ShowsContract.vb file.
3. Decorate the interface IShowsService with the ServiceContract attribute. Give the service contract
the XML namespace http://Fabrikam.com.
<ServiceContract(Namespace := "http://Fabrikam.com")>
Public Interface IShowsService
4. Decorate all the methods in the interface IShowsService with the OperationContract attribute. The
resulting code should resemble the following code example:
<OperationContract()>
Function FindShowsByCriteria(ByVal criteria As ShowCriteria) As Show()

<OperationContract()>
Function FindShowByID(ByVal showID As Integer) As Show

<OperationContract()>
Function CreateShow(ByVal newShow As Show) As Integer

<OperationContract()>
Sub UpdateShow(ByVal newShow As Show)

L4-12 Lab 4: Contract Design and Implementation

<OperationContract()>
Sub DeleteShow(ByVal showID As Integer)

<OperationContract()>
Function FindEventsByCrireria(ByVal criteria As EventCriteria)
As [Event]()

<OperationContract()>
Function FindEventByID(ByVal eventID As Guid) As [Event]

<OperationContract()>
<FaultContract(GetType(ShowExceptionInfo))>
Function CreateEvent(ByVal newEvent As [Event]) As Guid

<OperationContract()>
Sub UpdateEvent(ByVal newEvent As [Event])

<OperationContract()>
Sub DeleteEvent(ByVal EventID As Guid)

<OperationContract()>
Function ShowPrices(ByVal criteria As EventCriteria)
As ListPriceRecord()
5. Save the ShowContract.vb file.
From the File menu, select Save ShowContract.vb.
Task 3: Create three client notification service contracts
1. Locate the IClientNotification.vb file under the ClientNotifications project.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the ClientNotifications solution folder.
From the ClientNotificationContract project, open IClientNotification.vb.
2. Decorate the interfaces IClientNotification, INotificationManager, and
IRegisterForDuplexNotification, with the ServiceContract attribute. Give the service contract the
XML namespace http://Fabrikam.com.
<ServiceContract(Namespace := "http://Fabrikam.com")>

3. Decorate all the methods in the interfaces IClientNotification,INotificationManager, and
IRegisterForDuplexNotification, with the OperationContract attribute, and set the attribute for
one-way messaging.
<OperationContract(IsOneWay := True)>
4. Define the IClientNotification type as a callback interface for the IRegisterForDuplexNotification
contract.
Set the CallbackContract property of the ServiceContract attribute that decorates the
IRegisterForDuplexNotification interface to the type of IClientNotification.
<ServiceContract(Namespace := "http://Fabrikam.com",
CallbackContract := GetType(IClientNotification))>
Public Interface IRegisterForDuplexNotification
5. After editing the IClientNotification.vb file, its content should resemble the following code:
Lab 4: Contract Design and Implementation L4-13
Imports System.Text
Imports System.ServiceModel
Imports System.Runtime.Serialization

Namespace TicketingOffice.ClientNotification.Contract

''' <summary>
''' The contract implemented by the client to enable notifications
''' reception
''' </summary>
<ServiceContract(Namespace:="http://Fabrikam.com")>
Public Interface IClientNotification
<OperationContract(IsOneWay:=True)>
Sub MessageArrived(ByVal message As TicketingMessage)
End Interface


''' <summary>
''' Register a client for notifications
''' </summary>
<ServiceContract(Namespace:="http://Fabrikam.com")>
Public Interface INotificationManager
<OperationContract(IsOneWay:=True)>
Sub Register(ByVal clientUri As String,
ByVal notificationType As NotificationTypes)
End Interface


''' <summary>
''' Register a client for notifications using a duplex channel
''' </summary>
<ServiceContract(Namespace:="http://Fabrikam.com",
CallbackContract:=GetType(IClientNotification))>
Public Interface IRegisterForDuplexNotification
<OperationContract(IsOneWay:=True)>
Sub RegisterCallback(ByVal notificationType As NotificationTypes)
End Interface
End Namespace
6. Save the IClientNotification.vb file.
From the File menu, select Save IClientNotification.vb.
Results: After this exercise, you will have created a service contract for the Shows service.
Exercise 2: Creating Data Contracts
Task 1: Create a data contract for the Shows service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO : Ex2 - Decorate the Show class with the DataContract
attribute. This opens the Show.vb file.
3. Decorate the Show class with the DataContract attribute. Give the data contract the XML namespace
http://Fabrikam.com.
<DataContract(Namespace := "http://Fabrikam.com")>
Public Class Show
L4-14 Lab 4: Contract Design and Implementation

4. Decorate all the properties in the Show class with the DataMember attribute.
<DataMember>
5. Add an Imports directive for the System.Runtime.Serialization namespace to the Imports section of
the Show class.
Imports System.Runtime.Serialization

Note: To use the DataContract and DataMember attributes, make sure you have a reference to
the System.Runtime.Serialization assembly.
6. After editing the Show.vb file, its content should resemble the following code:
Imports System.Text
Imports System.Runtime.Serialization
Namespace TicketingOffice.ShowsService.Contracts

''' <summary>
''' Data contract for show
''' </summary>
<DataContract(Namespace:="http://Fabrikam.com")>
Public Class Show
<DataMember()>
Public Property ShowID() As Integer
<DataMember()>
Public Property Title() As String
<DataMember()>
Public Property Category() As String
<DataMember()>
Public Property Description() As String
<DataMember()>
Public Property DetailsLink() As Uri
<DataMember()>
Public Property Preview() As Uri
<DataMember()>
Public Property Cast() As String
<DataMember()>
Public Property Duration() As TimeSpan
<DataMember()>
Public Property Events() As [Event]()
<DataMember()>
Public Property Logo() As Byte()
End Class
End Namespace
7. Save the Show.vb file.
From the File menu, select Save Show.vb.
Lab 4: Contract Design and Implementation L4-15
Task 2: Handle data contract that contains an inheritance hierarchy
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO : Ex2 - Decorate the TicketingMessage class with the
KnownType attribute for each of the derived types. This opens the Messages.vb file.
3. Decorate the TicketingMessage class with the KnownType attribute for each of the derived types,
ShowMessage, EventMessage, OrderMessage, PaymentMessage, PricingRuleMessage, and
CrmMessage.
<DataContract(Namespace := "http://Fabrikam.com"),
KnownType(GetType(ShowMessage)),
KnownType(GetType(EventMessage)),
KnownType(GetType(OrderMessage)),
KnownType(GetType(PaymentMessage)), KnownType(GetType(PricingRuleMessage)),
KnownType(GetType(CrmMessage))>
Public Class TicketingMessage
4. Save the Messages.vb file.
From the File menu, select Save Messages.vb.
Task 3: Create a fault contract for the shows service
1. Locate the ShowsContract.vb file under the ShowsContract project.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, then open the Shows
solution folder, and then open the Contracts solution folder.
From the ShowsContract project, open ShowsContract.vb.
2. Decorate the CreateEvent method in the IShowsService interface with a
FaultContract(GetType(ShowExceptionInfo)) attribute.
<OperationContract, FaultContract(GetType(ShowExceptionInfo))>
Function CreateEvent(ByVal newEvent As [Event]) As Guid
3. Save the ShowsContract.vb file.
From the File menu, select Save ShowsContract.vb.
Task 4: Remove cyclic reference prior to serialization
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double click the comment TODO : Ex2 - Assure no cyclic reference is returned through the
service operation. This opens the ShowsService.svc.vb file.
3. Verify that the class ShowsAndEventsService implements the IShowsService (the contracts you
defined before).
4. Add the following code to the FindShowsByCriteria method, before the Return statement in order
to remove cyclic reference in the data contract.
For Each l_show As Show In result
For Each anEvent As [Event] In l_show.Events
L4-16 Lab 4: Contract Design and Implementation

anEvent.ShowDetails = Nothing
Next anEvent
Next l_show

Note: Data contract serialization supports cyclic references but a special configuration is required. In this
case, there is no business need for a cyclic reference.
5. After updating the FindShowsByCriteria method, its content should resemble the following code:
Public Function FindShowsByCriteria(ByVal criteria As ShowCriteria)
As Show() Implements IShowsService.FindShowsByCriteria
'Clear the loop reference between show and event to solve
'serialization issues.
'DataContract serialization does support loop reference but there is
'no business need to use it here.
Dim result = showsManager.FindShows(criteria)

For Each l_show As Show In result
For Each anEvent As [Event] In l_show.Events
anEvent.ShowDetails = Nothing
Next anEvent
Next l_show

Return result
End Function
6. Save the ShowsService.svc.vb file.
From the File menu, select Save ShowsService.svc.vb.
Results: After this exercise you will have built a data contract for the shows service. The contract
contains complex data classes that must be serialized into messages. In addition, you will have declared
a fault contract for the Shows service's operations, and removed a cyclic reference from the service's
implementation.
Exercise 3: Implementing Message Exchange
Task 1: Configure the Shows service to allow metadata exposure
1. Open Services solution folder, then open the Shows solution folder, then open the ShowsService
project and open the web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Shows
solution folder.
From the Shows solution folder, open ShowsService, and then open the web.config file.
2. In the web.config file, locate the behaviors section.
In the web.config file, under the configuration XML element, locate the behaviors section that
is under the system.serviceModel section.
3. Add the following section inside the StandardBehavior behavior.
<serviceMetadata httpGetEnabled="True" />
Lab 4: Contract Design and Implementation L4-17
Task 2: Examine the Shows service WSDL document
1. Browse the ShowsService.svc file.
In ShowsService project, right-click the ShowsService.svc file, and then select View in Browser.
2. Click on the WSDL link.
In the browser window, click the link http://localhost:5007/ShowsService.svc?wsdl.
3. Navigate to the location written in the wsdl:import element that displays at the top of the XML.
In the shown XML, look for the element named wsdl:import.
Copy the value of the location attribute to the address bar, and press ENTER. The address should
be http://localhost:5007/ShowsService.svc?wsdl=wsdl0.
4. Navigate to the schema location written in the first xsd:import element that displays at the top of
the XML, under the xsd:schema that is under the wsdl:types element.
In the following screen shot, locate the element named wsdl:types.
Inside the wsdl:types, under the xsd:schema, locate the first xsd:import element.
Copy the value of the schemaLocation attribute to the address bar, and then press ENTER. The
address should be http://localhost:5007/ShowsService.svc?xsd=xsd0.


5. Examine the complex type elements that describe the data contracts used in the Shows service.
6. Close the browser, and return to Visual Studio 2010.
Task 3: Configure the Shows Service for message logging
1. Open the ShowsService project's Web.config in the WCF Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor utility, open the File menu, then select Open, and
then select Config File.
In the Open dialog box, navigate to
D:\LabFiles\Starter\M04\VB\Services\Shows\ShowsService folder.
L4-18 Lab 4: Contract Design and Implementation

Select the Web.config file, and then click Open.
2. Turn on MessageLogging.
In the Configuration tree, click the Diagnostics node.
Turn the MessageLogging on by clicking the Enable MessageLogging.
3. Configure MessageLogging to log entire messages.
In the Configuration tree, open the Diagnostics node, and then select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True. Leave all other settings
as they are.
4. Save the Configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor, and return to Visual Studio 2010.
If a reload confirmation message appears when you are switching back to Visual Studio 2010,
click Yes.
6. Locate the ASP.NET Development Server in the system tray and stop it.
In the system tray (bottom-right side of the window), locate the ASP.NET Development Server
icon.
Right-click the icon, and then select Stop.

If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
7. Browse the ShowsService.svc file to restart the service host.
In the ShowsService project, right-click the ShowsService.svc file, and then select View in
Browser.
8. Close the browser.
Task 4: Test the Shows service, using the WcfTestClient utility
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start. and then click Computer.
Open drive D. and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the Shows service, using the address http://localhost:5007/ShowsService.svc.
Lab 4: Contract Design and Implementation L4-19
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5007/ShowsService.svc, and
then click OK.
3. Invoke the CreateShow operation to test the service.
In the My Service Projects tree, double-click the CreateShow operation.
Fill the following parameters in the Request grid:
Cast: Limor Henig
Category: Comedy
Description: A comedy by William Shakespeare
ShowID: 100
Title: A Midsummer Night's Dream
Click Invoke, and if a security warning appears, click OK.
4. Click the XML tab, and look at the XML representation of the request and the response.
5. Close the WcfTestClient utility.
Task 5: Examine the message logging output
1. Open the ShowsService project's folder.
Return to Visual Studio 2010, and in the Solution Explorer window, open the Services solution
folder .
In the Services solution folder, open the Shows solution folder, right-click the ShowsService
project, and then select Open Folder in Windows Explorer.
2. Close Visual Studio 2010, and return to the Windows Explorer window where the ShowsService
project's folder is already open.
3. In the ShowsService project folder, open Web_messages.svclog .
Double-click the Web_messages.svclog file. This opens the with the Microsoft Service Trace
Viewer tool.
If an Error Report window displays, click OK. (This window displays because the file is currently
opened for writing by the Shows service.)
4. Click the Message tab on the left pane, and look at the list of messages that were sent to the service.
5. Locate the CreateShow and CreateShowResponse messages. (You might need to expand the Action
column to see the entire action name.)
Scroll down to find the actions labeled http://Fabrikam.com/IShowsService/CreateShow, and
http://Fabrikam.com/IShowsService/CreateShowResponse.
6. Select the CreateShow message, on the right side under the Description list, click the Message tab,
and examine the content of the message.
7. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have exposed the Shows service using a Web Services Description
Language (WSDL) document, examined the WSDL document, tested the service, and examined the
message output using the Service Trace Viewer utility.

L4-20 Lab 4: Contract Design and Implementation






Lab 5: WCF Endpoints and Behaviors L5-1
Module 5: Endpoints and Behaviors
Lab 5: WCF Endpoints and Behaviors
Section 1: Visual C#
Exercise 1: Exposing Multiple Endpoints
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M05\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M05\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M05\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M05\CS folder, click the
TicketingOffice.sln file, and then click Open.
6. Build the solution.
From the Build menu, select Build Solution.
Task 2: Create two different endpoints for two different contracts
1. In the Crm solution folder, which is under the Services solution folder, locate the CRMService
project, and open the web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
From the Crm solution folder, open the CrmService project, and then open the web.config file.
2. Locate the CustomerRelationsService service configuration in the services section of the
web.config.
In the web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element with the name attribute value of
TicketingOffice.CrmService.CustomerRelationsService.
3. Add the following endpoints inside the service XML element.
<endpoint
address="InternalCrm"
L5-2 Lab 5: WCF Endpoints and Behaviors
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
<endpoint
address="PrivateCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
4. Save the web.config file.
From the File menu, select Save web.config.
5. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file in the services section, locate the CustomerRelationsService service
configuration.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element with the name attribute value of
TicketingOffice.CrmService.CustomerRelationsService.
7. Add the following endpoints inside the service XML element.
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
<endpoint
address="PrivateCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
8. Save the App.config file.
From the File menu, select Save App.config.
Results: After this exercise, you will have exposed multiple endpoints for the CRM service.
Lab 5: WCF Endpoints and Behaviors L5-3
Exercise 2: Using Queued Services
Task 1: Examine the one-way operations in the Ticketing service contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.

2. Double-click the comment TODO: Ex2 Examine the one-way service contract. This opens the
TicketingServiceContracts.cs file.
3. Examine the interface ITicketingServiceOneWay. Each of the service operations uses the one-way
messaging pattern.

Note: Queues are one-way by design. Fortunately, the ticketing service provides a wrapper
implementing a One-Way contract. This One-Way implementation will internally call the original
version of the ticketing service to execute the ticketing functionality.
Task 2: Add a service configuration for the one-way version of the Ticketing service
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. Locate the services configuration section in the Web.config file.
In the Web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
3. Add the ticketing service configuration inside the services XML element.
<service
name="TicketingOffice.TicketingService.QueuedTicketingService"
behaviorConfiguration="StandardBehavior">
<!--Place endpoint settings here-->
</service>
4. Add the following MSMQ endpoint to the service's configuration element that you have just added.
<endpoint
address="BridgeRequestQueue"
binding="netMsmqBinding"
bindingConfiguration="TransactionalNoSecurity"
contract="TicketingOffice.TicketingService.Contracts.ITicketingServiceOneWay">
</endpoint>
5. Locate the SimpleServiceHost project under the Host solution folder, and open the App.config file.
Open the View menu, and then select Solution Explorer.
L5-4 Lab 5: WCF Endpoints and Behaviors
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. Locate the services configuration section in the App.config file.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
7. Add the ticketing service configuration inside the services XML element.
<service
name="TicketingOffice.TicketingService.QueuedTicketingService"
behaviorConfiguration="StandardBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5009"/>
<add baseAddress="net.msmq://localhost/private/"/>
</baseAddresses>
</host>
<!--Place endpoint settings here-->
</service>
8. Add the following MSMQ endpoint to the service's configuration element that you have just added.
<endpoint
address="BridgeRequestQueue"
binding="netMsmqBinding"
bindingConfiguration="TransactionalNoSecurity"
contract="TicketingOffice.TicketingService.Contracts.ITicketingServiceOneWay">
</endpoint>
Task 3: Add an MSMQ binding configuration
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the bindings section.
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. Add the following binding configuration to the bindings XML element.
<netMsmqBinding>
<binding
name="TransactionalNoSecurity"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveRetryCount="20"
retryCycleDelay="00:05:00">
<security mode="None"/>
</binding>
Lab 5: WCF Endpoints and Behaviors L5-5
</netMsmqBinding>
4. Save the Web.config file.
From the File menu, select Save Web.config.
5. Locate the SimpleServiceHost project under the Host solution folder, and then open the App.config
file.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
7. Add the following binding configuration to the bindings XML element.
<netMsmqBinding>
<binding
name="TransactionalNoSecurity"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveRetryCount="20"
retryCycleDelay="00:05:00">
<security mode="None"/>
</binding>
</netMsmqBinding>
8. Save the App.config file.
From the File menu, select Save App.config.
Task 4: Add code for MSMQ queues creation in the hosting manager
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add code to create MSMQ queues. This opens the
HostingManager.cs file.
3. Add the following code to the CreateMsmq static method.
string req_queue =
ConfigurationManager.AppSettings["BridgeRequestQueue"];
string res_queue =
ConfigurationManager.AppSettings["BridgeResponseQueue"];

if (!MessageQueue.Exists(req_queue))
MessageQueue.Create(req_queue,true);

if (!MessageQueue.Exists(res_queue))
MessageQueue.Create(res_queue,true);
4. Save the HostingManager.cs file.
L5-6 Lab 5: WCF Endpoints and Behaviors
From the File menu, select Save HostingManager.cs.
Task 5: Consume the QueuedTicketingService using an MSMQ channel

Note: The client application will use a special bridge service that exposes a request-response messaging
pattern contract. When the bridge receives a message, it forwards the message to the
QueuedTicketingService using a one-way channel and listens on its own endpoint for a response. When a
response arrives, the bridge returns the result back to the client.
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add code to call the one-way service. This opens the
TicketingBridgeService.svc.cs file.
3. Place the following code inside the try block in the OrderTicket method. (First remove the existing
return statement in the method.)
// Find a proxy to the ticketing service (one-way)
prox = TicketingServiceOneWayProxyFactory.GetProxy(false);
AutoResetEvent arrived = new AutoResetEvent(false);

// Create a ResultPackage with a wait handle to wait on until a response arrives (on
another channel)
ResultPackage pack = new ResultPackage() { ResultArrived = arrived };
ResultsCache.Current.SetPackage(callId, pack);

// Call the pricing service on MSMQ channel on another thread.
Action<ITicketingServiceOneWay> del =
(p => p.OrderTicket(newOrder, seats, callId));
del.BeginInvoke(prox, null, null);

//Wait until result arrives
arrived.WaitOne(timeout);
Guid result = (Guid)ResultsCache.Current.GetResult(callId);
ResultsCache.Current.ClearResult(callId);
return result;
4. Save the TicketingBridgeService.svc.cs file.
From the File menu, select Save TicketingBridgeService.svc.cs.
5. Double-click the comment TODO: Ex2 Add code that sets the auto reset event. This opens the
TicketingBridgeCallBack.svc.cs file.
6. Place the following code inside the HandleResult method.
var resultPack = ResultsCache.Current.GetResultPack(callID);
if (resultPack != null)
{
resultPack.Result = result;
resultPack.ResultArrived.Set();
}
7. Save the TicketingBridgeCallBack.svc.cs file.
From the File menu, select Save TicketingBridgeCallBack.svc.cs.
Lab 5: WCF Endpoints and Behaviors L5-7

Note: The TicketingBridge class implements the contract ITicketingService, and the
TicketingBridgeCallBack class implements the contract ITicketingCallBack. The TicketingBridge class
exposes the original ticketing contract to the client, while the TicketingBridgeCallBack exposes a
callback contract to be consumed by the QueuedTicketingService.
Results: After this exercise, you will have hosted the queued ticketing service, configured the service to
expose an endpoint that uses MSMQ, and consumed the service from the ticketing bridge service.
Exercise 3: Using Transactions
Task 1: Place the TransactionFlow attribute over the service contract methods
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Decorate the ITicketingService methods with the
TransactionFlow attribute. This opens the TicketingServiceContracts.cs file.
3. In the ITicketingService interface, decorate the methods OrderTicket, PayForTicket, CancelTicket,
and PrintTicket, with the TransactionFlow attribute, specifying that the transaction is mandatory.
[TransactionFlow(TransactionFlowOption.Mandatory)]
4. Double-click the comment TODO: Ex3 Decorate the ITicketingServiceOneWay methods with
the TransactionFlow attribute to locate the ITicketingServiceOneWay interface.
5. In the ITicketingServiceOneWay interface, decorate the methods OrderTicket, PayForTicket,
CancelTicket, and PrintTicket, with the TransactionFlow attribute, specifying that the transaction is
allowed.
[TransactionFlow(TransactionFlowOption.Allowed)]
6. The resulting ITicketingService interface should resemble the following code.
/// <summary>
/// The Contract for the ticketing service
/// This is a request response contract
/// </summary>
[ServiceContract(Namespace = @"http://Fabrikam.com")]
public interface ITicketingService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
Guid OrderTicket(Contracts.Order newOrder, SeatIndex[] seats);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
Payment PayForTicket(
Guid orderID, Guid payingCustomerID,
double amount, PaymentType methodOfPayment,
Currencies? currency, string creditCard);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
Payment CancelTicket(Guid orderID, Guid payingCustomerID,
string creditCard);

[OperationContract]
L5-8 Lab 5: WCF Endpoints and Behaviors
Order FindOrder(Guid orderID);

[OperationContract]
Order[] FindOrders(OrderCriteria criteria);

[OperationContract]
Guid[] FindBestCustomersIds(int numberOfCustomers);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string PrintTicket(Guid orderID);
}
7. The resulting ITicketingServiceOneWay interface should resemble the following code.
/// <summary>
/// The Contract for the ticketing service
/// This is a One-Way contract
/// </summary>
[ServiceContract(Namespace = @"http://Fabrikam.com")]
public interface ITicketingServiceOneWay
{
[OperationContract(IsOneWay = true)]
[TransactionFlow(TransactionFlowOption.Allowed)]
void OrderTicket(Contracts.Order newOrder,
SeatIndex[] seats, Guid callID);

[OperationContract(IsOneWay = true)]
[TransactionFlow(TransactionFlowOption.Allowed)]
void PayForTicket(Guid orderID, Guid payingCustomerID,
double amount, PaymentType methodOfPayment,
Currencies? currency, Guid callID, string creditCard);

[OperationContract(IsOneWay = true)]
[TransactionFlow(TransactionFlowOption.Allowed)]
void CancelTicket(Guid orderID, Guid payingCustomerID,
Guid callID, string creditCard);

[OperationContract(IsOneWay = true)]
void FindOrder(Guid orderID, Guid callID);

[OperationContract(IsOneWay = true)]
void FindOrders(OrderCriteria criteria, Guid callID);

[OperationContract(IsOneWay = true)]
void FindBestCustomersIds(int numberOfCustomers, Guid callID);

[OperationContract(IsOneWay = true)]
[TransactionFlow(TransactionFlowOption.Allowed)]
void PrintTicket(Guid orderID, Guid callID);
}
8. Save the TicketingServiceContracts.cs file.
From the File menu, select Save TicketingServiceContracts.cs.
Task 2: Add transaction service behavior and operation behavior to the Ticketing service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
Lab 5: WCF Endpoints and Behaviors L5-9
2. Double-click the comment TODO: Ex3 Decorate the GeneralTicketingService service with a
ServiceBehavior attribute. This opens the TicketingService.svc.cs file.
3. Decorate the GeneralTicketingService class with the ServiceBehavior attribute, and set it to
automatically set the transaction as completed, when the session closes.
[ServiceBehavior(TransactionAutoCompleteOnSessionClose = true)]
4. Inside the GeneralTicketingService class, decorate the OrderTicket, PayForTicket, CancelTicket,
and PrintTicket methods with the OperationBehavior attribute as follows:
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = true)]
5. Save the TicketingService.svc.cs file.
From the File menu, select Save TicketingService.svc.cs.
6. Double-click the comment TODO: Ex3 Decorate the QueuedTicketingService service with a
ServiceBehavior attribute. This opens the QueuedTicketingService.svc.cs file.
7. Decorate the QueuedTicketingService class with the ServiceBehavior attribute, and set it to
automatically set the transaction as completed when the session closes.
[ServiceBehavior(TransactionAutoCompleteOnSessionClose = true)]
8. Inside the QueuedTicketingService class, decorate the OrderTicket, PayForTicket, CancelTicket,
and PrintTicket methods with the OperationBehavior attribute as follows:
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = true)]
9. Save the QueuedTicketingService.svc.cs file.
From the File menu, select Save QueuedTicketingService.svc.cs.
Task 3: Enable the transaction binding element in the binding configuration of all the
services
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the bindings section.
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. In the bindings section, turn on transaction flow in each of the binding configurations that belong to
the ws2007HttpBinding and the netTCPBinding XML elements.
In the bindings section, look for the ws2007HttpBinding element, and place the
transactionFlow attribute in each of the binding XML elements that are inside it. Set the
attribute's value to True.
L5-10 Lab 5: WCF Endpoints and Behaviors
In the bindings section, look for the netTcpBinding element, and place the transactionFlow
attribute in each of the binding XML elements that are inside it. Set the attribute's value to True.
4. Save the Web.config file.
From the File menu, select Save Web.config.
5. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
7. In the bindings section, turn on transaction flow in each of the binding configurations that belong to
the ws2007HttpBinding and the netTCPBinding XML elements.
In the bindings section, look for the ws2007HttpBinding element, and place the
transactionFlow attribute in each of the binding XML elements that are inside it. Set the
attribute's value to True.
In the bindings section, look for the netTcpBinding element, and place the transactionFlow
attribute in each of the binding XML elements that are inside it. Set the attribute's value to True.
8. Save the App.config file.
From the File menu, select Save App.config.
Results: After this exercise, you will have configured the ticketing service contract to use transactions,
and configured the service bindings to accept transaction flow.
Exercise 4: Using Reliable Messaging
Task 1: Enable reliable messaging in the binding configuration of the Ticketing HTTP
Bridge service
1. In the Ticketing solution folder, which is under the Services solution folder, locate the Bridge
project, and open the Web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the Bridge project, and then open the Web.config file.
2. In the Web.config file, locate the bindings section.
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. In the bindings section, locate the section for ws2007HttpBinding, and add the following binding
configurations inside it:
<binding
name="RM_NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
Lab 5: WCF Endpoints and Behaviors L5-11
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<reliableSession enabled="true" ordered="false"/>
<security mode="None"></security>
</binding>
4. Locate the TicketingBridge service configuration in the services section of the web.config file.
In the web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element that has the name attribute value of
TicketingOffice.Bridge.TicketingBridge.
5. Change the service's endpoint to use the RM_NoSecurity binding configuration.
Locate the endpoint configuration inside the TicketingBridge service XML element.
Add the bindingConfiguration attribute to the endpoint element, and set its value to
RM_NoSecurity.
6. Save the Web.config file.
From the File menu, select Save Web.config.
7. Locate the SimpleServiceHost project under the Host solution folder, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
8. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
9. In the bindings section, locate the section for ws2007HttpBinding, and add the following binding
configurations inside it:
<binding
name="RM_NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<reliableSession enabled="true" ordered="false"/>
<security mode="None"></security>
</binding>
10. Save the App.config file.
From the File menu, select Save App.config.
Results: After this exercise, you will have added reliable messaging binding configuration to your
service host.
Exercise 5: Configuring Instancing and Concurrency
Task 1: Set the concurrency and instancing mode of the Ticketing HTTP Bridge service
1. Examine the content of the task list.
L5-12 Lab 5: WCF Endpoints and Behaviors
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex5 Change the concurrency and instancing mode of the
TicketingBridge service. This opens the TicketingBridgeService.svc.cs file.
3. Locate the ServiceBehavior attribute that decorates the TicketingBridge class; set the
ConcurrencyMode parameter to Multiple, and the InstanceContextMode to PerCall.
[ServiceBehavior(
ReleaseServiceInstanceOnTransactionComplete = false,
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerCall)]
public class TicketingBridge : ITicketingService
{
...
}
4. Save the TicketingBridgeService.svc.cs file.
From the File menu, select Save TicketingBridgeService.svc.cs.
5. Double-click the comment TODO: Ex5 Change the concurrency and instancing mode of the
TicketingBridgeCallBack service. This opens the TicketingBridgeCallBack.svc.cs file.
6. Locate the ServiceBehavior attribute that decorates the TicketingBridgeCallBack class; set the
ConcurrencyMode parameter to Multiple, and the InstanceContextMode to PerCall.
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerCall)]
public class TicketingBridgeCallBack : ITicketingCallBack
{
...
}
7. Save the TicketingBridgeCallBack.svc.cs file.
From the File menu, select Save TicketingBridgeCallBack.svc.cs.
Task 2: Examine the statelessness of the Ticketing HTTP Bridge service
1. Open the file TicketingBridgeService.svc.cs from the Bridge project.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the Bridge project, and then open the
TicketingBridgeService.svc.cs file.
2. Examine the TicketingBridge class. Notice that the service implementation does not hold any state
information.
3. Examine the OrderTicket method in the class. Notice that to save state, the method uses the
singleton pattern by using the ResultsCache.Current, and a new instance is created for each call.
Lab 5: WCF Endpoints and Behaviors L5-13
Task 3: Examine the instancing mode of the Notifications service in the client application
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex5 Examine the instancing mode of the Client Notification
service. This opens the ServiceNotificationWindow.xaml.cs file.
3. Examine how the Client Notification service uses the Single instancing context mode. Notice that the
ServiceNotificationWindow implements the Notification service, but it is also a Window object
when a message is sent to the client, it will be directed to the opened Window object.
4. In the ServiceNotificationWindow, look for the btnListen_Click method. Examine how the
ServiceHost constructor is called. Notice that the instance of the window is passed as the service
implementation instance.
Results: After this exercise, you will have set the concurrency and instancing mode on the Ticketing
Bridge.
Exercise 6: Using WCF Discovery
Task 1: Add dedicated discovery endpoints to all the services
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the services section.
In the Web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
3. Add the following new endpoint settings element in each of the service elements.
<endpoint
name="udpDiscovery"
kind="udpDiscoveryEndpoint"
endpointConfiguration="adhocDiscoveryEndpointConfiguration"/>
4. In the Web.config file, locate the standardEndpoints section.
In the Web.config file, under the configuration XML element, locate the standardEndpoints
section under the system.serviceModel section.
5. Add the following endpoints configuration inside the standardEndpoints element:
<!-- Specify the discovery protocol version and maxResponseDelay -->
<udpDiscoveryEndpoint>
<standardEndpoint
name="adhocDiscoveryEndpointConfiguration"
discoveryVersion="WSDiscovery11"
maxResponseDelay="00:00:10" />
</udpDiscoveryEndpoint>

L5-14 Lab 5: WCF Endpoints and Behaviors
<!--Specify the discovery mode of the proxy discovery endpoint is Managed and not Ad-
hoc-->
<discoveryEndpoint>
<standardEndpoint
name="managedDiscoveryEndpoint"
discoveryMode="Managed"
maxResponseDelay="00:01:00"/>
</discoveryEndpoint>
6. Save the Web.config file.
In the File menu, select Save Web.config.
7. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
8. In the App.config file, locate the services section.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
9. Add the following endpoint settings in each of the service elements, except for the
TicketingOffice.PricingBrokerService.DiscoveryProxyService service configuration:
<endpoint
name="udpDiscovery"
kind="udpDiscoveryEndpoint"
endpointConfiguration="adhocDiscoveryEndpointConfiguration"/>
10. In the App.config file, locate the standardEndpoints section.
In the App.config file, under the configuration XML element, locate the standardEndpoints
section under the system.serviceModel section.
11. Add the following endpoints configuration inside the standardEndpoints element:
<!-- Specify the discovery protocol version and maxResponseDelay -->
<udpDiscoveryEndpoint>
<standardEndpoint
name="adhocDiscoveryEndpointConfiguration"
discoveryVersion="WSDiscovery11"
maxResponseDelay="00:00:10" />
</udpDiscoveryEndpoint>

<!--Specify the discovery mode of the proxy discovery endpoint is Managed and not Ad-
hoc-->
<discoveryEndpoint>
<standardEndpoint
name="managedDiscoveryEndpoint"
discoveryMode="Managed"
maxResponseDelay="00:01:00"/>
</discoveryEndpoint>
12. Save the App.config file.
In the File menu, select Save App.config.
Task 2: Create a dynamic endpoint to locate the Ticketing service
1. Examine the content of the task list.
Lab 5: WCF Endpoints and Behaviors L5-15
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex6 Use a dynamic endpoint to find the ticketing service.
This opens the TicketingBridgeService.svc.cs file.
3. In the GetProxy method, locate the second if statement.
if (discovery)
{
// TODO: Ex6 - Use a dynamic endpoint to find the ticketing service
return null;
}
4. Inside the if statement, replace the return statement with the following code:
DynamicEndpoint dynamicEndpoint = new
DynamicEndpoint(ContractDescription.GetContract(
typeof(ITicketingServiceOneWay)),
new NetMsmqBinding());
return _chf.CreateChannel(dynamicEndpoint.Address);
5. Save the TicketingBridgeService.svc.cs file.
From the File menu, select Save TicketingBridgeService.svc.cs.
Task 3: Examine the code of the discovery proxy
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex6 Examine the discovery proxy service implementation.
This opens the DiscoveryProxy.svc.cs file.
3. Examine the implementation of the DiscoveryProxyService classthe discovery proxy has a simple
internal service repository that is used to maintain service information. The discovery proxy overrides
the OnBeginOfflineAnnouncement/OnEndOfflineAnnouncement and
OnBeginOnlineAnnouncement/OnEndOnlineAnnouncement methods to respond to
announcement messages that are coming from within its local subnet, and to manage the internal
service repository.
The Discovery proxy also overrides the OnBeginFind / OnEndFind and OnBeginResolve /
OnEndResolve methods to process Probe and Resolve messages coming from outside the subnet,
and respond with service details based on the services repository.
Task 4: Consume the discovery proxy in the broker between the Pricing service and the
Pricing Rules service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex6 Find a service that exposes the IPricingRulesService
service contract. This opens the PricingService.svc.cs file.
3. In the GetRulesFromService method, locate the try block, and place the following code inside it:
lock (this)
L5-16 Lab 5: WCF Endpoints and Behaviors
{
if (chf == null)
chf = new ChannelFactory<IPricingRulesService>("PricingRulesEP"); }

// Find IPricingRulesService endpoints
try
{
findResponse = discoveryClient.Find(
new FindCriteria(typeof(IPricingRulesService)));
}
catch (Exception) { }

if (findResponse != null)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format("Discovery proxy found {0} endpoints",
findResponse.Endpoints.Count));
addresses = (from ep in findResponse.Endpoints
select ep.Address).ToArray();
}
else
//Set a default address for the pricing rules service
addresses = new EndpointAddress[] { chf.Endpoint.Address };

// look for the rules in all the endpoints found.
// When rules are found stop searching.
foreach (var address in addresses)
{
prox = chf.CreateChannel(address);
rules = prox.GetPricingRulesByCriteria(new RulesCriteria()
{ Scope = policyName,
FromDate = DateTime.Today,
ToDate = DateTime.Today.AddDays(1)
});
if ((rules != null) && (rules.Count() > 0))
break;
}
4. Save the PricingService.svc.cs file.
From the File menu, select Save PricingService.svc.cs.
Results: After this exercise, you will have added ad-hoc discovery endpoints for all the services, used a
dynamic endpoint to consume a service, and used a discovery client to call a discovery proxy service.
Exercise 7: Verifying MSMQ Topology
Task 1: Start all the services, except the Queued Ticketing service
1. Set the SimpleServiceHost project as the startup project.
In the Solution Explorer window, open the Host solution folder.
Right-click the SimpleServiceHost project, and then select Set as StartUp Project.
2. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
From the Debug menu, select Start Without Debugging.
3. In the SimpleServiceHost console, press the 8 key, and then press ENTER to stop the Ticketing
service.
Lab 5: WCF Endpoints and Behaviors L5-17
Task 2: Use the client application to order a ticket
1. Set the TicketingOffice.UI project as the startup project.
In the Solution Explorer window, open the Client solution folder.
Right-click the TicketingOffice.UI project, and then select Set as StartUp Project.
2. Run the TicketingOffice.UI project without debugging.
From the Debug menu, select Start Without Debugging.
3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and select Hanson, Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to retrieve the layout of the hall, and to see which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
8. In the window's status bar, notice the "Waiting for the service to complete" message. Leave the all the
client windows and the service host console window open, and return to Visual Studio 2010.

Important: The endpoint's binding for the Ticketing Bridge service is configured to time out after 4
minutes. Therefore, you will need to perform the following Task 3 in less than 4 minutes, or else you will
get an exception on the client side, and you will have to perform Tasks 2 and 3 again.
Task 3: Look at the MSMQ messages
1. Using the Server Explorer window, examine the content of the BridgeRequestQueue queue; you
should see a messages inside the queue.
From the View menu, select Server Explorer.
In the Server Explorer window, select Servers, then select 10263A-SVR1, then select Message
Queues, then select Private Queues, then select bridgerequestqueue, and then select Queue
messages.
2. Return to the service host console application, press 8, and then press ENTER to start the Ticketing
service.
3. Return to the OrderTicketWindow window of the client application, wait for the operation completion
message box to appear, and then close it by clicking OK. Notice that the seats you selected are now
marked as reserved.

Note: If you look at the outputted messages in the service host console application, you will notice a
message that logs how many endpoints of the Ticketing service the discovery proxy returned.
4. Return to Visual Studio 2010, and refresh the queue's content. The queue is now empty.
Return to Visual Studio 2010.
Right-click the BridgeRequestQueue queue, and then select Refresh.
5. Close all of the client application windows.
6. Close the service host console window.
L5-18 Lab 5: WCF Endpoints and Behaviors
Results: After this exercise, you will have verified that MSMQ can save messages for stopped services,
and you will have verified that a service pulls messages out of MSMQ when it is working.




Lab 5: WCF Endpoints and Behaviors L5-19
Module 5: Endpoints and Behaviors
Lab 5: WCF Endpoints and Behaviors
Section 2: Visual Basic
Exercise 1: Exposing Multiple Endpoints
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M05\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M05\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M05\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, browse to the D:\LabFiles\Starter\M05\VB folder, click the
TicketingOffice.sln file, and then click Open.
6. Build the solution.
From the Build menu, select Build Solution.
Task 2: Create two different endpoints for two different contracts
1. In the Crm solution folder, which is under the Services solution folder, locate the CRMService
project, and open the web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
From the Crm solution folder, open the CrmService project, and then open the web.config file.
2. Locate the CustomerRelationsService service configuration in the services section of the
web.config.
In the web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element with the name attribute value of
TicketingOffice.CrmService.CustomerRelationsService.
3. Add the following endpoints inside the service XML element.
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
L5-20 Lab 5: WCF Endpoints and Behaviors
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
<endpoint
address="PrivateCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
4. Save the web.config file.
From the File menu, select Save web.config.
5. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file in the services section, locate the CustomerRelationsService service
configuration.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element with the name attribute value of
TicketingOffice.CrmService.CustomerRelationsService.
7. Add the following endpoints inside the service XML element.
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
<endpoint
address="PrivateCrm"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
8. Save the App.config file.
From the File menu, select Save App.config.
Results: After this exercise, you will have exposed multiple endpoints for the CRM service.
Lab 5: WCF Endpoints and Behaviors L5-21
Exercise 2: Using Queued Services
Task 1: Examine the one-way operations in the Ticketing service contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Examine the one-way service contract. This opens the
TicketingServiceContracts.vb file.
3. Examine the interface ITicketingServiceOneWay. Each of the service operations uses the one-way
messaging pattern.

Note: Queues are one-way by design. Fortunately, the ticketing service provides a wrapper
implementing a One-Way contract. This One-Way implementation will internally call the original
version of the ticketing service to execute the ticketing functionality.
Task 2: Add a service configuration for the one-way version of the Ticketing service
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. Locate the services configuration section in the Web.config file.
In the Web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
3. Add the ticketing service configuration inside the services XML element.
<service
name="TicketingOffice.TicketingService.QueuedTicketingService"
behaviorConfiguration="StandardBehavior">
<!--Place endpoint settings here-->
</service>
4. Add the following MSMQ endpoint to the service's configuration element that you have just added.
<endpoint
address="BridgeRequestQueue"
binding="netMsmqBinding"
bindingConfiguration="TransactionalNoSecurity"
contract="TicketingOffice.TicketingService.Contracts.ITicketingServiceOneWay">
</endpoint>
5. Locate the SimpleServiceHost project under the Host solution folder, and open the App.config file.
Open the View menu, and then select Solution Explorer.
L5-22 Lab 5: WCF Endpoints and Behaviors
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. Locate the services configuration section in the App.config file.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
7. Add the ticketing service configuration inside the services XML element.
<service
name="TicketingOffice.TicketingService.QueuedTicketingService"
behaviorConfiguration="StandardBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5009"/>
<add baseAddress="net.msmq://localhost/private/"/>
</baseAddresses>
</host>
<!--Place endpoint settings here-->
</service>
8. Add the following MSMQ endpoint to the service's configuration element that you have just added.
<endpoint
address="BridgeRequestQueue"
binding="netMsmqBinding"
bindingConfiguration="TransactionalNoSecurity"
contract="TicketingOffice.TicketingService.Contracts.ITicketingServiceOneWay">
</endpoint>
Task 3: Add an MSMQ binding configuration
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the bindings section.
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. Add the following binding configuration to the bindings XML element.
<netMsmqBinding>
<binding
name="TransactionalNoSecurity"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveRetryCount="20"
retryCycleDelay="00:05:00">
<security mode="None"/>
</binding>
</netMsmqBinding>
Lab 5: WCF Endpoints and Behaviors L5-23
4. Save the Web.config file.
From the File menu, select Save Web.config.
5. Locate the SimpleServiceHost project under the Host solution folder, and then open the App.config
file.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
7. Add the following binding configuration to the bindings XML element.
<netMsmqBinding>
<binding
name="TransactionalNoSecurity"
durable="true"
exactlyOnce="true"
maxReceivedMessageSize="2147483647"
maxRetryCycles="1"
receiveRetryCount="20"
retryCycleDelay="00:05:00">
<security mode="None"/>
</binding>
</netMsmqBinding>
8. Save the App.config file.
From the File menu, select Save App.config.
Task 4: Add code for MSMQ queues creation in the hosting manager
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add code to create MSMQ queues. This opens the
HostingManager.vb file.
3. Add the following code to the CreateMsmq shared method.
Dim req_queue As String =
ConfigurationManager.AppSettings("BridgeRequestQueue")
Dim res_queue As String =
ConfigurationManager.AppSettings("BridgeResponseQueue")

If Not MessageQueue.Exists(req_queue) Then
MessageQueue.Create(req_queue, True)
End If

If Not MessageQueue.Exists(res_queue) Then
MessageQueue.Create(res_queue, True)
End If
4. Save the HostingManager.vb file.
From the File menu, select Save HostingManager.vb.
L5-24 Lab 5: WCF Endpoints and Behaviors
Task 5: Consume the QueuedTicketingService using an MSMQ channel

Note: The client application will use a special bridge service that exposes a request-response messaging
pattern contract. When the bridge receives a message, it forwards the message to the
QueuedTicketingService using a one-way channel and listens on its own endpoint for a response. When a
response arrives, the bridge returns the result back to the client.
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add code to call the one-way service. This opens the
TicketingBridgeService.svc.vb file.
3. Place the following code inside the Try block in the OrderTicket method. (First remove the existing
Return statement in the method.)
' Find a proxy to the ticketing service (one-way)
prox = TicketingServiceOneWayProxyFactory.GetProxy(False)
Dim arrived As New AutoResetEvent(False)

' Create a ResultPackage with a wait handle to wait on until a
' response arrives (on another channel)
Dim pack As New ResultPackage() With {.ResultArrived = arrived}
ResultsCache.Current.SetPackage(callId, pack)

' Call the pricing service on MSMQ channel on another thread.
Dim del As Action(Of ITicketingServiceOneWay) = (Sub(p) _
p.OrderTicket(newOrder, seats, callId))

del.BeginInvoke(prox, Nothing, Nothing)
'Wait until result arrives
arrived.WaitOne(timeout)
Dim result As Guid =
CType(ResultsCache.Current.GetResult(callId), Guid)
ResultsCache.Current.ClearResult(callId)
Return result
4. Save the TicketingBridgeService.svc.vb file.
From the File menu, select Save TicketingBridgeService.svc.vb.
5. Double-click the comment TODO: Ex2 Add code that sets the auto reset event. This opens the
TicketingBridgeCallBack.svc.vb file.
6. Place the following code inside the HandleResult method.
Dim resultPack = ResultsCache.Current.GetResultPack(callID)
If resultPack IsNot Nothing Then
resultPack.Result = result
resultPack.ResultArrived.Set()
End If
7. Save the TicketingBridgeCallBack.svc.vb file.
From the File menu, select Save TicketingBridgeCallBack.svc.vb.
Lab 5: WCF Endpoints and Behaviors L5-25

Note: The TicketingBridge class implements the contract ITicketingService, and the
TicketingBridgeCallBack class implements the contract ITicketingCallBack. The TicketingBridge class
exposes the original ticketing contract to the client, while the TicketingBridgeCallBack exposes a
callback contract to be consumed by the QueuedTicketingService.
Results: After this exercise, you will have hosted the queued ticketing service, configured the service to
expose an endpoint that uses MSMQ, and consumed the service from the ticketing bridge service.
Exercise 3: Using Transactions
Task 1: Place the TransactionFlow attribute over the service contract methods
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list shows User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Decorate the ITicketingService methods with the
TransactionFlow attribute. This opens the TicketingServiceContracts.vb file.
3. In the ITicketingService interface, decorate the methods OrderTicket, PayForTicket, CancelTicket,
and PrintTicket, with the TransactionFlow attribute, specifying that the transaction is mandatory.
<TransactionFlow(TransactionFlowOption.Mandatory)>
4. Double-click the comment TODO: Ex3 Decorate the ITicketingServiceOneWay methods with
the TransactionFlow attribute to locate the ITicketingServiceOneWay interface.
5. In the ITicketingServiceOneWay interface, decorate the methods OrderTicket, PayForTicket,
CancelTicket, and PrintTicket, with the TransactionFlow attribute, specifying that the transaction is
allowed.
<TransactionFlow(TransactionFlowOption.Allowed)>
6. The resulting ITicketingService interface should resemble the following code.
''' <summary>
''' The Contract for the ticketing service
''' This is a request response contract
''' </summary>
<ServiceContract(Namespace:="http://Fabrikam.com")>
Public Interface ITicketingService
<OperationContract()>
<TransactionFlow(TransactionFlowOption.Mandatory)>
Function OrderTicket(ByVal newOrder As Contracts.Order,
ByVal seats() As SeatIndex) As Guid

<OperationContract()>
<TransactionFlow(TransactionFlowOption.Mandatory)>
Function PayForTicket(ByVal orderID As Guid,
ByVal payingCustomerID As Guid, ByVal amount As Double,
ByVal methodOfPayment As PaymentType,
ByVal currency? As Currencies, ByVal creditCard As String) _
As Payment

<OperationContract()>
<TransactionFlow(TransactionFlowOption.Mandatory)>
Function CancelTicket(ByVal orderID As Guid,
ByVal payingCustomerID As Guid, ByVal creditCard As String) _
As Payment
L5-26 Lab 5: WCF Endpoints and Behaviors

<OperationContract()>
Function FindOrder(ByVal orderID As Guid) As Order

<OperationContract()>
Function FindOrders(ByVal criteria As OrderCriteria) As Order()

<OperationContract()>
Function FindBestCustomersIds(ByVal numberOfCustomers As Integer) _
As Guid()

<OperationContract()>
<TransactionFlow(TransactionFlowOption.Mandatory)>
Function PrintTicket(ByVal orderID As Guid) As String
End Interface
7. The resulting ITicketingServiceOneWay interface should resemble the following code.
<ServiceContract(Namespace:="http://Fabrikam.com")>
Public Interface ITicketingServiceOneWay
<OperationContract(IsOneWay:=True)>
<TransactionFlow(TransactionFlowOption.Allowed)>
Sub OrderTicket(ByVal newOrder As Contracts.Order,
ByVal seats() As SeatIndex, ByVal callID As Guid)

<OperationContract(IsOneWay:=True)>
<TransactionFlow(TransactionFlowOption.Allowed)>
Sub PayForTicket(ByVal orderID As Guid,
ByVal payingCustomerID As Guid,
ByVal amount As Double,
ByVal methodOfPayment As PaymentType,
ByVal currency? As Currencies,
ByVal callID As Guid,
ByVal creditCard As String)

<OperationContract(IsOneWay:=True)>
<TransactionFlow(TransactionFlowOption.Allowed)>
Sub CancelTicket(ByVal orderID As Guid,
ByVal payingCustomerID As Guid,
ByVal callID As Guid,
ByVal creditCard As String)

<OperationContract(IsOneWay:=True)>
Sub FindOrder(ByVal orderID As Guid, ByVal callID As Guid)

<OperationContract(IsOneWay:=True)>
Sub FindOrders(ByVal criteria As OrderCriteria,
ByVal callID As Guid)

<OperationContract(IsOneWay:=True)>
Sub FindBestCustomersIds(ByVal numberOfCustomers As Integer,
ByVal callID As Guid)

<OperationContract(IsOneWay:=True)>
<TransactionFlow(TransactionFlowOption.Allowed)>
Sub PrintTicket(ByVal orderID As Guid, ByVal callID As Guid)

End Interface
8. Save the TicketingServiceContracts.vb file.
From the File menu, select Save TicketingServiceContracts.vb.
Lab 5: WCF Endpoints and Behaviors L5-27
Task 2: Add transaction service behavior and operation behavior to the Ticketing service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Decorate the GeneralTicketingService service with a
ServiceBehavior attribute. This opens the TicketingService.svc.vb file.
3. Decorate the GeneralTicketingService class with the ServiceBehavior attribute, and set it to
automatically set the transaction as completed, when the session closes.
<ServiceBehavior(TransactionAutoCompleteOnSessionClose := True)>
4. Inside the GeneralTicketingService class, decorate the OrderTicket, PayForTicket, CancelTicket,
and PrintTicket methods with the OperationBehavior attribute as follows:
<OperationBehavior(TransactionScopeRequired := True,
TransactionAutoComplete := True)>
5. Save the TicketingService.svc.vb file.
From the File menu, select Save TicketingService.svc.vb.
6. Double-click the comment TODO: Ex3 Decorate the QueuedTicketingService service with a
ServiceBehavior attribute. This opens the QueuedTicketingService.svc.vb file.
7. Decorate the QueuedTicketingService class with the ServiceBehavior attribute, and set it to
automatically set the transaction as completed when the session closes.
<ServiceBehavior(TransactionAutoCompleteOnSessionClose := True)>
8. Inside the QueuedTicketingService class, decorate the OrderTicket, PayForTicket, CancelTicket,
and PrintTicket methods with the OperationBehavior attribute as follows:
<OperationBehavior(
TransactionScopeRequired := True,
TransactionAutoComplete := True)>
9. Save the QueuedTicketingService.svc.vb file.
From the File menu, select Save QueuedTicketingService.svc.vb.
Task 3: Enable the transaction binding element in the binding configuration of all the
services
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the bindings section.
L5-28 Lab 5: WCF Endpoints and Behaviors
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. In the bindings section, turn on transaction flow in each of the binding configurations that belong to
the ws2007HttpBinding and the netTCPBinding XML elements.
In the bindings section, look for the ws2007HttpBinding element, and place the
transactionFlow attribute in each of the binding XML elements that are inside it. Set the
attribute's value to True.
In the bindings section, look for the netTcpBinding element, and place the transactionFlow
attribute in each of the binding XML elements that are inside it. Set the attribute's value to True.
4. Save the Web.config file.
From the File menu, select Save Web.config.
5. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
6. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
7. In the bindings section, turn on transaction flow in each of the binding configurations that belong to
the ws2007HttpBinding and the netTCPBinding XML elements.
In the bindings section, look for the ws2007HttpBinding element, and place the
transactionFlow attribute in each of the binding XML elements that are inside it. Set the
attribute's value to True.
In the bindings section, look for the netTcpBinding element, and place the transactionFlow
attribute in each of the binding XML elements that are inside it. Set the attribute's value to True.
8. Save the App.config file.
From the File menu, select Save App.config.
Results: After this exercise, you will have configured the ticketing service contract to use transactions,
and configured the service bindings to accept transaction flow.
Exercise 4: Using Reliable Messaging
Task 1: Enable reliable messaging in the binding configuration of the Ticketing HTTP
Bridge service
1. In the Ticketing solution folder, which is under the Services solution folder, locate the Bridge
project, and open the Web.config file
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the Bridge project, and then open the Web.config file.
2. In the Web.config file, locate the bindings section.
Lab 5: WCF Endpoints and Behaviors L5-29
In the Web.config file, under the configuration XML element, locate the bindings section
under the system.serviceModel section.
3. In the bindings section, locate the section for ws2007HttpBinding, and add the following binding
configurations inside it:
<binding
name="RM_NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<reliableSession enabled="true" ordered="false"/>
<security mode="None"></security>
</binding>
4. Locate the TicketingBridge service configuration in the services section of the web.config file.
In the web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
In the services section, locate the service XML element that has the name attribute value of
TicketingOffice.Bridge.TicketingBridge.
5. Change the service's endpoint to use the RM_NoSecurity binding configuration.
Locate the endpoint configuration inside the TicketingBridge service XML element.
Add the bindingConfiguration attribute to the endpoint element, and set its value to
RM_NoSecurity.
6. Save the Web.config file.
From the File menu, select Save Web.config.
7. Locate the SimpleServiceHost project under the Host solution folder, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
8. In the App.config file, locate the bindings section.
In the App.config file, under the configuration XML element, locate the bindings section under
the system.serviceModel section.
9. In the bindings section, locate the section for ws2007HttpBinding, and add the following binding
configurations inside it:
<binding
name="RM_NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<reliableSession enabled="true" ordered="false"/>
<security mode="None"></security>
</binding>
10. Save the App.config file.
From the File menu, select Save App.config.
L5-30 Lab 5: WCF Endpoints and Behaviors
Results: After this exercise, you will have added reliable messaging binding configuration to your
service host.
Exercise 5: Configuring Instancing and Concurrency
Task 1: Set the concurrency and instancing mode of the Ticketing HTTP Bridge service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex5 Change the concurrency and instancing mode of the
TicketingBridge service. This opens the TicketingBridgeService.svc.vb file.
3. Locate the ServiceBehavior attribute that decorates the TicketingBridge class; set the
ConcurrencyMode parameter to Multiple, and the InstanceContextMode to PerCall.
<ServiceBehavior(
ReleaseServiceInstanceOnTransactionComplete := False,
ConcurrencyMode := ConcurrencyMode.Multiple,
InstanceContextMode := InstanceContextMode.PerCall)>
Public Class TicketingBridge
Implements ITicketingService
...
End Class
4. Save the TicketingBridgeService.svc.vb file.
From the File menu, select Save TicketingBridgeService.svc.vb.
5. Double-click the comment TODO: Ex5 Change the concurrency and instancing mode of the
TicketingBridgeCallBack service. This opens the TicketingBridgeCallBack.svc.vb file.
6. Locate the ServiceBehavior attribute that decorates the TicketingBridgeCallBack class; set the
ConcurrencyMode parameter to Multiple, and the InstanceContextMode to PerCall.
<ServiceBehavior(
ConcurrencyMode := ConcurrencyMode.Multiple,
InstanceContextMode := InstanceContextMode.PerCall)>
Public Class TicketingBridgeCallBack
Implements ITicketingCallBack
...
End Class
7. Save the TicketingBridgeCallBack.svc.vb file.
From the File menu, select Save TicketingBridgeCallBack.svc.vb.
Task 2: Examine the statelessness of the Ticketing HTTP Bridge service
1. Open the file TicketingBridgeService.svc.vb from the Bridge project.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the Bridge project, and then open the
TicketingBridgeService.svc.vb file.
Lab 5: WCF Endpoints and Behaviors L5-31
2. Examine the TicketingBridge class. Notice that the service implementation does not hold any state
information.
3. Examine the OrderTicket method in the class. Notice that to save state, the method uses the
singleton pattern by using the ResultsCache.Current, and a new instance is created for each call.
Task 3: Examine the instancing mode of the Notifications service in the client application
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex5 Examine the instancing mode of the Client Notification
service. This opens the ServiceNotificationWindow.xaml.vb file.
3. Examine how the Client Notification service uses the Single instancing context mode. Notice that the
ServiceNotificationWindow implements the Notification service, but it is also a Window object
when a message is sent to the client, it will be directed to the opened Window object.
4. In the ServiceNotificationWindow, look for the btnListen_Click method. Examine how the
ServiceHost constructor is called. Notice that the instance of the window is passed as the service
implementation instance.
Results: After this exercise, you will have set the concurrency and instancing mode on the Ticketing
Bridge.
Exercise 6: Using WCF Discovery
Task 1: Add dedicated discovery endpoints to all the services
1. In the Ticketing solution folder, which is under the Services solution folder, locate the
TicketingService project, and open the Web.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Ticketing
solution folder.
From the Ticketing solution folder, open the TicketingService project, and then open the
Web.config file.
2. In the Web.config file, locate the services section.
In the Web.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
3. Add the following new endpoint settings element in each of the service elements.
<endpoint
name="udpDiscovery"
kind="udpDiscoveryEndpoint"
endpointConfiguration="adhocDiscoveryEndpointConfiguration"/>
4. In the Web.config file, locate the standardEndpoints section.
In the Web.config file, under the configuration XML element, locate the standardEndpoints
section under the system.serviceModel section.
5. Add the following endpoints configuration inside the standardEndpoints element:
<!-- Specify the discovery protocol version and maxResponseDelay -->
L5-32 Lab 5: WCF Endpoints and Behaviors
<udpDiscoveryEndpoint>
<standardEndpoint
name="adhocDiscoveryEndpointConfiguration"
discoveryVersion="WSDiscovery11"
maxResponseDelay="00:00:10" />
</udpDiscoveryEndpoint>

<!--Specify the discovery mode of the proxy discovery endpoint is Managed and not Ad-
hoc-->
<discoveryEndpoint>
<standardEndpoint
name="managedDiscoveryEndpoint"
discoveryMode="Managed"
maxResponseDelay="00:01:00"/>
</discoveryEndpoint>
6. Save the Web.config file.
In the File menu, select Save Web.config.
7. In the Host solution folder, locate the SimpleServiceHost project, and open the App.config file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, open the SimpleServiceHost
project, and then open the App.config file.
8. In the App.config file, locate the services section.
In the App.config file, under the configuration XML element, locate the services section under
the system.serviceModel section.
9. Add the following endpoint settings in each of the service elements, except for the
TicketingOffice.PricingBrokerService.DiscoveryProxyService service configuration:
<endpoint
name="udpDiscovery"
kind="udpDiscoveryEndpoint"
endpointConfiguration="adhocDiscoveryEndpointConfiguration"/>
10. In the App.config file, locate the standardEndpoints section.
In the App.config file, under the configuration XML element, locate the standardEndpoints
section under the system.serviceModel section.
11. Add the following endpoints configuration inside the standardEndpoints element:
<!-- Specify the discovery protocol version and maxResponseDelay -->
<udpDiscoveryEndpoint>
<standardEndpoint
name="adhocDiscoveryEndpointConfiguration"
discoveryVersion="WSDiscovery11"
maxResponseDelay="00:00:10" />
</udpDiscoveryEndpoint>

<!--Specify the discovery mode of the proxy discovery endpoint is Managed and not Ad-hoc-
->
<discoveryEndpoint>
<standardEndpoint
name="managedDiscoveryEndpoint"
discoveryMode="Managed"
maxResponseDelay="00:01:00"/>
</discoveryEndpoint>
12. Save the App.config file.
Lab 5: WCF Endpoints and Behaviors L5-33
In the File menu, select Save App.config.
Task 2: Create a dynamic endpoint to locate the Ticketing service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex6 Use a dynamic endpoint to find the ticketing service.
This opens the TicketingBridgeService.svc.vb file.
3. In the GetProxy method, locate the second If statement.
If discovery Then
' TODO: Ex6 - Use a dynamic endpoint to find the ticketing service
Return Nothing
End If
4. Inside the If statement, replace the Return statement with the following code:
Dim l_dynamicEndpoint As New DynamicEndpoint(
ContractDescription.GetContract(GetType(ITicketingServiceOneWay)),
New NetMsmqBinding())

Return _chf.CreateChannel(l_dynamicEndpoint.Address)
5. Save the TicketingBridgeService.svc.vb file.
From the File menu, select Save TicketingBridgeService.svc.vb.
Task 3: Examine the code of the discovery proxy
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.

2. Double-click the comment TODO: Ex6 Examine the discovery proxy service implementation.
This opens the DiscoveryProxy.svc.vb file.
3. Examine the implementation of the DiscoveryProxyService classthe discovery proxy has a simple
internal service repository that is used to maintain service information. The discovery proxy overrides
the OnBeginOfflineAnnouncement/OnEndOfflineAnnouncement and
OnBeginOnlineAnnouncement/OnEndOnlineAnnouncement methods to respond to
announcement messages that are coming from within its local subnet, and to manage the internal
service repository.
The Discovery proxy also overrides the OnBeginFind / OnEndFind and OnBeginResolve /
OnEndResolve methods to process Probe and Resolve messages coming from outside the subnet,
and respond with service details based on the services repository.
L5-34 Lab 5: WCF Endpoints and Behaviors
Task 4: Consume the discovery proxy in the broker between the Pricing service and the
Pricing Rules service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex6 Find a service that exposes the IPricingRulesService
service contract. This opens the PricingService.svc.vb file.
3. In the GetRulesFromService method, locate the Try block, and place the following code inside it:
SyncLock Me
If chf Is Nothing Then
chf = New ChannelFactory(Of IPricingRulesService)(
"PricingRulesEP")
End If
End SyncLock

' Find IPricingRulesService endpoints
Try
l_findResponse = l_discoveryClient.Find(
New FindCriteria(GetType(IPricingRulesService)))
Catch e1 As Exception
End Try

If l_findResponse IsNot Nothing Then
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format("Discovery proxy found {0} endpoints",
l_findResponse.Endpoints.Count))

addresses = (
From ep In l_findResponse.Endpoints
Select ep.Address).ToArray()
Else
'Set a default address for the pricing rules service
addresses = New EndpointAddress() { chf.Endpoint.Address }
End If
' look for the rules in all the endpoints found.
' When rules are found stop searching.
For Each address In addresses
prox = chf.CreateChannel(address)
rules = prox.GetPricingRulesByCriteria(
New RulesCriteria() With {
.Scope = policyName,
.FromDate = Date.Today,
.ToDate = Date.Today.AddDays(1)})

If (rules IsNot Nothing) AndAlso (rules.Count() > 0) Then
Exit For
End If
Next address
4. Save the PricingService.svc.vb file.
From the File menu, select Save PricingService.svc.vb.
Results: After this exercise, you will have added ad-hoc discovery endpoints for all the services, used a
dynamic endpoint to consume a service, and used a discovery client to call a discovery proxy service.
Lab 5: WCF Endpoints and Behaviors L5-35
Exercise 7: Verifying MSMQ Topology
Task 1: Start all the services, except the Queued Ticketing service
1. Set the SimpleServiceHost project as the startup project.
In the Solution Explorer window, open the Host solution folder.
Right-click the SimpleServiceHost project, and then select Set as StartUp Project.
2. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
From the Debug menu, select Start Without Debugging.
3. In the SimpleServiceHost console, press the 8 key, and then press ENTER to stop the Ticketing
service.
Task 2: Use the client application to order a ticket
1. Set the TicketingOffice.UI project as the startup project.
In the Solution Explorer window, open the Client solution folder.
Right-click the TicketingOffice.UI project, and then select Set as StartUp Project.
2. Run the TicketingOffice.UI project without debugging.
From the Debug menu, select Start Without Debugging.
3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and select Hanson, Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to retrieve the layout of the hall, and to see which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
8. In the window's status bar, notice the "Waiting for the service to complete" message. Leave the all the
client windows and the service host console window open, and return to Visual Studio 2010.

Important: The endpoint's binding for the Ticketing Bridge service is configured to time out after 4
minutes. Therefore, you will need to perform the following Task 3 in less than 4 minutes, or else you will
get an exception on the client side, and you will have to perform Tasks 2 and 3 again.
Task 3: Look at the MSMQ messages
1. Using the Server Explorer window, examine the content of the BridgeRequestQueue queue; you
should see a messages inside the queue.
From the View menu, select Server Explorer.
In the Server Explorer window, select Servers, then select 10263A-SVR1, then select Message
Queues, then select Private Queues, then select bridgerequestqueue, and then select Queue
messages.
2. Return to the service host console application, press 8, and then press ENTER to start the Ticketing
service.
L5-36 Lab 5: WCF Endpoints and Behaviors
3. Return to the OrderTicketWindow window of the client application, wait for the operation completion
message box to appear, and then close it by clicking OK. Notice that the seats you selected are now
marked as reserved.

Note: If you look at the outputted messages in the service host console application, you will notice a
message that logs how many endpoints of the Ticketing service the discovery proxy returned.
4. Return to Visual Studio 2010, and refresh the queue's content. The queue is now empty.
Return to Visual Studio 2010.
Right-click the BridgeRequestQueue queue, and then select Refresh.
5. Close all of the client application windows.
6. Close the service host console window.
Results: After this exercise, you will have verified that MSMQ can save messages for stopped services,
and you will have verified that a service pulls messages out of MSMQ when it is working.




Lab 6: Testing and Troubleshooting WCF Services L6-1
Module 6: Testing and Troubleshooting Microsoft Windows
Communication Foundation Services
Lab 6: Testing and Troubleshooting WCF
Services
Section 1: Visual C#
Exercise 1: Viewing Unplanned SOAP Faults
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. Open Microsoft Visual Studio 2010:
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
3. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M06\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M06\CS folder, click the
TicketingOffice.sln file, and then click Open.
Task 2: Call the Reservation service with invalid input
1. Run the SimpleServiceHost project without debugging.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
2. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
3. Add the Reservation service using the address http://localhost:5003.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
4. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
L6-2 Lab 6: Testing and Troubleshooting WCF Services
In the My Service Projects tree, open the IHallStateStateService node, and double-click the
FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.


5. After a few seconds, an error message will display, showing an exception thrown by the service.
Review the error message, and notice that no exception details are sent to the client.

6. Close the error window.
In the error window, click the Close button.
7. Switch to the XML tab, and examine the fault message.
Lab 6: Testing and Troubleshooting WCF Services L6-3


8. Close the Windows Communication Foundation (WCF) Test Client utility.
9. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and press ENTER again to close the console window.
Task 3: Configure the service to expose exception details inside fault messages
1. Return to Visual Studio 2010, and from the Solution Explorer window, open the Host solution folder,
and then open the SimpleServiceHost project.
2. In the SimpleServiceHost project, double-click the App.config file.
3. Under the configuration system.serviceModel behaviors serviceBehaviors, locate the
service behavior name StandardBehavior. The behavior configuration should look like the following
XML fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<!-- Add Configuration here -->
<serviceDiscovery/>
</behavior>
4. Replace the <!-- Add Configuration here --> XML comment with the following serviceDebug
element:
<serviceDebug includeExceptionDetailInFaults="true"/>
5. The behavior configuration should now resemble the following XML fragment:
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceDiscovery/>
</behavior>
6. Save the App.config file.
From the File menu, select Save App.config.
L6-4 Lab 6: Testing and Troubleshooting WCF Services
Task 4: Retest the service
1. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and select Start Without Debugging.
2. Open the WcfTestClient, and add the Reservation service, using the address http://localhost:5003.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
3. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
In the My Service Projects tree, open the IHallStateStateService node, and double-click the
FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.
4. After a few seconds, an error message will display, showing an exception thrown by the service.
Review the error message, and notice that the exception details are now included inside the fault
message.

5. Close the error window
In the error window, click the Close button
6. Switch to the XML tab, and review the fault message.
7. Close the WCF Test Client utility.
8. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Press ENTER to stop the service host, and press ENTER again to close the console window.
Results: After this exercise, you will have tested a service that does not include exception details in
SOAP faults. In addition, you will have configured the service to include exception details in SOAP
faults, and then retested the service to see the difference between the two responses.
Lab 6: Testing and Troubleshooting WCF Services L6-5
Exercise 2: Using Fault Contracts
Task 1: Create a fault contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Decorate operations with a FaultContractAttribute. This
opens the ShowsContract.cs file.
3. Decorate the CreateEvent and UpdateEvent methods with the FaultContract attribute.
[FaultContract(typeof(ShowExceptionInfo))]
4. The resulting code should resemble the following code sample.
[OperationContract]
[FaultContract(typeof(ShowExceptionInfo))]
Guid CreateEvent(Event newEvent);

[OperationContract]
[FaultContract(typeof(ShowExceptionInfo))]
void UpdateEvent(Event newEvent);
5. Save the ShowsContract.cs file.
From the File menu, select Save ShowsContract.cs.
Task 2: Throw a fault exception
1. Open the Task List window and double-click the comment TODO: Ex2 Place code to validate
event information. This opens the ShowsService.svc.cs file.
2. In the ValidateEvent method, add the following code to throw a fault exception when either the
show details are not supplied, or when the show cannot be found using its ID.
if (eventToValidate.ShowDetails == null)
{
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = StringsResource.NullShow
});
}

int id = eventToValidate.ShowDetails.ShowID;
if (FindShowByID(id) == null)
{
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = string.Format(StringsResource.ShowNotFound, id)
});
}
3. Save the ShowsService.svc.cs file.
From the File menu, select Save ShowsService.svc.cs.
Results: After this exercise, you will have decorated several service operations with the FaultContract
attribute, and added the necessary code to the ValidateEvent method to throw a FaultException.
L6-6 Lab 6: Testing and Troubleshooting WCF Services
Exercise 3: Using Error Handlers and Handling Faults
Task 1: Create and attach an error handler
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Convert a normal Exception to a FaultException. This
opens the ShowsErrorHandler.cs file.
3. In the ProvideFault method, add code to convert a normal exceptionthrown somewhere in your
codeto a FaultException<ShowExceptionInfo>.
FaultException<ShowExceptionInfo> faultException =
new FaultException<ShowExceptionInfo>(
new ShowExceptionInfo
{
Message = error.Message,
ExceptionInfo = error.ToString()
});

MessageFault messageFault = faultException.CreateMessageFault();

fault = Message.CreateMessage(
version, messageFault, faultException.Action);
4. Save the ShowsErrorHandler.cs file.
From the File menu, select Save ShowsErrorHandler.cs.
5. In the Task List window, double-click the comment TODO: Ex3 Decorate the service
implementation with the error handling service behavior. This opens the ShowsService.svc.cs
file.
6. Attach the new error handler by decorating the ShowsAndEventsService class with the
ErrorBehavior attribute, as demonstrated in the following code.
[ErrorBehavior(typeof(ShowsErrorHandler))]
7. Save the ShowsService.svc.cs file.
From the File menu, select Save ShowsService.svc.cs.

Note: The ErrorBehavior attribute is a custom attribute that is implemented in the
Behaviors\ErrorHandlingBehavior.cs file which belongs to the TicketingOffice.Common
project that can be found in the Common solution folder.
Task 2: Throw a standard .NET exception instead of a fault exception
1. Open the Task List window, and double-click the comment TODO: Ex2 Place code to validate
event information. This opens the ShowsService.svc.cs file.
If the comment exists in the Task List window, double-click the comment to open the
ValidateEvent method.
If the comment was removed, open the View menu, select Solution Explorer, and in the
Solution Explorer window, open the Services solution folder, then open the Shows solution
Lab 6: Testing and Troubleshooting WCF Services L6-7
folder, then open the ShowsService project, and then open the ShowsService.svc.cs file, which
is under the ShowsService.svc file. The ValidateEvent method is located at the end of the file
2. In the ValidateEvent method, place both throw statements in comment. The resulting code should
resemble the following code sample.
if (eventToValidate.ShowDetails == null)
{
/*
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = StringsResource.NullShow
});
*/
}

int id = eventToValidate.ShowDetails.ShowID;
if (FindShowByID(id) == null)
{
/*
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = string.Format(StringsResource.ShowNotFound, id)
});
*/
}
3. Under each throw statement that you have commented, add a standard throw statement that throws
a ShowException object.
if (eventToValidate.ShowDetails == null)
{
/*
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = StringsResource.NullShow
});
*/
Option 2: Throw a normal exception. The error handler will
convert it to a FaultException<ShowExceptionInfo>.
throw new ShowException(StringsResource.NullShow);
}

int id = eventToValidate.ShowDetails.ShowID;
if (FindShowByID(id) == null)
{
/*
//Option 1: Throw a Fault<ShowExceptionInfo>
throw new FaultException<ShowExceptionInfo>(new ShowExceptionInfo
{
ExceptionInfo = "",
Message = string.Format(StringsResource.ShowNotFound, id)
});
*/
Option 2: Throw a normal exception. The error handler will
convert it to a FaultException<ShowExceptionInfo>.
throw new ShowException(
L6-8 Lab 6: Testing and Troubleshooting WCF Services
string.Format(StringsResource.ShowNotFound, id));
}
4. Save the ShowsService.svc.cs file.
From the File menu, select Save ShowsService.svc.cs.
Task 3: Invoke the service and catch any fault exceptions
1. Open the Task List window, and double-click the comment TODO: Ex3 Call the CreateEvent
operation of the Shows service and catch any fault exceptions. This opens the
Lab6HelperForm.cs file.
2. In the btnFault_Click method event handler, replace the comment with the following code:
try
{
ShowsTestHelper.CreateFaultyEvent();
MessageBox.Show("Done");
}
catch (FaultException<ShowExceptionInfo> fault)
{
MessageBox.Show(fault.Detail.Message, "Show exception",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
3. Save the Lab6HelperForm.cs file.
From the File menu, select Save Lab6HelperForm.cs.
4. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and select Start Without Debugging.
5. Run the Lab_6_Helper project without debugging.
Return to Visual Studio 2010, and from the Solution Explorer window, open the Helpers solution
folder.
Right-click the Lab_6_Helper project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
6. Click the Create faulty event button. After a few seconds, a message containing the error will
appear.
7. Close the Lab_6_Helper window.
8. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Results: After this exercise, you will have created an error handler, attached it to the service, threw
standard .NET exceptions instead of fault exceptions, and caught fault exceptions on the client side.
Lab 6: Testing and Troubleshooting WCF Services L6-9
Exercise 4: Using WCF Message Logging and Tracing
Task 1: Use the WCF Configuration utility to add tracing and message logging
1. Open the SimpleServiceHost project's App.config file in the WCF Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor utility, open the File menu, then select Open, and
then select Config File.
In the Open dialog box, navigate to the D:\LabFiles\Starter\M06\CS\Host\SimpleServiceHost
folder.
Select the App.config file, and click Open.
2. Turn on MessageLogging and Tracing.
In the Configuration tree, click the Diagnostics node.
Turn MessageLogging on by clicking enable MessageLogging.
Turn Tracing on by click enable Tracing.
3. Save the configuration file.
Open the File menu, and then click Save.
4. Close the WCF Service Configuration Editor, and return to Visual Studio 2010.
If a reload confirmation message appears when you return to Visual Studio 2010, click Yes.
Task 2: Cause the service to throw an exception
1. Create an exception by commenting out the TicketingOfficeHallsEntities connection string to the
database in the SimpleServiceHost project's App.config file.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
Locate the connectionStrings element (it should appear after the system.diagnostics element),
and comment out the TicketingOfficeHallsEntities connection string, as shown in the following
XML fragment:
<connectionStrings>
<add name="ApplicationServices" connectionString="Data Source=.\SQLEXPRESS;Initial
Catalog=TicketingOffice;Integrated Security=True;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />

<add name="TicketingOfficeCrmEntities"
connectionString="metadata=res://*/CrmModel.csdl|res://*/CrmModel.ssdl|res://*/CrmModel.
msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeExchangeEntities"
connectionString="metadata=res://*/ExchangeModel.csdl|res://*/ExchangeModel.ssdl|res://*
/ExchangeModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

L6-10 Lab 6: Testing and Troubleshooting WCF Services
<!--<add name="TicketingOfficeHallsEntities"
connectionString="metadata=res://*/ReservationsModel.csdl|res://*/ReservationsModel.ssdl
|res://*/ReservationsModel.msl;provider=System.Data.SqlClient;provider connection
string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />-->

<add name="TicketingOfficePaymentEntities"
connectionString="metadata=res://*/PaymentModel.csdl|res://*/PaymentModel.ssdl|res://*/P
aymentModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficePricingEntities"
connectionString="metadata=res://*/PricingRulesModel.csdl|res://*/PricingRulesModel.ssdl
|res://*/PricingRulesModel.msl;provider=System.Data.SqlClient;provider connection
string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeShowEntities"
connectionString="metadata=res://*/ShowModel.csdl|res://*/ShowModel.ssdl|res://*/ShowMod
el.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeOrderEntities"
connectionString="metadata=res://*/OrdersModel.csdl|res://*/OrdersModel.ssdl|res://*/Ord
ersModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
2. Change the behavior of the service to exclude exception details in faults.
In the App.config file, locate the service behavior named StandardBehavior, which is located at
configuration system.serviceModel behaviors serviceBehaviors.
Change the serviceDebug element, so it will not include exception details in faults, by changing
the includeExceptionDetailInFaults attribute to false.
The resulting behavior configuration should resemble the following XML fragment:
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceDiscovery/>
</behavior>
3. Save the App.config file.
From the File menu, select Save App.config.
4. Run the SimpleServiceHost project without debugging.
Right-click the SimpleServiceHost project, and select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
5. Start the WcfTestClient utility from the D:\LabFiles folder.
Lab 6: Testing and Troubleshooting WCF Services L6-11
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
6. Add the Reservation service, using the address http://localhost:5003.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
7. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
In the My Service Projects tree, open the IHallStateStateService node, and then double-click
the FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.
8. After the error message displays, close the error window.
In the error window, click the Close button.
9. Close the WCF Test Client utility.
10. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Task 3: Use the SvcTraceViewer.exe utility to inspect the exception
1. Return to Visual Studio 2010, and open the Host solution folder from the Solution Explorer window.
2. Right-click the SimpleServiceHost project, and then select Open Folder in Windows Explorer.
3. Double-click the App_tracelog.svclog file to open it with the Microsoft Service Trace Viewer.
4. Return to the Windows Explorer window, where the log files display, and drag the
App_messages.svclog into the opened Microsoft Service Trace Viewer window.
5. Locate the FindTheater message that in the Activity tab is marked in red.
Click the Activity tab to see the service's activity log.
Scroll down to find the activity labeled Process action
'http://Fabrikam.com/IHallStateService/FindTheater'.
Select the activity, and from the activity's description list, click the red row with the description
Handling an exception.
6. Examine the exception's content that displays in the Formatted tab.
L6-12 Lab 6: Testing and Troubleshooting WCF Services

7. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have added tracing and message logging support to your service,
caused the service to throw an exception, and looked at the exception information in the Service Trace
Viewer utility.
Exercise 5: Supporting Large Messages
Task 1: Clear the database from all the shows with Category = Comedy
1. Run the Lab_6_Helper project without debugging.
Return to Visual Studio 2010, and from the Solution Explorer window, open the Helpers solution
folder.
Right-click the Lab_6_Helper project, and then select Set as StartUp Project.
Open the Debug menu, and then select Start Without Debugging.

2. Click the Clear Comedies button, and when the message box appears, press OK.
Task 2: Create 10 comedies
1. Select the value 10 from the combo box.
2. Click the Create Comedies button, and when the message box appears, press OK.
Lab 6: Testing and Troubleshooting WCF Services L6-13
3. Leave the helper utility running, and return to Visual Studio 2010.
Task 3: Start the Shows service
1. Run the SimpleServiceHost without debugging.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
Task 4: Call the FindShowsByCriteria operation of the Shows service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the Shows service, using the address http://localhost:5007.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5007, and then click OK.
3. Test the FindShowsByCriteria operation of the IShowsService contract with the Comedy category.
In the My Service Projects tree, open the IShowsService node, and double-click the
FindShowsByCriteria operation.
In the Request property page, set the Category to Comedy.
Click Invoke to activate the service, and if a security warning appears, click OK.
4. Verify that the relevant shows are returned.
Task 5: Create 100 more comedies
1. Return to the Lab_6_Helper window. (Leave the WCF Test Client utility open.)
2. Change the value in the combo box from 10 to 100.
3. Click the Create Comedies button, and when the message box appears, press OK.
Task 6: Call the service again
1. Return to the WCF Test Client utility.
2. Click Invoke to activate the service again, and if a security warning appears, click OK.
3. The service will fail. Read the error message in the exception.
L6-14 Lab 6: Testing and Troubleshooting WCF Services

4. Close the error window.
In the error window, click the Close button.
Task 7: Configure the service to support large messages
1. Close the SimpleServiceHost console window, but leave the WCF Test Client running.
Press ENTER to stop the service host, and then press ENTER again to close the SimpleServiceHost
console window.
2. Return to Visual Studio 2010, and from the Solution Explorer window, open the Host solution folder,
and then open the SimpleServiceHost project.
3. In the SimpleServiceHost project, double-click the App.config file to open it.
4. Under configuration system.serviceModel bindings ws2007HttpBinding, locate the
binding named NoSecurity. The binding configuration should look like the following XML fragment:
<binding
name="NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="None"></security>
</binding>
5. Add the maxReceivedMessageSize attribute to the binding configuration, and set it to 200000. The
resulting binding configuration should resemble the following XML fragment:
<binding
name="NoSecurity"
maxReceivedMessageSize="200000"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="None"></security>
</binding>
Lab 6: Testing and Troubleshooting WCF Services L6-15
6. Save the App.config file.
From the File menu, click Save App.config.
7. Run the SimpleServiceHost without debugging.
Open the Debug menu, and select Start Without Debugging.
Task 8: Change the configuration used by the WCF Test Client
1. Return to the WCF Test Client utility.
2. In the My Service Projects tree, right-click the Config File node, and then select Edit with
SvcConfigEditor.

3. In the Service Configuration Editor, select the WS2007HttpBinding_IShowsService binding
configuration.
In the Configuration tree, open the Bindings node.
Click the WS2007HttpBinding_IShowsService (wsHttpBinding) binding configuration.
4. In the Binding tab, change the MaxReceivedMessageSize from 65536 to 200000.
L6-16 Lab 6: Testing and Troubleshooting WCF Services

5. Save the configuration, and close the Service Configuration Editor.
Open the File menu, and then click Save.
Open the File menu, and then click Exit.
6. Return to the WCF Test Client utility. When a message box asking for reload will displays, click Yes.
7. Test the FindShowsByCriteria operation of the IShowsService contract with the Comedy category.
In the My Service Projects tree, open the IShowsService node, and then double-click the
FindShowsByCriteria operation.
In the Request property page, set the Category to Comedy.
Click Invoke to activate the service, and if a security warning appears, click OK.
8. Make sure the shows are displayed correctly.
9. Close the WCF Test Client utility.
10. Return to the Lab_6_Helper window, click the Clear Comedies button, and when a message box
appears, press OK.
11. Close the Lab_6_Helper window.
12. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Results: After this exercise, you will have called a service operation that returned a fault due to a large
message being returned to the client. In addition, you will have configured both the service and the
client to support large messages, and successfully called the operation afterwards.




Lab 6: Testing and Troubleshooting WCF Services L6-17
Module 6: Testing and Troubleshooting Microsoft Windows
Communication Foundation Services
Lab 6: Testing and Troubleshooting WCF
Services
Section 2: Visual Basic
Exercise 1: Viewing Unplanned SOAP Faults
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. Open Microsoft Visual Studio 2010:
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
3. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M06\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M06\VB folder, click the
TicketingOffice.sln file, and then click Open.
Task 2: Call the Reservation service with invalid input
1. Run the SimpleServiceHost project without debugging.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
2. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
3. Add the Reservation service using the address http://localhost:5003.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
4. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
In the My Service Projects tree, open the IHallStateStateService node, and double-click the
FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.
L6-18 Lab 6: Testing and Troubleshooting WCF Services

5. After a few seconds, an error message will display, showing an exception thrown by the service.
Review the error message, and notice that no exception details are sent to the client.

6. Close the error window.
In the error window, click the Close button.
Lab 6: Testing and Troubleshooting WCF Services L6-19
7. Switch to the XML tab, and examine the fault message.


8. Close the Windows Communication Foundation (WCF) Test Client utility.
9. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and press ENTER again to close the console window.
Task 3: Configure the service to expose exception details inside fault messages
1. Return to Visual Studio 2010, and from the Solution Explorer window, open the Host solution folder,
and then open the SimpleServiceHost project.
2. In the SimpleServiceHost project, double-click the App.config file.
3. Under the configuration system.serviceModel behaviors serviceBehaviors, locate the
service behavior name StandardBehavior. The behavior configuration should look like the following
XML fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<!-- Add Configuration here -->
<serviceDiscovery/>
</behavior>
4. Replace the <!-- Add Configuration here --> XML comment with the following serviceDebug
element:
<serviceDebug includeExceptionDetailInFaults="true"/>
5. The behavior configuration should now resemble the following XML fragment:
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceDiscovery/>
</behavior>
6. Save the App.config file.
From the File menu, select Save App.config.
L6-20 Lab 6: Testing and Troubleshooting WCF Services
Task 4: Retest the service
1. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and select Start Without Debugging.
2. Open the WcfTestClient, and add the Reservation service, using the address http://localhost:5003.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
In the WcfTestClient utility, open the File menu, and select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
3. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
In the My Service Projects tree, open the IHallStateStateService node, and double-click the
FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.
4. After a few seconds, an error message will display, showing an exception thrown by the service.
Review the error message, and notice that the exception details are now included inside the fault
message.

5. Close the error window
In the error window, click the Close button
6. Switch to the XML tab, and review the fault message.
7. Close the WCF Test Client utility.
8. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Press ENTER to stop the service host, and press ENTER again to close the console window.
Results: After this exercise, you will have tested a service that does not include exception details in
SOAP faults. In addition, you will have configured the service to include exception details in SOAP
faults, and then retested the service to see the difference between the two responses.
Lab 6: Testing and Troubleshooting WCF Services L6-21
Exercise 2: Using Fault Contracts
Task 1: Create a fault contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Decorate operations with a FaultContractAttribute. This
opens the ShowsContract.vb file.
3. Decorate the CreateEvent and UpdateEvent methods with the FaultContract attribute.
<FaultContract(GetType(ShowExceptionInfo))>
4. The resulting code should resemble the following code sample.
<OperationContract(), FaultContract(GetType(ShowExceptionInfo))>
Function CreateEvent(ByVal newEvent As [Event]) As Guid

<OperationContract(), FaultContract(GetType(ShowExceptionInfo))>
Sub UpdateEvent(ByVal newEvent As [Event])
5. Save the ShowsContract.vb file.
From the File menu, select Save ShowsContract.vb.
Task 2: Throw a fault exception
1. Open the Task List window and double-click the comment TODO: Ex2 Place code to validate
event information. This opens the ShowsService.svc.vb file.
2. In the ValidateEvent method, add the following code to throw a fault exception when either the
show details are not supplied, or when the show cannot be found using its ID.
If eventToValidate.ShowDetails Is Nothing Then
'Option 1: Throw a Fault(Of ShowExceptionInfo)
Throw New FaultException(Of ShowExceptionInfo)(
New ShowExceptionInfo With {
.ExceptionInfo = "",
.Message = StringsResource.NullShow
})
End If

Dim id As Integer = eventToValidate.ShowDetails.ShowID

If FindShowByID(id) Is Nothing Then
'Option 1: Throw a Fault(Of ShowExceptionInfo)
Throw New FaultException(Of ShowExceptionInfo)(
New ShowExceptionInfo With {
.ExceptionInfo = "",
.Message = String.Format(StringsResource.ShowNotFound, id)
})
End If
3. Save the ShowsService.svc.vb file.
From the File menu, select Save ShowsService.svc.vb.
Results: After this exercise, you will have decorated several service operations with the FaultContract
attribute, and added the necessary code to the ValidateEvent method to throw a FaultException.
L6-22 Lab 6: Testing and Troubleshooting WCF Services
Exercise 3: Using Error Handlers and Handling Faults
Task 1: Create and attach an error handler
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 Convert a normal Exception to a FaultException. This
opens the ShowsErrorHandler.vb file.
3. In the ProvideFault method, add code to convert a normal exceptionthrown somewhere in your
codeto a FaultException(Of ShowExceptionInfo).
Dim l_faultException As New FaultException(Of ShowExceptionInfo)(
New ShowExceptionInfo() With {
.Message = [error].Message,
.ExceptionInfo = [error].ToString()
})

Dim l_messageFault As MessageFault =
l_faultException.CreateMessageFault()

fault = Message.CreateMessage(
version, l_messageFault, l_faultException.Action)
4. Save the ShowsErrorHandler.vb file.
From the File menu, select Save ShowsErrorHandler.vb.
5. In the Task List window, double-click the comment TODO: Ex3 Decorate the service
implementation with the error handling service behavior. This opens the ShowsService.svc.vb
file.
6. Attach the new error handler by decorating the ShowsAndEventsService class with the
ErrorBehavior attribute, as demonstrated in the following code.
<ErrorBehavior(GetType(ShowsErrorHandler))>
7. Save the ShowsService.svc.vb file.
From the File menu, select Save ShowsService.svc.vb.

Note: The ErrorBehavior attribute is a custom attribute that is implemented in the
Behaviors\ErrorHandlingBehavior.vb file which belongs to the TicketingOffice.Common
project that can be found in the Common solution folder.
Task 2: Throw a standard .NET exception instead of a fault exception
1. Open the Task List window, and double-click the comment TODO: Ex2 Place code to validate
event information. This opens the ShowsService.svc.vb file.
If the comment exists in the Task List window, double-click the comment to open the
ValidateEvent method.
If the comment was removed, open the View menu, select Solution Explorer, and in the
Solution Explorer window, open the Services solution folder, then open the Shows solution
Lab 6: Testing and Troubleshooting WCF Services L6-23
folder, then open the ShowsService project, and then open the ShowsService.svc.vb file, which
is under the ShowsService.svc file. The ValidateEvent method is located at the end of the file
2. In the ValidateEvent method, place both Throw statements in comment. The resulting code should
resemble the following code sample.
If eventToValidate.ShowDetails Is Nothing Then
'
'Option 1: Throw a Fault<ShowExceptionInfo>
'Throw New FaultException(Of ShowExceptionInfo)(
' New ShowExceptionInfo With
' {
' .ExceptionInfo = "",
' .Message = StringsResource.NullShow})
End If

Dim id As Integer = eventToValidate.ShowDetails.ShowID

If FindShowByID(id) Is Nothing Then
'Option 1: Throw a Fault(Of ShowExceptionInfo)
'Throw New FaultException(Of ShowExceptionInfo)(
' New ShowExceptionInfo With {
' .ExceptionInfo = "",
' .Message = String.Format(StringsResource.ShowNotFound, id)
' })
End If
3. Under each throw statement that you have commented, add a standard Throw statement that throws
a ShowException object.
If eventToValidate.ShowDetails Is Nothing Then
'Option 1: Throw a Fault<ShowExceptionInfo>
'Throw New FaultException(Of ShowExceptionInfo)(
' New ShowExceptionInfo With
' {
' .ExceptionInfo = "",
' .Message = StringsResource.NullShow})
'Option 2: Throw a normal exception. The Error handler will
'convert it to a Fault<ShowExceptionInfo>
Throw New ShowException(StringsResource.NullShow)
End If

Dim id As Integer = eventToValidate.ShowDetails.ShowID

If FindShowByID(id) Is Nothing Then
'Option 1: Throw a Fault(Of ShowExceptionInfo)
'Throw New FaultException(Of ShowExceptionInfo)(
' New ShowExceptionInfo With {
' .ExceptionInfo = "",
' .Message = String.Format(StringsResource.ShowNotFound, id)
' })

'Option 2: Throw a normal exception. The Error handler will
'convert it to a Fault(Of ShowExceptionInfo)
Throw New ShowException(String.Format(
StringsResource.ShowNotFound, id))
End If
4. Save the ShowsService.svc.vb file.
From the File menu, select Save ShowsService.svc.vb.
L6-24 Lab 6: Testing and Troubleshooting WCF Services
Task 3: Invoke the service and catch any fault exceptions
1. Open the Task List window, and double-click the comment TODO: Ex3 Call the CreateEvent
operation of the Shows service and catch any fault exceptions. This opens the
Lab6HelperForm.cs file.
2. In the btnFault_Click method event handler, replace the comment with the following code:
Try
ShowsTestHelper.CreateFaultyEvent()
MessageBox.Show("Done")
Catch fault As FaultException(Of ShowExceptionInfo)
MessageBox.Show(fault.Detail.Message, "Show exception",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error)
End Try
3. Save the Lab6HelperForm.vb file.
From the File menu, select Save Lab6HelperForm.vb.
4. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and select Start Without Debugging.
5. Run the Lab_6_Helper project without debugging.
Return to Visual Studio 2010, and from the Solution Explorer window, open the Helpers solution
folder.
Right-click the Lab_6_Helper project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
6. Click the Create faulty event button. After a few seconds, a message containing the error will
appear.
7. Close the Lab_6_Helper window.
8. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Results: After this exercise, you will have created an error handler, attached it to the service, threw
standard .NET exceptions instead of fault exceptions, and caught fault exceptions on the client side.
Exercise 4: Using WCF Message Logging and Tracing
Task 1: Use the WCF Configuration utility to add tracing and message logging
1. Open the SimpleServiceHost project's App.config file in the WCF Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor utility, open the File menu, then select Open, and
then select Config File.
In the Open dialog box, navigate to the D:\LabFiles\Starter\M06\VB\Host\SimpleServiceHost
folder.
Select the App.config file, and click Open.
2. Turn on MessageLogging and Tracing.
Lab 6: Testing and Troubleshooting WCF Services L6-25
In the Configuration tree, click the Diagnostics node.
Turn MessageLogging on by clicking enable MessageLogging.
Turn Tracing on by click enable Tracing.
3. Save the configuration file.
Open the File menu, and then click Save.
4. Close the WCF Service Configuration Editor, and return to Visual Studio 2010.
If a reload confirmation message appears when you return to Visual Studio 2010, click Yes.
Task 2: Cause the service to throw an exception
1. Create an exception by commenting out the TicketingOfficeHallsEntities connection string to the
database in the SimpleServiceHost project's App.config file.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
Locate the connectionStrings element (it should appear after the system.diagnostics element),
and comment out the TicketingOfficeHallsEntities connection string, as shown in the following
XML fragment:
<connectionStrings>
<add name="ApplicationServices" connectionString="Data Source=.\SQLEXPRESS;Initial
Catalog=TicketingOffice;Integrated Security=True;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />

<add name="TicketingOfficeCrmEntities"
connectionString="metadata=res://*/CrmModel.csdl|res://*/CrmModel.ssdl|res://*/CrmModel.
msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeExchangeEntities"
connectionString="metadata=res://*/ExchangeModel.csdl|res://*/ExchangeModel.ssdl|res://*
/ExchangeModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<!--<add name="TicketingOfficeHallsEntities"
connectionString="metadata=res://*/ReservationsModel.csdl|res://*/ReservationsModel.ssdl
|res://*/ReservationsModel.msl;provider=System.Data.SqlClient;provider connection
string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />-->

<add name="TicketingOfficePaymentEntities"
connectionString="metadata=res://*/PaymentModel.csdl|res://*/PaymentModel.ssdl|res://*/P
aymentModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficePricingEntities"
connectionString="metadata=res://*/PricingRulesModel.csdl|res://*/PricingRulesModel.ssdl
|res://*/PricingRulesModel.msl;provider=System.Data.SqlClient;provider connection
string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
L6-26 Lab 6: Testing and Troubleshooting WCF Services
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeShowEntities"
connectionString="metadata=res://*/ShowModel.csdl|res://*/ShowModel.ssdl|res://*/ShowMod
el.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />

<add name="TicketingOfficeOrderEntities"
connectionString="metadata=res://*/OrdersModel.csdl|res://*/OrdersModel.ssdl|res://*/Ord
ersModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data
Source=.\SQLEXPRESS;Initial Catalog=TicketingOffice;Integrated
Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
2. Change the behavior of the service to exclude exception details in faults.
In the App.config file, locate the service behavior named StandardBehavior, which is located at
configuration system.serviceModel behaviors serviceBehaviors.
Change the serviceDebug element, so it will not include exception details in faults, by changing
the includeExceptionDetailInFaults attribute to false.
The resulting behavior configuration should resemble the following XML fragment:
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceDiscovery/>
</behavior>
3. Save the App.config file.
From the File menu, select Save App.config.
4. Run the SimpleServiceHost project without debugging.
Right-click the SimpleServiceHost project, and select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
5. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
6. Add the Reservation service, using the address http://localhost:5003.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5003, and then click OK.
7. Test the FindTheater operation of the IHallStateStateService contract with a theaterID value of -1.
In the My Service Projects tree, open the IHallStateStateService node, and then double-click
the FindTheater operation.
In the Request property page, set the value of the theaterID parameter to -1.
Click Invoke to activate the service, and if a security warning appears, click OK.
Lab 6: Testing and Troubleshooting WCF Services L6-27
8. After the error message displays, close the error window.
In the error window, click the Close button.
9. Close the WCF Test Client utility.
10. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Task 3: Use the SvcTraceViewer.exe utility to inspect the exception
1. Return to Visual Studio 2010, and open the Host solution folder from the Solution Explorer window.
2. Right-click the SimpleServiceHost project, and then select Open Folder in Windows Explorer.
3. Double-click the App_tracelog.svclog file to open it with the Microsoft Service Trace Viewer.
4. Return to the Windows Explorer window, where the log files display, and drag the
App_messages.svclog into the opened Microsoft Service Trace Viewer window.
5. Locate the FindTheater message that in the Activity tab is marked in red.
Click the Activity tab to see the service's activity log.
Scroll down to find the activity labeled Process action
'http://Fabrikam.com/IHallStateService/FindTheater'.
Select the activity, and from the activity's description list, click the red row with the description
Handling an exception.
6. Examine the exception's content that displays in the Formatted tab.


7. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have added tracing and message logging support to your service,
caused the service to throw an exception, and looked at the exception information in the Service Trace
Viewer utility.
L6-28 Lab 6: Testing and Troubleshooting WCF Services
Exercise 5: Supporting Large Messages
Task 1: Clear the database from all the shows with Category = Comedy
1. Run the Lab_6_Helper project without debugging.
Return to Visual Studio 2010, and from the Solution Explorer window, open the Helpers solution
folder.
Right-click the Lab_6_Helper project, and then select Set as StartUp Project.
Open the Debug menu, and then select Start Without Debugging.

2. Click the Clear Comedies button, and when the message box appears, press OK.
Task 2: Create 10 comedies
1. Select the value 10 from the combo box.
2. Click the Create Comedies button, and when the message box appears, press OK.
3. Leave the helper utility running, and return to Visual Studio 2010.
Task 3: Start the Shows service
1. Run the SimpleServiceHost without debugging.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
Task 4: Call the FindShowsByCriteria operation of the Shows service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the Shows service, using the address http://localhost:5007.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address http://localhost:5007, and then click OK.
3. Test the FindShowsByCriteria operation of the IShowsService contract with the Comedy category.
In the My Service Projects tree, open the IShowsService node, and double-click the
FindShowsByCriteria operation.
In the Request property page, set the Category to Comedy.
Lab 6: Testing and Troubleshooting WCF Services L6-29
Click Invoke to activate the service, and if a security warning appears, click OK.
4. Verify that the relevant shows are returned.
Task 5: Create 100 more comedies
1. Return to the Lab_6_Helper window. (Leave the WCF Test Client utility open.)
2. Change the value in the combo box from 10 to 100.
3. Click the Create Comedies button, and when the message box appears, press OK.
Task 6: Call the service again
1. Return to the WCF Test Client utility.
2. Click Invoke to activate the service again, and if a security warning appears, click OK.
3. The service will fail. Read the error message in the exception.


4. Close the error window.
In the error window, click the Close button.
Task 7: Configure the service to support large messages
1. Close the SimpleServiceHost console window, but leave the WCF Test Client running.
Press ENTER to stop the service host, and then press ENTER again to close the SimpleServiceHost
console window.
2. Return to Visual Studio 2010, and from the Solution Explorer window, open the Host solution folder,
and then open the SimpleServiceHost project.
3. In the SimpleServiceHost project, double-click the App.config file to open it.
4. Under configuration system.serviceModel bindings ws2007HttpBinding, locate the
binding named NoSecurity. The binding configuration should look like the following XML fragment:
<binding
name="NoSecurity"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
L6-30 Lab 6: Testing and Troubleshooting WCF Services
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="None"></security>
</binding>
5. Add the maxReceivedMessageSize attribute to the binding configuration, and set it to 200000. The
resulting binding configuration should resemble the following XML fragment:
<binding
name="NoSecurity"
maxReceivedMessageSize="200000"
transactionFlow="true"
openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="None"></security>
</binding>
6. Save the App.config file.
From the File menu, click Save App.config.
7. Run the SimpleServiceHost without debugging.
Open the Debug menu, and select Start Without Debugging.
Task 8: Change the configuration used by the WCF Test Client
1. Return to the WCF Test Client utility.
2. In the My Service Projects tree, right-click the Config File node, and then select Edit with
SvcConfigEditor.

3. In the Service Configuration Editor, select the WS2007HttpBinding_IShowsService binding
configuration.
In the Configuration tree, open the Bindings node.
Click the WS2007HttpBinding_IShowsService (wsHttpBinding) binding configuration.

4. In the Binding tab, change the MaxReceivedMessageSize from 65536 to 200000.
Lab 6: Testing and Troubleshooting WCF Services L6-31

5. Save the configuration, and close the Service Configuration Editor.
Open the File menu, and then click Save.
Open the File menu, and then click Exit.
6. Return to the WCF Test Client utility. When a message box asking for reload will displays, click Yes.
7. Test the FindShowsByCriteria operation of the IShowsService contract with the Comedy category.
In the My Service Projects tree, open the IShowsService node, and then double-click the
FindShowsByCriteria operation.
In the Request property page, set the Category to Comedy.
Click Invoke to activate the service, and if a security warning appears, click OK.
8. Make sure the shows are displayed correctly.
9. Close the WCF Test Client utility.
10. Return to the Lab_6_Helper window, click the Clear Comedies button, and when a message box
appears, press OK.
11. Close the Lab_6_Helper window.
12. Close the SimpleServiceHost console window.
Press ENTER to stop the service host, and then press ENTER again to close the console window.
Results: After this exercise, you will have called a service operation that returned a fault due to a large
message being returned to the client. In addition, you will have configured both the service and the
client to support large messages, and successfully called the operation afterwards.



L6-32 Lab 6: Testing and Troubleshooting WCF Services



Lab 7: Implementing WCF Security L7-1
Module 7: Security
Lab 7: Implementing WCF Security
Section 1: Visual C#
Exercise 1: Implementing Security Policy
Task 1: Prepare the IIS for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M07\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M07\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it and then close the
Windows Explorer window.
Task 2: Examine how to configure IIS to support HTTPS
1. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
2. Open the Bindings setting for the Default Web Site.
From the Connections tree (left pane), select 10263A-SVR1 (10263A-SVR1\Administrator),
then select Sites, and then select Default Web Site.
Click the Bindings option from the Actions pane (right pane).
3. In the Site Bindings dialog box, verify that https is included in the bindings list.
4. Verify that the https binding uses the localhost certificate.
Select the https binding from the bindings list, and then click Edit.
In the Edit Site Binding dialog box, verify that the SSL Certificate is set to localhost.
Click OK to close the dialog box.
5. Close the Internet Information Services (IIS) Manager.
In the Site Bindings dialog box, click the Close button.
Close the IIS Manager window.
Task 3: Configure the CRM service to use transport security with no other user
credentials
1. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M07\CS folder.
In the File menu, select Open, and then select Project/Solution.
L7-2 Lab 7: Implementing WCF Security

In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M07\CS folder, click the
TicketingOffice.sln file, and then click Open.
3. Build the solution.
From the Build menu, select Build Solution.
4. Locate the CRMService project under the Services\Crm solution folder, and open the web.config
file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
From the Crm solution folder, open the CrmService, and then open the web.config file.
5. In the web.config file, locate the bindings XML element.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the bindings XML element under it.
6. In the bindings XML element, locate the XML element for basicHttpBinding, and add the following
binding configurations inside it:
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
7. Locate the customer relationship management (CRM) service configuration in the services XML
element of the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the services XML element under it.
In the services XML element, locate the service XML element that has the name attribute with a
value of TicketingOffice.CrmService.CustomerRelationsService.
8. Add an endpoint with the PrivateCrm address, basicHttpBinding, and
TicketingOffice.CrmService.Contracts.IPrivateCrm contract. Set the binding configuration to use
the TransportSecurity binding configuration that you just defined. The resulting endpoint
configuration should look as follows:
<endpoint address="PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
Task 4: Configure the CRM service to use message security and client credentials
1. In the web.config file, locate the bindings XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then open the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the bindings XML element under it.

Lab 7: Implementing WCF Security L7-3
2. In the bindings XML element, locate the XML element for ws2007HttpBinding, and then add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
3. Locate the CRM service configuration in the services XML element of the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the services XML element under it.
In the services XML element, locate the service XML element that has the name attribute with a
value of TicketingOffice.CrmService.CustomerRelationsService.
4. In the CRM service configuration, change the InternalCrm endpoint to use the UNMessageSecurity
binding configuration.
In the CRM service configuration, locate the endpoint XML element that has the address
attribute set to InternalCrm.
Replace the endpoint configuration that you have found, with the following configuration:
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
5. In the CRM service configuration, change the PartnerCrm endpoint to use the CertMessageSecurity
binding configuration.
In the CRM service configuration, locate the endpoint XML element that has the address attribute
set to PartnerCrm.
Replace the endpoint configuration that you have found with the following configuration:
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
6. In the web.config file, locate the behaviors XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then double-click the web.config file
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
7. In the behaviors XML element, locate the service behavior named StandardBehavior.
L7-4 Lab 7: Implementing WCF Security

In the behaviors XML element, locate the serviceBehaviors XML element.
In the serviceBehaviors XML element, locate the behavior XML element that has a name
attribute set to the value of StandardBehavior.
8. Add the following XML credentials to the behavior that you have found in the previous step.
<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>
Task 5: Configure identity and roles management using the ASP.NET Membership and
Roles providers
1. In the web.config file, locate the behaviors XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then double-click the web.config file
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
2. In the behaviors XML element, locate the service behavior named StandardBehavior.
In the behaviors XML element, locate the serviceBehaviors XML element.
In the serviceBehaviors XML element, locate the behavior XML element that has a name
attribute set to the value of StandardBehavior.
3. Add the following role management settings XML to the behavior that you found in the previous
step.
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
4. In the behavior configuration, locate the serviceCredentials XML element, and add to it the
following identity management XML.
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>
5. After adding the above XML fragments, the service behavior should resemble the following XML
fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>

<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>

<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
Lab 7: Implementing WCF Security L7-5
x509FindType="FindBySubjectName">
</serviceCertificate>

<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>

<serviceDiscovery/>
</behavior>
6. Save the web.config file.
From the File menu, select Save web.config.
Task 6: Authorize the access to the CRM service using Role Based Security
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the UpdateCustomer method with the
PrincipalPermission attribute. This opens the CrmService.svc.cs file.
3. Decorate the UpdateCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public void UpdateCustomer(Contracts.Customer newCustomer)

4. Double-click the comment TODO: Ex1 Decorate the GetCustomerOrders method with the
PrincipalPermission attribute.
5. Decorate the GetCustomerOrders method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Order[] GetCustomerOrders(
Guid customerID, DateTime? fromDate, DateTime? toDate)

6. Double-click the comment TODO: Ex1 Decorate the FindCustomersByCriteria method with the
PrincipalPermission attribute.
7. Decorate the FindCustomersByCriteria method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer[] FindCustomersByCriteria(
CustomerCriteria criteria)

8. Double-click the comment TODO: Ex1 Decorate the FindCustomerByOrder method with the
PrincipalPermission attribute.
9. Decorate the FindCustomerByOrder method with the PrincipalPermission attribute as follows:
L7-6 Lab 7: Implementing WCF Security

[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer FindCustomerByOrder(Guid orderID)

10. Double-click the comment TODO: Ex1 Decorate the FindBestCustomers method with the
PrincipalPermission attribute.
11. Decorate the FindBestCustomers method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Contracts.Customer[] FindBestCustomers(int numberOfCustomers)

12. Double-click the comment TODO: Ex1 Decorate the DeleteCustomer method with the
PrincipalPermission attribute.
13. Decorate the DeleteCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public void DeleteCustomer(Guid customerID)

14. Double-click the comment TODO: Ex1 Decorate the CreateCustomer method with the
PrincipalPermission attribute.
15. Decorate the CreateCustomer method with the PrincipalPermission attribute as follows:
[PrincipalPermission(SecurityAction.Demand, Role = "Managers")]
[PrincipalPermission(SecurityAction.Demand, Role = "Employees")]
public Guid CreateCustomer(Contracts.Customer newCustomer)

Task 7: Use imperative authorization
1. Double-click the comment TODO: Ex1 Add imperative authorization to the DeleteCustomer
method to locate the DeleteCustomer method.
2. In the DeleteCustomer method, replace the TODO comment with the following code that checks the
authorization for the Manager role.
if (Thread.CurrentPrincipal.IsInRole("Managers"))
Manager.DeleteCustomer(customerID);
else
throw new CrmException(StringsResource.UnauthorizedOperation);
Task 8: Log the name of the Identity using the all the CRM methods
1. Double-click the comment TODO: Ex1 Add identity logging to locate the LogUser method.
2. Add the following code to the method:
if ((ServiceSecurityContext.Current != null) &&
(ServiceSecurityContext.Current.PrimaryIdentity != null))
{
StackFrame stackFrame = new StackFrame(1);
string methodName = "CustomerRelationsService." +
stackFrame.GetMethod().Name; // Which method called me

LoggingManager.Logger.Log(
Lab 7: Implementing WCF Security L7-7
LoggingCategory.Info,
string.Format(
StringsResource.MethodCalledBy,
methodName,
ServiceSecurityContext.Current.PrimaryIdentity.Name));
}
3. Save the CrmService.svc.cs file.
From the File menu, select Save CrmService.svc.cs.
Results: After this exercise, you will have created endpoints for the CRM service that use transport
security and message security, and require client credentialssuch as username and certificate.
In addition, you will have added authorization checksboth imperative and declarativeto the CRM
service, and will have configured the service to use the Microsoft ASP.NET Membership and Roles
provider.
Exercise 2: Configuring Client
Task 1: Add an endpoint behavior to determine the location of the certificate to send
1. Open the App.config file of the TicketingOffice.UI project.
In the Solution Explorer window, open the Client solution folder, open the TicketingOffice.UI
project, and then double-click the App.config file.
2. In the App.config file, locate the behaviors XML element.
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
3. Add the following XML fragment inside the behaviors XML element.
<endpointBehaviors>
<behavior name="CredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>

Note: This CRM service uses a self-issued certificate whose issuer does not belong to a chain
trust. Therefore, you must change the way the service's certificate is validated from its default
value of ChainTrust, to the value of PeerOrChainTrust.
Task 2: Add a binding configuration that will match the security configuration
requirements of the CRM service
1. In the App.config file, locate the bindings XML element.
L7-8 Lab 7: Implementing WCF Security

If the App.config file is closed, open the Client solution folder, then open the
TicketingOffice.UI project, and then double-click the App.config file
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the bindings XML element under it.
2. Add the following binding configuration to the bindings XML element.
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
</basicHttpBinding>
3. In the bindings XML element, locate the XML element for ws2007HttpBinding, and add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
Task 3: Add client endpoints to consume the CrmService
1. Locate the client XML element in the App.config file.
If the App.config file is closed, open the Client solution folder, then open the
TicketingOffice.UI project, and then double-click the App.config file.
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the client XML element under it.
2. Add the following endpoints to the client XML element:
<endpoint
name="InternalCrm"
address="http://localhost/CrmService/CrmService.svc/InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PartnerCrm"
address="http://localhost/CrmService/CrmService.svc/PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PrivateCRM"
address="https://localhost/CrmService/CrmService.svc/PrivateCrm"
Lab 7: Implementing WCF Security L7-9
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm" />
3. Save the App.config file.
From the File menu, select Save App.config.
Task 4: Add client proxy initialization with username authentication
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add proxy creation and client authentication code. This
opens the InternalCRMWindow.xaml.cs file in the TicketingOffice.UI project.
3. Delete the content of the CreateCrmServiceProxy method.
4. Place the following code inside the method:
ChannelFactory<ICrmService> factory = new ChannelFactory<ICrmService>
("InternalCrm");
factory.Credentials.UserName.UserName = "Admin";
factory.Credentials.UserName.Password = "Pa$$w0rd";
return factory.CreateChannel();

Note: In real-world applications, avoid hard-coding user credentials into your code.
5. Save the InternalCRMWindow.xaml.cs file.
From the File menu, select Save InternalCRMWindow.xaml.cs.
Results: After this exercise, you will have configured your client application to consume the CrmService
using transport and message security, and you will have configured the client to send a specific
certificate and client authorization information to the service.
Exercise 3: Verifying Security
Task 1: Configure the CRM Service for message logging
1. Open the CrmService project's web.config file in the Microsoft Windows Communication
Foundation (WCF) Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor tool, open the File menu, select Open, and then select
Config File.
In the Open dialog box, navigate to the
D:\LabFiles\Starter\M07\CS\Services\Crm\CrmService folder.
Select the web.config file, and then click Open.
2. Turn on MessageLogging and Tracing.
In the Configuration tree, click the Diagnostics node.
Turn the MessageLogging on by clicking enable MessageLogging.
L7-10 Lab 7: Implementing WCF Security

Turn the Tracing on by click enable Tracing.
3. Configure Message Logging to log entire messages, and to log entire messages at the service level.
In the Configuration tree, open the Diagnostics node, and select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True, and set
LogMessagesAtServiceLevel to True. Leave all other settings as they are.
4. Save the configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
If a reload confirmation message appears when returning to Visual Studio 2010, click Yes.
Task 2: Deploy the service
1. Create a deployment package for the CrmService project.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
Right-click the CrmService project, and then select Build Deployment Package.
2. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import the package that you have created to the Default Web Site, and name it CrmService.
From the Connections tree (left pane), select 10263A-SVR1 (10263A-SVR1\Administrator),
then select Sites, and then select Default Web Site.
In the Actions pane (right pane), select Import Application.
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M07\CS\Services\Crm\CrmService\obj\Debug\Package\CrmService.zip
In the Import Application Package wizard, in the Select the Contents of the Package step,
click Next.
In the Import Application Package wizard, in the Enter Application Package Information
step, set the Application Path to CrmService, and then click Next.
If a message appears that asks whether to run the application in the default Microsoft .NET 4.0
application pool, click Yes.
In the Import Application Package wizard, in the Installation Progress and Summary step,
wait for the process to complete, and then click Finish.
4. Close the IIS Manager, and return to Visual Studio 2010.
Task 3: Consume the secured service from a client application
1. Set the TicketingOffice.UI project as the startup project.
In the Solution Explorer window, open the Client solution folder.
Right-click the TicketingOffice.UI project, and then select Set as StartUp Project.
2. Run the TicketingOffice.UI project.
Right-click the TicketingOffice.UI project, select Debug, and then select Start new instance.
Lab 7: Implementing WCF Security L7-11
3. In the client's main window, click the Show customer details (Internal) button.
4. In the InternalCRMWindow window, click the New button.
5. Enter new customer informationfirst name and last name are mandatory.
6. Click the Save button.
7. Click OK to close the operation completion message box.
8. Close the client application.
Close the InternalCRMWindow window.
Close the main window.
Task 4: Examine the message logging output
1. Open the Web_messages.svclog from the CrmService project folder.
Return to Visual Studio 2010, and open the Services solution folder from the Solution Explorer
window.
In the Services solution folder, open the Crm solution folder, right-click the CrmService project,
and then select Open Folder in Windows Explorer.
Double-click the Web_messages.svclog file to open it with the Microsoft Service Trace Viewer.
If an Error Report window opens, click OK. (This window displays because the file is currently
opened for writing by the CRM service.)
2. Click the Message tab on the left pane, and review the list of messages that were sent. You can see
the security negotiation that occurred before the business message was sent.

3. In the Message tab, locate the CreateCustomer message.
Click the Message tab to view the service actions log.
Scroll down to find the action labeled 'http://Fabrikam.com/ICrmService/CreateCustomer'.
Select the action, and in the action's description, click the XML tab to see the message that was
sent to the service. Notice that the data is encrypted. (Scroll to the end of the XML to view the
cipher value.)
L7-12 Lab 7: Implementing WCF Security


4. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have configured the CRM service for message logging. In addition,
you will have deployed the service in IIS, run the client application to test the service, and reviewed the
service message logs to see how messages appear when using message security.
Lab 7: Implementing WCF Security L7-13
Module 7: Security
Lab 7: Implementing WCF Security
Section 2: Visual Basic
Exercise 1: Implementing Security Policy
Task 1: Prepare the IIS for the lab
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M07\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and navigate to the LabFiles\Starter\M07\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it and then close the
Windows Explorer window.
Task 2: Examine how to configure IIS to support HTTPS
1. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
2. Open the Bindings setting for the Default Web Site.
From the Connections tree (left pane), select 10263A-SVR1 (10263A-SVR1\Administrator),
then select Sites, and then select Default Web Site.
Click the Bindings option from the Actions pane (right pane).
3. In the Site Bindings dialog box, verify that https is included in the bindings list.
4. Verify that the https binding uses the localhost certificate.
Select the https binding from the bindings list, and then click Edit.
In the Edit Site Binding dialog box, verify that the SSL Certificate is set to localhost.
Click OK to close the dialog box.
5. Close the Internet Information Services (IIS) Manager.
In the Site Bindings dialog box, click the Close button.
Close the IIS Manager window.
Task 3: Configure the CRM service to use transport security with no other user
credentials
1. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
2. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M07\VB folder.
In the File menu, select Open, and then select Project/Solution.
L7-14 Lab 7: Implementing WCF Security

In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M07\VB folder, click the
TicketingOffice.sln file, and then click Open.
3. Build the solution.
From the Build menu, select Build Solution.
4. Locate the CRMService project under the Services\Crm solution folder, and open the web.config
file.
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
From the Crm solution folder, open the CrmService, and then open the web.config file.
5. In the web.config file, locate the bindings XML element.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the bindings XML element under it.
6. In the bindings XML element, locate the XML element for basicHttpBinding, and add the following
binding configurations inside it:
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
7. Locate the customer relationship management (CRM) service configuration in the services XML
element of the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the services XML element under it.
In the services XML element, locate the service XML element that has the name attribute with a
value of TicketingOffice.CrmService.CustomerRelationsService.
8. Add an endpoint with the PrivateCrm address, basicHttpBinding, and
TicketingOffice.CrmService.Contracts.IPrivateCrm contract. Set the binding configuration to use
the TransportSecurity binding configuration that you just defined. The resulting endpoint
configuration should look as follows:
<endpoint address="PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm">
</endpoint>
Task 4: Configure the CRM service to use message security and client credentials
1. In the web.config file, locate the bindings XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then open the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel
XML element, and then locate the bindings XML element under it.
2. In the bindings XML element, locate the XML element for ws2007HttpBinding, and then add the
following binding configurations inside it:
Lab 7: Implementing WCF Security L7-15
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
3. Locate the CRM service configuration in the services XML element of the web.config file.
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the services XML element under it.
In the services XML element, locate the service XML element that has the name attribute with a
value of TicketingOffice.CrmService.CustomerRelationsService.
4. In the CRM service configuration, change the InternalCrm endpoint to use the UNMessageSecurity
binding configuration.
In the CRM service configuration, locate the endpoint XML element that has the address
attribute set to InternalCrm.
Replace the endpoint configuration that you have found, with the following configuration:
<endpoint
address="InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService">
</endpoint>
5. In the CRM service configuration, change the PartnerCrm endpoint to use the CertMessageSecurity
binding configuration.
In the CRM service configuration, locate the endpoint XML element that has the address attribute
set to PartnerCrm.
Replace the endpoint configuration that you have found with the following configuration:
<endpoint
address="PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase">
</endpoint>
6. In the web.config file, locate the behaviors XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then double-click the web.config file
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
7. In the behaviors XML element, locate the service behavior named StandardBehavior.
L7-16 Lab 7: Implementing WCF Security

In the behaviors XML element, locate the serviceBehaviors XML element.
In the serviceBehaviors XML element, locate the behavior XML element that has a name
attribute set to the value of StandardBehavior.
8. Add the following XML credentials to the behavior that you have found in the previous step.
<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName">
</serviceCertificate>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>
Task 5: Configure identity and roles management using the ASP.NET Membership and
Roles providers
1. In the web.config file, locate the behaviors XML element.
If the web.config file is closed, open the Services solution folder, then open the Crm solution
folder, then open the CrmService project, and then double-click the web.config file
In the web.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
2. In the behaviors XML element, locate the service behavior named StandardBehavior.
In the behaviors XML element, locate the serviceBehaviors XML element.
In the serviceBehaviors XML element, locate the behavior XML element that has a name
attribute set to the value of StandardBehavior.
3. Add the following role management settings XML to the behavior that you found in the previous
step.
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
4. In the behavior configuration, locate the serviceCredentials XML element, and add to it the
following identity management XML.
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>
5. After adding the above XML fragments, the service behavior should resemble the following XML
fragment.
<behavior name="StandardBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>

<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>

<serviceCredentials>
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
Lab 7: Implementing WCF Security L7-17
x509FindType="FindBySubjectName">
</serviceCertificate>

<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"/>

<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
</serviceCredentials>

<serviceDiscovery/>
</behavior>
6. Save the web.config file.
From the File menu, select Save web.config.
Task 6: Authorize the access to the CRM service using Role Based Security
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the UpdateCustomer method with the
PrincipalPermission attribute. This opens the CrmService.svc.vb file.
3. Decorate the UpdateCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Sub UpdateCustomer(ByVal newCustomer As Contracts.Customer) _
Implements ICrmService.UpdateCustomer

4. Double-click the comment TODO: Ex1 Decorate the GetCustomerOrders method with the
PrincipalPermission attribute.
5. Decorate the GetCustomerOrders method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function GetCustomerOrders(ByVal customerID As Guid, _
ByVal fromDate? As Date, ByVal toDate? As Date) _
As Order() Implements ICrmService.GetCustomerOrders

6. Double-click the comment TODO: Ex1 Decorate the FindCustomersByCriteria method with the
PrincipalPermission attribute.
7. Decorate the FindCustomersByCriteria method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindCustomersByCriteria( _
ByVal criteria As CustomerCriteria) As Contracts.Customer() _
Implements ICrmService.FindCustomersByCriteria

8. Double-click the comment TODO: Ex1 Decorate the FindCustomerByOrder method with the
PrincipalPermission attribute.
L7-18 Lab 7: Implementing WCF Security

9. Decorate the FindCustomerByOrder method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindCustomerByOrder(ByVal orderID As Guid) _
As Contracts.Customer Implements ICrmService.FindCustomerByOrder

10. Double-click the comment TODO: Ex1 Decorate the FindBestCustomers method with the
PrincipalPermission attribute.
11. Decorate the FindBestCustomers method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function FindBestCustomers(ByVal numberOfCustomers As Integer) _
As Contracts.Customer() Implements ICrmService.FindBestCustomers

12. Double-click the comment TODO: Ex1 Decorate the DeleteCustomer method with the
PrincipalPermission attribute.
13. Decorate the DeleteCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Sub DeleteCustomer(ByVal customerID As Guid) _
Implements ICrmService.DeleteCustomer

14. Double-click the comment TODO: Ex1 Decorate the CreateCustomer method with the
PrincipalPermission attribute.
15. Decorate the CreateCustomer method with the PrincipalPermission attribute as follows:
<PrincipalPermission(SecurityAction.Demand, Role := "Managers"),
PrincipalPermission(SecurityAction.Demand, Role := "Employees")>
Public Function CreateCustomer(
ByVal newCustomer As Contracts.Customer) As Guid _
Implements ICrmService.CreateCustomer

Task 7: Use imperative authorization
1. Double-click the comment TODO: Ex1 Add imperative authorization to the DeleteCustomer
method to locate the DeleteCustomer method.
2. In the DeleteCustomer method, replace the TODO comment with the following code that checks the
authorization for the Manager role.
If Thread.CurrentPrincipal.IsInRole("Managers") Then
Manager.DeleteCustomer(customerID)
Else
Throw New CrmException(StringsResource.UnauthorizedOperation)
End If
Task 8: Log the name of the Identity using the all the CRM methods
1. Double-click the comment TODO: Ex1 Add identity logging to locate the LogUser method.
2. Add the following code to the method:
Lab 7: Implementing WCF Security L7-19
If (ServiceSecurityContext.Current IsNot Nothing) AndAlso
(ServiceSecurityContext.Current.PrimaryIdentity IsNot Nothing) Then
Dim l_stackFrame As New StackFrame(1)
Dim methodName As String = "CustomerRelationsService." &
l_stackFrame.GetMethod().Name ' Which method called me?

LoggingManager.Logger.Log(
LoggingCategory.Info,
String.Format(
StringsResource.MethodCalledBy,
methodName,
ServiceSecurityContext.Current.PrimaryIdentity.Name))
End If
3. Save the CrmService.svc.vb file.
From the File menu, select Save CrmService.svc.vb.
Results: After this exercise, you will have created endpoints for the CRM service that use transport
security and message security, and require client credentialssuch as username and certificate.
In addition, you will have added authorization checksboth imperative and declarativeto the CRM
service, and will have configured the service to use the Microsoft ASP.NET Membership and Roles
provider.
Exercise 2: Configuring Client
Task 1: Add an endpoint behavior to determine the location of the certificate to send
1. Open the App.config file of the TicketingOffice.UI project.
In the Solution Explorer window, open the Client solution folder, open the TicketingOffice.UI
project, and then double-click the App.config file.
2. In the App.config file, locate the behaviors XML element.
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the behaviors XML element under it.
3. Add the following XML fragment inside the behaviors XML element.
<endpointBehaviors>
<behavior name="CredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>

Note: This CRM service uses a self-issued certificate whose issuer does not belong to a chain
trust. Therefore, you must change the way the service's certificate is validated from its default
value of ChainTrust, to the value of PeerOrChainTrust.
L7-20 Lab 7: Implementing WCF Security

Task 2: Add a binding configuration that will match the security configuration
requirements of the CRM service
1. In the App.config file, locate the bindings XML element.
If the App.config file is closed, open the Client solution folder, then open the
TicketingOffice.UI project, and then double-click the App.config file
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the bindings XML element under it.
2. Add the following binding configuration to the bindings XML element.
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" ></transport>
</security>
</binding>
</basicHttpBinding>
3. In the bindings XML element, locate the XML element for ws2007HttpBinding, and add the
following binding configurations inside it:
<binding name="UNMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="true"/>
</security>
</binding>
<binding name="CertMessageSecurity" transactionFlow="true">
<security mode="Message">
<message clientCredentialType="Certificate"
establishSecurityContext="true"/>
</security>
</binding>
Task 3: Add client endpoints to consume the CrmService
1. Locate the client XML element in the App.config file.
If the App.config file is closed, open the Client solution folder, then open the
TicketingOffice.UI project, and then double-click the App.config file.
In the App.config file, under the configuration XML element, locate the system.serviceModel,
and then locate the client XML element under it.
2. Add the following endpoints to the client XML element:
<endpoint
name="InternalCrm"
address="http://localhost/CrmService/CrmService.svc/InternalCrm"
binding="ws2007HttpBinding"
bindingConfiguration="UNMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmService"
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PartnerCrm"
address="http://localhost/CrmService/CrmService.svc/PartnerCrm"
binding="ws2007HttpBinding"
bindingConfiguration="CertMessageSecurity"
contract="TicketingOffice.CrmService.Contracts.ICrmBase"
Lab 7: Implementing WCF Security L7-21
behaviorConfiguration="CredentialsBehavior"/>

<endpoint
name="PrivateCRM"
address="https://localhost/CrmService/CrmService.svc/PrivateCrm"
binding="basicHttpBinding"
bindingConfiguration="TransportSecurity"
contract="TicketingOffice.CrmService.Contracts.IPrivateCrm" />
3. Save the App.config file.
From the File menu, select Save App.config.
Task 4: Add client proxy initialization with username authentication
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add proxy creation and client authentication code. This
opens the InternalCRMWindow.xaml.vb file in the TicketingOffice.UI project.
3. Delete the content of the CreateCrmServiceProxy method.
4. Place the following code inside the method:
Dim factory As New ChannelFactory(Of ICrmService)("InternalCrm")
factory.Credentials.UserName.UserName = "Admin"
factory.Credentials.UserName.Password = "Pa$$w0rd"
Return factory.CreateChannel()

Note: In real-world applications, avoid hard-coding user credentials into your code.
5. Save the InternalCRMWindow.xaml.vb file.
From the File menu, select Save InternalCRMWindow.xaml.vb.
Results: After this exercise, you will have configured your client application to consume the CrmService
using transport and message security, and you will have configured the client to send a specific
certificate and client authorization information to the service.
Exercise 3: Verifying Security
Task 1: Configure the CRM Service for message logging
1. Open the CrmService project's web.config file in the Microsoft Windows Communication
Foundation (WCF) Service Configuration Editor.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor tool, open the File menu, select Open, and then select
Config File.
In the Open dialog box, navigate to the
D:\LabFiles\Starter\M07\VB\Services\Crm\CrmService folder.
Select the web.config file, and then click Open.
2. Turn on MessageLogging and Tracing.
L7-22 Lab 7: Implementing WCF Security

In the Configuration tree, click the Diagnostics node.
Turn the MessageLogging on by clicking enable MessageLogging.
Turn the Tracing on by click enable Tracing.
3. Configure Message Logging to log entire messages, and to log entire messages at the service level.
In the Configuration tree, open the Diagnostics node, and select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True, and set
LogMessagesAtServiceLevel to True. Leave all other settings as they are.
4. Save the configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
If a reload confirmation message appears when returning to Visual Studio 2010, click Yes.
Task 2: Deploy the service
1. Create a deployment package for the CrmService project.
In the Solution Explorer window, open the Services solution folder, and then open the Crm
solution folder.
Right-click the CrmService project, and then select Build Deployment Package.
2. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import the package that you have created to the Default Web Site, and name it CrmService.
From the Connections tree (left pane), select 10263A-SVR1 (10263A-SVR1\Administrator),
then select Sites, and then select Default Web Site.
In the Actions pane (right pane), select Import Application.
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M07\VB\Services\Crm\CrmService\obj\Debug\Package\CrmService.zip
In the Import Application Package wizard, in the Select the Contents of the Package step,
click Next.
In the Import Application Package wizard, in the Enter Application Package Information
step, set the Application Path to CrmService, and then click Next.
If a message appears that asks whether to run the application in the default Microsoft .NET 4.0
application pool, click Yes.
In the Import Application Package wizard, in the Installation Progress and Summary step,
wait for the process to complete, and then click Finish.
4. Close the IIS Manager, and return to Visual Studio 2010.
Task 3: Consume the secured service from a client application
1. Set the TicketingOffice.UI project as the startup project.
In the Solution Explorer window, open the Client solution folder.
Right-click the TicketingOffice.UI project, and then select Set as StartUp Project.
Lab 7: Implementing WCF Security L7-23
2. Run the TicketingOffice.UI project.
Right-click the TicketingOffice.UI project, select Debug, and then select Start new instance.

3. In the client's main window, click the Show customer details (Internal) button.
4. In the InternalCRMWindow window, click the New button.
5. Enter new customer informationfirst name and last name are mandatory.
6. Click the Save button.
7. Click OK to close the operation completion message box.
8. Close the client application.
Close the InternalCRMWindow window.
Close the main window.
Task 4: Examine the message logging output
1. Open the Web_messages.svclog from the CrmService project folder.
Return to Visual Studio 2010, and open the Services solution folder from the Solution Explorer
window.
In the Services solution folder, open the Crm solution folder, right-click the CrmService project,
and then select Open Folder in Windows Explorer.
Double-click the Web_messages.svclog file to open it with the Microsoft Service Trace Viewer.
If an Error Report window opens, click OK. (This window displays because the file is currently
opened for writing by the CRM service.)
2. Click the Message tab on the left pane, and review the list of messages that were sent. You can see
the security negotiation that occurred before the business message was sent.


3. In the Message tab, locate the CreateCustomer message.
Click the Message tab to view the service actions log.
Scroll down to find the action labeled 'http://Fabrikam.com/ICrmService/CreateCustomer'.
Select the action, and in the action's description, click the XML tab to see the message that was
sent to the service. Notice that the data is encrypted. (Scroll to the end of the XML to view the
cipher value.)
L7-24 Lab 7: Implementing WCF Security



4. Close the Microsoft Service Trace Viewer.
Results: After this exercise, you will have configured the CRM service for message logging. In addition,
you will have deployed the service in IIS, run the client application to test the service, and reviewed the
service message logs to see how messages appear when using message security.


Lab 8: Advanced Topics L8-1
Module 8: Introduction to Advanced Microsoft Windows
Communication Foundation Topics
Lab 8: Advanced Topics
Section 1: Visual C#
Exercise 1: Using Message Inspectors and Behaviors
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M08\CS folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and then navigate to the LabFiles\Starter\M08\CS folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual
Studio 2010.

5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M08\CS folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M08\CS folder, click the
TicketingOffice.sln file, and then click Open.
Task 2: Add the new bridge and message forwarder contracts
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Add code to the IBridge interface which handles all
incoming messages. This opens the TicketingServiceContracts.cs file.
3. Add the following code to the interface IBridge.
[OperationContract(Action="*", ReplyAction="*")]
Message ProcessMessage(Message message);
4. Double-click the comment TODO: Ex1 Add code to the IBridgeCallBack interface which
handles all incoming messages. This locates the IBridgeCallback interface.
5. Add the following code to the interface IBridgeCallBack.
[OperationContract(IsOneWay=true, Action="*")]
void ProcessResult(Message message);

L8-2 Lab 8: Advanced Topics

6. Double-click the comment TODO: Ex1 Add code to the IBridgeOneWayForwarder interface
which handles all incoming messages to locate the IBridgeOneWayForwarder interface.
7. Add the following code to the interface IBridgeOneWayForwarder.
[OperationContract(IsOneWay=true, Action="*")]
void ProcessMessage(Message message);
8. Save the TicketingServiceContracts.cs file.
From the File menu, select Save TicketingServiceContracts.cs.
Task 3: Write the implementation of the HTTP Bridge contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HttpBridge ProcessMessage method.
This opens the HttpBridgeService.svc.cs file.
3. Replace the content of the try block in the ProcessMessage method in class HttpBridge, with the
following code:
// Create a proxy to QueuedTicketingGeneralService
prox = QueuedTicketingGeneralProxyFactory.GetProxy(false);

AutoResetEvent arrived = new AutoResetEvent(false);
// Create a MessagePackage with a wait handle to wait on
//until a response arrives (on another channel)
MessagePackage pack = new MessagePackage()
{MessageArrived = arrived };
MessageCache.Current.SetMessagePack(callId, pack);

//Put the callID inside a header
var header = new MessageHeader<Guid>(callId);
var headerBase = header.GetUntypedHeader(
"CallID", "http://Fabrikam.com");

// Write the header inside the message received from the client.
IncommingMessage.Headers.Add(headerBase);

//Send the message (the original message + the new header)
//to the ticketing service (One-Way)
//Call the ticketing service via MSMQ channel on another thread.
Action<IBridgeOneWayForwarder> del = (
p => p.ProcessMessage(IncommingMessage));
del.BeginInvoke(prox, null, null);

//Wait until result arrives
arrived.WaitOne();

// Clone the message before sending it back
result = MessageCache.Current.GetResponse(callId).Clone();
// Clear the callID header so it will not arrive back to the client.
result.Headers.RemoveAll("CallID", "http://Fabrikam.com");
// Clear the message cache
MessageCache.Current.ClearMessagePack(callId);
return result;
4. Save the HttpBridgeService.svc.cs file.
Lab 8: Advanced Topics L8-3
From the File menu, select Save HttpBridgeService.svc.cs.
Task 4: Create a message inspector
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultMessageInspector
AfterReceiveRequest Method. This opens the MessageInspectors.cs file.
3. Replace the content of AfterReceiveRequest method in class
HandleBridgeResultMessageInspector, with the following code:
MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
if (request.Headers.FindHeader("CallID", "http://Fabrikam.com") > 0)
{
var callId = request.Headers.GetHeader<Guid>
("CallID", "http://Fabrikam.com");
var MessageResultPackage =
MessageCache.Current.GetMessagePack(callId);
if (MessageResultPackage != null)
{
//Save the message in the appropriate ResultPackage.
//The message will be forwarded to the client.
MessageResultPackage.Response = buffer;

//Notify a message has arrived.
//When converting Request Response to one way the bridge
//waits on this handle.
MessageResultPackage.MessageArrived.Set();
}
}
return null;
4. Save the MessageInspectors.cs file.
From the File menu, select Save Behaviors\MessageInspectors.cs.
Task 5: Create a custom behavior as an attribute
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultAttribute
ApplyDispatchBehavior method. This opens the ServiceBehaviors.cs file.
3. Add the following code to ApplyDispatchBehavior method:
foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
{
epDisp.DispatchRuntime.MessageInspectors.Add(
new HandleBridgeResultMessageInspector());
}
}
4. Save the ServiceBehaviors.cs file.
L8-4 Lab 8: Advanced Topics

From the File menu, select Save Behaviors\ServiceBehaviors.cs.
Task 6: Use the custom behavior attribute
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the HttpBridgeCallBack class with the
HandleBridgeResult attribute. This opens the HttpBridgeCallBack.svc.cs file.
3. Decorate the HttpBridgeCallBack class with the HandleBridgeResult attribute. The resulting class
declaration should resemble the following code:
[HandleBridgeResult]
public class HttpBridgeCallBack : IBridgeCallBack
4. Save the HttpBridgeCallBack.svc.cs file.
From the File menu, select Save HttpBridgeCallBack.svc.cs.
Task 7: Implement the callback channel
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the QueuedTicketingGeneralService
ProcessMessage method. This opens the QueuedTicketingGeneralService.svc.cs file.
3. Add the following code to ProcessMessage method:
IBridgeCallBack prox;
Message response;

if (request.Headers.FindHeader("CallID", "http://Fabrikam.com") <= 0)
throw new TicketingException(StringsResource.CallIDNotFound);

Guid callId = request.Headers.GetHeader<Guid>(
"CallID", "http://Fabrikam.com");

//Forward the message to the R.R ticketing service.
IRequestChannel ticketingChannel = TicketingRequestChannelFactory.GetProxy();

response = ticketingChannel.Request(request);

//Send the message back to the bridge and then back to the client
prox = HttpBridgeCallBackChannelFactory.GetProxy(false);
using (OperationContextScope scope =
new OperationContextScope(prox as IContextChannel))
{
InjectCallIDHeader(callId);
prox.ProcessResult(response);
}
4. Save the QueuedTicketingGeneralService.svc.cs file.
From the File menu, select Save QueuedTicketingGeneralService.svc.cs.

Lab 8: Advanced Topics L8-5
Task 8: Configure the SimpleServiceHost for message logging
1. In the WCF Service Configuration Editor, open the SimpleServiceHost project's App.config file.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor tool, open the File menu, then select Open, and then
select Config File.
In the Open dialog box, navigate to the D:\LabFiles\Starter\M08\CS\Host\SimpleServiceHost
folder.
Select the App.config file, and then click Open.
2. Turn on MessageLogging and Tracing.
In the Configuration tree, click the Diagnostics node.
Turn MessageLogging on by clicking enable MessageLogging.
Turn Tracing on by clicking enable Tracing.
3. Configure Message Logging to log entire messages, and to log messages at the service level.
In the Configuration tree, open the Diagnostics node, and then select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True, and then set
LogMessagesAtServiceLevel to True. Leave all other settings as they are.
4. Save the configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
6. If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
Task 9: Use the client application to call the HTTP Bridge service
1. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
2. Start the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to view which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
L8-6 Lab 8: Advanced Topics

8. When an operation completion message displays, click OK, and then close all the client application
windows.
9. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the SimpleServiceHost console window, press ENTER to stop the service host, and then
press ENTER again to close the console window.
Return to Visual Studio 2010.
Task 10: Use the SvcTraceViewer utility
1. Open the Host solution folder from the Solution Explorer window.
Right-click the SimpleServiceHost project, and then select Open Folder in Windows Explorer.
2. Double-click the app_messages.svclog file to open it with the Microsoft Service Trace Viewer.
3. If an Error Report window opens, click OK. (This window might display if the file is still opened for
writing by the service host.)
4. On the left Message tab, select the last OrderTicket message. (You might need to expand the width
of the Action column to see the entire string.)
Click the Message tab to view the service's activity log.
Scroll down to find the last activity labeled
http://Fabrikam.com/ITicketingService/OrderTicket.
5. In the activity's information (the right side of the window), click the Message tab, and then search for
the CallID SOAP header this is the header that was placed by the message inspector.

6. Close the Microsoft Service Trace Viewer ,and return to Visual Studio 2010.
Results: After this exercise, you will have created a new Bridge contract and implemented it in a service,
created a message inspector and a custom inspector, and used the client application to consume the
service.
Exercise 2: Attaching and Accessing Host Extensions
Task 1: Create a host extension
1. Examine the content of the task list.
From the View menu, select the Task List option.
Lab 8: Advanced Topics L8-7
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Attach method. This
opens the CacheHostExtension.cs file.
3. Add the following code to the Attach method.
HostCache = HttpRuntime.Cache;
owner.Closed += new EventHandler(owner_Closed);
owner.Faulted += new EventHandler(owner_Faulted);
4. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Detach method to
locate the Detach method.
5. Add the following code to the Detach method.
HostCache = null;
owner.Closed -= owner_Closed;
owner.Faulted -= owner_Faulted;
6. Save the CacheHostExtension.cs file.
From the File menu, select Save HostExtensions\CacheHostExtension.cs.
Task 2: Attach the extension to the host and use it
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the hosting manager.
This opens the HostingManager.cs file.
3. Add the following code to the CreateHosts method after the TODO comment:
Hosts[item.Name].Extensions.Add(new CacheHostExtension());
4. Save the HostingManager.cs file.
From the File menu, select Save HostingManager.cs.
5. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the pricing service host
factory. This opens the PricingServiceHostFactory.cs file.
6. Add the following code to the CreateServiceHost method after the TODO comment.
host.Extensions.Add(new CacheHostExtension());
7. Save the PricingServiceHostFactory.cs file.
From the File menu, select Save PricingServiceHostFactory.cs.
8. Double-click the comment TODO: Ex2 Update the code to use the host extension caching. This
opens the PricingService.svc.cs file.
9. Replace the Line rules = GetRulesFromService(policyName); with the following code:
//Look in the rules cache (plugged as a host extension) for the rule
string cacheKey = policyName + DateTime.Today.ToString();
CacheHostExtension cacheHost =
(CacheHostExtension)
(OperationContext.Current.Host.Extensions.Find<CacheHostExtension>());
L8-8 Lab 8: Advanced Topics


if (cacheHost != null)
rules = cacheHost.GetItem(cacheKey) as PricingRule[];

//If there are no rules in the cache call the pricing rules service
if (rules == null)
{
rules = GetRulesFromService(policyName);

//put the rules in the cache for future use.
if ((rules != null) && (rules.Count() > 0))
cacheHost.SetItem(cacheKey, rules, DateTime.Today.AddDays(1));
}
10. Save the PricingService.svc.cs file.
From the File menu, select Save PricingService.svc.cs.
Results: After this exercise, you will have created a host extension, attached the extension to the host, and
accessed the extension in the Pricing service.
Exercise 3: Configuring and Using Routing
Task 1: Create the endpoints to be used by the router
1. In the SimpleServiceHost project App.config file, locate the client section.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
In the configuration element, locate the client element. (It should appear after the services
element.)
2. Add the following endpoints to the end of the client section:
<endpoint name="PricingRouterEP"
address="http://localhost:6000/RoutingService/"
binding="basicHttpBinding"
contract="TicketingOffice.Pricing.Contracts.IPricingService" />
<endpoint name="PricingNormalEP"
address="http://localhost:5005/TicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="VipPricingEP"
address="http://localhost:50051/VipTicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="DeadDestination"
address="http://localhost:9999/TicketesPricing"
binding="ws2007HttpBinding" contract="*" />
Task 2: Add routing configuration
1. In the SimpleServiceHost project App.config file, locate the routing section.
Locate the system.serviceModel section, and then locate the routing XML element inside it.
2. Add the following filter definitions to the routing element:
<namespaceTable>
<add prefix="pricing" namespace="http://Fabrikam.com"/>
</namespaceTable>
Lab 8: Advanced Topics L8-9

<filters>
<!--Filter according to the policyName parameter sent to the pricing service-->
<filter name="VipPricing"
filterType="XPath"
filterData="//pricing:policyName = 'Vip'"/>
<filter name="NormalPricing"
filterType="XPath"
filterData="//pricing:policyName != 'Vip'"/>
</filters>
3. Add the filter table definitions in the routing section after the filters element that you have added.
<filterTables>
<!-- Set up the Routing Service's Message Filter Table -->
<filterTable name="PricingFilterTable">
<add filterName="VipPricing"
endpointName="VipPricingEP" />
<add filterName="NormalPricing"
endpointName="DeadDestination"
backupList="backupEndpointList"/>
</filterTable>
</filterTables>
4. Add a backup list in the routing section after the filterTables element that you have added.
<!-- Create the backup endpoint list -->
<backupLists>
<!-- Add an endpoint list that contains the backup destination -->
<backupList name="backupEndpointList">
<add endpointName="PricingNormalEP" />
</backupList>
</backupLists>
Task 3: Create a routing behavior
1. In the SimpleServiceHost project App.config file, locate the serviceBehaviors section.
Locate the system.serviceModel section, and then locate the behaviors section inside it.
In the behaviors section, locate the serviceBehaviors XML element.
2. Add the following behavior configuration in the serviceBehaviors configuration section:
<!-- Set up the Routing Behavior -->
<behavior name="routingConfiguration">
<routing
filterTableName="PricingFilterTable"
routeOnHeadersOnly="false" />
<serviceDebug
includeExceptionDetailInFaults="true"/>
</behavior>
Task 4: Host the Routing Service
1. In the SimpleServiceHost project App.config file, locate the services section.
Locate the services element. (It should appear inside the system.serviceModel element.)
2. Add the following service configuration in the services section:
<service behaviorConfiguration="routingConfiguration"
name="System.ServiceModel.Routing.RoutingService">
L8-10 Lab 8: Advanced Topics

<host>
<baseAddresses>
<add baseAddress="http://localhost:6000/RoutingService/" />
</baseAddresses>
</host>
<!-- Create the Routing Service endpoint -->
<endpoint
address=""
binding="basicHttpBinding"
name="RoutingServiceEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
3. Save the App.config file.
From the File menu, select Save App.config.
4. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
5. Double-click the comment TODO: Ex3 Add ServiceTypeResolver to the collection. This opens
the HostingManager.cs file.
6. Add the following element to the ServiceTypeResolver collection initialization:
{"System.ServiceModel.Routing.RoutingService",typeof(System.ServiceModel.Routing.RoutingS
ervice)},
7. After adding the previous code, the ServiceTypeResolver definition should resemble the following
code:
static Dictionary<string, Type> ServiceTypeResolver = new Dictionary<string, Type>()
{
// TODO: Ex3 - Add ServiceTypeResolver to the collection
{"System.ServiceModel.Routing.RoutingService",
typeof(System.ServiceModel.Routing.RoutingService)},
{"TicketingOffice.CrmService.CustomerRelationsService",
typeof(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
typeof(CurrencyExchangeService)},
{"TicketingOffice.HallStateService.ReservationsService",
typeof(ReservationsService)},
{"TicketingOffice.PaymentService.TicketsPaymentService",
typeof(TicketsPaymentService)},
{"TicketingOffice.PricingService.TicketsPricingService",
typeof(TicketsPricingService)},
{"TicketingOffice.PricingService.VipPricingService",
typeof(VipPricingService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
typeof(TicketingPricingRulesService)},
{"TicketingOffice.ShowsService.ShowsAndEventsService",
typeof(ShowsAndEventsService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
typeof(GeneralTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingService",
typeof(QueuedTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingGeneralService",
typeof(QueuedTicketingGeneralService)},
{"TicketingOffice.Bridge.TicketingBridge",
typeof(TicketingBridge)},
{"TicketingOffice.Bridge.TicketingBridgeCallBack",
Lab 8: Advanced Topics L8-11
typeof(TicketingBridgeCallBack)},
{"TicketingOffice.Bridge.HttpBridge",
typeof(HttpBridge)},
{"TicketingOffice.Bridge.HttpBridgeCallBack",
typeof(HttpBridgeCallBack)},
{"TicketingOffice.PricingBrokerService.DiscoveryProxyService",
typeof(DiscoveryProxyService)}
};
8. Save the HostingManager.cs file.
From the File menu, select Save HostingManager.cs.
Task 5: Use the client application to call the Routing service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 call the pricing routing service. This opens the
OrderTicketWindow.xaml.cs file.
3. Add the following code to the BackgroundTicketOrderWork method, after the TODO comment:
CalculateTicketsPrice(e, parameters);
4. Save the OrderTicketWindow.xaml.cs file.
From the File menu, select Save OrderTicketWindow.xaml.cs.
5. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
Open the Debug menu, and then select Start Without Debugging.
6. Start the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
7. In the client's main window, click the Order a ticket button.
8. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
9. From the shows list, select Othello, and from the events list, select the first event in the list.
10. Click the Get hall state button to view which seats are available.
11. Select two available seats, and then click the Order button.
12. When an operation completion message displays, verify that the price is 400 (200 per seat).
13. Click OK, select two other available seats, select the "VIP" check box, and then click the Order button.
14. When an operation completion message displays, verify that the price is 360 (400 minus a 10 percent
discount for VIP customers).
15. Click OK, and then close all the client application windows.
16. Switch to the SimpleServiceHost console window, and examine the console output. Notice that the
VIP Pricing service was called.
L8-12 Lab 8: Advanced Topics

17. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the service host console window, press ENTER to stop the service host, and then press
ENTER again to close the console window.
Return to Visual Studio 2010.
Results: After this exercise, you will have created the endpoints to be used by the routing service, added
routing configuration to the routing service, and called the routing service using a client application.
Exercise 4: Implementing Asynchronous Invocation
Task 1: Use the Asynchronous pattern on the Client
1. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and then select Start Without Debugging.
2. Leave the service host console running, and return to Visual Studio 2010.
3. In the TicketingOffice.UI project, in the Client solution folder, locate the
HallStateServiceReference service reference.
Open the View menu and select Solution Explorer.
In the Solution Explorer window, open the Client solution folder, and then open the
TicketingOffice.UI project.
In the TicketingOffice.UI project, open the Service References folder, and locate the
HallStateServiceReference service reference.
4. Right-click the HallStateServiceReference service reference, and then select Configure Service
Reference.
5. In the Service Reference Settings dialog box, select the Generate asynchronous operations check
box, and then click OK.
6. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the service host console window, press ENTER to stop the service host, and then press
ENTER again to close the console window.
Return to Visual Studio 2010.
7. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
8. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous client
call. This opens the OrderTicketWindow.xaml.cs file.
9. Add the following code in the AsyncType.ClientAsync switch section, between the TODO comment
and the break statement:
HallStateServiceClient asyncClientProxy = new
HallStateServiceClient("WS2007HttpBinding_IHallStateService");
asyncClientProxy.BeginGetHallState(
SelectedEvent.EventID, GetHallStateCallback, asyncClientProxy);
10. Add the following method to the OrderTicketWindow class, after the GetHallState method:
void GetHallStateCallback(IAsyncResult ar)
{
Lab 8: Advanced Topics L8-13
SeatIndex[] seats;
seats = ((HallStateServiceClient)ar.AsyncState).EndGetHallState(ar);
this.Dispatcher.Invoke(
new Action(() => {ShowAvailableSeats(seats);}));
}
11. Save the OrderTicketWindow.xaml.cs file.
From the File menu, select Save OrderTicketWindow.xaml.cs.
Task 2: Implement and use the Asynchronous pattern on the service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex4 - Add the IAsyncHallStateService service contract. This
opens the HallStateContract.cs file.
3. Add the following contract code.
[ServiceContract(Namespace = "http://Fabrikam.com")]
public interface IAsyncHallStateService
{
[OperationContract(AsyncPattern=true, Name="GetHallStateAsync")]
IAsyncResult BeginGetHallState(
Guid eventID, AsyncCallback callback, object state);

SeatIndex[] EndGetHallState(IAsyncResult ar);

[OperationContract(AsyncPattern=true, Name="FindTheaterAsync")]
IAsyncResult BeginFindTheater(
string name, int? theaterID,
AsyncCallback callback, object state);

Theater EndFindTheater(IAsyncResult ar);
}
4. Save the HallStateContract.cs file.
From the File menu, select Save HallStateContract.cs.
5. Double-click the comment TODO: Ex4 Implement the IAsyncHallStateService interface. This
opens the HallStateService.svc.cs file.
6. Make the ReservationsService class implement the IAsyncHallStateService interface. The result
class declaration should resemble the following code.
[ServiceBehavior(
InstanceContextMode=InstanceContextMode.Single,
Namespace = "http://Fabrikam.com")]
public class ReservationsService :
IHallStateService, IReservationService,
IHallManagementService, IAsyncHallStateService
7. Double-click the comment TODO: Ex4 Add IAsyncHallStateService contract implementation.
8. Add the following implementation of the IAsyncHallStateService interface to the
ReservationsService class, after the TODO comment:
public IAsyncResult BeginGetHallState(
L8-14 Lab 8: Advanced Topics

Guid eventID, AsyncCallback callback, object state)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"BeginGetHallState",
Thread.CurrentThread.ManagedThreadId));

return manager.BeginGetHallState(eventID, callback, state);
}

public SeatIndex[] EndGetHallState(IAsyncResult ar)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"EndGetHallState",
Thread.CurrentThread.ManagedThreadId));
return manager.EndGetHallState(ar);
}

public IAsyncResult BeginFindTheater(
string name, int? theaterID, AsyncCallback callback, object state)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"BeginFindTheater",
Thread.CurrentThread.ManagedThreadId));
return manager.BeginFindTheater(name, callback, state);
}

public Theater EndFindTheater(IAsyncResult ar)
{
LoggingManager.Logger.Log(LoggingCategory.Info,
string.Format(StringsResource.AsyncExecution,
"EndFindTheater",
Thread.CurrentThread.ManagedThreadId));
return manager.EndFindTheater(ar);
}
9. Save the HallStateService.svc.cs file.
From the File menu, select Save HallStateService.svc.cs.
10. In the SimpleServiceHost project App.config file, locate the service configuration section of the
TicketingOffice.HallStateService.ReservationsService service.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
In the App.config file, under the configuration XML element, locate the services section in the
system.serviceModel section.
In the services section, locate the service XML element that has the name attribute with the
value of TicketingOffice.HallStateService.ReservationsService.
11. Add an endpoint to the service, with the AsyncHallState address, ws2007HttpBinding binding, and
the TicketingOffice. HallState.contracts.IAsyncHallStateService contract. Set the binding
configuration to use the NoSecurity binding configuration. The resulting endpoint configuration
should look as follows:
<endpoint
address="AsyncHallState"
Lab 8: Advanced Topics L8-15
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.HallState.Contracts.IAsyncHallStateService"></endpoint>
12. Save the App.config file.
From the File menu, select Save App.config.
13. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and then select Start Without Debugging.
14. Leave the service host console running, and return to Visual Studio 2010.
15. In the Client solution folder, in the TicketingOffice.UI project, locate the
HallStateServiceReference service reference .
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Client solution folder, and then open the
TicketingOffice.UI project.
In the TicketingOffice.UI project, open the Service References folder, and locate the
HallStateServiceReference service reference.
16. Right-click the HallStateServiceREference service reference, and then select Update Service
Reference.
17. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous service
operation. This opens the OrderTicketWindow.xaml.cs file.
18. Add the following code in the AsyncType.ServiceAsync switch section, between the TODO
comment and the break statement:
AsyncHallStateServiceClient asyncServiceProxy = new
AsyncHallStateServiceClient(
"WS2007HttpBinding_IAsyncHallStateService");
seats = asyncServiceProxy.GetHallStateAsync(SelectedEvent.EventID);
ShowAvailableSeats(seats);
19. Save the OrderTicketWindow.xaml.cs file.
From the File menu, select Save OrderTicketWindow.xaml.cs.
Task 3: Test the Asynchronous client and service
1. Run the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
2. In the client's main window, click the Order a ticket button.
3. In the OrderTicketWindow window, open the shows list, select Othello, and then from the events list,
select the first event in the list.
4. Click the Get hall state (Async client) button to view which seats are available. Examine the service
host console application outputyou should see the log message Running GetHallState on thread.
5. Return to the OrderTicketWindow window in the client application, and then click the Get hall state
(Async service) button. Examine the service host console application outputyou should see the log
messages Running BeginGetHallState on thread , and Running EndGetHallState on thread .
6. Close all the client application windows.
L8-16 Lab 8: Advanced Topics

7. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the SimpleServiceHost console window, press ENTER to stop the service host, and then
press ENTER again to close the console window.
Return to Visual Studio 2010.
Results: After this exercise, you will have implemented and used the asynchronous pattern in both the
client and the service.
Exercise 5: Implementing Workflow Services
Task 1: Open the workflow service project
1. Open the CreditPayment.xamlx file in the CreditCardPaymentService project.
In the Solution Explorer window, open the Services solution folder, then open the Payment
solution folder, and then open the CreditCardPaymentService project.
Double-click the CreditPayment.xamlx file to open it.
2. Verify that an empty workflow appears with a single sequence activity, and that the display name of
the activity is Credit Service.
Task 2: Add activities to the workflow
1. Add a ReceiveAndSendReply activity from the Messaging group into the sequence activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a ReceiveAndSendReply activity from the Messaging
group into the Sequence activity.
2. Rename the Receive activity to InitPayment.
Right-click the Receive activity, and then select Properties.
In the Properties window, set the OperationName property to InitPayment.
3. Drag an InvokeMethod activity from the Primitives group to between the Receive and the
SendReplyToReceive activities.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an InvokeMethod activity from the Primitives group to
between the Receive and the SendReplyToReceive activities.
4. In the new InvokeMethod activity, open the Properties window.
Right-click the new InvokeMethod activity, and then select Properties.
Lab 8: Advanced Topics L8-17

5. In the TargetObject property, type the following:
New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
6. In the MethodName property, type the following: IsPaymentTypeEnabled
7. In the Result property type the following: CreditEnabled
8. Click the ellipses () button in the Parameters collection text box to open the Parameters dialog
box, and complete the first row, and then click OK.
In the Direction column, select In.
In the Type column, select Browse for Types.
In the Type Name text box, type PaymentType, select the PaymentType from the tree, and
then click OK.
In the Value column, enter PaymentType.CreditCard.
Click OK to close the Parameters dialog box.

9. The workflow should display as follows:

L8-18 Lab 8: Advanced Topics


10. In the Receive activity, open the Properties window.
Right-click the Receive activity, and then select Properties.
11. Select the CanCreateInstance check box.
12. In the ServiceContractName, type: {http://Fabrikam.com/}ICreditCardPaymentService
13. In the SendReplyToReceive activity, open the Properties window.
Right-click the SendReplyToReceive activity, and then select Properties.
14. In the Properties window, click the ellipse () button in the Content field to open the Content
Definition dialog box.
15. In the Content Definition window, select Parameters.
16. Set the content to the following values:
Name: Results
Type: Boolean
Value: CreditEnabled
17. Click OK to close the Content Definition dialog box.
18. Add an If activity from the ControlFlow group after the sequence activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an If activity after the sequence activity from the
ControlFlow group.
19. In the If Activity, open the Properties window.
Right-click the If activity, and then select Properties.
Lab 8: Advanced Topics L8-19
20. In the Condition property, type CreditEnabled.

21. Add a ReceiveAndSendReply activity from the Messaging group into the Then area of the If
activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a ReceiveAndSendReply activity from the Messaging
group into the Then area of the If activity.
22. Add a Receive activity from the Messaging group, and drag it before the Receive activity that is
already inside the Then area of the If activity. Set the new activity OperationName to
ProvidePaymentDetails, and set the DisplayName to ProvidePaymentDetails.
L8-20 Lab 8: Advanced Topics

Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a Receive activity from the Messaging group before the
Receive activity that is already inside the Then area of the If activity.
Right-click the new Receive activity, and then select Properties.
Set the OperationName to ProvidePaymentDetails.
Set the DisplayName to ProvidePaymentDetails.
23. Set the DisplayName of the second Receive activity inside the Then activity to PerformPayment,
and set the OperationName to PerformPayment.
Right-click the second Receive activity inside the Then activity, and select Properties.
Set the activity DisplayName to PerformPayment.
Set the OperationName to PerformPayment.
24. Update the display name of the SendReplyToReceive activity in the Then activity to
SendReplyToPerformPayment.
Right-click the second SendReplyToReceive activity inside the Then activity, and select
Properties.
Set the activity DisplayName to SendReplyToPerformPayment.


Lab 8: Advanced Topics L8-21
25. In both Receive activities, change the ServiceContractName to
{http://Fabrikam.com/}ICreditCardPaymentService.
Right-click the ProvidePaymentDetails receive activity inside the Then activity, and select
Properties.
Set the ServiceContractName to {http://Fabrikam.com/}ICreditCardPaymentService.
Right-click the PerformPayment receive activity inside the Then activity, and select Properties.
Set the ServiceContractName to {http://Fabrikam.com/}ICreditCardPaymentService.
26. Right-click the ProvidePaymentDetails activity, select Properties, and set the Content property as
follows:
In the Properties window, in the Content field, click the ellipses () button to open the Content
Definition dialog box.
In the Content Definition window, select Parameters.
Set the content to the following values:
For the Guid and Double types, select Browse for Types in the Type column, type the name
(Guid/Double) in the Type Name text box, select the required type from the tree, and then
click OK.
Name Type Assign To
OrderID Guid OrderID
CustomerID Guid PayingCustomerID
Amount Double Amount
CreditCardNumber String CreditCard

Click OK to close the Content Definition dialog box.
Note: After browsing for a parameter type, some types may appear with their full namespace. For
example, Guid might display as System.Guid.
L8-22 Lab 8: Advanced Topics

27. Right-click the SendReplyToPerformPayment activity, and then select Properties.
28. Set the content property as follows:
In the Properties window, in the Content field, click the ellipses () button to open the Content
Definition dialog box.
In the Content Definition window, select Parameters.
Set the content to the following values:
For the Payment type, select Browse for Types in the Type column, type Payment in the
Type Name text box, and then select the Payment type from the tree.
Name Type Value
PaymentResult Payment PaymentResult

29. Click OK to close the Content Definition dialog box.
30. Add an InvokeMethod activity from the Primitives group between the PerformPayment activity
and the SendReplyToPerformPayment activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an InvokeMethod activity from the Primitives group
between the PerformPayment activity and the SendReplyToPerformPayment activity.
31. In the InvokeMethod activity, set the properties.
Right-click the InvokeMethod activity, and then select Properties.
Set the value of the properties as follows:
TargetObject: New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
MethodName: PayForOrder
Result: PaymentResult
32. In the Properties window, in the Parameters field, click the ellipses () button, add the following
parameters, and then click OK:
Lab 8: Advanced Topics L8-23
Direction Type Value
In Guid OrderID
In Guid PayingCustomerID
In Double Amount
In PaymentType PaymentType.CreditCard
In String CreditCard
33. Save the CreditPayment.xamlx file.
From the File menu, select Save CreditPayment.xamlx.
34. Rebuild the project.
In the Solution Explorer window, open the Services solution folder, and then open the Payment
solution folder.
Right-click CreditCardPaymentService project, and then select Rebuild.
Task 3: Deploy the CreditCardPayment service to AppFabric using a deployment
package
1. Create a Deployment package for the CreditCardPaymentService project.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
Open the Payment solution folder, right-click the CreditCardPaymentService project, and
select Build Deployment Package.
2. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import the package that you have created to the Default Web Site, and name it
FabrikamTicketingCreditPayment.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the Actions pane (the right pane), select Import Application.
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M08\CS\Services\Payment\CreditCardPaymentService\obj\Debug\Pac
kage\CreditCardPaymentService.zip.
In the Select the Contents of the Package step of the Import Application Package wizard, click
Next.
In the Enter Application Package Information step of the Import Application Package wizard,
set the Application Path to FabrikamTicketingCreditPayment, and then click Next.
If a message displays asking whether to run the application in the default Microsoft .NET 4.0
application pool, click Yes.
In the Installation Progress and Summary step of the Import Application Package wizard, wait
for the process to complete, and then click Finish.
L8-24 Lab 8: Advanced Topics

4. Close the IIS Manager.
Task 4: Test the CreditCardPayment workflow service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
Click Start, and then click Computer.
Open drive D, and then navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CreditPayment service, using the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx, and then click OK.
3. Call the InitPayment operation to test the workflow service.
In the My Service Projects tree, double-click the InitPayment operation.
Click Invoke, and if a security warning appears, click OK.
4. After receiving a response, close the Windows Communication Foundation (WCF) Test Client.
5. Open the IIS Manager
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
6. In the IIS console, open AppFabric Dashboard.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the AppFabric category, double-click AppFabric Dashboard.
7. Examine the WF Instance History section, and notice that the CreditPayment.xamlx is activated.
8. Close the IIS Manager.
Results: After this exercise, you will have created a workflow service that executes the process of credit
card payment, and then tested it.
Lab 8: Advanced Topics L8-25
Module 8: Introduction to Advanced Microsoft Windows
Communication Foundation Topics
Lab 8: Advanced Topics
Section 2: Visual Basic
Exercise 1: Using Message Inspectors and Behaviors
Task 1: Open the starter solution
1. Log on to the virtual machine named 10263A-SVR1 as Administrator with the password Pa$$w0rd.
2. In the D:\LabFiles\Starter\M08\VB folder, run setup.bat.
Click Start, and then click Computer.
Open drive D, and then navigate to the LabFiles\Starter\M08\VB folder.
Double-click the setup.bat file.
3. After the batch completes, press any key in the command window to close it, and then close the
Windows Explorer window.
4. Open Microsoft Visual Studio 2010.
Click Start, click All Programs, click Microsoft Visual Studio 2010, and then click Microsoft
Visual Studio 2010.
5. Open the solution TicketingOffice.sln from the D:\LabFiles\Starter\M08\VB folder.
In the File menu, select Open, and then select Project/Solution.
In the Open Project dialog box, navigate to the D:\LabFiles\Starter\M08\VB folder, click the
TicketingOffice.sln file, and then click Open.
Task 2: Add the new bridge and message forwarder contracts
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Add code to the IBridge interface which handles all
incoming messages. This opens the TicketingServiceContracts.vb file.
3. Add the following code to the interface IBridge.
<OperationContract(Action:="*", ReplyAction:="*")>
Function ProcessMessage(ByVal message As Message) As Message
4. Double-click the comment TODO: Ex1 Add code to the IBridgeCallBack interface which
handles all incoming messages. This locates the IBridgeCallback interface.
5. Add the following code to the interface IBridgeCallBack.
<OperationContract(IsOneWay := True, Action := "*")>
Sub ProcessResult(ByVal message As Message)
6. Double-click the comment TODO: Ex1 Add code to the IBridgeOneWayForwarder interface
which handles all incoming messages to locate the IBridgeOneWayForwarder interface.
L8-26 Lab 8: Advanced Topics

7. Add the following code to the interface IBridgeOneWayForwarder.
<OperationContract(IsOneWay := True, Action := "*")>
Sub ProcessMessage(ByVal message As Message)
8. Save the TicketingServiceContracts.vb file.
From the File menu, select Save TicketingServiceContracts.vb.
Task 3: Write the implementation of the HTTP Bridge contract
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HttpBridge ProcessMessage method.
This opens the HttpBridgeService.svc.vb file.
3. Change the method declaration so it will implement the IBridge interface.
Public Function ProcessMessage(ByVal IncommingMessage As Message) _
As Message Implements IBridge.ProcessMessage
4. Replace the content of the Try block in the ProcessMessage method in class HttpBridge, with the
following code:
' Create a proxy to QueuedTicketingGeneralService
prox = QueuedTicketingGeneralProxyFactory.GetProxy(False)
Dim arrived As New AutoResetEvent(False)
' Create a MessagePackage with a wait handle to wait on
'until a response arrives (on another channel)
Dim pack As New MessagePackage() With {.MessageArrived = arrived}
MessageCache.Current.SetMessagePack(callId, pack)

'Put the callID inside a header
Dim header = New MessageHeader(Of Guid)(callId)
Dim headerBase = header.GetUntypedHeader("CallID",
"http://Fabrikam.com")

' Write the header inside the message received from the client.
IncommingMessage.Headers.Add(headerBase)

'Send the message (the original message + the new header)
'to the ticketing service (One-Way)
'Call the ticketing service via MSMQ channel on another thread.
Dim del As Action(Of IBridgeOneWayForwarder) = (Sub(p) _
p.ProcessMessage(IncommingMessage))
del.BeginInvoke(prox, Nothing, Nothing)

'Wait until result arrives
arrived.WaitOne()

' Clone the message before sending it back
result = MessageCache.Current.GetResponse(callId).Clone()
' Clear the callID header so it will not arrive back to the client.
result.Headers.RemoveAll("CallID", "http://Fabrikam.com")
' Clear the message cache
MessageCache.Current.ClearMessagePack(callId)

Return result
Lab 8: Advanced Topics L8-27
5. Save the HttpBridgeService.svc.vb file.
From the File menu, select Save HttpBridgeService.svc.vb.
Task 4: Create a message inspector
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultMessageInspector
AfterReceiveRequest Method. This opens the MessageInspectors.vb file.
3. Replace the content of AfterReceiveRequest method in class
HandleBridgeResultMessageInspector, with the following code:
Dim buffer As MessageBuffer = request.CreateBufferedCopy(Integer.MaxValue)
If request.Headers.FindHeader("CallID", "http://Fabrikam.com") _
> 0 Then
Dim callId = request.Headers.GetHeader(Of Guid)(
"CallID",
"http://Fabrikam.com")
Dim MessageResultPackage =
MessageCache.Current.GetMessagePack(callId)
If MessageResultPackage IsNot Nothing Then
'Save the message in the appropriate ResultPackage.
'The message will be forwarded to the client.
MessageResultPackage.Response = buffer

'Notify a message has arrived.
'When converting Request Response to one way the bridge
'waits on this handle.
MessageResultPackage.MessageArrived.Set()
End If
End If
Return Nothing
4. Save the MessageInspectors.vb file.
From the File menu, select Save Behaviors\MessageInspectors.vb.
Task 5: Create a custom behavior as an attribute
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the HandleBridgeResultAttribute
ApplyDispatchBehavior method. This opens the ServiceBehaviors.vb file.
3. Add the following code to ApplyDispatchBehavior method:
For Each chDisp As ChannelDispatcher In
serviceHostBase.ChannelDispatchers
For Each epDisp As EndpointDispatcher In chDisp.Endpoints
epDisp.DispatchRuntime.MessageInspectors.Add(
New HandleBridgeResultMessageInspector())
Next epDisp
Next chDisp
4. Save the ServiceBehaviors.vb file.
L8-28 Lab 8: Advanced Topics

From the File menu, select Save Behaviors\ServiceBehaviors.vb.
Task 6: Use the custom behavior attribute
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Decorate the HttpBridgeCallBack class with the
HandleBridgeResult attribute. This opens the HttpBridgeCallBack.svc.vb file.
3. Decorate the HttpBridgeCallBack class with the HandleBridgeResult attribute. The resulting class
declaration should resemble the following code:
<HandleBridgeResult>
Public Class HttpBridgeCallBack
Implements IBridgeCallBack
4. Change the method declaration so it will implement the IBridgeCallBack interface.
Public Sub ProcessResult(ByVal l_message As Message) _
Implements IBridgeCallBack.ProcessResult
5. Save the HttpBridgeCallBack.svc.vb file.
From the File menu, select Save HttpBridgeCallBack.svc.vb.
Task 7: Implement the callback channel
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex1 Implement the QueuedTicketingGeneralService
ProcessMessage method. This opens the QueuedTicketingGeneralService.svc.vb file.
3. Change the method declaration so it will implement the IBridgeOneWayForwarder interface.
Public Sub ProcessMessage(ByVal request As Message) _
Implements IBridgeOneWayForwarder.ProcessMessage
4. Add the following code to ProcessMessage method:
Dim prox As IBridgeCallBack
Dim response As Message

If request.Headers.FindHeader("CallID", "http://Fabrikam.com") _
<= 0 Then
Throw New TicketingException(StringsResource.CallIDNotFound)
End If

Dim callId As Guid = request.Headers.GetHeader(Of Guid)(
"CallID", "http://Fabrikam.com")

'Forward the message to the R.R ticketing service.
Dim ticketingChannel As IRequestChannel =
TicketingRequestChannelFactory.GetProxy()

response = ticketingChannel.Request(request)

Lab 8: Advanced Topics L8-29
'Send the message back to the bridge and then back to the client
prox = HttpBridgeCallBackChannelFactory.GetProxy(False)
Using scope As New OperationContextScope(
TryCast(prox, IContextChannel))
InjectCallIDHeader(callId)
prox.ProcessResult(response)
End Using
5. Save the QueuedTicketingGeneralService.svc.vb file.
From the File menu, select Save QueuedTicketingGeneralService.svc.vb.
Task 8: Configure the SimpleServiceHost for message logging
1. In the WCF Service Configuration Editor, open the SimpleServiceHost project's App.config file.
From the Tools menu, select WCF Service Configuration Editor.
In the WCF Service Configuration Editor tool, open the File menu, then select Open, and then
select Config File.
In the Open dialog box, navigate to the D:\LabFiles\Starter\M08\VB\Host\SimpleServiceHost
folder.
Select the App.config file, and then click Open.
2. Turn on MessageLogging and Tracing.
In the Configuration tree, click the Diagnostics node.
Turn MessageLogging on by clicking enable MessageLogging.
Turn Tracing on by clicking enable Tracing.
3. Configure Message Logging to log entire messages, and to log messages at the service level.
In the Configuration tree, open the Diagnostics node, and then select Message Logging.
In the Message Logging configuration, set LogEntireMessage to True, and then set
LogMessagesAtServiceLevel to True. Leave all other settings as they are.
4. Save the configuration file.
Open the File menu, and then click Save.
5. Close the WCF Service Configuration Editor and return to Visual Studio 2010.
6. If a reload confirmation message displays when returning to Visual Studio 2010, click Yes.
Task 9: Use the client application to call the HTTP Bridge service
1. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Host solution folder, right-click the
SimpleServiceHost project, and then select Set as StartUp Project.
Open the Debug menu, and select Start Without Debugging.
2. Start the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
L8-30 Lab 8: Advanced Topics

3. In the client's main window, click the Order a ticket button.
4. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
5. From the shows list, select Othello, and from the events list, select the first event in the list.
6. Click the Get hall state button to view which seats are available.
7. Select two available seats, select the Use Ticketing Bridge check box, and then click the Order
button.
8. When an operation completion message displays, click OK, and then close all the client application
windows.
9. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the SimpleServiceHost console window, press ENTER to stop the service host, and then
press ENTER again to close the console window.
Return to Visual Studio 2010.
Task 10: Use the SvcTraceViewer utility
1. Open the Host solution folder from the Solution Explorer window.
Right-click the SimpleServiceHost project, and then select Open Folder in Windows Explorer.
2. Double-click the app_messages.svclog file to open it with the Microsoft Service Trace Viewer.
3. If an Error Report window opens, click OK. (This window might display if the file is still opened for
writing by the service host.)
4. On the left Message tab, select the last OrderTicket message. (You might need to expand the width
of the Action column to see the entire string.)
Click the Message tab to view the service's activity log.
Scroll down to find the last activity labeled
http://Fabrikam.com/ITicketingService/OrderTicket.
5. In the activity's information (the right side of the window), click the Message tab, and then search for
the CallID SOAP header this is the header that was placed by the message inspector.

6. Close the Microsoft Service Trace Viewer ,and return to Visual Studio 2010.
Lab 8: Advanced Topics L8-31
Results: After this exercise, you will have created a new Bridge contract and implemented it in a service,
created a message inspector and a custom inspector, and used the client application to consume the
service.
Exercise 2: Attaching and Accessing Host Extensions
Task 1: Create a host extension
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Attach method. This
opens the CacheHostExtension.vb file.
3. Add the following code to the Attach method.
HostCache = HttpRuntime.Cache
AddHandler owner.Closed, AddressOf owner_Closed
AddHandler owner.Faulted, AddressOf owner_Faulted
4. Double-click the comment TODO: Ex2 Implement the CacheHostExtension Detach method to
locate the Detach method.
5. Add the following code to the Detach method.
HostCache = Nothing
RemoveHandler owner.Closed, AddressOf owner_Closed
RemoveHandler owner.Faulted, AddressOf owner_Faulted
6. Save the CacheHostExtension.vb file.
From the File menu, select Save HostExtensions\CacheHostExtension.vb.
Task 2: Attach the extension to the host and use it
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the hosting manager.
This opens the HostingManager.vb file.
3. Add the following code to the CreateHosts method after the TODO comment:
Hosts(item.Name).Extensions.Add(New CacheHostExtension())
4. Save the HostingManager.vb file.
From the File menu, select Save HostingManager.vb.
5. Double-click the comment TODO: Ex2 Add the CacheHostExtension to the pricing service host
factory. This opens the PricingServiceHostFactory.vb file.
6. Add the following code to the CreateServiceHost method after the TODO comment.
host.Extensions.Add(New CacheHostExtension())
7. Save the PricingServiceHostFactory.vb file.
L8-32 Lab 8: Advanced Topics

From the File menu, select Save PricingServiceHostFactory.vb.
8. Double-click the comment TODO: Ex2 Update the code to use the host extension caching. This
opens the PricingService.svc.vb file.
9. Replace the Line rules = GetRulesFromService(policyName) with the following code:
'Look in the rules cache (plugged as a host extension) for the rule
Dim cacheKey As String = policyName & Date.Today.ToString()
Dim cacheHost As CacheHostExtension =
CType(OperationContext.Current.Host.Extensions.
Find(Of CacheHostExtension)(), CacheHostExtension)

If cacheHost IsNot Nothing Then
rules = TryCast(cacheHost.GetItem(cacheKey), PricingRule())
End If

'If there are no rules in the cache call the pricing rules service
If rules Is Nothing Then
rules = GetRulesFromService(policyName)

'put the rules in the cache for future use.
If (rules IsNot Nothing) AndAlso (rules.Count() > 0) Then
cacheHost.SetItem(cacheKey, rules, Date.Today.AddDays(1))
End If
End If
10. Save the PricingService.svc.vb file.
From the File menu, select Save PricingService.svc.vb.
Results: After this exercise, you will have created a host extension, attached the extension to the host, and
accessed the extension in the Pricing service.
Exercise 3: Configuring and Using Routing
Task 1: Create the endpoints to be used by the router
1. In the SimpleServiceHost project App.config file, locate the client section.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
In the configuration element, locate the client element. (It should appear after the services
element.)
2. Add the following endpoints to the end of the client section:
<endpoint name="PricingRouterEP"
address="http://localhost:6000/RoutingService/"
binding="basicHttpBinding"
contract="TicketingOffice.Pricing.Contracts.IPricingService" />
<endpoint name="PricingNormalEP"
address="http://localhost:5005/TicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="VipPricingEP"
address="http://localhost:50051/VipTicketesPricing"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity" contract="*"/>
<endpoint name="DeadDestination"
address="http://localhost:9999/TicketesPricing"
Lab 8: Advanced Topics L8-33
binding="ws2007HttpBinding" contract="*" />
Task 2: Add routing configuration
1. In the SimpleServiceHost project App.config file, locate the routing section.
Locate the system.serviceModel section, and then locate the routing XML element inside it.
2. Add the following filter definitions to the routing element:
<namespaceTable>
<add prefix="pricing" namespace="http://Fabrikam.com"/>
</namespaceTable>

<filters>
<!--Filter according to the policyName parameter sent to the pricing service-->
<filter name="VipPricing"
filterType="XPath"
filterData="//pricing:policyName = 'Vip'"/>
<filter name="NormalPricing"
filterType="XPath"
filterData="//pricing:policyName != 'Vip'"/>
</filters>
3. Add the filter table definitions in the routing section after the filters element that you have added.
<filterTables>
<!-- Set up the Routing Service's Message Filter Table -->
<filterTable name="PricingFilterTable">
<add filterName="VipPricing"
endpointName="VipPricingEP" />
<add filterName="NormalPricing"
endpointName="DeadDestination"
backupList="backupEndpointList"/>
</filterTable>
</filterTables>
4. Add a backup list in the routing section after the filterTables element that you have added.
<!-- Create the backup endpoint list -->
<backupLists>
<!-- Add an endpoint list that contains the backup destination -->
<backupList name="backupEndpointList">
<add endpointName="PricingNormalEP" />
</backupList>
</backupLists>
Task 3: Create a routing behavior
1. In the SimpleServiceHost project App.config file, locate the serviceBehaviors section.
Locate the system.serviceModel section, and then locate the behaviors section inside it.
In the behaviors section, locate the serviceBehaviors XML element.
2. Add the following behavior configuration in the serviceBehaviors configuration section:
<!-- Set up the Routing Behavior -->
<behavior name="routingConfiguration">
<routing
filterTableName="PricingFilterTable"
routeOnHeadersOnly="false" />
<serviceDebug
L8-34 Lab 8: Advanced Topics

includeExceptionDetailInFaults="true"/>
</behavior>
Task 4: Host the Routing Service
1. In the SimpleServiceHost project App.config file, locate the services section.
Locate the services element. (It should appear inside the system.serviceModel element.)
2. Add the following service configuration in the services section:
<service behaviorConfiguration="routingConfiguration"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6000/RoutingService/" />
</baseAddresses>
</host>
<!-- Create the Routing Service endpoint -->
<endpoint
address=""
binding="basicHttpBinding"
name="RoutingServiceEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
3. Save the App.config file.
From the File menu, select Save App.config.
4. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
5. Double-click the comment TODO: Ex3 Add ServiceTypeResolver to the collection. This opens
the HostingManager.vb file.
6. Add the following element to the ServiceTypeResolver collection initialization:
{"System.ServiceModel.Routing.RoutingService",GetType(
System.ServiceModel.Routing.RoutingService)},
7. After adding the previous code, the ServiceTypeResolver definition should resemble the following
code:
Private Shared ServiceTypeResolver As New Dictionary(Of String, Type)() From {
{"System.ServiceModel.Routing.RoutingService",
GetType(System.ServiceModel.Routing.RoutingService)},
{"TicketingOffice.CrmService.CustomerRelationsService",
GetType(CustomerRelationsService)},
{"TicketingOffice.CurrencyExchange.Wcf.CurrencyExchangeService",
GetType(CurrencyExchangeService)},
{"TicketingOffice.HallStateService.ReservationsService",
GetType(ReservationsService)},
{"TicketingOffice.PaymentService.TicketsPaymentService",
GetType(TicketsPaymentService)},
{"TicketingOffice.PricingService.TicketsPricingService",
GetType(TicketsPricingService)}, {"TicketingOffice.PricingService.VipPricingService",
GetType(VipPricingService)},
{"TicketingOffice.PricingRulesService.TicketingPricingRulesService",
Lab 8: Advanced Topics L8-35
GetType(TicketingPricingRulesService)},
{"TicketingOffice.ShowsService.ShowsAndEventsService",
GetType(ShowsAndEventsService)},
{"TicketingOffice.TicketingService.GeneralTicketingService",
GetType(GeneralTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingService",
GetType(QueuedTicketingService)},
{"TicketingOffice.TicketingService.QueuedTicketingGeneralService",
GetType(QueuedTicketingGeneralService)}, {"TicketingOffice.Bridge.TicketingBridge",
GetType(TicketingBridge)}, {"TicketingOffice.Bridge.TicketingBridgeCallBack",
GetType(TicketingBridgeCallBack)}, {"TicketingOffice.Bridge.HttpBridge",
GetType(HttpBridge)},
{"TicketingOffice.Bridge.HttpBridgeCallBack",
GetType(HttpBridgeCallBack)},
{"TicketingOffice.PricingBrokerService.DiscoveryProxyService",
GetType(DiscoveryProxyService)}}
8. Save the HostingManager.vb file.
From the File menu, select Save HostingManager.vb.
Task 5: Use the client application to call the Routing service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex3 call the pricing routing service. This opens the
OrderTicketWindow.xaml.vb file.
3. Add the following code to the BackgroundTicketOrderWork method, after the TODO comment:
CalculateTicketsPrice(e, parameters)
4. Save the OrderTicketWindow.xaml.vb file.
From the File menu, select Save OrderTicketWindow.xaml.vb.
5. Build and run the SimpleServiceHost project without debugging.
From the Build menu, select Build Solution.
Open the Debug menu, and then select Start Without Debugging.
6. Start the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
7. In the client's main window, click the Order a ticket button.
8. In the OrderTicketWindow window, open the customers drop-down list, and then select Hanson,
Mark.
9. From the shows list, select Othello, and from the events list, select the first event in the list.
10. Click the Get hall state button to view which seats are available.
11. Select two available seats, and then click the Order button.
12. When an operation completion message displays, verify that the price is 400 (200 per seat).
13. Click OK, select two other available seats, select the "VIP" check box, and then click the Order button.
L8-36 Lab 8: Advanced Topics

14. When an operation completion message displays, verify that the price is 360 (400 minus a 10 percent
discount for VIP customers).
15. Click OK, and then close all the client application windows.
16. Switch to the SimpleServiceHost console window, and examine the console output. Notice that the
VIP Pricing service was called.
17. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the service host console window, press ENTER to stop the service host, and then press
ENTER again to close the console window.
Return to Visual Studio 2010.
Results: After this exercise, you will have created the endpoints to be used by the routing service, added
routing configuration to the routing service, and called the routing service using a client application.
Exercise 4: Implementing Asynchronous Invocation
Task 1: Use the Asynchronous pattern on the Client
1. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and then select Start Without Debugging.
2. Leave the service host console running, and return to Visual Studio 2010.
3. In the TicketingOffice.UI project, in the Client solution folder, locate the
HallStateServiceReference service reference.
Open the View menu and select Solution Explorer.
In the Solution Explorer window, open the Client solution folder, and then open the
TicketingOffice.UI project.
In the TicketingOffice.UI project, open the Service References folder, and locate the
HallStateServiceReference service reference.
4. Right-click the HallStateServiceReference service reference, and then select Configure Service
Reference.
5. In the Service Reference Settings dialog box, select the Generate asynchronous operations check
box, and then click OK.
6. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the service host console window, press ENTER to stop the service host, and then press
ENTER again to close the console window.
Return to Visual Studio 2010.
7. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
8. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous client
call. This opens the OrderTicketWindow.xaml.vb file.
Lab 8: Advanced Topics L8-37
9. Add the following code in the AsyncType.ClientAsync Select section, between the TODO comment
and the next Case statement:
Dim asyncClientProxy As New _
HallStateServiceClient("WS2007HttpBinding_IHallStateService")
asyncClientProxy.BeginGetHallState(SelectedEvent.EventID,
AddressOf GetHallStateCallback, asyncClientProxy)
10. Add the following method to the OrderTicketWindow class, after the GetHallState method:
Private Sub GetHallStateCallback(ByVal ar As IAsyncResult)
Dim seats() As SeatIndex
seats =
(CType(ar.AsyncState, HallStateServiceClient)).EndGetHallState(ar)
Me.Dispatcher.Invoke(New Action(Sub() ShowAvailableSeats(seats)))
End Sub
11. Save the OrderTicketWindow.xaml.vb file.
From the File menu, select Save OrderTicketWindow.xaml.vb.
Task 2: Implement and use the Asynchronous pattern on the service
1. Examine the content of the task list.
From the View menu, select the Task List option.
In the Task List window, if the list displays User Tasks, change it to Comments.
2. Double-click the comment TODO: Ex4 - Add the IAsyncHallStateService service contract. This
opens the HallStateContract.vb file.
3. Add the following contract code.
<ServiceContract(Namespace := "http://Fabrikam.com")>
Public Interface IAsyncHallStateService

<OperationContract(AsyncPattern := True,
Name := "GetHallStateAsync")>
Function BeginGetHallState(ByVal eventID As Guid,
ByVal callback As AsyncCallback, ByVal state As Object) _
As IAsyncResult

Function EndGetHallState(ByVal ar As IAsyncResult) As SeatIndex()


<OperationContract(AsyncPattern := True,
Name := "FindTheaterAsync")>
Function BeginFindTheater(ByVal name As String,
ByVal theaterID? As Integer, ByVal callback As AsyncCallback,
ByVal state As Object) As IAsyncResult

Function EndFindTheater(ByVal ar As IAsyncResult) As Theater
End Interface
4. Save the HallStateContract.vb file.
From the File menu, select Save HallStateContract.vb.
5. Double-click the comment TODO: Ex4 Implement the IAsyncHallStateService interface. This
opens the HallStateService.svc.vb file.
6. Make the ReservationsService class implement the IAsyncHallStateService interface. The result
class declaration should resemble the following code.
L8-38 Lab 8: Advanced Topics

<ServiceBehavior(InstanceContextMode := InstanceContextMode.Single,
Namespace := "http://Fabrikam.com")>
Public Class ReservationsService : Implements _
IHallStateService, IReservationService,
IHallManagementService, IAsyncHallStateService
7. Double-click the comment TODO: Ex4 Add IAsyncHallStateService contract implementation.
8. Add the following implementation of the IAsyncHallStateService interface to the
ReservationsService class, after the TODO comment:
Public Function BeginGetHallState(ByVal eventID As Guid,
ByVal callback As AsyncCallback, ByVal state As Object) _
As IAsyncResult Implements IAsyncHallStateService.BeginGetHallState
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "BeginGetHallState",
Thread.CurrentThread.ManagedThreadId))

Return manager.BeginGetHallState(eventID, callback, state)
End Function

Public Function EndGetHallState(ByVal ar As IAsyncResult) _
As SeatIndex() Implements IAsyncHallStateService.EndGetHallState
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "EndGetHallState",
Thread.CurrentThread.ManagedThreadId))
Return manager.EndGetHallState(ar)
End Function

Public Function BeginFindTheater(ByVal name As String,
ByVal theaterID? As Integer, ByVal callback As AsyncCallback,
ByVal state As Object) As IAsyncResult _
Implements IAsyncHallStateService.BeginFindTheater
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "BeginFindTheater",
Thread.CurrentThread.ManagedThreadId))

Return manager.BeginFindTheater(name, callback, state)
End Function

Public Function EndFindTheater(ByVal ar As IAsyncResult) As Theater _
Implements IAsyncHallStateService.EndFindTheater
LoggingManager.Logger.Log(LoggingCategory.Info,
String.Format(StringsResource.AsyncExecution, "EndFindTheater",
Thread.CurrentThread.ManagedThreadId))

Return manager.EndFindTheater(ar)
End Function
9. Save the HallStateService.svc.vb file.
From the File menu, select Save HallStateService.svc.vb.
10. In the SimpleServiceHost project App.config file, locate the service configuration section of the
TicketingOffice.HallStateService.ReservationsService service.
In the Solution Explorer window, open the Host solution folder, and then open the
SimpleServiceHost project.
Double-click the App.config file to open it.
In the App.config file, under the configuration XML element, locate the services section in the
system.serviceModel section.
Lab 8: Advanced Topics L8-39
In the services section, locate the service XML element that has the name attribute with the
value of TicketingOffice.HallStateService.ReservationsService.
11. Add an endpoint to the service, with the AsyncHallState address, ws2007HttpBinding binding, and
the TicketingOffice. HallState.contracts.IAsyncHallStateService contract. Set the binding
configuration to use the NoSecurity binding configuration. The resulting endpoint configuration
should look as follows:
<endpoint
address="AsyncHallState"
binding="ws2007HttpBinding"
bindingConfiguration="NoSecurity"
contract="TicketingOffice.HallState.Contracts.IAsyncHallStateService"></endpoint>
12. Save the App.config file.
From the File menu, select Save App.config.
13. Run the SimpleServiceHost project without debugging.
Open the Debug menu, and then select Start Without Debugging.
14. Leave the service host console running, and return to Visual Studio 2010.
15. In the Client solution folder, in the TicketingOffice.UI project, locate the
HallStateServiceReference service reference .
Open the View menu, and select Solution Explorer.
In the Solution Explorer window, open the Client solution folder, and then open the
TicketingOffice.UI project.
In the TicketingOffice.UI project, open the Service References folder, and locate the
HallStateServiceReference service reference.
16. Right-click the HallStateServiceREference service reference, and then select Update Service
Reference.
17. Double-click the comment TODO: Ex4 Call the HallState service using an asynchronous service
operation. This opens the OrderTicketWindow.xaml.vb file.
18. Add the following code in the AsyncType.ServiceAsync Select section, between the TODO comment
and the end of the section:
Dim asyncServiceProxy As New AsyncHallStateServiceClient(
"WS2007HttpBinding_IAsyncHallStateService")
seats = asyncServiceProxy.GetHallStateAsync(SelectedEvent.EventID)
ShowAvailableSeats(seats)
19. Save the OrderTicketWindow.xaml.vb file.
From the File menu, select Save OrderTicketWindow.xaml.vb.
Task 3: Test the Asynchronous client and service
1. Run the TicketingOffice.UI client.
In the Solution Explorer window, open the Client solution folder, right-click the
TicketingOffice.UI project, then select Debug, and then select Start new instance.
2. In the client's main window, click the Order a ticket button.
3. In the OrderTicketWindow window, open the shows list, select Othello, and then from the events list,
select the first event in the list.
L8-40 Lab 8: Advanced Topics

4. Click the Get hall state (Async client) button to view which seats are available. Examine the service
host console application outputyou should see the log message Running GetHallState on thread.
5. Return to the OrderTicketWindow window in the client application, and then click the Get hall state
(Async service) button. Examine the service host console application outputyou should see the log
messages Running BeginGetHallState on thread , and Running EndGetHallState on thread .
6. Close all the client application windows.
7. Close the SimpleServiceHost console window, and return to Visual Studio 2010.
Return to the SimpleServiceHost console window, press ENTER to stop the service host, and then
press ENTER again to close the console window.
Return to Visual Studio 2010.
Results: After this exercise, you will have implemented and used the asynchronous pattern in both the
client and the service.
Exercise 5: Implementing Workflow Services
Task 1: Open the workflow service project
1. Open the CreditPayment.xamlx file in the CreditCardPaymentService project.
In the Solution Explorer window, open the Services solution folder, then open the Payment
solution folder, and then open the CreditCardPaymentService project.
Double-click the CreditPayment.xamlx file to open it.
2. Verify that an empty workflow appears with a single sequence activity, and that the display name of
the activity is Credit Service.
Task 2: Add activities to the workflow
1. Add a ReceiveAndSendReply activity from the Messaging group into the sequence activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a ReceiveAndSendReply activity from the Messaging
group into the Sequence activity.
2. Rename the Receive activity to InitPayment.
Right-click the Receive activity, and then select Properties.
In the Properties window, set the OperationName property to InitPayment.
3. Drag an InvokeMethod activity from the Primitives group to between the Receive and the
SendReplyToReceive activities.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an InvokeMethod activity from the Primitives group to
between the Receive and the SendReplyToReceive activities.
4. In the new InvokeMethod activity, open the Properties window.
Right-click the new InvokeMethod activity, and then select Properties.

Lab 8: Advanced Topics L8-41

5. In the TargetObject property, type the following:
New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
6. In the MethodName property, type the following: IsPaymentTypeEnabled
7. In the Result property type the following: CreditEnabled
8. Click the ellipses () button in the Parameters collection text box to open the Parameters dialog
box, and complete the first row, and then click OK.
In the Direction column, select In.
In the Type column, select Browse for Types.
In the Type Name text box, type PaymentType, select the PaymentType from the tree, and
then click OK.
In the Value column, enter PaymentType.CreditCard.
Click OK to close the Parameters dialog box.

9. The workflow should display as follows:
L8-42 Lab 8: Advanced Topics


10. In the Receive activity, open the Properties window.
Right-click the Receive activity, and then select Properties.
11. Select the CanCreateInstance check box.
12. In the ServiceContractName, type: {http://Fabrikam.com/}ICreditCardPaymentService
13. In the SendReplyToReceive activity, open the Properties window.
Right-click the SendReplyToReceive activity, and then select Properties.

14. In the Properties window, click the ellipse () button in the Content field to open the Content
Definition dialog box.
15. In the Content Definition window, select Parameters.
16. Set the content to the following values:
Name: Results
Type: Boolean
Value: CreditEnabled
17. Click OK to close the Content Definition dialog box.
18. Add an If activity from the ControlFlow group after the sequence activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an If activity after the sequence activity from the
ControlFlow group.
19. In the If Activity, open the Properties window.
Lab 8: Advanced Topics L8-43
Right-click the If activity, and then select Properties.
20. In the Condition property, type CreditEnabled.

21. Add a ReceiveAndSendReply activity from the Messaging group into the Then area of the If
activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a ReceiveAndSendReply activity from the Messaging
group into the Then area of the If activity.
22. Add a Receive activity from the Messaging group, and drag it before the Receive activity that is
already inside the Then area of the If activity. Set the new activity OperationName to
ProvidePaymentDetails, and set the DisplayName to ProvidePaymentDetails.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop a Receive activity from the Messaging group before the
Receive activity that is already inside the Then area of the If activity.
Right-click the new Receive activity, and then select Properties.
L8-44 Lab 8: Advanced Topics

Set the OperationName to ProvidePaymentDetails.
Set the DisplayName to ProvidePaymentDetails.
23. Set the DisplayName of the second Receive activity inside the Then activity to PerformPayment,
and set the OperationName to PerformPayment.
Right-click the second Receive activity inside the Then activity, and select Properties.
Set the activity DisplayName to PerformPayment.
Set the OperationName to PerformPayment.
24. Update the display name of the SendReplyToReceive activity in the Then activity to
SendReplyToPerformPayment.
Right-click the second SendReplyToReceive activity inside the Then activity, and select
Properties.
Set the activity DisplayName to SendReplyToPerformPayment.

25. In both Receive activities, change the ServiceContractName to
{http://Fabrikam.com/}ICreditCardPaymentService.
Right-click the ProvidePaymentDetails receive activity inside the Then activity, and select
Properties.
Set the ServiceContractName to {http://Fabrikam.com/}ICreditCardPaymentService.
Right-click the PerformPayment receive activity inside the Then activity, and select Properties.
Set the ServiceContractName to {http://Fabrikam.com/}ICreditCardPaymentService.
26. Right-click the ProvidePaymentDetails activity, select Properties, and set the Content property as
follows:
Lab 8: Advanced Topics L8-45
In the Properties window, in the Content field, click the ellipses () button to open the Content
Definition dialog box.
In the Content Definition window, select Parameters.
Set the content to the following values:
For the Guid and Double types, select Browse for Types in the Type column, type the name
(Guid/Double) in the Type Name text box, select the required type from the tree, and then
click OK.
Name Type Assign To
OrderID Guid OrderID
CustomerID Guid PayingCustomerID
Amount Double Amount
CreditCardNumber String CreditCard



Click OK to close the Content Definition dialog box.
Note: After browsing for a parameter type, some types may appear with their full namespace. For
example, Guid might display as System.Guid.
27. Right-click the SendReplyToPerformPayment activity, and then select Properties.
28. Set the content property as follows:
In the Properties window, in the Content field, click the ellipses () button to open the Content
Definition dialog box.
In the Content Definition window, select Parameters.
L8-46 Lab 8: Advanced Topics

Set the content to the following values:
For the Payment type, select Browse for Types in the Type column, type Payment in the
Type Name text box, and then select the Payment type from the tree.
Name Type Value
PaymentResult Payment PaymentResult


29. Click OK to close the Content Definition dialog box.
30. Add an InvokeMethod activity from the Primitives group between the PerformPayment activity
and the SendReplyToPerformPayment activity.
Open the View menu, and then select Toolbox.
In the Toolbox window, drag and drop an InvokeMethod activity from the Primitives group
between the PerformPayment activity and the SendReplyToPerformPayment activity.
31. In the InvokeMethod activity, set the properties.
Right-click the InvokeMethod activity, and then select Properties.
Set the value of the properties as follows:
TargetObject: New TicketingOffice.PaymentService.BusinessLogic.PaymentManager
MethodName: PayForOrder
Result: PaymentResult
32. In the Properties window, in the Parameters field, click the ellipses () button, add the following
parameters, and then click OK:
Direction Type Value
In Guid OrderID
In Guid PayingCustomerID
In Double Amount
Lab 8: Advanced Topics L8-47
Direction Type Value
In PaymentType PaymentType.CreditCard
In String CreditCard
33. Save the CreditPayment.xamlx file.
From the File menu, select Save CreditPayment.xamlx.
34. Rebuild the project.
In the Solution Explorer window, open the Services solution folder, and then open the Payment
solution folder.
Right-click CreditCardPaymentService project, and then select Rebuild.
Task 3: Deploy the CreditCardPayment service to AppFabric using a deployment
package
1. Create a Deployment package for the CreditCardPaymentService project.
Open the View menu, and then select Solution Explorer.
In the Solution Explorer window, open the Services solution folder.
Open the Payment solution folder, right-click the CreditCardPaymentService project, and
select Build Deployment Package.
2. Open the IIS Manager.
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
3. Import the package that you have created to the Default Web Site, and name it
FabrikamTicketingCreditPayment.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the Actions pane (the right pane), select Import Application.
In the Import Application Package dialog box, enter the following location for the package
path, and then click Next:
D:\LabFiles\Starter\M08\VB\Services\Payment\CreditCardPaymentService\obj\Debug\Pac
kage\CreditCardPaymentService.zip.
In the Select the Contents of the Package step of the Import Application Package wizard, click
Next.
In the Enter Application Package Information step of the Import Application Package wizard,
set the Application Path to FabrikamTicketingCreditPayment, and then click Next.
If a message displays asking whether to run the application in the default Microsoft .NET 4.0
application pool, click Yes.
In the Installation Progress and Summary step of the Import Application Package wizard, wait
for the process to complete, and then click Finish.
4. Close the IIS Manager.
Task 4: Test the CreditCardPayment workflow service
1. Start the WcfTestClient utility from the D:\LabFiles folder.
L8-48 Lab 8: Advanced Topics

Click Start, and then click Computer.
Open drive D, and then navigate to the LabFiles folder.
Double-click the WcfTestClient shortcut.
2. Add the CreditPayment service, using the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx.
In the WcfTestClient utility, open the File menu, and then select the Add Service option.
In the Add Service dialog box, enter the address
http://localhost/FabrikamTicketingCreditPayment/CreditPayment.xamlx, and then click OK.
3. Call the InitPayment operation to test the workflow service.
In the My Service Projects tree, double-click the InitPayment operation.
Click Invoke, and if a security warning appears, click OK.
4. After receiving a response, close the Windows Communication Foundation (WCF) Test Client.
5. Open the IIS Manager
Click Start, click Administrative Tools, and then click Internet Information Services (IIS)
Manager.
6. In the IIS console, open AppFabric Dashboard.
From the Connections tree (the left pane), select 10263A-SVR1 (10263A-
SVR1\Administrator), then select Sites, and then select Default Web Site.
In the AppFabric category, double-click AppFabric Dashboard.
7. Examine the WF Instance History section, and notice that the CreditPayment.xamlx is activated.
8. Close the IIS Manager.
Results: After this exercise, you will have created a workflow service that executes the process of credit
card payment, and then tested it.

Potrebbero piacerti anche