PUBLISHED BY Microsoft Press A Division of Microsoft Corporation One Microsoft Way Redmond, Washington 98052-6399 Copyright © 2007 by GrandMasters, LLC and Mark Blomsma All rights reserved. No part of the contents of this book may be reproduced or transmitted in any form or by any means without the written permission of the publisher. Library of Congress Control Number 2006932074 ISBN-13: 978-0-7356-2332-3 ISBN-10: 0-7356-2332-5 Printed and bound in the United States of America. 1 2 3 4 5 6 7 8 9 QWT 1 0 9 8 7 6 Distributed in Canada by H.B. Fenn and Company Ltd. A CIP catalogue record for this book is available from the British Library. Microsoft Press books are available through booksellers and distributors worldwide. For further information about international editions, contact your local Microsoft Corporation office or contact Microsoft Press International directly at fax (425) 936-7329. Visit our Web site at www.microsoft.com/mspress. Send comments to
[email protected]. Microsoft, Microsoft Press, Active Directory, BackOffice, BizTalk, Excel, IntelliSense, Internet Explorer, MSDN, MSN, Visual Basic, Visual C#, Visual J#, Visual SourceSafe, Visual Studio, Windows, Windows Mobile, Windows NT, Windows Server, and WinFX are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Other product and company names mentioned herein may be the trademarks of their respective owners. The example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious. No association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred. This book expresses the author’s views and opinions. The information contained in this book is provided without any express, statutory, or implied warranties. Neither the authors, Microsoft Corporation, nor its resellers, or distributors will be held liable for any damages caused or alleged to be caused either directly or indirectly by this book. Acquisitions Editor: Ken Jones Project Editor: Maureen Williams Zimmerman Editorial Production: nSight, Inc. Copy Editor: Teresa Horton Technical Reviewer: Jim Fuchs Indexer: Lucie Haskins Body Part No. X12-48725
Dedication
For my best friend —Sara Morgan
To my mom and dad, Carole and Walter. And to the other two most important people in my life, Kim and Sara. —Bill Ryan
For Patricia, Nashly, Abbi, and London —Shannon Horn
For my angel, Belina; and my family, Greta, Tim, and Jerri, who have always been there for me. I love you all so much. —Murray Gordon
About the Authors Sara Morgan Sara Morgan, MCSD, MCDBA, is an independent author and consultant located in Baton Rouge, Louisi ana. She specializes in developing leading-edge Webbased applications utilizing Microsoft technologies. Since graduating from Louisiana State University in 1993 with a degree in quantitative business analysis, she has been developing software for a variety of indus tries, including a not-for-profit hospital, a financial com pany offering mortgages, a major retailer, a software company that writes legislative software, and an Application Service Provider. In 1998, she wrote an article on stress-testing Web sites, which was featured on the front cover of MSDN Magazine, formerly named Microsoft Interactive Developer (MIND). Since then, she has written articles featured in Enterprise Development, .NET Development, Visual Studio Magazine and DevX.com. To reference the articles Sara Morgan has written, refer to http://www.custsolutions.net. This Web site also fea tures her latest research efforts and is a good resource for readers who want to learn more about enhanced computing.
Bill Ryan Bill Ryan is a consultant with Magenic Technologies in its Atlanta office. Bill is a Microsoft MVP in the Windows Embedded category. Bill is also the coauthor of Pro fessional ADO.NET 2 and Professional WinFX Beta, both by Wrox Press. Bill is a fre quent speaker at events such as Microsoft Code Camps, Speech Server Days, and .NET User’s Groups. He also runs two .NET-focused Web sites, www.devbuzz.com and www.knowdotnet.com.
v
vi
About the Authors
Mark Blomsma Mark Blomsma is a software architect and owner of his own business, Develop-One (www.develop-one.com). A frequent speaker and writer of articles for a variety of magazines, he specializes in Microsoft .NET technology, enterprise application development, application integra tion, and software renovation. Visit his blog at http:// blog.develop-one.com.
Shannon Horn Shannon speaks and trains for companies such as Microsoft, AppDev, Carrig Learn ing, WestLake Internet Training, LearnIt, Accelebrate, Webucator, and Hands on Technology Transfer and has been a featured speaker on training videos with LearnKey. He has also worked with large corporate clients including Microsoft, Universal Studios, MGM Studios, Monster.com/FlipDog.com, Intel, Polygram Pictures, Pruden tial, Micro Accounting Systems, Sky Harbor International Airport, and Evans Newton, Inc., on projects utilizing Microsoft technologies such as Visual FoxPro, Visual Stu dio.NET, C#, ADO.NET, and ASP.NET. Shannon is currently pursuing his seconddegree black belt in tae kwon do (Kukkiwon / WTF 2nd Dan) through Grand Master Won Ki Hong and Master Choi (http://www.masterhong.com). Shannon has been playing electric bass guitar since he was young and plays weekly in multiple bands in the large church he attends in Peoria, Arizona (http://www.lighthouseaz.com). Physical fitness is a major part of Shannon’s life, and he lives for his kids! You can find out more about Shannon by visiting http://shannonhorn.spaces.live.com/.
Olof Nyström Olof is a senior software developer and Microsoft trainer at RBAM AB, a professional software company located in Sweden. Olof is a Microsoft Certified Trainer and spe cializes in distributed .NET development. He is a frequent speaker at many local sem inars in Sweden and currently does most of his teaching for Sweden’s largest CPLS.
About the Authors
vii
Murray Gordon Murray Gordon is the Director of Technology at Cambar
Solutions (www.cambarsolutions.com), a consultation ser
vices and custom supply chain software company to many
of the world’s largest distribution companies. Murray
actively consults on legacy modernization to the world’s
leading distribution companies. His vision is to transform
rigid, heavily customized IT environments into flexible,
adaptive environments that are competitive with contem
porary enterprise solutions. This vision embraces a
respect for and the preservation of his client’s differentiat
ing competitive practices, using phased transformation
roadmaps that are governed by their business priorities.
Murray has led consulting engagements for development, implementation, operation, and support of mission-critical systems in food, healthcare, petroleum, finance, man ufacturing, and retail sales. He has been an active contributor to the evolution of dis tributed computing architectures since 1994. His most recent efforts have been in Legacy Host Integration, Service Oriented Architecture, User Interface Modernization to Smart Clients and Thin Clients, E-Commerce (B2B and B2C), Internet/Intranet Portals and Reporting Systems, Warehouse Management Systems, Order Manage ment Systems and Data Warehousing, and Transaction Processing Solutions. Murray is a frequent speaker at events such as Microsoft Code Camps and .NET User’s Groups. He is the President of the Greater Charleston .NET User’s Group (www.gcnug.org) in Charleston, South Carolina.
Scott Allen Scott Allen has 14 years of experience in delivering commercial software on platforms as diverse as 8-bit embedded firmware to highly scalable Web applications. Scott is a Microsoft MVP and currently focuses on development with the .NET Framework. He has published books with Wrox Press and Packt Publishing, and he has published articles with MSDN Magazine, Dr. Dobb’s Journal, and Windows Developer Maga zine. Scott speaks at national conferences and regional user groups. Scott is a founder of OdeToCode.com and writes regularly for his blog, which can be found at http:// www.OdeToCode.com/blogs/scott.
Contents at a Glance
1
Creating an XML Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2
Extending XML Web Services with SOAP Formatting,
Custom Headers, and Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3
Configuring and Publishing XML Web Services . . . . . . . . . . . . . . . . . . . . 91
4
Creating a Remoting Server Application . . . . . . . . . . . . . . . . . . . . . . . . . 125
5
Creating a Remoting Client Application. . . . . . . . . . . . . . . . . . . . . . . . . . 167
6
Debugging and Deploying Remote Applications . . . . . . . . . . . . . . . . . . 219
7
Method Invocations and Event Management
with .NET Web Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
8
Method Invocations and Event Management
with .NET Remoting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
9
Web Services Enhancements 3.0 in Client and
Server Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
10
WSE Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
11
Messaging and Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
12
Creating Serviced Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
13
Serviced Component Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
ix
Table of Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvii Hardware Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvii Software Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxviii Installing SQL Server 2005 Express . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxx Installing the Adventure Works Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxi Using the CD and DVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxi How to Install the Practice Tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxii How to Use the Practice Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxii Microsoft Certified Professional Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxiv Technical Support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxiv Foundation Edition Software Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxxv
1
Creating an XML Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
Lesson 1: How to Create a Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3
What Is a Web Service? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3
How to Create a New Web Service Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
The WebMethods Framework. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
Lab 1: Creating a Web Service Project Using Visual Studio . . . . . . . . . . . . . . . . .11
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
Lesson 2: How to Create a Web Service Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15
Applying the WebMethod Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15
Configuring a Web Service Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16
Creating a One-Way Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
Lab 2: Creating a Public Web Service Method . . . . . . . . . . . . . . . . . . . . . . . . . . .20
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23
What do you think of this book? We want to hear from you!
Microsoft is interested in hearing your feedback about this publication so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit: www.microsoft.com/learning/booksurvey/
xi
xii
Contents
Lesson 3: How to Test and Consume a Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Testing Your Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Consuming a Web Service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Lab 3: Testing and Consuming a Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Case Scenario 1: Deciding to Use Web Services . . . . . . . . . . . . . . . . . . . . . . . . . 34
Case Scenario 2: Testing your Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2
Extending XML Web Services with SOAP Formatting,
Custom Headers, and Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Lesson 1: How to Configure SOAP Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Configuring SOAP Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Customizing SOAP Messages with XML Serialization . . . . . . . . . . . . . . . . . . . . . 49
Lab 1: How to Configure SOAP Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Lesson 2: How to Implement SOAP Headers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
What Is a SOAP Header? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Adding a Custom SOAP Header Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Building a Client that Processes the SOAP Header . . . . . . . . . . . . . . . . . . . . . . . 60
How to Handle Unknown SOAP Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Lab 2: How to Implement a Custom SOAP Header. . . . . . . . . . . . . . . . . . . . . . . 63
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Lesson 3: How to Implement SOAP Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
What Is a SOAP Extension? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Contents
xiii
Creating a Custom SOAP Extension Class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74
Configuring the SOAP Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .78
Lab 3: How to Implement a Custom SOAP Extension . . . . . . . . . . . . . . . . . . . . .80
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .85
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .85
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .87
Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .87
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .88
Case Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .88
Case Scenario 1: Creating a Custom SOAP Header . . . . . . . . . . . . . . . . . . . . . . .88
Case Scenario 2: Creating a SOAP Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . .88
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .89
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .89
3
Configuring and Publishing XML Web Services . . . . . . . . . . . . . . . . . . . . 91
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .92
Lesson 1: How to Manage State in a Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93
Using the Application Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93
Using the Session Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95
Handling Session State on the Client with Cookies . . . . . . . . . . . . . . . . . . . . . . .96
Performance Implications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99
Lab 1: Using the Session Object to Maintain State in a Web Service . . . . . . . . .99
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Lesson 2: How to Configure a Web Service Application. . . . . . . . . . . . . . . . . . . . . . 104
Using a Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Using the Machine.config File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Configuring the Session State Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Lab 2: Configuring a Web Service Application . . . . . . . . . . . . . . . . . . . . . . . . . 109
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Lesson 3: How to Deploy and Publish a Web Service . . . . . . . . . . . . . . . . . . . . . . . . 112
Publishing Your Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Using a Static Discovery File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
xiv
Contents
Using a Dynamic Discovery File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Deploying a Web Service Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Lab 3: Deploying a Web Service Using a Web Setup Project . . . . . . . . . . . . . 117
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Case Scenario 1: Creating a Session Variable to Store the
Selected Vendor ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Case Scenario 2: Creating a Custom Service Help Page for
All Your Web Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Case Scenario 3: Creating Setup Projects to Deploy Your
Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4
Creating a Remoting Server Application. . . . . . . . . . . . . . . . . . . . . . . . . 125
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Lesson 1: Remoting Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
What Is Remoting? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Types of Remote Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Hosting a Remote Server Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Activating Your Remote Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Selecting a Communication Channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Marshal-by-Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Creating a Remote Server Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Lab 1: Creating a Remote Server Application. . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Lesson 2: How to Configure a Server Application Programmatically . . . . . . . . . . . 141
Specifying the Name of the Server Application. . . . . . . . . . . . . . . . . . . . . . . . . 142
Registering the Remote Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Contents
xv
Configuring Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Registering a Communication Channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Lab 2: How to Configure a Remote Server Application
Programmatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Lesson 3: How to Configure a Server Application with a Configuration File. . . . . 152
Creating a Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
The Application Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Configuring Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Configuring Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Configuration Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Lab 3: How to Configure a Server Application Using a
Configuration File. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Case Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Case Scenario 1: Suggesting a Distributed Technology . . . . . . . . . . . . . . . . . 165
Case Scenario 2: Using a Configuration File to Configure
Your Remoting Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
5
Creating a Remoting Client Application. . . . . . . . . . . . . . . . . . . . . . . . . . 167
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Lesson 1: Creating a Client Application to Access a Remote Object. . . . . . . . . . . . 169
How to Create a Client Instance of a Remote Object . . . . . . . . . . . . . . . . . . . . 169
How to Configure a Client Application Programmatically . . . . . . . . . . . . . . . 171
Lab 1: Creating a Client Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
xvi
Contents
Lesson 2: How to Configure a Client Application Using a Configuration File . . . . 193
Configuring the Communication Channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Configuring the Activation Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Lab 2: Creating a Client Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Lesson 3: How to Access a Remote Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Lab 3: How to Access a Remote Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Case Scenario 1: Creating a Secure Globally Distributed Application . . . . . . 215
Case Scenario 2: Improving the Remoting Client Using Interfaces . . . . . . . . 216
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
6
Debugging and Deploying Remote Applications . . . . . . . . . . . . . . . . . 219
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Lesson 1: How to Deploy a Remoting Application . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
.NET Remoting Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Hosting Remote Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Deploying Remote Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Creating a Web Setup Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Lab 1: Creating and Installing a Web Setup Project . . . . . . . . . . . . . . . . . . . . . 235
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Lesson 2: How to Debug a Remoting Application . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Visual Studio 2005 Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
The RemotingException Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Using Performance Counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
.NET Remoting Tracking Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
Contents
xvii
Lab 2: Debugging a Remoting Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Lesson 3: How to Manage the Lifetime of Remote Objects . . . . . . . . . . . . . . . . . . . 255
Lab 3: Managing the Lifetime of Remote Objects. . . . . . . . . . . . . . . . . . . . . . . 261
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Case Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Case Scenario 1: Tracking and Improving the Performance
of a Distributed Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Case Scenario 2: Simplifying Remote Object Deployment . . . . . . . . . . . . . . . 265
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
7
Method Invocations and Event Management
with .NET Web Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Lesson 1: Calling Web Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Calling a Web Method Synchronously . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Calling a Web Method Asynchronously . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Lab 1: Calling a Web Method. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Lesson 2: Polling Web Methods for Completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Polling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Begin and IAsyncResult . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Lab 2: Calling a Web Method Asynchronously . . . . . . . . . . . . . . . . . . . . . . . . . 290
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
xviii
Contents
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Case Scenario 1: Exposing Functionality Through .NET Web Services . . . . . 296
Case Scenario 2: Refining the Use of Web Services . . . . . . . . . . . . . . . . . . . . . 298
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
8
Method Invocations and Event Management
with .NET Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Lesson 1: Calling Remoting Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
Calling a Remoting Method Synchronously . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
Stateless Invocation Using One-Way Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Calling a Remoting Method Asynchronously . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Lab 1: Invoking a Remoting Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Lesson 2: Callbacks and Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
Polling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
Determining Whether an Asynchronous Call Has Finished . . . . . . . . . . . . . . . 320
Polling for Completion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
Polling Using a Callback Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Lab 2: Calling a Remoting Method Asynchronously . . . . . . . . . . . . . . . . . . . . . 327
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Lesson 3: Implementing and Responding to Events . . . . . . . . . . . . . . . . . . . . . . . . . 336
Handled Remote Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Lab 3: Handle Events from a Remote Object . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Contents
xix
Case Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
Case Scenario 1: Building Robust, Scalable Enterprise Applications . . . . . . . 348
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
9
Web Services Enhancements 3.0 in Client and
Server Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
Lesson 1: Enabling and Referencing WSE 3.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Adding References to WSE Assemblies in Client Applications . . . . . . . . . . . . 356
Inheriting from the WebServicesClientProtocol Class . . . . . . . . . . . . . . . . . . . . 358
Editing the Proxy Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
Lab 1: Adding WSE 3.0 to a Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
Lesson 2: Using soapExtensionTypes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
Configuration File Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
Adding a Child Element with the Element . . . . . . . . . . . . . . . . . . . . . . 369
Specifying a Priority . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Specifying a Group. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Lab 2: Creating a Class That Inherits from WebServicesClientProtocol. . . . . . 370
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Lesson 3: Using Digital Signatures to Ensure Message Integrity . . . . . . . . . . . . . . . 379
Digital Signature Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
X.509 Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
Kerberos Token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
UserNameToken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
Lab 3: Creating a Policy for Digital Signatures. . . . . . . . . . . . . . . . . . . . . . . . . . 383
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
xx
Contents
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
Case Scenario 1: Where Does WSE Fit into My Application
Development Strategy? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
Case Scenario 2: Refining the Process?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
10
WSE Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
Lesson 1: Web Service Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
Creating a Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
Using a Policy File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Lab 1: Configuring Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
Lesson 2: Custom Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Basic Encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Creating a Custom Policy Assertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
Encryption with a Security Token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Decryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
Using a Security Token Issuing Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
Lab 2: Signing and Encrypting a Message Exchange
Using Custom Policy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Lesson 3: Message Filters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Message Filters Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
Implementation and Migration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Lab 3: Creating a Custom Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Contents
xxi
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
Case Scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
Case Scenario 1: How Secure Is Secure Enough? . . . . . . . . . . . . . . . . . . . . . . . 452
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
11
Messaging and Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Lesson 1: How to Configure WSE Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
WSE Soap Messaging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Selecting a Communication Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
Implementing One-Way Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
Implementing Two-Way (Bidirectional) Messaging . . . . . . . . . . . . . . . . . . . . . 463
Sending Attachments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
Lab 1: Data Transfer with MTOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
Lesson 2: How to Create a WSE Router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
What Is a WSE Router? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
Creating a WSE Router Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
Configuring the WSE Router Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484
Configuring a Referral Cache for Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
Lab 2: Creating a WSE Router. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
Lesson 3: How to Add and Verify Security Credentials . . . . . . . . . . . . . . . . . . . . . . . 494
Why Add Security Credentials? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
Adding Security Credentials Using an X.509 Certificate . . . . . . . . . . . . . . . . . 494
Other Security Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
Verifying the Security Credential . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
Lab 3: Adding Security to Your WSE Router. . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
Chapter Review. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
xxii
Contents
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
Case Scenario 1: Performing a Server Upgrade . . . . . . . . . . . . . . . . . . . . . . . . 506
Case Scenario 2: Selecting a Security Method for Your WSE Router . . . . . . . 506
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
Implement WSE SOAP Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
Route SOAP Messages by using a WSE Router . . . . . . . . . . . . . . . . . . . . . . . . . 507
Add and Verify Security Credentials. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
12
Creating Serviced Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Lesson 1: Serviced Component Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
COM+ Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
Creating a Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
Register a Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521
Adding Attributes to a Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . . . 525
Implementing Security on a Serviced Component . . . . . . . . . . . . . . . . . . . . . . 537
Services Without Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
System.Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
Lab 1: Building a Simple Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . 546
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553
Lesson 2: Consuming the Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
Referencing the Assembly that Contains the Component . . . . . . . . . . . . . . . . 555
Declaring and Instantiating the Component . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
Access Properties, Methods, and Events of the Component . . . . . . . . . . . . . . 557
Lab 2: Using the Serviced Component in a Separate Application . . . . . . . . . 558
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
Contents
xxiii
Case Scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562
Case Scenario 1: Reliability Through Transactions . . . . . . . . . . . . . . . . . . . . . . 562
Case Scenario 2: Optimizing Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
Create, Configure, and Access a Serviced Component . . . . . . . . . . . . . . . . . . 563
Implement Security in a Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . . 564
Using Automatic Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
13
Serviced Component Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Before You Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
Lesson 1: Message Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Message Queuing Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Setting Up a Message Queue. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
Sending a Message to a Message Queue. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577
Reading a Message from a Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
Deleting a Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588
Sending and Receiving a Message Asynchronously . . . . . . . . . . . . . . . . . . . . . 588
Sending and Receiving a Message Synchronously . . . . . . . . . . . . . . . . . . . . . . 588
Listening to a Queue Asynchronously. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
Sending Objects Using Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
Sending a Message Using Queued Components . . . . . . . . . . . . . . . . . . . . . . . 595
Setting Permissions on a Message Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
Peeking and Enumerating Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
Correlating Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
Rules and Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610
Lab 1: Creating a Message and Sending It to a Queue . . . . . . . . . . . . . . . . . . 610
Lesson Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
Lesson 2: Securing Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
Signing a Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
Validating a Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 627
Encrypting a Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
xxiv
Contents
Lab 2: Encrypting a Message and Verifying Its Authenticity
After Transmission. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
Lesson Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
Lesson Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
Chapter Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
Chapter Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
Key Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
Case Scenarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
Case Scenario 1: Online Shop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
Case Scenario 2: Batches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Suggested Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Create, Delete, and Set Permissions on a Message Queue. . . . . . . . . . . . . . . . 642
Send and Receive Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
Sign and Encrypt Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
Take a Practice Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
Glossary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
What do you think of this book? We want to hear from you!
Microsoft is interested in hearing your feedback about this publication so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit: www.microsoft.com/learning/booksurvey/
Acknowledgments
The authors of this book would like to gratefully acknowledge Lisa Kreissler from GrandMasters LLC, Maureen Zimmerman from Microsoft, and Ken Jones from Microsoft. In addition, the authors would like to thank the following people.
Bill Ryan This isn’t an easy acknowledgment to write because there are so many people who deserve my eternal gratitude. First I’d like to thank Laura Sackerman, Maureen Zim merman, and Ken Jones at Microsoft for helping me out so much along the way. You are a true joy to work with. I’d like to thank our technical editor, Jim Fuchs, for work ing so hard and providing such helpful feedback. I’d like to thank Lisa Kreissler, Derek Moore, and everyone at GrandMasters for being so supportive and helpful. Next I’d like to thank Magenic for providing a great work environment, which allowed me to take on such a project (and a special thanks to Chris Winland for being the coolest guy I’ve partnered with on a project). To all the readers of the 70-536 book, Mohammad Ali Khankan in particular, for providing all the invaluable feedback that you did, I’d like to say thank you, as well. Finally, I’d like to thank Herb Sewell, the Bellhaven family, Vernon Dozier, Chris Norton, Phil what’s his name, for keeping me smiling all year.
Mark Blomsma I’d like to thank Maurice de Beijer and Frank Boyne for their help while writing some of the materials for this book. Thanks guys!
xxv
Introduction
This training kit is designed for software developers who plan to take the Microsoft Certified Technology Specialist (MCTS) exam 70-529: Distributed Application Devel opment with the .NET Framework 2.0. The primary objective of this exam is to certify that developers know how to create and implement distributed applications using the .NET Framework 2.0. We assume that, before you begin using this kit, you have a working knowledge of application development with Microsoft Visual Studio 2005 and that you understand basic programming concepts such as object-oriented pro gramming. We also assume that you have a working knowledge of relational data bases and the use of Transact-SQL to query databases for information. Specifically, this training kit uses the Microsoft SQL Server 2005 Express Edition, which is avail able as a free download from Microsoft’s Web site. By using this training kit, you will learn how to: ■
Create and access XML Web services.
■
Configure and customize a Web service application.
■
Create, configure, and deploy remoting applications.
■
Implement asynchronous calls and remoting events.
■
Implement Web Services Enhancements (WSE) 3.0.
■
Create and access a serviced component and use message queueing.
Hardware Requirements We recommend that you use a computer that is not your primary workstation to do the practice exercises in this book because you will make changes to the operating sys tem and application configuration. You might also need to make security changes that will make your workstation vulnerable to security violations. The following hardware is required to complete the practice exercises: ■
Personal computer with a 600-Mhz Pentium III compatible or faster processor (1 GHz or faster recommended)
■
512 MB RAM or more (1 GB or more recommended)
■
600 MB free hard disk space (1 GB or more recommended)
xxvii
xxviii
Introduction
■
CD-ROM drive or DVD-ROM drive
■
Super VGA (1,024 × 768) or higher resolution video adapter and monitor
■
Keyboard and Microsoft Mouse, or compatible pointing device
Software Requirements The following software is required to complete the practice exercises. You need Visual Studio 2005 and SQL Server 2005 Express to complete the labs included with each chapter. Although these products can be installed on a production server, that is not recommended. It would be best to install these products and execute the labs in each chapter on a single development machine. ■
One of the following operating systems: ❑
Microsoft Windows 2000 Professional Service Pack 4
❑
Microsoft Windows 2000 Server Service Pack 4
❑
Microsoft Windows 2000 Advanced Server Service Pack 4
❑
Microsoft Windows 2000 Datacenter Server Service Pack 4
❑
Microsoft Windows XP Professional x64 Edition (WOW)
❑
Microsoft Windows XP Professional Service Pack 2
❑
Microsoft Windows XP Home Edition Service Pack 2
❑
Microsoft Windows XP Media Center Edition 2002 Service Pack 2
❑
Microsoft Windows XP Media Center Edition 2004 Service Pack 2
❑
Microsoft Windows XP Media Center Edition 2005
❑
Microsoft Windows XP Tablet PC Edition Service Pack 2
❑
Microsoft Windows Server 2003, Standard Edition Service Pack 1
❑
Microsoft Windows Server 2003, Enterprise Edition Service Pack 1
❑
Microsoft Windows Server 2003, Datacenter Edition Service Pack 1
❑
Microsoft Windows Server 2003, Web Edition Service Pack 1
❑
Microsoft Windows Server 2003, Standard x64 Edition Service Pack 1 (WOW)
❑
Microsoft Windows Server 2003, Enterprise x64 Edition Service Pack 1 (WOW)
Introduction
■
xxix
❑
Microsoft Windows Server 2003, Datacenter x64 Edition Service Pack 1 (WOW)
❑
Microsoft Windows Server 2003 R2, Standard Edition
❑
Microsoft Windows Server 2003 R2, Standard x64 Edition (WOW)
❑
Microsoft Windows Server 2003 R2, Enterprise Edition
❑
Microsoft Windows Server 2003 R2, Enterprise x64 Edition (WOW)
❑
Microsoft Windows Server 2003 R2, Datacenter Edition
❑
Microsoft Windows Server 2003 R2, Datacenter x64 Edition (WOW)
❑
Microsoft Windows Vista
Microsoft Visual Studio 2005 (A 180-day Evaluation Edition is available for free download from the MSDN Web site at http://msdn.microsoft.com/vstudio/. A 90 day Evaluation Edition of Visual Studio 2005 Professional Edition is included on the DVD with this book.) IMPORTANT
Evaluation edition is not the full retail product
The 90-day evaluation edition of Microsoft Visual Studio 2005 Professional Edition provided with this training kit is not the full retail product and is provided only for the purposes of training and evaluation. Microsoft and Microsoft Technical Support do not support this eval uation edition. Information about any issues relating to the use of this evaluation edition with this training kit is posted to the Support section of the Microsoft Press Web site (www.microsoft.com/learning/ support/books/). For information about ordering the full version of any Microsoft software, please call Microsoft Sales at (800) 426-9400 or visit www.microsoft.com. ■
Microsoft SQL Server 2005 Express Edition (This is available for free down load from the MSDN Web site at http://msdn.microsoft.com/vstudio/express/ sql/default.aspx.)
■
Adventure Works database (This is available as a separate download with the SQL Server 2005 samples at http://msdn.microsoft.com/vstudio/express/sql/default.aspx.)
■
Microsoft Internet Explorer 6.0, Service Pack 1 or later
■
Microsoft Internet Information Services (IIS) 5.0 or later
xxx
Introduction
Installing SQL Server 2005 Express SQL Server 2005 offers a free download Express Edition of its product. The Express Edition is required to run some of the code samples provided in this book. To down load and install this product, use the following instructions: 1. Browse to the link at http://msdn.microsoft.com/vstudio/express/sql/default.aspx and click Download Now. 2. Read and follow the instructions on the download page to download the SQL Server 2005 Express Edition Service Pack 1. You do not need to download the SQL Server Management Studio Express product. 3. Once the install executable has been downloaded to your local machine, execute the downloaded file (Sqlexpr.exe) to extract the setup files to your local devel opment machine. 4. Select the I Accept The Licensing Terms And Conditions check box and click Next to continue the installation. 5. In the Installing Prerequisites dialog box, click Install. Once complete, click Next to continue. 6. The installation then performs a system configuration check. In the Welcome dialog box, click Next to begin the installation. 7. Once the System Configuration Check is complete, click Next. 8. Enter name and company information in the Registration Information dialog box and click Next to continue. 9. In the Feature Selection dialog box, click Next to accept the defaults. 10. In the Instance Name dialog box, click Next to accept the defaults. 11. In the Logon Information dialog box, click Next to accept the defaults. 12. In the Error And Usage Report Settings dialog box, click Next to accept the defaults. 13. In the Ready To Install dialog box, click Install and wait for the installation to complete. 14. You now have to download and install the Adventure Works database, which is referenced in some of the chapter labs.
Introduction
xxxi
Installing the Adventure Works Database Adventure Works is a fictional retailer, and you can download and install a sample database that is referenced in some of the labs for this book. To install the sample database, execute the following instructions: 1. Browse to the link at http://msdn.microsoft.com/vstudio/express/sql/default.aspx and click Download Now. 2. Select the SQL Server 2005 Samples download and follow the instructions on the download page to save the case-insensitive collation DB installation package (AdventureWorksDBCI.msi) to your local development machine. 3. Once the installation package has finished downloading, double-click the exe cutable file to execute the installer. 4. In the Welcome dialog box, click Next. 5. Select the I Accept The Terms In The License Agreement check box and in the License Agreement dialog box, click Next. 6. In the Destination Folder dialog box, click Next to accept the defaults. 7. In the Ready To Install dialog box, click Install. 8. In the Wizard Completed dialog box, click Finish.
Using the CD and DVD A companion CD and an evaluation software DVD are included with this training kit. The companion CD contains the following: You can reinforce your understanding of how to develop .NET Framework 2.0 distributed applications by using electronic practice tests you customize to meet your needs from the pool of Lesson Review questions in this book. Or you can practice for the 70-529 certification exam by using tests cre ated from a pool of about 300 realistic exam questions, which is enough to give you many different practice exams to ensure that you’re prepared.
■ Practice tests
Most chapters in this book include sample files associated with the lab exercises at the end of every lesson. For some exercises, you will be instructed to open a project prior to starting the exercise. For other exercises, you will create a project on your own and be able to reference a completed project on the CD in the event you experience a problem following the exercise.
■ Code
xxxii
Introduction
An electronic version (eBook) of this book is included for times when you don’t want to carry the printed book with you. The eBook is in Portable Doc ument Format (PDF), and you can view it by using Adobe Acrobat or Adobe Reader.
■ eBook
The evaluation software DVD contains a 90-day evaluation edition of Visual Studio 2005 Professional Edition, in case you want to use it with this book.
How to Install the Practice Tests To install the practice test software from the companion CD to your hard disk, do the following: 1. Insert the companion CD into your CD drive, and accept the license agreement. A CD menu appears. NOTE
If the CD menu doesn’t appear
If the CD menu or the license agreement doesn’t appear, AutoRun might be disabled on your computer. Refer to the Readme.txt file on the CD-ROM for alternate installation instructions.
2. Click the Practice Tests item, and follow the instructions on the screen.
How to Use the Practice Tests To start the practice test software, follow these steps: 1. Click Start, All Programs, Microsoft Press Training Kit Exam Prep. A window appears that shows all the Microsoft Press training kit exam prep suites installed on your computer. 2. Double-click the lesson review or practice test you want to use. NOTE
Lesson reviews vs. practice tests
Select the (70-529) Microsoft .NET Framework 2.0–Distributed Application Development lesson review to use the questions from the “Lesson Review” sections of this book. Select the (70-529) Microsoft .NET Framework 2.0–Distributed Application Development practice test to use a pool of about 300 questions similar to those in the 70-529 certification exam.
Lesson Review Options When you start a lesson review, the Custom Mode dialog box appears so that you can configure your test. You can click OK to accept the defaults, or you can customize the
Introduction
xxxiii
number of questions you want, how the practice test software works, which exam objectives you want the questions to relate to, and whether you want your lesson review to be timed. If you’re retaking a test, you can select whether you want to see all the questions again or only those questions you missed or didn’t answer. After you click OK, your lesson review starts. ■
To take the test, answer the questions and use the Next, Previous, and Go To but tons to move from question to question.
■
After you answer an individual question, if you want to see which answers are correct—along with an explanation of each answer—click Explanation.
■
If you’d rather wait until the end of the test to see how you did, answer all the questions and then click Score Test. You’ll see a summary of the exam objectives you chose and the percentage of questions you got right overall and per objec tive. You can print a copy of your test, review your answers, or retake the test.
Practice Test Options When you start a practice test, you choose whether to take the test in Certification Mode, Study Mode, or Custom Mode: Closely resembles the experience of taking a certification exam. The test has a set number of questions, it’s timed, and you cannot pause and restart the timer.
■ Certification Mode
Creates an untimed test in which you can review the correct answers and the explanations after you answer each question.
■ Study Mode
Gives you full control over the test options so that you can cus tomize the options as you like.
■ Custom Mode
In all modes, the user interface you see when taking the test is basically the same, but with different options enabled or disabled depending on the mode. The main options are discussed in the preceding section, “Lesson Review Options.” When you review your answer to an individual practice test question, a “References” section is provided that lists where in the training kit you can find the information that relates to that question and provides links to other sources of information. After you click Test Results to score your entire practice test, you can click the Learning Plan tab to see a list of references for every objective.
xxxiv
Introduction
How to Uninstall the Practice Tests To uninstall the practice test software for a training kit, use the Add Or Remove Pro grams option in Windows Control Panel.
Microsoft Certified Professional Program The Microsoft certifications provide the best method to prove your command of cur rent Microsoft products and technologies. The exams and corresponding certifica tions are developed to validate your mastery of critical competencies as you design and develop, or implement and support, solutions with Microsoft products and tech nologies. Computer professionals who become Microsoft-certified are recognized as experts and are sought after industry-wide. Certification brings a variety of benefits to the individual and to employers and organizations. MORE INFO
All the Microsoft certifications
For a full list of Microsoft certifications, go to www.microsoft.com/learning/mcp/default.asp.
Technical Support Every effort has been made to ensure the accuracy of this book and the contents of the companion CD. If you have comments, questions, or ideas regarding this book or the companion CD, please send them to Microsoft Press by using either of the following methods: E-mail: tkinput@ Microsoft.com Postal Mail: Microsoft Press Attn: MCTS Self-Paced Training Kit (Exam 70-529): Microsoft .NET Framework 2.0 Distributed Application Development Editor One Microsoft Way Redmond, WA 98052–6399 For additional support information regarding this book and the CD-ROM (includ ing answers to commonly asked questions about installation and use), visit the Microsoft Press Technical Support Web site at www.microsoft.com/learning/support/ books/. For support information regarding Microsoft software, please connect to http://support.microsoft.com.
Introduction
xxxv
Foundation Edition Software Support The 90-day evaluation edition provided with this training kit is not the full retail prod uct and is provided only for the purposes of training and evaluation. Microsoft and Microsoft Technical Support do not support this evaluation edition. Information about any issues relating to the use of this evaluation edition with the training kit is posted to the Support section of the Microsoft Press Web site (www.microsoft.com/learning/support/books/). For information about ordering the full version of any Microsoft software, please call Microsoft Sales at (800) 426-9400 or visit www.microsoft.com.
Chapter 1
Creating an XML Web Service
This chapter reviews the steps necessary to create a Web service application in Microsoft Visual Studio. You will learn how to create and configure a Web application using the WebService declaration. You will also learn how to create and configure a public method by attaching the WebMethod attribute. Finally, you will learn how to test and deploy a Web service application by copying files to a Web server.
Exam objectives in this chapter: ■
Create and configure an XML Web service method. ❑
Create a public method.
❑
Attach the WebMethodAttribute attribute.
❑
Create a OneWay Web method.
❑
Configure a Web service method.
■
Configure a Web service method by using the properties of the WebMethodAttribute attribute.
■
Configure SOAP messages. ❑
Specify the basic information for a Web service application.
Lessons in this chapter: ■
Lesson 1: How to Create a Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
■
Lesson 2: How to Create a Web Service Method. . . . . . . . . . . . . . . . . . . . . . . . . 15
■
Lesson 3: How to Test and Consume a Web Service . . . . . . . . . . . . . . . . . . . . . 24
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction at the beginning of this book.
1
2
Chapter 1
Creating an XML Web Service
■
Visual Studio 2005 and the .NET Framework 2.0.
■
Knowledge of programming in Microsoft Visual Basic or C# and a basic under standing of Extensible Markup Language (XML).
Real World Sara Morgan Many developers want to know which distributed technology they should use—Web services, Remoting, or .NET Enterprise Services. The answer to this question depends a lot on what you need out of the application. There is no magic bullet that is right for all scenarios, but in my opinion, and Microsoft’s as well, you should start simple. Start with Web services and only use Remot ing or .NET Enterprise Services if necessary. Although every business problem is unique, here are some helpful rules to use as a starting point when trying to determine which distributed technology to pursue: ■
If the application or applications accessing your objects are located on dif ferent platforms, most often Web services will meet your needs. This is especially true if overall performance is not a primary concern.
■
If you know the client and server platforms will be .NET and efficiency is a primary concern, then Remoting is your best option. Remoting is most effi cient when you host the Remoting application inside a managed executable.
■
If your application requires access to specialized functionalities such as object pooling, queued components, and role-based security, then .NET Enterprise Services is likely your best option.
Lesson 1: How to Create a Web Service
3
Lesson 1: How to Create a Web Service This lesson begins by providing a general definition for a Web service. After walking through the steps for creating a Web service project in Visual Studio, this lesson explores the basics of what constitutes a Web service application. This includes one or more public methods that are exposed with the WebMethod attribute. The methods are wrapped inside a class file that is distinguished with a WebService declaration. First, however, this lesson just focuses on creating the Web service project and config uring the Web service with the WebService attribute. After this lesson, you will be able to: ■
Answer what a Web service is and why it is important to know how to create one.
■
Create a Web service project using the project template provided in Visual Studio.
■
Identify the code necessary to configure a Web service using the WebService attribute.
Estimated lesson time: 30 minutes
What Is a Web Service? A Web service is a piece of software that is used to expose data and functionality in a distributed environment. The data exposed can be as simple as a list of product cate gories or as complex as a multileveled dataset containing a complete customer pur chase history. The functionality exposed can also range in complexity, and generally complex tasks are broken down into a series of exposed public Web methods. Web services are XML based, and distributed applications access them over the Inter net using a communications protocol such as Simple Object Access Protocol (SOAP). SOAP provides a standard and simple way to present messages in an XML format. SOAP also allows developers to describe what the service does and make it available to other applications. Because the data returned by a Web service is in the form of a stan dardized XML message, applications residing on different platforms can access the same Web services. This capability makes Web services quite useful when multiple cli ents located over vast geographical areas need access to the same kind of information. NOTE
Selecting a distributed application method
When selecting a distributed application method, first consider Web services because Web services are highly interoperable and accessible from almost any platform.
4
Chapter 1
Creating an XML Web Service
You can think of a Web service application in the same way that you think of a regular ASP.NET application. The primary difference between a Web service application and an ASP.NET application is the interface. ASP.NET applications utilize traditional graphical user interface (GUI) elements, such as text boxes and labels. An XML Web service application has none of these elements. Instead, it relies on help pages and dis covery files to interface with its users. The user of a Web service is typically another application, so no traditional user interface is necessary. Web services are especially useful for applications that must expose key pieces of their data or functionality to outside and unknown sources. For instance, a retail company can utilize a complex application to manage sales and inventory. There is likely a need for outside vendors to access inventory levels specific to the products they provide. The retail company could expose a Web service method that allowed specific vendors to access this information in the form of an XML dataset. The retail company would not need to provide an interface specific to each vendor’s operating platform. Instead, they would only be responsible for exposing one Web service method that all vendors could utilize.
How to Create a New Web Service Project To create a Web service project, you need to create a project using the Web service template in Visual Studio 2005. Using the template adds certain files and directories to your project by default. This makes it easier to get started on building your first Web service. Figure 1-1 shows the New Web Site dialog box that is displayed when you cre ate a new ASP.NET Web service project.
Figure 1-1
Use the New Web Site dialog box to create a new ASP.NET Web service project
Lesson 1: How to Create a Web Service
5
The Web service project template creates two directories named App_code and App_data, along with an initial Web service file named Service.asmx (see Figure 1-2). The App_code directory contains source files for all classes and business objects. The App_data directory contains any data files needed for the project, including XML files or any other data storage files. NOTE
The .asmx file extension
The Service file included with your new Web service project has an .asmx file extension. All Web service files will have an .asmx extension, as opposed to ASP.NET applications that use files with an .aspx extension. The .asmx file will be referenced when another user or distributed application needs to access methods within the Web service.
Figure 1-2
A new Web service solution built with the Visual Studio installed template
After the new project has been created, the code pane displays the code for the Service class file, named Service.cs (or Service.vb for Visual Basic). By default, this class con tains references to the following .NET Framework namespaces: This namespace is used to represent the base data types in the .NET Framework.
■ System
6
Chapter 1
Creating an XML Web Service
■ System.Web
This namespace is used to enable browser-to-server communication.
This namespace contains the base classes needed to create XML Web services. This namespace includes the WebService and WebMethodAt tribute classes, which are needed when creating methods exposed within your Web service application.
■ System.Web.Services
This namespace contains the classes needed to transmit XML data across the Internet.
■ System.Web.Services.Protocols
The Web services template also inserts the following code into the Service class file: 'VB _ _ _ Public Class Service Inherits System.Web.Services.WebService _
Public Function HelloWorld() As String
Return "Hello World"
End Function
End Class
//C# [WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () { //Uncomment the following line if using designed components //InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}
If you do nothing to modify the code added to the Service class, your Web service will contain one method named HelloWorld. Once invoked, this method returns the string “Hello World”. At this point, you have created the shell of a Web service project. Next, we review what it takes to make an ordinary Web application a Web service and what you can do to specify the basic information for your Web service application.
Lesson 1: How to Create a Web Service
7
The WebMethods Framework ASP.NET includes a WebMethods framework for the purpose of easily creating Web services. Otherwise, developers would need to use a low-level technique and write a custom IHttpHandler class. The WebMethods framework allows developers to utilize built-in functionality that masks much of the complexity of implementing Web ser vices. The framework is used to map SOAP messages to the methods within a .NET class.
The WebService Declaration The WebService processing directive is the key to making an .asmx file a Web service. It tells the .asmx handler where to locate the class files that contain the Web methods. The directive also includes other attributes that identify how the Web service should be handled. To view the source code used in the Service.asmx file, right-click the file in Solution Explorer and Open With. You will then click Source Code (Text) Editor and click OK. In the Service.asmx file that was installed with the Web service tem plate, the following code was used to identify it as a Web service: 'VB //C#
The processing directive used in the Service.asmx file includes the following three important attributes: This attribute is used to identify the programming language used in the code-behind file. It can be set to VB, C#, or J#, which identifies the program ming language as Visual Basic, C#, or JScript.
■ Language
This attribute references the class file that will contain the Web methods. For the Web service template, the code-behind is located in a class file named Service and it is located in the App_code directory.
■ CodeBehind
This attribute is used to identify the class name referenced in the codebehind file.
■ Class
NOTE
Renaming the class file
If you want to rename the class file, you will also need to change the Class attribute in the WebSer vice processing directive.
8
Chapter 1
Creating an XML Web Service
It is possible for the Web service code and the .asmx file to reside in different assem blies. To specify this arrangement, you need to set the Class attribute to include the class name, followed by a comma, and then the assembly name. The following code gives you an example of what this would look like. 'VB //C#
NOTE
Specifying an assembly name
If you do not specify the assembly name when the class file resides in a different assembly, ASP.NET will be forced to search through all the assemblies in the application’s \bin folder. This will cause your Web service to perform slower than it should.
The WebService Class The WebService class is the base class used for all Web services, and it is part of the Sys tem.Web.Services namespace. Table 1-1 lists the attributes and members that are part of this class. Table 1-1
Public Properties of the WebService Class
Name
Description
Application
Retrieves the application object for the current Hypertext Transfer Protocol (HTTP) request. This object is used to store application state.
Container
Retrieves the container for the component. This container is used when passing properties such as MarshallByValue.
Context
Retrieves the HttpContext object for the current request. This object allows you to reference HTTP items for the cur rent Web service request.
DesignMode
Retrieves the value true if the component is in design mode.
Server
Retrieves the HttpServerUtility object for the current request. This object can be used when there is a need to instantiate Component Object Model (COM) objects.
Lesson 1: How to Create a Web Service
Table 1-1
9
Public Properties of the WebService Class
Name
Description
Session
Retrieves the HttpSessionState instance from the current Web service request. This object is used when referencing session state.
Site
Retrieves or sets the site of the component. If the value is not null, the value has been added to the container.
SoapVersion
Retrieves the version of the SOAP protocol used to make the Web service request. This property is new in the .NET Framework 2.0.
User
Retrieves the User object and can be used to determine whether a user is allowed to make a Web service request.
The WebServiceAttribute Class The WebService attribute used in the Service class file was very basic and did not use more than one property. It only specified the Namespace attribute, which should be set to a unique XML namespace value, as shown in the following code: 'VB //C# [WebService(Namespace = "http://tempuri.org/")]
By default, the Namespace property is set to http://tempuri.org for all Web services. It is acceptable to keep Namespace set this way while you are testing your Web service, but it needs to be changed before the Web service is moved into production. The XML namespace should be unique to distinguish it from all other Web services. Typically, you will use your company’s domain name as part of the value. In many cases, the namespace value will be a valid Uniform Resource Locator (URL), but it is not neces sary for the URL to be valid. Other properties that are available with the WebService attribute are Description and Name (see Table 1-2). The value for Description should be set to a short descriptive message that identifies the basic function of the Web service. The Name property should be set to a value that uniquely identifies the Web service. If you do not specify
10
Chapter 1
Creating an XML Web Service
a Name property, the .asmx handler uses the name of the class that implements your Web service. Table 1-2
Public Properties of the WebServiceAttribute Class
Name
Description
Description
Sets a message that describes the function and purpose of the Web service.
Name
Retrieves or sets the name of the Web service. If you do not specifically set this property, the .asmx handler uses the name of the class that implements the Web service.
Namespace
Retrieves or sets the XML namespace used for the Web ser vice. By default, this property is set to http://tempuri.org.
TypeId
Retrieves a unique identifier used to identify the attribute when it is implemented in a derived class.
Real World Sara Morgan I recently worked for a company that produces legislative software for city and state governments. The company’s flagship product is a complex ASP.NET appli cation that interfaces with a third-party vendor that manages video content. The ASP.NET application called Web service methods exposed by the third-party vendor. When we first started working with the vendor to integrate our applica tions, the applications exposed a Web service that used the default namespace http://tempuri.org. The namespace remained that way even after we moved the application into production. One day, the vendor decided to change the Namespace property but did not bother notifying us of the change. This imme diately broke our application because it could no longer identify the Web ser vice. There was some late-night scrambling to get the Web Services Description Language (WSDL) document updated and the application repaired. The moral of this story is that it is important to change the namespace of your Web services before you move your application into production. If your applica tions access external Web services, make sure they are not using the default namespace either.
Lesson 1: How to Create a Web Service
11
Lab 1: Creating a Web Service Project Using Visual Studio This lab steps you through how to create a Web service project using Visual Studio. It begins by creating a new Web service project using one of the project templates for a new Web site. The Web service project that is created in this lab does not have any Web methods attached to it. This lab is only meant to demonstrate how a Web service project is created using one of the Visual Studio templates. It also demonstrates how the basic information for a Web service can be set using the WebService attribute. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. Although the certification exam does not specifically cover the objective of creating a Web service project, it is important for you to know how to begin the process of cre ating a Web service. To do so, follow these steps : 1. Open Visual Studio 2005. 2. Click File, New, Web Site. 3. In the New Web Site dialog box (see Figure 1-1), select ASP.NET Web Service as the template and name the project file MyWebService. By default, Visual Studio saves the project in the \My Documents\VisualStudio 2005\WebSites\directory. 4. Set the language by selecting Visual Basic, Visual C#, or Visual J# from the Lan guage drop-down list box. By default, Visual Studio selects the language speci fied when you configured the development environment. 5. A new solution (see Figure 1-2) named MyWebService is created. By default, the solution file corresponding to the project is stored in your \My Docu ments\Visual Studio 2005\WebSites directory. The Web service project files themselves are stored in the directory specified in step 3. 6. In Solution Explorer, right-click the Service.asmx file and click Rename. Change the name to MyWebService.asmx. 7. Double-click the MyWebService.asmx file and replace the existing code with the following: 'VB //C#
12
Chapter 1
Creating an XML Web Service
8. In Solution Explorer, right-click the Service.cs (or Service.vb) file in the App_code directory and click Rename. Change the name to MyWebService.cs (or MyWebService.vs). 9. Right-click the MyWebService.cs (or MyWebService.vb) file and click View Code. 10. From the code window, replace all the existing code with the following: 'VB Imports Imports Imports Imports Imports Imports Imports Imports
System.Web
System.Web.Services
System.Web.Services.Protocols
System.Data.SqlClient
System.Data.SqlTypes
System.Data
System.Xml
System.Web.Services.Description
_ _ Public Class MyWebService
Inherits System.Web.Services.WebService
Public Sub New()
MyBase.New()
End Sub
End Class
//C# using using using using using using using using using
System;
System.Web;
System.Web.Services;
System.Web.Services.Protocols;
System.Data.SqlClient;
System.Data.SqlTypes;
System.Data;
System.Xml;
System.Web.Services.Description;
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [WebService(Name = "MyWebService", Description = "This Web Service is used to " + "experiment with some of the Web service concepts", Namespace = "http://www.mycompany.com/")] public class MyWebService : System.Web.Services.WebService
{
public MyWebService () { } }
Lesson 1: How to Create a Web Service
13
11. Build the project, and resolve any errors. You’ll be using this Web service in the following lessons, but for now leave the project alone.
Lesson Summary ■
Web services are software applications that expose data and functionality to multiple platforms over the Internet using a communication protocol known as SOAP.
■
The WebService declaration must be placed in each .asmx file of your Web service application. This declaration is used to tell the .asmx handler where to find the class file that implements the code for your Web service.
■
The WebService class is the base class for all Web services, and it is included in the System.Web.Services namespace.
■
The WebService attribute can be used to specify basic information about your Web service. This information can include a name, description, and unique namespace. It is a good idea to set the namespace to something other than the default before a Web service is deployed into production.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “How to Create a Web Service.” The questions are also available on the com panion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What namespaces are included by default with the Visual Studio Web services template? (Select all that apply.) A. System.Web B. System.WebServices C. System.Web.Services D. System.Web.Services.Protocols
14
Chapter 1
Creating an XML Web Service
2. Identify the Visual Basic code that contains an invalid WebService declaration: A.
B.
C.
D.
3. What is the primary purpose of the Namespace property, which is used in the WebService attribute? A. To set the unique XML namespace that will be used to distinguish your Web service from other Web services B. To reference the organization that establishes standards related to all Web services published on the Internet C. To reference the URL where more information regarding this Web service can be found D. To reference your company’s Web site
Lesson 2: How to Create a Web Service Method
15
Lesson 2: How to Create a Web Service Method This lesson expands on Lesson 1 by going into what is involved in creating a publicly exposed Web method. After creating a public method, the lesson steps through the process of applying the WebMethod attribute. The Web method can then be config ured by setting one of several properties for the WebMethod attribute. The lesson con cludes by showing an example of a specialized Web method known as a one-way method. After this lesson, you will be able to: ■
Create a public Web method and apply the WebMethod attribute.
■
Configure a Web service method.
■
Identify the code necessary to configure a Web service using the WebService attribute.
Estimated lesson time: 30 minutes
Creating a Public Method At the most basic level, you can make a method accessible through a Web service application by attaching the WebMethod attribute to a public method. The public method is stored in the class file of your Web service file (the one with the .asmx extension). When you create a Web service project using the Web service project tem plate, one public method named HelloWorld is created for you by default. You can see the code for the HelloWorld method by right-clicking the Service.asmx file in Solution Explorer and clicking View Code. NOTE
Methods that aren’t public
Your Web service class can contain other methods that are not public, but they will not be accessi ble as Web methods. Instead, they will only be available to the other methods in your Web service class.
Applying the WebMethod Attribute The HelloWorld public method does not become available through the Web service until you attach the WebMethod attribute. This method must be applied to each method declaration that will be accessible. The following code shows how the WebMethod appears at the top of the HelloWorld method.
16
Chapter 1
Creating an XML Web Service
'VB _ Public Function HelloWorld() As String
Return "Hello World"
End Function //C# [WebMethod] public string HelloWorld() {
return "Hello World";
}
Configuring a Web Service Method Web methods can be configured using one of several different properties. These prop erties allow you to specify everything from the Web method description to how it will handle transactions. The different properties available with the WebMethod attribute are as follows: This property provides a general description for what the Web method is supposed to accomplish. Although the default value for this property is an empty string, it is a good idea to always provide at least one sentence that briefly describes your Web method. Later you will see how the value specified for the description is displayed on the Service help page.
■ Description
This property is the value that identifies your Web method in the XML sent with your SOAP message. By default, it is set to the name of the Web method, but you might want to change this.
■ MessageName
If session state is not specified directly, it is disabled for all Web service methods. This arrangement allows the methods to operate more effi ciently. If your Web method requires the use of session state, you need to include the EnableSession property and set the value to true. You will then be able to access the session state through the HttpContext.Current.Session property.
■ EnableSession
The value for this property specifies the number of seconds that ASP.NET will cache the Web method response. By default, this value is set to 0, so no caching will occur.
■ CacheDuration
Buffering can be used to improve the performance of your Web service because it minimizes the amount of communication needed between the worker process and Internet Information Services (IIS). By default, this property is set to true, but you might want to set it to false if you are returning a large amount of data and do not want it all stored in the buffer.
■ BufferResponse
Lesson 2: How to Create a Web Service Method
17
This property is used to indicate whether the Web method can participate in a transaction. By default, the transaction option is set to Dis abled, but you might need to change that value to either NotSupported, Supported, Required, or RequiresNew.
■ TransactionOption
NOTE
Requiring transactions
If your Web method performs updates on more than one database or if the sequence of updates is critical to the overall success of the Web method, then you should ensure that the TransactionOp tion is set to Required.
Creating a One-Way Method In many cases, the Web method you expose through your Web service does not require a response from the client. In cases such as this, you can specify that your Web method is a one-way method by applying the OneWay attribute. Applying this attribute makes your method perform more efficiently because it will not wait for a response from the client. Your method will only process input parameters and cannot be used to return referenced values or throw exceptions. The System.Web.Services.Protocols namespace includes the SoapDocumentMethodAt tribute (see Table 1-3) and SoapRpcMethodAttribute (see Table 1-4) classes, which rep resent the SoapDocumentMethod and the SoapRpcMethod. These methods are used to format SOAP messages and allow you to set the value of a OneWay property. This property accepts a Boolean value indicating whether the Web service client has to wait for a response from the Web server. If the property is set to false (the default value), then the Web service client waits for an acknowledgment from the Web server, even if no values need to be passed back. So, if you know that no values need to be passed back, the Web service client is immediately free to go on to other processing tasks. Table 1-3
Public Properties of the SoapDocumentMethodAttribute Class
Name
Description
Action
Retrieves or sets the SOAPAction HTTP header field for the Web service request.
Binding
Retrieves or sets the binding value, which is by default the name of the Web service followed by the word Soap.
18
Chapter 1
Creating an XML Web Service
Table 1-3
Public Properties of the SoapDocumentMethodAttribute Class
Name
Description
OneWay
Retrieves or sets the Boolean value that determines whether the method will be able to return any values from the request.
ParameterStyle
Retrieves or sets a value that determines where parame ters will be stored in the request’s Body element. The property can be set to Bare, Default, or Wrapped.
RequestElementName
Retrieves or sets the name of the XML element associ ated with the request method. By default, this property is set to the name of the Web service method.
RequestNamespace
Retrieves or sets the namespace of the request method binding. By default, this property is set to http://tem puri.org.
ResponseElementName
Retrieves or sets the name of the XML element associ ated with the response method. By default, this property is set to the name of the Web service method.
ResponseNamespace
Retrieves or sets the namespace of the response method binding. By default, this property is set to http://tempuri.org.
TypeId
Retrieves a unique identifier used to identify the attribute when it is implemented in a derived class.
Use
Retrieves or sets the name of the binding used when invoking the Web method. This property is new for the .NET Framework 2.0.
Lesson 2: How to Create a Web Service Method
Table 1-4
19
Public Properties of the SoapRpcMethodAttribute Class
Name
Description
Action
Retrieves or sets the SOAPAction HTTP header field for the Web service request.
Binding
Retrieves or sets the binding value, which is by default the name of the Web service followed by the word Soap.
OneWay
Retrieves or sets the Boolean value that determines whether the method will be able to return any val ues from the request.
RequestElementName
Retrieves or sets the name of the XML element asso ciated with the request method. By default, this property is set to the name of the Web service method.
RequestNamespace
Retrieves or sets the namespace of the request method binding. By default, this property is set to http://tempuri.org.
ResponseElementName
Retrieves or sets the name of the XML element asso ciated with the response method. By default, this property is set to be the name of the Web service method.
ResponseNamespace
Retrieves or sets the namespace of the response method binding. By default, this property is set to http://tempuri.org.
TypeId
Retrieves a unique identifier used to identify the attribute when it is implemented in a derived class.
Use
Retrieves or sets the name of the binding used when invoking the Web method. This property is new for the .NET Framework 2.0.
20
Chapter 1
Creating an XML Web Service
The following code shows how the property can be set for the HelloWorld method. 'VB _
Public Function HelloWorld() As String
Return "Hello World"
End Function
//C# [SoapDocumentMethod(OneWay=true)]
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
Lab 2: Creating a Public Web Service Method This lab steps you through how to create a Web service method. The public method created in this lab is added to the Web service project created in the last lab. If you have not yet completed the steps in Lab 1, you need to do so before continuing on with this lab. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. The method created in this lab is named GetVendorList and it returns an XML string containing all active vendors. The vendor data come from the AdventureWorks data base, which is available as a free download with SQL Server Express at http:// www.microsoft.com/downloads/details.aspx?FamilyId=E719ECF7-9F46-4312-AF89 6AD8702E4E6E&displaylang=en. You can find helpful instructions on installing the database at http://msdn2.microsoft.com/en-us/library/ms310325.aspx. 1. Open Visual Studio 2005. 2. Click File, Open, Web Site. 3. In the Open Web Site dialog box, browse to the location where the MyWebSer vice project was created in Lab 1. 4. Within the MyWebService.cs or MyWebService.vb file, add the following code right under the class constructor: 'VB _ Public Function GetVendorList() as String
Dim sqlConn As New SqlConnection
Dim rdr As XmlReader
Dim ret As String = ""
Lesson 2: How to Create a Web Service Method
21
Try
'Open the connection to SQL Server Express
Dim connString As String = _
"server=.\sqlexpress;Integrated Security=SSPI;initial catalog=AdventureWorks" sqlConn.ConnectionString = connString sqlConn.Open() 'Return XML data using the FOR XML AUTO clause Dim sqlString As String = "SELECT VendorID, AccountNumber, " + _ "Name, CreditRating " + _ "FROM Purchasing.Vendor " + _ "WHERE ActiveFlag = 1 " + _ "ORDER BY Name " + _ "FOR XML AUTO " Dim command As New SqlCommand(sqlString, sqlConn) 'Execute the SQL query and return XML to an XMLReader
rdr = command.ExecuteXmlReader()
'Loop through the reader and get our XML
rdr.Read()
Do While rdr.ReadState System.Xml.ReadState.EndOfFile
ret += rdr.ReadOuterXml
Loop
'Add a root element
ret = " " + ret + ""
sqlConn.Close()
rdr.Close()
Catch ex As Exception 'Add some exception handling code here
End Try
Return ret
End Function //C# [WebMethod(Description = "Retrieve a list of active vendors ordered by name")]
public string GetVendorList()
{
SqlConnection sqlConn; XmlReader rdr;
string ret = "";
try
{
//Open the Connection to SQL Server Express string connString = @"server=.\sqlexpress;Integrated Security=SSPI;initial catalog=AdventureWorks"; sqlConn = new SqlConnection(connString);
22
Chapter 1
Creating an XML Web Service
sqlConn.Open(); // Return XML data using the FOR XML AUTO clause string sqlString = "SELECT VendorID, AccountNumber, Name, CreditRating " + "FROM Purchasing.Vendor " + "WHERE ActiveFlag = 1 " + "ORDER BY Name " + "FOR XML AUTO "; SqlCommand command = new SqlCommand(sqlString, sqlConn);
//Execute the SQL query and return XML to an XMLReader
rdr = command.ExecuteXmlReader();
//Loop through the reader and get our XML
rdr.Read();
while (rdr.ReadState != System.Xml.ReadState.EndOfFile) {
ret += rdr.ReadOuterXml();
}
//Add a root element
ret = " " + ret + "";
sqlConn.Close();
rdr.Close();
}
catch
{
//Do some exception handling here
}
return ret;
}
5. Build the project, and resolve any errors.
Lesson Summary ■
Methods exposed through a Web service must be declared as public. Private methods can exist in the Web service class file, but they will not be available for public consumption.
■
The WebMethod attribute must be applied to all public methods that need to be exposed through a Web service. Several public properties are exposed through this attribute that allow you to configure each Web service method.
■
The System.Web.Services.Protocols namespace includes the SoapDocumentMethodAttribute and SoapRpcMethodAttribute classes, which are used to format SOAP mes sages. Both of these methods allow you to set the value of a OneWay property.
Lesson 2: How to Create a Web Service Method
23
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “How to Create a Web Service Method.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What are the most basic requirements for making an ASP.NET application a Web service? (Select all that apply.) A. One or more public methods B. The WebService processing directive C. A WebService configuration section in the web.config file D. The WebMethod attribute attached to each method that will be exposed through the Web service 2. How do you allow your Web service to participate in a transaction? A. Transaction processing is not available with Web services in the .NET Framework 2.0. B. Set the Transaction property for the WebMethod attribute to one of the fol lowing values: Required or RequiredNew. C. Set the TransactionOption property for the WebMethod attribute to one of the following values: Required or RequiredNew. D. Set the Transaction property for the WebService attribute to true. 3. How do you create a one-way method? A. For the WebMethod attribute, set the OneWay property to true. B. For the SoapDocumentMethod and SoapRpcMethod methods, set the OneWay property to true. C. Import the System.Web.Services.Protocols namespace and set the SoapProto col property to OneWay. D. Either A or B is correct.
24
Chapter 1
Creating an XML Web Service
Lesson 3: How to Test and Consume a Web Service This lesson shows you how to test and consume a Web service application. Testing a Web service involves invoking each of the public Web methods and verifying that the results returned are accurate. This testing can be done directly using a URL that points to the Web service file or by invoking the Web method using a separate client application. After this lesson, you will be able to: ■
Test a Web service method using a debugging session or directly with a URL.
■
Consume a Web service method using a client application.
Estimated lesson time: 20 minutes
Testing Your Web Service The Service help page (see Figure 1-3) contains links to all the public methods exposed with the WebMethod attribute. In Lab 2, only one Web method was created, so if you were to compile and test the application from this lab, only one link would be displayed on the Service help page.
Figure 1-3 After executing the project created in Lab 1 and Lab 2, you should see this Service help page
Lesson 3: How to Test and Consume a Web Service
25
There are two methods you can use for testing your Web service. The first involves building your application and starting a debugging session so that you can step through the code of your application. This task is done by first selecting a start page for your application. For the application created in Lab 1, the start page would be the MyWebService.asmx file. You select the start page by right-clicking the file in Solution Explorer and clicking Set As Start Page. The next step is to initiate a debugging session by choosing Start Debugging on the Debug menu. Alternatively, you can press F5 to start debugging. The first time you initiate a debugging session for a Web project you’ll see the dialog box shown in Figure 1-4. Click OK to start debugging.
Figure 1-4
The Debugging Not Enabled dialog box
When you start the debugging session, the Service help page is displayed in your Web browser (see Figure 1-3). It should display a link to the GetVendorList Web method. If you were to click this link, you would then be brought to the Service method help page for GetVendorList (see Figure 1-5). The Service method help page allows you to invoke a particular Web method. If the Web method accepts parameters, you would also be prompted to enter those values. Not only can you invoke the Web method and test your application, but you can also see sample request and response SOAP messages for this Web method. SOAP mes sages are discussed further in Chapter 2, “Extending XML Web Services with SOAP Formatting, Headers, and Extensions.” After you click Invoke on the Service method help page, the code for that Web method executes. If you set a breakpoint in your code using the Toggle Breakpoint (F9) com mand, the code stops executing at this point and allows you to step through the remaining code using the Step Over (F10), Step Into (F11), or Step Out (Shift + F11) commands. If the Web method executes successfully and returns a value, the next page you see should contain the results.
26
Chapter 1
Figure 1-5
Creating an XML Web Service
The Service method help page for the GetVendorList Web method
In Lab 2, you created a Web method named GetVendorList. This Web method should return an XML string containing a list of active vendors from the AdventureWorks data base. The results should be displayed inside a new instance of your Web browser (refer to Figure 1-6). The GetVendorList Web method uses the FOR XML AUTO clause to automatically return a valid XML string directly from the database. If the Web method is unable to execute successfully and an exception is thrown, you should see a page displaying the exception encountered. It might be necessary to set a breakpoint using the Toggle Breakpoint function and step through the code until you are able to resolve the problem. NOTE
Refer to setup instructions
The Introduction for this Training Kit contains information that you need to execute and test Web services created in the labs. Refer to these instructions if you are having trouble executing and test ing your Web service.
Lesson 3: How to Test and Consume a Web Service
Figure 1-6
27
XML results returned after invoking the GetVendorList Web method created in Lab 2
The second method for testing a Web service is to use your Web browser to access the Web service page (the one with the .asmx extension) directly. Web services built on your local development machine can be accessed using the name Localhost to specify the machine name. The remaining portion of the URL should be the name of the Web service project, followed by the name of the Web service page. For example, the Web service method created in Lab 2 can be accessed directly with the following URL: http://localhost:/MyWebService/MyWebService.asmx. NOTE
Using a port number with Visual Studio 2005
Visual Studio 2005 utilizes port numbers when debugging Web sites. The exact port number that is assigned is displayed in a balloon that appears above your task tray when you begin debugging. Write down this port number and you can use a Web browser to navigate to your Web service using the port number for your machine.
28
Chapter 1
Creating an XML Web Service
Accessing the Web service method with the URL should bring you to the Service help page. This allows you to select any public Web method exposed with the WebMethod attribute. From there, you can invoke any Web method and verify that the results are returned as expected.
Consuming a Web Service Another alternative for testing your Web service is to create a separate Web applica tion project that acts as the client consumer of your Web service. This Web applica tion project can reside in the same solution file with your Web service project and allows you to simulate the experience of your Web service consumers. Using this method allows you to process and manipulate the data returned from your Web ser vice. Even though you can see the data returned just by browsing to the Web service URL, until you actually try to use those data, you might not be able to identify all potential issues surrounding its consumption.
Setting a Web Reference You can add a client Web application project to your Web service solution by clicking Add, New Web Site from the File menu. After adding your new project to the solution, you will be able to set a Web reference that refers to the Web service project. This task is done by right-clicking the newly created project in Solution Explorer and clicking Add Web Reference. The Add Web Reference dialog box (see Figure 1-7) can be used to set a Web reference to a Web service residing in your current solution. Once the Web reference is added, you are able to refer to Web methods from your Web service project as if you were referring to methods within class files in your current project. When you add a Web reference, you are telling Visual Studio to download the Web service description and generate a proxy class that can be used to communicate with the Web service. Assume you were to create a project that had a label control named lblDisplay. Further assume that you created a Web reference named WebService that referenced a Web ser vice on your local machine named Service.asmx. The code used to call the HelloWorld method and return a string to the lblDisplay control would appear as follows: 'VB Dim ws As New WebService.Service
lblDisplay.Text = ws.HelloWorld
//C# ws WebService = new WebService.Service();
lblDisplay.Text = ws.HelloWorld
Lesson 3: How to Test and Consume a Web Service
29
Figure 1-7 Use the Add Web Reference dialog box to set a Web reference to a project in the current solution
At this point, you can test how clients of your Web service will be able to interact with the data returned from your Web methods. By doing this testing, you will quickly be able to see whether the return values match the anticipated results. NOTE
Distribute a client application with your Web service
It might be a good idea to distribute a test ASP.NET application with your Web service that demon strates how clients can consume the data returned from your Web methods.
Lab 3: Testing and Consuming a Web Service This lab guides you through adding a test client application to the Web service appli cation created in Lab 1. This client application is used to demonstrate how the results of the GetVendorList Web method can be used to populate a drop-down list box con trol. If you have not yet completed the steps in Lab 1 and Lab 2, you need to do so before continuing on with this lab. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005. 2. Click File, Open, Web Site. 3. In the Open Web Site dialog box, browse to the location where the MyWebSer vice was created in Lab 1 and click Open.
30
Chapter 1
Creating an XML Web Service
4. On the File menu, click Add, New Web Site. Select the ASP.NET Web Site tem plate, enter MyWebServiceClient as the project name, and click OK. 5. Right-click the new project file and click Add Web Reference. In the Add Web Reference dialog box select Web Services In This Solution. 6. Click the MyWebService link, enter the name WebService in the Web Reference Name text box, and click Add Reference. 7. Right-click the Default.aspx file in Solution Explorer and click View Designer. 8. Click the Toolbox and drag a DropDownList control onto the design surface. Click the design surface to close the DropDownList Tasks window and then click the control. In the Properties window, set the ID property to ddlVendors. 9. Click the Toolbox and drag an XMLDataSource control onto the design surface. Click the design surface to close the XmlDataSource Tasks window. 10. Double-click the design surface to open the Page_load method in the code win dow. Add the following code to this method: 'VB Dim ws As New WebService.MyWebService
XmlDataSource1.Data = ws.GetVendorList
ddlVendors.DataSource = XmlDataSource1
ddlVendors.DataTextField = "name"
ddlVendors.DataValueField = "vendorid"
ddlVendors.DataBind()
//C# WebService.MyWebService ws = new WebService.MyWebService();
XmlDataSource1.Data = ws.GetVendorList();
ddlVendors.DataSource = XmlDataSource1;
ddlVendors.DataTextField = "name";
ddlVendors.DataValueField = "vendorid";
ddlVendors.DataBind();
11. Right-click the MyWebServiceClient project in Solution Explorer and click Set As StartUp Project. 12. Right-click the Default.aspx file in Solution Explorer and click Set As Start Page. 13. Build the project, and resolve any errors. 14. On the Debug menu, click Start Debugging (or press F5). The default.aspx page should open in a Web browser and display a single drop-down list box that lists all the active vendors in the AdventureWorks database.
Lesson 3: How to Test and Consume a Web Service
31
Lesson Summary ■
You can verify that the results returned from a Web service method are valid by using a debugging session from the Web service project. You can then step through the project and use Visual Studio’s debug commands to identify prob lems with your Web service.
■
Alternatively, you can invoke the Web method directly by browsing to the URL for the Web service file (the file with the .asmx extension).
■
The results from a Web service can also be verified by creating a client ASP.NET application that consumes Web methods from your Web service. By testing in this manner, you ensure that consumers of your Web service will be able to effec tively utilize the data returned from your method.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “How to Test and Consume a Web Service.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What page is used to display a list of links to your Web service? A. The Service method help page B. The Service help page C. The Web method help page D. All of the above 2. What methods can be used to verify the results of your Web service? (Select all that apply.) A. Calling the Web service directly by browsing to the .asmx file B. Using the Web service Object Browser to invoke a particular Web method C. Using a debugging session within the Web service project to step through the code D. Creating an ASP.NET client application to consume a particular Web ser vice method
32
Chapter 1
Creating an XML Web Service
3. What steps are required when creating an application to test your Web service? (Select all that apply.) A. Create a Web reference and point it to the .asmx file for your Web service. B. Create a routine that publishes your Web service to the destination Web server. C. Instantiate a new variable that points to the new Web reference. D. Call the Web method and access the results using the variable created in option C.
Chapter 1 Review
33
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Web services are Web-based applications that are used to expose data and func tionality in a distributed and interoperable environment.
■
The WebMethods framework is used to easily create Web services by attaching a WebMethod declaration to a public Web method.
■
The WebService attribute is used to specify certain key information about your Web services.
■
Web Services can be tested in one of two ways. You can access Web methods by loading the Web service page in a Web browser and drilling down to each Web method using the Web method help startup page. Or, you can create a test project that sets a reference to the .asmx file. You can then call each Web method using this reference and manipulate the results that are returned from the Web service.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
attribute
■
Simple Object Access Protocol (SOAP)
■
template
34
Chapter 1 Review
■
Web Services Description Language (WSDL)
■
Extensible Markup Language (XML)
Case Scenarios In the following case scenarios, you apply what you’ve learned about how to validate input using regular expressions and how to process text files with different encoding types. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Deciding to Use Web Services Your company maintains a large database of customer data. Customer service repre sentatives utilize a complex ASP.NET application to access and manipulate the data in this database. Your boss comes to you and tells you that one of your partner compa nies needs access to some of this customer data. She explains that it is necessary to expose only a portion of the data to this partner company. The partner company does have programming resources available to them and they are requesting that they be given access to the database through a SQL Server port. Your boss has asked what you think is the best way to handle this situation. What do you suggest?
Case Scenario 2: Testing your Web Service In the previous scenario, it was determined that a Web service was the correct distrib uted technology to utilize. You have now designed and created the Web service, and you are ready to let the partners begin accessing the data. You believe that the queries used to retrieve data for your Web methods are all valid, efficient, and well tested. Your boss now comes to you and asks whether you can publish the newly created Web service to your Web servers that day. What do you tell your boss?
Suggested Practices To help you successfully master the exam objectives presented in this chapter, com plete the following tasks: ■
Choose to utilize Web services as your distributed technology, unless your appli cation requires functionality only available with Remoting and .NET Enterprise Services.
Chapter 1 Review
35
■
Change the namespace of your Web service from the default value of http:// tempuri.org before the application is deployed to production.
■
Always test your Web services before making them accessible to the public. It is wise to create a test application that simulates the way clients will consume the data from your Web methods. Ensure that the data are inclusive and formatted properly in order to be useful to the consumer.
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions This chapter begins by reviewing the steps necessary to format and extend your Extensible Markup Language (XML) Web services. The .NET Framework version 2.0 provides a method-based way to alter the format of your Simple Object Access Proto col (SOAP) messages, giving you a finer level of control over the way your request and response messages are formatted. This formatting can be done by specifying the parameter encoding and encapsulation. You can also specify the binding that SOAP uses and customize the SOAP message using XML serialization. Lesson 2 focuses on the ability to implement SOAP headers. A custom SOAP header can be used to control how a request is executed. Lesson 3 moves on to the ability to implement custom SOAP extensions. This process involves creating a custom SOAP extension and then configuring it using a custom attribute.
Exam objectives in this chapter: ■
Configure SOAP messages. ❑
■
■
Configure the formatting of SOAP messages for a Web service method.
Implement SOAP headers. ❑
Add a custom SOAP header class.
❑
Create a public instance of the custom SOAP header class in a Web service class.
❑
Apply a SoapHeader attribute to a Web method.
❑
Access and process a SOAP header in the Web method.
❑
Set the direction of a SOAP header.
Implement SOAP extensions. ❑
Create a custom SOAP extension.
❑
Configure the SOAP extension. 37
38
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Lessons in this chapter: ■
Lesson 1: How to Configure SOAP Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
■
Lesson 2: How to Implement SOAP Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
■
Lesson 3: How to Implement SOAP Extensions . . . . . . . . . . . . . . . . . . . . . . . . . 72
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction at the beginning of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Knowledge of programming in Microsoft Visual Basic .NET or C# and a basic understanding of XML.
■
Completed the lab provided in Lesson 1 of Chapter 1, “Creating an XML Web Service,” and know how to create a Web service project using Visual Studio 2005.
Lesson 1: How to Configure SOAP Messages
39
Lesson 1: How to Configure SOAP Messages This lesson begins by examining the different ways you can configure SOAP mes sages. The SOAP specification allows for several different formatting styles through the Style and Use attributes. The .NET Framework 2.0 allows you to configure these styles using the System.Web.Services.Protocols namespace. Further configuration can be done by specifying the parameter encoding and encapsulation. By default, the .NET Framework 2.0 supports the Web Services Interoperability (WS I) Basic Profile through the WebServicesBinding attribute. Using this attribute, you can assign multiple bindings to your Web service and assign a certain one to each Web method. Further customization of your SOAP messages can be done using the Sys tem.Xml.Serialization namespace and the XmlElement attribute. After this lesson, you will be able to: ■
Understand what information is included on the Service method help page.
■
Understand what basic elements are included in a SOAP message.
■
Specify paramater encoding and encapsulation.
■
Configure SOAP bindings using the WebServiceBinding attribute.
■
Customize a SOAP message with XML serialization.
Estimated lesson time: 60 minutes
Configuring SOAP Messages By default, each Web service page in your project will have a Service help page (see Figure 2-1). This Web page contains a listing of all the public Web methods available with your Web service. Each method includes a link and a description. The descrip tion displayed on this page comes directly from the Description property that was set with the WebMethod attribute (refer to Lesson 1 of Chapter 1). The link can be used to drill down to the Service method help page, which can be used to invoke a partic ular Web method (see Figure 2-2).
40
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Figure 2-1 After executing the project created in Lab 1 of Chapter 1, you should see a Service help page such as this
The Service Method Help Page The Service method help page (see Figure 2-2) not only contains a button that can be used to invoke your Web method, but it also provides sample request and response SOAP messages. Because the .NET Framework 2.0 supports both versions of SOAP (1.1 and 1.2), sample messages for each version are included on this page. By default, Web pages with an .asmx extension are handled by aspnet_isapi.dll, which is the standard Internet Server API (ISAPI) extension for the .NET Framework. This handling is seen if you go to the application configuration properties for your Web service (see Figure 2-3). Messages that are sent to this handler are forwarded to the .asmx handler, which takes care of handling the XML, SOAP, and Web Services Description Language (WSDL) for you. It essentially shields you, the developer, from all the nasty details behind the scenes. The .asmx handler inspects the Hypertext Transfer Protocol (HTTP) message and looks for information that tells it how to handle the SOAP request. Standard SOAP messages rely on an industry-defined schema known as WSDL to define what exactly goes into a SOAP message. The latest version of the SOAP specification is version 1.2, which is based on the XML Infoset. The purpose of the XML Infoset is to ensure that
Lesson 1: How to Configure SOAP Messages
41
the document is well-formed and satisfies certain namespace constraints. The previ ous version of the SOAP specification, version 1.1, was based on XML 1.0. The previ ous version of the SOAP specification relied exclusively on HTTP POST headers to transmit SOAP messages. The new version also allows for the HTTP GET header. The .NET Framework 2.0 supports both versions of the SOAP protocol because version 1.1 is still being used widely in the industry.
Figure 2-2
The Service method help page displayed by default when you create a Web method
Figure 2-3 The Internet Information Services (IIS) Application Mappings for the .asmx extension show that it maps to the aspnet_isapi.dll file
42
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
SOAP Message Formats To get an idea of what a SOAP message built for the SOAP 1.2 specification looks like, you can look at a sample of the request message associated with the GetVendorList Web method, which was created in Lab 1 of Chapter 1: POST /mywebservice/service.asmx HTTP/1.1
ost: localhost
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
Because the .NET Framework 2.0 supports both the SOAP 1.1 and 1.2 specifications, you can also use the Service help page to see what the request message formatted with the SOAP 1.1 specification looks like: POST /MyWebService/MyWebService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: http://www.mycompany/GetVendorList
NOTE
SOAP specification versions
The element prefix for messages created for SOAP version 1.2 is soap12. The prefix for messages created for SOAP version 1.1 is just soap. You will not be tested on the differences between each version, but it is useful for you to know how to recognize each version.
Both SOAP 1.1 and 1.2 messages contain the following three elements: This element is the highest level and it contains both the Header and Body elements.
■ Envelope
Lesson 1: How to Configure SOAP Messages
43
This element contains any metadata that describes what is in the Body element. This element is optional, but it must be placed before the Body element.
■ Header
This element is the main portion of the message, where all the data is located. This is also where most of the special formatting occurs.
■ Body
The elements in the SOAP message are used by the .asmx handler to handle message dispatching. Basically, the handler reads the values in these elements to figure out what to do. Therefore, if you want the handler to do something different with your SOAP request, you can alter the values in these elements. MORE INFO
The XML Protocol Working Group
If you are interested in learning more about SOAP and the latest specifications recommended and approved by the World Wide Web Consortium (W3C), you can refer to the Web page for the XML Protocol Working Group at http://www.w3.org/2000/xp/Group/.
The SOAP specification allows for two formatting options: Style and Use. Style is used when formatting the Body element. The Style attribute can be set with one of the fol lowing two values: In the early days of the SOAP specification, Remote Procedure Call (RPC) was the only formatting alternative. This style requires that the Body element fol low a very specific schema and must contain a set of parameters. More than likely the only reason you would need to utilize the RPC style was if you knew you were interfacing to a client that required the RPC style.
■ RPC
This is the default style used when creating Web services with Visual Studio. It was introduced as a way to allow for unstructured documents, and it allows for greater flexibility in the way it handles parameters.
■ Document
The .NET Framework 2.0 provides an attribute mechanism to alter the formatting of your SOAP messages. This mechanism allows you to specifically control the way the SOAP message will be handled without modifying the message directly. The Sys tem.Web.Services.Protocols namespace includes the SoapDocumentMethodAttribute (see Table 1-3) and SoapRpcMethodAttribute (see Table 1-4) classes, which represent the SoapDocumentMethod and SoapRpcMethod. These methods are used to format SOAP messages; as you can guess, the SoapDocumentMethod is used to format messages using the Document style, and SoapRpcMethod is used to format messages using the RPC style.
44
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Real World Sara Morgan I recently did contract work for a company that consumed Web services to access remote data in real time. The data was remote because it was provided by the company’s headquarters, which was located in another state within the United States. The local office had no real development staff and relied on con tractors to make changes to some of the local applications they had developed internally. For some reason, the company headquarters decided to use an RPC-encoded style to implement their Web services. This resulted in a tight coupling between the Web service and the client. Every time a developer at the corporate office would make a change to one of the Web method interfaces, the change would cause the local company’s application to break. The change could have been a simple one in which a parameter previously defined as a double was changed to be an integer. For RPC-encoded messages, the type is encoded within the mes sage and so a change to the parameter type breaks the contract between the Web service and the client. Every time this problem occurred, which for a period of time was about once a month, the local office would have to call me in to look at the problem. The fix usually just involved getting a new copy of the WSDL from the corporate office, but the fact that the tight coupling caused such problems when changes occurred demonstrated how fragile such a situation can be. This situation dem onstrates that there is no real benefit to using an RPC-encoded style when changes to the interface are possible.
Specifying Parameter Encoding As stated earlier, the SOAP specification allows for two formatting options: Style and Use. The Use attribute relates to Web method parameters and return values. By spec ifying encoding values, you effectively are telling SOAP to attach certain attributes to an XML element so that it can be identified correctly. In this case, it can be set with one of the following two encoding values: This encoding value is the default, and it indicates that the SOAP mes sage is formatted exactly as dictated by the schema.
■ Literal
Lesson 1: How to Configure SOAP Messages
45
This encoding value indicates that the SOAP message is formatted as specified by XML Schema definitions specified in the WSDL. SOAP messages that are formatted with the SoapRpcMethod attribute always use the encoded value.
■ Encoded
NOTE
Parameter encoding enumeration
In addition to the Literal and Encoded values, the .NET Framework 2.0 allows for a third enumeration value of Default. The Default value indicates that the SOAP message Use attribute will be set to an empty string.
The System.Web.Services.Description namespace includes a SoapBindingUse enumera tion, which allows you to specify what encoding style your Web method will utilize. To utilize this enumeration, you must include a reference to this namespace at the top of your Web service class file. To specify parameter formatting using the encoding style for a GetVendorList Web method, you would use the following code: 'VB _ Public Sub GetVendorList() Dim sqlConn As New SqlConnection Dim rdr As XmlReader Dim ret As String = "" '... End Sub //C# [SoapDocumentMethod(Use=SoapBindingUse.Encoded)] [WebMethod(Description="Retrieve a list of active vendors ordered by name")] public string GetVendorList() { SqlConnection sqlConn;
XmlReader rdr;
string ret = "";
//...
}
Specifying Parameter Encapsulation The System.Web.Services.Protocols namespace includes a SoapParameterStyle enumera tion that can be used to specify how parameters are formatted in a SOAP message. This involves a process known as encapsulation, in which certain members of the object will be hidden and only what is needed is exposed to the client. It can be used to specify one of the following values:
46
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
All parameters will be placed within individual XML elements directly below the Body element of the SOAP message.
■ Bare
Indicates that this method will use the SoapParameterStyle that is applied to the entire Web service. The method will thus essentially inherit its value from the Web service. The default value for a Web service is Wrapped.
■ Default
All parameters will be wrapped within a single XML element and placed below the Body element of the SOAP message.
■ Wrapped
To specify parameter encapsulation using the SoapParameterStyle enumeration you must ensure that there is a reference to the System.Web.Services.Protocols namespace at the top of your Web service class file. You can then use the following code to specify the parameter using the SoapDocumentMethod attribute: 'VB _ Public Sub GetVendorList()
Dim sqlConn As New SqlConnection
Dim rdr As XmlReader
Dim ret As String = ""
'...
End Sub //C# [SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare, Use=SoapBindingUse.Literal)] [WebMethod(Description="Retrieve a list of active vendors ordered by name")] public string GetVendorList() { SqlConnection sqlConn;
XmlReader rdr;
string ret = "";
//...
}
Configuring SOAP Bindings The .NET Framework 2.0 supports the WS-I Basic Profile. The Basic Profile was devel oped by the Web Services Interoperability Organization with the goal of ensuring that Web services are built for the “real world.” MORE INFO
The Web Services Interoperability Organization
You can obtain more information about the WS-I from the following Web site: http://www.ws-i.org/ deliverables/workinggroup.aspx?wg=basicprofile.
Lesson 1: How to Configure SOAP Messages
47
You can build a Web service that complies with the WS-I Basic Profile by using the WebServiceBinding attribute on your Web service class file. The WebServiceBindingAt tribute class (see Table 2-1) allows you to declare one or more bindings for your Web service. Bindings represent a method of ensuring that the Web service conforms to cer tain specifications. Web services built using the Web services template are WS-I-compliant by default, as demonstrated by the WebServiceBinding attribute that was added to the Service.asmx file in Lab 1 in Chapter 1.The following code can be used to make the Web service cre ated in the last chapter WS-I-compliant and ensure that compliance claims are included in the WSDL that accompanies this Web service: 'VB _ //C# [WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1, EmitConformanceClaims=true)] [WebService(Namespace = "http://tempuri.org/")]
Table 2-1
Public Properties of the WebServiceBindingAttribute Class
Name
Description
ConformsTo
Retrieves or sets the WS-I specification to which the binding conforms. This property is new for the .NET Framework 2.0.
EmitConformanceClaims
Also new with the .NET Framework 2.0, this property retrieves or sets a Boolean value indicating whether the binding emits conformance claims.
Location
Retrieves or sets the location where the binding is defined. By default, this property is set to the Uniform Resource Locator (URL) for the Web service.
Name
Retrieves or sets the name of the binding. By default, this prop erty is the name of the Web service with the word Soap appended.
Namespace
Retrieves or sets the namespace of the binding. By default, this property is set to http://tempuri.org.
TypeId
Retrieves a unique identifier used to identify the attribute when it is implemented in a derived class.
48
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Specifying a Binding for Each Web Method In some cases you might want to specify multiple bindings for your Web service. To determine which binding is associated with each Web method, you use the Binding property for SoapDocumentMethod attribute. The following code is an example of a Web service that uses two different bindings and assigns a separate binding to each of its two Web methods: 'VB WebServiceBinding(Name := "BindingCompany1", _
Namespace := "http://www.company1.com/MyBinding"), _
WebServiceBinding(Name := "BindingCompany2", _
Namespace := "http://www.company2.com/MyBinding"> _
Public Class MultipleBindings _
Public Function BindingMethod1() As String
Return "Calling Binding Method 1"
End Function
_
Public Function BindingMethod2() As String
Return "Calling Binding Method 2"
End Function
End Class //C# [WebServiceBinding(Name="BindingCompany1",
Namespace="http://www.company1.com/MyBinding")]
[WebServiceBinding(Name="BindingCompany2",
Namespace="http://www.company2.com/MyBinding")]
public class MultipleBindings { [SoapDocumentMethod(Binding="BindingCompany1")] [WebMethod(Description="Binding used when calling the first Web method")] public string BindingMethod1() { return "Calling Binding Method 1";
}
[SoapDocumentMethod(Binding="BindingCompany2")] [WebMethod(Description="Binding used when calling the second Web method") ] public string BindingMethod2() { return "Calling Binding Method 2";
}
}
Lesson 1: How to Configure SOAP Messages
49
Customizing SOAP Messages with XML Serialization The System.Xml.Serialization namespace contains the XmlSerializer class, which is the underlying transport mechanism for Web services built with the .NET Framework 2.0. This class is what is used by the .asmx handler to map the XML in a SOAP mes sage to an actual .NET object through a process called serialization. Deserialization is the process of generating a .NET object from XML. The XmlSerializer class can be used to customize SOAP messages using the XmlEle ment attribute. By controlling the XML, you can apply special attributes to class mem bers and method parameters. Table 2-2 lists the public properties available with the XmlSerializer class. Table 2-2 Public Methods of the XmlSerializer Class
Name
Description
CanDeserialize
Gets a Boolean value that indicates whether the XML docu ment can be deserialized.
Deserialize
Used to deserialize the document for a Stream, TextReader, XmlReader, XmlSerializationReader, or String.
Equals
Used to determine whether two objects are equal.
FromMappings
Retrieves an instance of the XmlSerializer class from the spec ified mappings.
FromTypes
Retrieves an array of XmlSerializer object types.
GenerateSerializer
Returns an assembly of serializers.
GetHashCode
Used in hashing algorithms and represents a hash function for a particular type.
GetType
Retrieves the type of the current instance.
GetXmlSerializerAssemblyName
Retrieves the name of the assembly used to serialize or deserialize the types.
Serialize
Used to serialize an object into an XML document.
ToString
Retrieves a string that represents the object it references.
50
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Changing an Element Name Using Serialization You can override the serialization of your objects and alter the name of certain fields using the XmlElementAttribute class. Therefore, you can choose what to set as the name of an element based on the value of some variable, which allows you a finer level of control over the XML your Web method generates. Assume you have a Vendor class that can be used to generate XML for one of your Web methods. The Vendor class might appear as follows: 'VB Public Class Vendor
Public VendorID As Integer
Public AccountNumber As String
Public Name As String
End Class //C# public class Vendor {
public int VendorID;
public string AccountNumber;
public string Name;
}
If you were to use this class to generate XML for your Web method, the output might look like the following:
9
ADATUM0001
A. Datum Corporation
Suppose that you want to alter the element name AccountNumber to read ReferenceNumber. To do this renaming, you would first need to add references to the Sys tem.Xml.Serialization and System.IO classes such as the following: 'VB Imports System.Xml.Serialization
Imports System.IO
//C# using System.Xml.Serialization;
using System.IO;
You would then need to create an instance of the XmlElementAttribute class and assign an alternative name for your element. You would then add your element to the
Lesson 1: How to Configure SOAP Messages
51
XmlAttributes class and create an instance of the XmlAttributesOverrides class that can be used to specify the element to change. After the Vendor fields were assigned values, a new instance of the XmlSerializer class could be used to serialize the XML stream into an XML document. The following code could be used to accomplish this task: 'VB ' Create an instance of the XmlElementAttribute class
Dim myElementAttribute As New XmlElementAttribute
' Define the alternative element name
myElementAttribute.ElementName = "ReferenceNumber"
' Create an instance of the XmlAttributes class
Dim myAttributes As New XmlAttributes
' Add the newly created Element attribute
myAttributes.XmlElements.Add(myElementAttribute)
' Create an instance of the XmlAttributeOverrides class
Dim myOverrides As New XmlAttributeOverrides
' Specify the object to be overridden
myOverrides.Add(GetType(Vendor), "AccountNumber", myAttributes)
' Create an instance of the XmlSerializer class
Dim mySerializer As New XmlSerializer(GetType(vendor), myOverrides)
' Create a new instance of the Vendor class and set the values
Dim Ven As New Vendor
Ven.VendorID = 9
Ven.AccountNumber = "ADATUM0001"
Ven.Name = "A. Datum Corporation"
' Creates a StreamWriter to write the XML stream to.
Dim myWriter As New StreamWriter("Vendor.xml")
' Serialize the object to an XML document
mySerializer.Serialize(myWriter, Ven)
//C# // Create an instance of the XmlElementAttribute class XmlElementAttribute myElementAttribute = new XmlElementAttribute(); //Define the alternative element name myElementAttribute.ElementName = "ReferenceNumber"; //Create an instance of the XmlAttributes class XmlAttributes myAttributes = new XmlAttributes(); //Add the newly created Element attribute
52
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
myAttributes.XmlElements.Add(myElementAttribute); //Create an instance of the XMLAttributeOverrides class
XmlAttributeOverrides myOverrides = new XmlAttributeOverrides();
//Specify the object to be overridden
myOverrides.Add(typeof(Vendor), "AccountNumber", myAttributes);
//Create an instance of the XmlSerializer class
XmlSerializer mySerializer = new XmlSerializer(typeof(Vendor), myOverrides);
//Create a new instance of the Vendor class and set the values
Vendor Ven = new Vendor();
Ven.VendorID = 9;
Ven.AccountNumber = "ADATUM0001";
Ven.Name = "A. Datum Corporation";
// Creates a StreamWriter to write the XML stream to.
StreamWriter myWriter = new StreamWriter("Vendor.xml");
//Serialize the object to an XML document
mySerializer.Serialize(myWriter, Ven);
Lab 1: How to Configure SOAP Messages This lab steps you through the process of configuring SOAP messages using the method-based alternative available with the .NET Framework 2.0. You will add to the Web service project created in Lab 1 of Chapter 1 and create two Web methods that can be used to compare the results of encoding your SOAP messages. The actual code used in the Web method is not important. What is important is the format of the SOAP message depending on which encoding method is utilized. By completing this lab, you will be able to compare the resulting SOAP messages for each Web method. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005 and load the project named MyWebService that was created in Lab 1 of Chapter 1. 2. Right-click the MyWebService.asmx file in Solution Explorer and click View Code. Remove the following line of code from near the top of the MyWebSer vice.asmx class file: 'VB _ //C# [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
Lesson 1: How to Configure SOAP Messages
53
3. Add the following code below the last Web method in the MyWebService.asmx class file: 'VB _ Public Function GetReturnValue(ByVal parm1 As Integer, ByVal parm2 As String) As String Return Convert.ToString(parm1) + parm2 End Function _
_
Public Function GetReturnValueEncoded(ByVal parm1 As Integer, _
ByVal parm2 As String) As String Return Convert.ToString(parm1) + parm2
End Function
//C# [WebMethod(Description = "Get a Return Value, but use the default use of Literal")]
public string GetReturnValue(int parm1, string parm2)
{
return Convert.ToString(parm1) + parm2;
}
[SoapDocumentMethod(Use = SoapBindingUse.Encoded)]
[WebMethod(Description = "Get a Return Value, but set the use attribute to be encoded")]
public string GetReturnValueEncoded(int parm1, string parm2)
{
return Convert.ToString(parm1) + parm2;
}
4. Build the project, and resolve any errors. 5. Right-click the MyWebService project in Solution Explorer and click Set As StartUp Project. 6. Right-click the MyWebService.asmx file in Solution Explorer and click Set As Start Page. 7. Press Ctrl+F5 to start without debugging. Your Web browser should open and point to the MyWebService.asmx file in your local Web service project. You will be brought to the Service help page for your Web service. It should display links to the following three methods: GetReturnValue, GetReturnValueEncoded, and GetVendorList. 8. Click the link for each of the first two methods and you will be brought to the Service method help page for that Web method. From here you can compare the sample SOAP messages for each Web method. Note that the Body element for the GetReturnValueEncoded Web method will appear as follows:
54
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
int string
9. Alternatively, the Body element for the GetReturnValue Web method will appear as follows:
int
string
Lesson Summary ■
The Service method help page can be used to invoke each public Web method. It also displays sample request and response SOAP messages in both the SOAP 1.1 and 1.2 specifications.
■
Envelope is the highest element in a SOAP message. It can contain an optional Header element and must contain a required Body element.
■
Style and Use are the two formatting attributes used to format SOAP messages.
■
RPC and Document are the two values available for the Style attribute. The .NET Framework 2.0 provides an attribute mechanism for altering these values. To do so you would apply the SoapRpcMethod and SoapDocument attributes.
■
Literal and Encoded are the two values available for specifying parameter encod ing as it applies to the Use attribute. Literal is the default value.
■
Bare, Default, and Wrapped are the enumeration values available for specifying parameter encapsulation.
■
One or more bindings can be specified with the WebServiceBindingAttribute class. This capability allows you to make your Web service components conform to the WS-I Basic Profile.
■
Web services utilize a two-step process known as serialization and deserializa tion to map XML generated by Web methods to .NET objects. The XmlSerializa tion class, which is part of the System.Xml.Serialization namespace, can be used to customize the SOAP messages generated by your Web methods.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “How to Configure SOAP Messages.” The questions are also available on the companion CD if you prefer to review them in electronic form.
Lesson 1: How to Configure SOAP Messages
NOTE
55
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What are the three main sections for a SOAP message? A. SOAP messages formatted with the SOAP 1.1 specification might contain a Header, Action, and Body element. B. SOAP messages formatted with the SOAP 1.1 or 1.2 specification might contain a Header, Action, and Body element. C. SOAP messages formatted with the SOAP 1.1 or 1.2 specification must con tain an Envelope, Header, and Body element. D. SOAP messages formatted with the SOAP 1.1 or 1.2 specification might contain an Envelope, Header, and Body element. 2. What is the purpose of the Encoded value as it applies to SOAP message formatting? A. This encoding value indicates that the SOAP message will be formatted as specified by XML Schema definitions in the WSDL. B. This encoding value indicates that the Web method will be secured using an encryption method. C. This is the default value used to specify parameter encoding. D. This is the default value used to specify parameter encapsulation. 3. Identify the Visual Basic code used to specify that a Web service complies with the WS-I Basic Profile. A.
B.
C. D.
4. What public method from the XmlSerializer class is used to serialize an object into an XML document? A. ToSerial B. Deserialize C. Serialize D. XmlSerialize
56
Chapter 2
Extending XML Web Services with SOAP Formatting, Custom Headers, and Extensions
Lesson 2: How to Implement SOAP Headers This lesson examines the different ways to implement a custom SOAP header. It begins by defining what a SOAP header is and what information is typically included in one. It then demonstrates how a header block can be specified through the WebMethod attribute. You will see how to create a custom class file that inherits from the System.Web.Services.Protocols.SoapHeader namespace. The Web method that imple ments the custom SOAP header will use the SoapHeader attribute to reference the cus tom class file. After this lesson, you will be able to: ■
Understand what basic elements are included in a SOAP header.
■
Know how to add a custom SOAP header class.
■
Build a client that processes the SOAP header.
■
Know how to handle unknown SOAP headers.
Estimated lesson time: 45 minutes
What Is a SOAP Header? Headers are one of the three elements that a SOAP message can contain. According to both the SOAP 1.1 and 1.2 specifications, the Header element is optional. You might recall from Lesson 1 that a SOAP message can contain up to three elements: the Enve lope (or the root element), the Header (the only optional element), and a Body (which contains the bulk of the message). When the Header is included, it should be placed directly below the Envelope element. Typically, the Header element should contain metadata, which describes what will be contained in the body of the message. The element can also specify how the SOAP request should be processed. In many cases the element contains information about authentication and transactions. According to the SOAP specification, there are three attributes that can be used in a Header element. They are as follows: Specifies how data should be encoded. This attribute is applica ble when the header is used to handle authentication requests.
■ encodingStyle
Specifies the actual node that will process the header block. For the SOAP 1.2 specification, this attribute was renamed to role.
■ actor/role
Binary value that specifies whether the block conforms to cer tain specifications.
■ mustUnderstand
Lesson 2: How to Implement SOAP Headers
57
The Header element can contain multiple header blocks, but each header block must have its own unique namespace. The following is an example of what a single SOAP header block might look like for a Web method named GetPurchaseTotal.
D.
2. Which attribute must be used when configuring an IPC channel? (Select the best answer.) A. portName B. port C. portNumber D. useIPAddress
164
Chapter 4 Review
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Remoting is a distributed technology that allows you to efficiently call objects located on different machines as if they resided on the same machine.
■
You can create single call or singleton objects, which are server-activated, or you can create a client-activated object.
■
Remote objects are hosted within a console application, Windows executable, ASP.NET application, or Windows service.
■
Remote applications can be configured programmatically by using the RemotingConfiguration class.
■
Remote applications can also be configured using a configuration file. This is the most flexible option because it allows you to make changes without requiring a code recompile.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
access control list (ACL)
■
application domain
■
asynchronous
■
Common Language Runtime (CLR)
165
Chapter 4 Review
■
supercomputer
■
Uniform Resource Identifier (URI)
Case Scenarios
In the following case scenarios, you will apply what you’ve learned about creating a remoteable type and configuring your remoting application. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Suggesting a Distributed Technology You are the lead developer for a scientific research institute. One of the scientists has requested that you design an application to process large amounts of data collected from several of the labs’ equipment. The data collected will need to be analyzed imme diately and any data outliers reported immediately to the responsible scientist. What type of distributed technology would be appropriate to use in this scenario?
Case Scenario 2: Using a Configuration File to Configure Your Remoting Application Expanding on Case Scenario 1, imagine that you are the lead developer for the scien tific research institute and you are now developing the remoting application proposed in that scenario. Because data needs to be collected from several pieces of equipment and very often there is a need to swap out this equipment, you realize that it is often necessary to change the port assignments assigned to the client applications. In order to effectively handle this situation, what method do you suggest should be used to configure your remoting solution?
Suggested Practices ■
Host your remote objects in IIS as an ASP.NET application so that you can take advantage of all the built-in functionality available. This functionality is espe cially true for security because you can take advantage of SSL for a secure line.
■
Use the binary formatter whenever possible because it is typically faster than the SOAP formatter.
166
Chapter 4 Review
■
Consider writing to an event log or log file when your object starts up or encoun ters an error. Include a timestamp, name of the remote object, and a port num ber. This information can be very useful for identifying and debugging problems with remoting.
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 5
Creating a Remoting Client Application This chapter elaborates on the process of using Microsoft Visual Studio 2005 to create a client application capable of consuming services provided by a remote object. You learn about proxies, activating remote objects, and accessing remote methods. You also learn about channels. Finally, you learn how to manage the remoting process through a configuration file.
Exam objectives in this chapter: ■
Create a client application to access a remote object. ❑
Create a remote object.
❑
Configure a client application programmatically.
❑
Configure a client application manually by using configuration files.
❑
Access the remoting service by calling a remote method.
❑
Call a remote method synchronously in a client application.
Lessons in this chapter: ■
Lesson 1: Creating a Client Application to Access a Remote Object . . . . . . . 169
■
Lesson 2: How to Configure a Client Application Using a Configuration File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
■
Lesson 3: How to Access a Remote Method . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction at the beginning of the book.
■
Visual Studio 2005 and the .NET Framework 2.0.
167
168
Chapter 5
Creating a Remoting Client Application
■
Familiarity with how to create a console application using either Microsoft Visual Basic or Microsoft Visual C#.
■
Familiarity with how to add references to projects.
Real World Shannon Horn Last year I worked on a project for a client located in Phoenix, Arizona. The client creates distributed applications for medical facilities. The applications are used to manage patient data for the facility. The applications provide a distinct user interface for each department in the medical facility, and each user interface can have one or more templates applied to it that customize the look and feel of the user interface. The templates used by the application function very similarly to cascading stylesheets used in Web applications. Furthermore, each user inter face is created as a separate .NET application and uses .NET remoting to connect to the central business tier and data tier, which reside in different application domains. The application also provides synchronization for doctors that use Microsoft Windows mobile devices to collect data during patient visits. However, integrat ing mobile devices involves a bit more complexity because, as of version 2.0, the .NET Compact Framework does not support .NET remoting. The use of .NET remoting to connect the distributed components of my client’s medical application proved to be a wise one. .NET remoting offers a high level of flexibility when adding new user interfaces to accommodate new departments and types of users. .NET remoting also provides the ability to easily relocate the components of the distributed application, provides very granular control over permissions and security, and fits the bill perfectly for this client because each component of the application is managed by a different development team.
Lesson 1: Creating a Client Application to Access a Remote Object
169
Lesson 1: Creating a Client Application to Access a Remote Object This lesson describes and demonstrates the process of creating a client application that consumes the services of a remote object using Visual Studio 2005. Successfully creating a remoting client application includes configuring the object activation mode and the communication channel. After this lesson, you will be able to: ■
Programmatically create and configure an application to serve as a client that con sumes services of a remote object.
■
Identify how proxy objects are used to relay data between remoting endpoints.
■
Identify and configure communication channels and the benefits inherent in each type of channel.
■
Describe how formatters are used to serialize and deserialize data in transit between remoting endpoints.
Estimated lesson time: 60 minutes
How to Create a Client Instance of a Remote Object Before diving headlong into a demonstration on creating an instance of a remote object in a client application, you must gain some background knowledge. Under standing the terminology introduced in the following sections is vital to mastering the client side of .NET remoting.
What Is a Proxy Object? A proxy is a substitute for a real item and is typically used as a security barrier between a real item and other items. For example, a proxy server is commonly used as a gate way between a corporate network and the Internet to provide a higher level of security when the network is exposed to the Web. As it relates to .NET remoting, in general terms, when a client application accesses a remote object, a proxy object is created on the client that represents and behaves in the same manner as the real remote object. There are two types of remote objects, mar shal-by-value (MBV) and marshal-by-reference (MBR). When an MBV remote object is accessed by a client application, a copy of the remote object is serialized on the server, passed to the client application, and deserialized on
170
Chapter 5
Creating a Remoting Client Application
the client, where it becomes a local copy of the remote object for the client application. Because the MBV object is copied local to the client application, a proxy is not neces sary to access the MBV object. MBV remote objects typically provide better perfor mance than MBR remote objects. However, after an MBV remote object is copied to the client, it might no longer be able to access resources available only on the server. Conversely, when an MBR remote object is accessed by a client application, the remote object is instantiated on the server and a reference to the object is passed to the client application. A proxy object is created on the client that represents and behaves like the MBR remote object on the server. All calls made to the remote object by the client application are made to the proxy object that is local to the client appli cation. The proxy object, in turn, serializes the call to the remote object and passes it to the remote object. The server receives the call from the client proxy, deserializes it, and forwards the call to the remote object on the server. The response from the remote object on the server is serialized by the server, passed back to the client proxy, and then passed to the client application. Hence, the proxy object gives the client application the impression that the remote object is local to the client application. MBR remote objects don’t normally perform as fast as MBV remote objects but do provide access to resources that reside on the server. In terms of the .NET Framework as previously described, a proxy object created to represent a remote object is called a transparent proxy. A transparent proxy is derived from the System.Runtime.Remoting.Proxies.RealProxy class. The RealProxy class is a managed class, hence transparent proxies are also managed by the Common Lan guage Runtime (CLR). Furthermore, the RealProxy class can be extended to create custom proxy classes.
Discovering Application URLs The first step in consuming the services of a remotable object is to locate and gather information about the remotable object. The process of gathering information about a remote object or service is commonly referred to as discovery. It can be challenging to discover information about a Web service created by a third party due to the wide open environment of the Web. However, .NET remoting objects are most commonly used in intranet environments and, as such, information about remotable objects is typically well known to the developers of an intranet that hosts remotable objects. Beyond the name of the remote object, the key piece of information that needs to be discovered about a remotable object is the application URL (Uniform Resource Locator).
Lesson 1: Creating a Client Application to Access a Remote Object
171
URLs are a form of Uniform Resource Identifier (URI) and the standard method used to identify a unique location for a resource using Internet protocols. The URL stan dard was created by Timothy Berners-Lee, the founder of the W3C (http:// www.w3.org/), and is governed by the W3C and the Internet Engineering Task Force (http://www.ietf.org). The URLs used in the code examples are shown here. Application URLs http://localhost:9000/Person.rem tcp://localhost:9000/Person.rem
The syntax of a URL consists of four segments. The first segment identifies the proto col to be used. In the preceding examples, http and tcp are the protocols being used. The second segment identifies the server where the URL is located. In the preceding examples, localhost is the server. The third segment identifies the port to be used. The default port used by Web servers for the Hypertext Transfer Protocol (HTTP) protocol is port 80. In the preceding examples, 9000 is the port. The fourth segment identifies the unique identifier for the resource known as the URI. In the preceding examples, Person.rem is the URI. MORE INFO
URIs, URNs, and URLs
For more information on URIs, URNs, and URLs, visit the overview provided by the W3C at http:// www.w3.org/Addressing/.
How to Configure a Client Application Programmatically The .NET Framework provides classes and methods to assist in programmatically configuring a client application to access a remote object. These classes are located in the System.Runtime.Remoting namespace and child namespaces. The following topics discuss how to programmatically configure a .NET remoting client application.
Configuring the Communication Channel The next step in the process of preparing to create a client instance of a remote object is to determine the communication channel to be used. A communication channel establishes a communication conduit or connection between two endpoints using a particular protocol. In terms of .NET remoting, a channel is used to communicate across remoting boundaries such as application domains or computers.
172
Chapter 5
Creating a Remoting Client Application
Channels can be used to send messages as they commonly do from a client. Channels can be used to listen for and receive incoming messages as they commonly do from a server. Additionally, a single channel can be used to both send and receive messages. As a practical analogy, a communication channel is similar to a television channel or radio channel. A signal is transmitted using a television or radio channel. If you would like to consume a particular television or radio signal, you must tune to the channel on which the signal is transmitted. The .NET Framework includes three prebuilt com munication channels: the HTTP channel, the Transmission Control Protocol (TCP) channel, and the interprocess communication (IPC) channel. Additionally, custom communication channels can be created by implementing the channel interfaces. A client application makes calls to methods on a remote object and receives the results of method calls by transporting messages across a communication channel. Messages can include advanced parameters and types that cannot be transported across a chan nel in their native form. To remedy this situation, all messages transported over a com munication channel are serialized before being transported and deserialized on arrival and processing. There are points along a communication channel where messages are prepared for serialization and deserialization as they are transported. These points are known as sinks. There are several types of sinks used by each channel. Sinks utilize serialization formatters to perform serialization and deserialization. The type of serialization implemented is determined based on the type of channel utilized. A remote object can enable communication using multiple types of channels simultaneously, but the cli ent application must use one of the communication channels implemented by the remote object to establish communication with the remote object. Recall the televi sion or radio analogy where you, as a consumer, must tune to the correct channel to receive a desired signal. The most common formats used to serialize messages transported across channels are binary format and Simple Object Access Protocol (SOAP) format. Binary format is more compressed than SOAP format but is not very portable. If portability is a con cern, such as when transporting messages over the Web, the SOAP format should be used. SOAP, being an Extensible Markup Language (XML) grammar, is extremely por table. However, in contrast to the binary format, the SOAP format is considered bloated.
Lesson 1: Creating a Client Application to Access a Remote Object
173
The .NET Framework provides classes in namespaces under the System.Runtime .Remoting.Channels namespace that represent each channel. To utilize a communica tion channel, an instance of a communication channel class must be created. After you determine the type of channel to be used and create an instance of the channel, the channel instance must be registered with the .NET Framework remoting system on the client machine. When you register a channel with the .NET Framework remoting sys tem, the remoting system enables the channel for communication. The System.Runtime .Remoting.Channels.ChannelServices class exposes static (Shared) members that are used to manage channel registration. The HTTP channel is used to transport messages across remoting boundaries using HTTP. The HTTP channel is instantiated on the client using the System.Runtime .Remoting.Channels.Http.HttpClientChannel class. The HttpClientChannel class can be configured to transport messages into either binary format or SOAP format. However, the HTTP channel is most commonly used with a SOAP formatter.
HTTP
The primary justification in using the HTTP channel to transport messages is the wide support for the HTTP protocol. Most Web servers open port 80 as the default port for sending and receiving HTTP messages to enable communication over the Web. Due to this arrangement, use of the HTTP channel enables .NET remoting without firewall blocks. The HTTP channel is typically used when remotable objects are hosted using Microsoft Internet Information Services (IIS). Instantiating the HttpClientChannel Class 'VB Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Http
Namespace MSLearning.Chapter5.Standard.ClientHttp Module HttpModule Sub Main() ' Create an instance of the HTTP client channel. Dim channel As HttpClientChannel = New HttpClientChannel() ' Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, False)
' more code to follow...
End Sub
174
Chapter 5
Creating a Remoting Client Application
End Module
End Namespace
//C# using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Http;
namespace MSLearning.Chapter5.Standard.ClientHttp {
class Program
{
static void Main(string[] args)
{
// Create an instance of the HTTP client channel. HttpClientChannel channel = new HttpClientChannel(); // Register the channel with the remoting system. ChannelServices.RegisterChannel(channel,false); // more code to follow...
}
}
}
The TCP channel is used to transport messages across remoting boundaries using TCP. The TCP channel is instantiated using the System.Runtime.Remoting.Chan nels.Tcp.TcpServerChannel class. The TcpServerChannel class can be configured to trans port messages into either binary format or SOAP format. The TCP channel is most commonly used with a binary formatter. Unlike the HTTP channel, the TCP channel can easily be blocked by firewalls and an open and valid port must be selected to com municate with the remote object.
TCP
Instantiating the TcpClientChannel Class 'VB Imports Imports Imports Imports Imports
System
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main()
Lesson 1: Creating a Client Application to Access a Remote Object
175
' Create an instance of the TCP client channel.
Dim channel As TcpClientChannel = New TcpClientChannel()
' Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, False)
' more code to follow... End Sub End Module End Namespace //C# using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
namespace MSLearning.Chapter5.Standard.ClientTcp
{ class Program { static void Main(string[] args)
{
// Create an instance of the TCP client channel.
TcpClientChannel channel = new TcpClientChannel();
// Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, false);
// more code to follow... } } }
The IPC channel is used to transport messages using Windows IPC. IPC is used to transport messages across remoting boundaries such as application domains that reside on the same computer. The IPC channel outperforms the HTTP channel and the TCP channel when remoting across boundaries on the same computer.
IPC
The IPC channel is instantiated using the System.Runtime.Remoting.Channels.Ipc.IpcServerChannel class. The IpcServerChannel class can be configured to transport mes sages into either binary format or SOAP format. The IPC channel is most commonly used with a binary formatter. Instantiating the IpcClientChannel Class 'VB Imports System Imports System.Runtime
176
Chapter 5
Creating a Remoting Client Application
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Ipc
Namespace MSLearning.Chapter5.Standard.ClientIpc Module IpcModule Sub Main() ' Create an instance of the IPC client channel. Dim channel As IpcClientChannel = New IpcClientChannel() ' Register the channel with the remoting system. ChannelServices.RegisterChannel(channel, False) ' more code to follow...
End Sub
End Module
End Namespace
//C# using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Ipc;
namespace MSLearning.Chapter5.Standard.ClientIpc {
class Program
{
static void Main(string[] args)
{
// Create a new instance of the IPC client channel. IpcClientChannel channel = new IpcClientChannel(); // Register the channel with the remoting system. ChannelServices.RegisterChannel(channel, false); // more code to follow...
}
}
}
Remote Object Activation Thus far we have mentioned that to create an instance of a remote object on a client, you must discover information about the remote object including the object name and the URL where the object is hosted. Typically, discovery should not be difficult
Lesson 1: Creating a Client Application to Access a Remote Object
177
for remote objects, particularly those that are hosted on your local intranet. We also mentioned that you must configure a channel for communicating with the remote object. Code on the client that creates an instance of the remote object does not compile unless it has access to the remote object during compilation. The remote object is accessible to code when using Visual Studio by adding a reference to the remote object for the project being compiled. The process of adding a reference to a project in Visual Studio creates a copy of the remote object in the local project bin directory. To add a ref erence to a project in Visual Studio 2005, right-click the project in Solution Explorer and click Add Reference. The Add Reference dialog box, shown in Figure 5-1, is dis played. In .NET remoting, you add a reference to a .NET assembly. To navigate to a user-defined assembly, click the Browse tab, navigate to the assembly, and click OK.
Figure 5-1
The Visual Studio 2005 Add Reference dialog box
After you add a reference to the remote object to a project, any code that instantiates the remote object must fully qualify the namespace and name of the object when instantiating it or address the namespace with a using statement or Imports statement. Client code should compile after a reference is added to the project; however, at run time, the client calling code should be directed to the actual remote object instead of the local copy.
178
Chapter 5
Creating a Remoting Client Application
The next step in the remotable object discovery process is to determine the activation mode for the remote object. Server-Activated Objects A remote object must be activated, or created and initial ized just as any other object, before a client can call methods on the remote object. Because MBV remote objects are serialized, copied, and deserialized on the client machine, they are treated like a local client object and activated on deserialization. The .NET Framework remoting system supports two methods for activating an MBR remote object: server activation and client activation.
Server-activated objects come in two flavors: Singleton and SingleCall. Singleton serveractivated objects implement the Singleton design pattern. Only a single instance of a Singleton object is instantiated and that single instance services all incoming client calls to methods on that object. The lifetime of an instance of a Singleton object can span multiple calls from a client and, as such, it can maintain state between client calls. In contrast to Singleton objects, a new instance of a SingleCall server-activated object is created for every client method call. Likewise, SingleCall objects do not maintain state between client calls. A client application must register server-activated objects on the client to be able to instantiate the object. Server-activated objects are generally registered programmati cally on a client using the WellKnownClientTypeEntry class. The WellKnownClientTypeEntry class is used identically the same for the HTTP channel and the TCP channel. The IPC channel is only used to access objects on the same machine, hence it is not necessary to use the WellKnownClientTypeEntry class to register a server-acti vated object when using the IPC channel. The following code sample illustrates reg istering a remote object named IPerson using the TCP channel. The IPerson remote object is located at the URL tcp://localhost:9000/Person.rem and is in the namespace MSLearning.Chapter8.Standard.Server. After the WellKnownClientTypeEntry class is used to register the remote object with the client remoting system, the RemotingConfiguration class is used to complete the object registration. The RemotingConfiguration class exposes several static methods includ ing the RegisterWellKnownClientType method and the Configure method. The most commonly used of the two methods is the RegisterWellKnownClientType method as shown in the following code example.
Lesson 1: Creating a Client Application to Access a Remote Object
Registering Server-Activated Object on Client 'VB Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.Standard.Interfaces
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Create an instance of the TCP client channel.
Dim channel As TcpClientChannel = New TcpClientChannel()
' Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, False)
' Register the remote object. Dim remoteObject As WellKnownClientTypeEntry = _ New WellKnownClientTypeEntry(GetType(IPerson), _ "tcp://localhost:9000/Person.rem") RemotingConfiguration.RegisterWellKnownClientType(remoteObject) ' more code to follow... End Sub End Module End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.Standard.Interfaces;
namespace MSLearning.Chapter5.Standard.ClientTcp
{ class Program { static void Main(string[] args)
{
// Create an instance of the TCP client channel.
TcpClientChannel channel = new TcpClientChannel();
// Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, false);
179
180
Chapter 5
Creating a Remoting Client Application
// Register the remote object. WellKnownClientTypeEntry remoteObject =
new WellKnownClientTypeEntry(typeof(IPerson),
"tcp://localhost:9000/Person.rem");
RemotingConfiguration.RegisterWellKnownClientType(
remoteObject);
// more code to follow... } } }
As with many methods in the .NET Framework, the RegisterWellKnownClientType method is overloaded to provide a shortcut. The preceding code example using the WellKnownClientTypeEntry method and the RegisterWellKnownClientType method can be consolidated into a single call to the RegisterWellKnownClientType method, as the following shows. Registering Server-Activated Object on Client 'VB Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.Standard.Interfaces
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Create an instance of the TCP client channel.
Dim channel As TcpClientChannel = New TcpClientChannel()
' Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, False)
' Register the remote object. RemotingConfiguration.RegisterWellKnownClientType( _ GetType(IPerson), "tcp://localhost:9000/Person.rem") ' more code to follow... End Sub End Module End Namespace //C# using System; using System.Runtime; using System.Runtime.Remoting;
Lesson 1: Creating a Client Application to Access a Remote Object
181
using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using MSLearning.Chapter5.Standard.Interfaces; namespace MSLearning.Chapter5.Standard.ClientTcp { class Program { static void Main(string[] args)
{
// Create an instance of the TCP client channel.
TcpClientChannel channel = new TcpClientChannel();
// Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, false);
// Register the remote object. RemotingConfiguration.RegisterWellKnownClientType( typeof(IPerson), "tcp://localhost:9000/Person.rem"); // more code to follow... } } }
As mentioned, when calling client code references the remote object in Visual Studio, a copy of the remote object is created in the project bin directory. How does the client application handle changes that might be made to the remote object on the server? One option is to delete the reference to the remote object in the client project and add a new reference to the new version of the remote object. However, this option is not practical, as it requires that the developer remains aware of any updates to the remote object and recompiles the client project for each update. A design alternative to referencing the remote object in the client project is to refer ence an interface implemented by the remote object. The client project does not require full implementation of the remote object to compile; an interface will suffice. This approach is best implemented if utilized from the beginning of the remote object development cycle. The preceding code examples implemented the interface design approach, and this is evident when the remote object instance is created from the IPerson interface. The primary benefit of designing remote objects to implement an interface is that the full remote object does not need to be distributed to the client. This approach increases the stability of your application that uses .NET remoting by allowing it to easily accommodate functional updates to methods in the remote object, as the method implementation is not distributed with the interface. Furthermore, this
182
Chapter 5
Creating a Remoting Client Application
design approach increases security for the server that hosts the remote object, as infra structure details on the server accessed by code in the remote object are not exposed. Client-Activated Objects The .NET Framework remoting system also supports clientactivated objects. Client-activated objects are instantiated on the client instead of on the server. Each instance of a client-activated object is unique, and the client manages the lifetime of the object. Because the client is in complete control of the lifetime, clientactivated objects can maintain state between client calls.
Client-activated objects are generally registered programmatically using the Remot ingConfiguration.RegisterActivatedClientType method. The RegisterActivatedClientType method is used to register a remote object on the client as an object that can be accessed on the server. The following code illustrates using the RegisterActivatedClientType method and the TCP channel to create an instance of a remote object that implements the IPerson inter face, is located at the URL tcp://localhost:9000/Person.rem, and is in the namespace MSLearning.Chapter5.Standard.Server. Registering Client-Activated Object on Client 'VB Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.Standard.Interfaces
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Create an instance of the TCP client channel.
Dim channel As TcpClientChannel = New TcpClientChannel()
' Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, False)
' Register the remote object.
RemotingConfiguration.RegisterActivatedClientType( _
GetType(IPerson), "tcp://localhost:9000/Person.rem")
' more code to follow...
End Sub
End Module
Lesson 1: Creating a Client Application to Access a Remote Object
183
End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.Standard.Interfaces;
namespace MSLearning.Chapter5.Standard.ClientTcp
{ class Program { static void Main(string[] args)
{
// Create an instance of the TCP client channel.
TcpClientChannel channel = new TcpClientChannel();
// Register the channel with the remoting system.
ChannelServices.RegisterChannel(channel, false);
// Register the remote object.
RemotingConfiguration.RegisterActivatedClientType(
typeof(IPerson), "tcp://localhost:9000/Person.rem");
// more code to follow... } } }
Just as with the RegisterWellKnownClientType method, the RegisterActivatedClientType method is overloaded twice. The first overload accommodates you registering the remote type first and then passing that object to the RegisterActivatedClientType method. The second overload accommodates you passing the registration informa tion directly to the RegisterActivatedClientType method and it handles registering the object. The latter overload is used in the preceding code examples.
Calling a Remote Object Method Now that the groundwork has been set for programmatically configuring a .NET remoting client, our next task is to create an instance of the remote object and call methods on the object. There are several ways to call a method on a remote object. Each means for calling remote methods is covered in detail in Lesson 3. In the follow ing code example, we illustrate how to create an instance of a remote object represent ing a patient by instantiating it as any other object.
184
Chapter 5
Creating a Remoting Client Application
Instantiating a Remote Object 'VB Imports Imports Imports Imports Imports Imports
System
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter5.PatientClasses
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Create an instance of the TCP client channel. Dim channel As TcpClientChannel = New TcpClientChannel() ' Register the channel with the remoting system. ChannelServices.RegisterChannel(channel, False) ' Register the remote object. RemotingConfiguration.RegisterActivatedClientType( _ GetType(Patient), "tcp://localhost:9000/Patient.rem") ' Create an instance of the remote Patient class. Dim newPatient As Patient = New Patient() ' Call the PersonalInformation method on the remote object. Console.WriteLine(newPatient.PersonalInformation()) End Sub End Module End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
namespace MSLearning.Chapter5.ClientTcp {
class Program
{
static void Main(string[] args) { // Create an instance of the TCP client channel. TcpClientChannel channel = new TcpClientChannel();
Lesson 1: Creating a Client Application to Access a Remote Object
185
// Register the channel with the remoting system. ChannelServices.RegisterChannel(channel, false); // Register the remote object. RemotingConfiguration.RegisterWellKnownClientType( typeof(Patient), "tcp://localhost:9000/Patient.rem"); // Create an instance of the remote Patient class. Patient newPatient = new Patient(); // Call the PersonalInformation method on the remote object.
Console.WriteLine(newPatient.PersonalInformation());
}
}
}
Lab 1: Creating a Client Application This lab is a simplified simulated version of an application that manages patient data. The lab walks you through the process of creating and programmatically configuring a .NET remoting server, remote object, and client. The remote object includes meth ods to retrieve data for a sample patient. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. �
Exercise 1: Creating a Remote Object
1. Start Visual Studio 2005, and on the File menu, click New, Project to create a new project that will serve as the remote object. The remote object simulates an object that provides patient information. a. In the Project Types pane, select your language of choice (Visual Basic or Visual C#). b. In the Templates pane, click Class Library. c. In the Name text box, type RemotePatient. d. In the Location drop-down list, type or browse to the location where you would like to create the new project. e. Click OK. 2. In the Class1.cs file (Visual C#) or the Class1.vb file (Visual Basic), add the fol lowing namespace references: 'VB Imports System
Imports System.Runtime.Remoting
186
Chapter 5
Creating a Remoting Client Application
//C# using System;
using System.Runtime.Remoting;
3. Rename Class1 to Patient and modify the Patient class to extend the MarshalB yRefObject as the following shows. Wrap the Patient class in a namespace named MSLearning.Chapter5.PatientClasses. 'VB Namespace MSLearning.Chapter5.PatientClasses
Public Class Patient
Inherits MarshalByRefObject
End Class
End Namespace
//C# namespace MSLearning.Chapter5.PatientClasses {
public class Patient : MarshalByRefObject
{
}
}
4. In the Patient class, create two functions that return a string. The first function should be named PersonalInformation and the second should be named History. The functions are shown here: 'VB Public Function PersonalInformation() As String Return "Patient ID: 001 :: Demo Patient"
End Function
Public Function History() As String Return "01/12/2001; Diagnosis: cold | Treatment: take 2 and call " & _ "me in the morning." + Chr(13) + Chr(10) + _ "03/04/2005; Diagnosis: broken toe | Treatment: nothing." End Function //C# public string PersonalInformation()
{
return "Patient ID: 001 :: Demo Patient";
}
public string History()
{
Lesson 1: Creating a Client Application to Access a Remote Object
187
return "01/12/2001; Diagnosis: cold | Treatment: take 2 and call " + "me in the morning.\n\r03/04/2005; Diagnosis: broken toe | " + "Treatment: nothing."; }
5. On the Build menu, click Build RemotePatient to compile the project. �
Exercise 2: Creating a Server
1. On the File menu, click New, Project to create a new project that will serve as the server application that hosts the Patient remote object. a. In the Project Types pane, select your language of choice (Visual Basic or Visual C#). b. In the Templates pane, click Console Application. c. In the Name text box, type LabServer. d. In the Location drop-down list box, type or browse to the location where you would like to create the new project. e. Click OK. 2. Right-click the LabServer project in Solution Explorer and click Add Reference to add references to the Remoting namespace and the Patient remote object. a. On the .NET tab, scroll to the System.Runtime.Remoting namespace and double-click it. b. Right-click on the project in Solution Explorer and click Add Reference again. c. On the Browse tab, navigate to the RemotePatient\Bin\Debug directory and double-click the RemotePatient.dll file. 3. In the Program.cs file (Visual C#) or the Module1.vb file (Visual Basic), add the following namespace references: 'VB Imports Imports Imports Imports //C# using using using using
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
188
Chapter 5
Creating a Remoting Client Application
4. Wrap the Program class (C#) or Module1 (Visual Basic) in a namespace named MSLearning.Chapter5.Server. 'VB Namespace MSLearning.Chapter5.Server Module Module1 Sub Main() End Sub
End Module
End Namespace
//C# namespace MSLearning.Chapter5.Server {
class Program
{
static void Main(string[] args)
{
}
}
}
5. Right-click the project in Solution Explorer and click Add, New Item. In the Add New Item dialog box, select Application Configuration File and click Add. Mod ify the application configuration file as shown here:
6. In the Main method (Visual C#) or Sub Main (Visual Basic), type the following code. This code is used to load the application configuration file and load the remote object. 'VB RemotingConfiguration.Configure("LabServer.exe.config", False)
Lesson 1: Creating a Client Application to Access a Remote Object
189
Console.WriteLine("Press return to exit..." + Chr(10))
Console.ReadLine()
//C# RemotingConfiguration.Configure("LabServer.exe.config", false);
Console.WriteLine("Press return to exit...\n");
Console.ReadLine();
7. On the Build menu, click Build LabServer to compile the project. After the server successfully builds, press Ctrl+F5 to start the server without debugging. A con sole window should be displayed for the server; minimize this window. �
Exercise 3: Creating a Remote Client
1. On the File menu, click New, Project to create a new project that will serve as the client application to consume the Patient remote object from the LabServer. a. In the Project Types pane, select your language of choice (Visual Basic or Visual C#). b. In the Templates pane, click Console Application. c. In the Name text box, type LabConsumer. d. In the Location drop-down list box, type or browse to the location where you would like to create the new project. e. Click OK. 2. Right-click the LabConsumer project in Solution Explorer and click Add Refer ence to add references to the Remoting namespace and the Patient remote object. a. On the .NET tab, scroll to the System.Runtime.Remoting namespace and double-click it. b. Right-click the project in Solution Explorer and click Add Reference again. c. On the Browse tab, navigate to the RemotePatient\Bin\Debug directory and double-click the RemotePatient.dll file. 3. In the Program.cs file (Visual C#) or the Module1.vb file (Visual Basic), add the following namespace references: 'VB Imports Imports Imports Imports Imports
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter5.PatientClasses
//C# using System.Runtime;
190
Chapter 5
using using using using
Creating a Remoting Client Application
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
4. In the Main method (Visual C#) or Sub Main (Visual Basic), type the following code. This code is used to instantiate an instance of the TCP channel. 'VB Dim channel As TcpClientChannel = New TcpClientChannel() //C# TcpClientChannel channel = new TcpClientChannel();
5. Below the TcpClientChannel instance, type the following code to register the channel: 'VB ChannelServices.RegisterChannel(channel, False) //C# ChannelServices.RegisterChannel(channel, false);
6. Below the channel registration, type the following code to register the remote Patient object: 'VB RemotingConfiguration.RegisterWellKnownClientType( _ GetType(Patient), "tcp://localhost:9000/Patient.rem") //C# RemotingConfiguration.RegisterWellKnownClientType( typeof(Patient), "tcp://localhost:9000/Patient.rem");
7. Below the channel registration, type the following code to create an instance of the remote Patient type: 'VB Dim newPatient As Patient = New Patient() //C# Patient newPatient = new Patient();
8. Below the code that creates an instance of the Patient object, type the following code or something similar to utilize and test the PersonalInformation method and the History method on the remote object: 'VB Console.WriteLine(newPatient.PersonalInformation())
Console.WriteLine(newPatient.History())
Lesson 1: Creating a Client Application to Access a Remote Object
191
//C# Console.WriteLine(newPatient.PersonalInformation());
Console.WriteLine(newPatient.History());
9. On the Build menu, click Build LabConsumer to compile the project. After the project successfully builds, press Ctrl+F5 to start the program without debug ging. The console output should render something similar to this: Patient ID: 001 :: John Doe :: 123 Main Street :: Someplace, AZ 85000 01/12/2001; Diagnosis: cold | Treatment: take 2 and call me in the morning. 03/04/2005; Diagnosis: broken toe | Treatment: nothing.
10. Close the console window for the LabConsumer project and the LabServer project.
Lesson Summary ■
There are two types of remotable objects: marshal-by-value and marshal-by reference.
■
Marshal-by-value objects are serialized on the hosted server, transported to the client machine, deserialized, and behave as a locally defined object.
■
Marshal-by-reference objects reside on the hosted server and calls from the client are transported to the object.
■
A proxy object is used to serve as a local client representation of a marshal-by reference object so that the object appears to be a local object although it is on the server.
■
There are two types of proxy objects: transparent proxy and real proxy. Real proxy is the base class for the transparent proxy. Real proxy can be extended to create custom proxy classes.
■
The URL where a remote object can be located is required to successfully con nect to the object when connecting via HTTP or TCP.
■
A communication channel is used to establish a communication conduit between your calling client code and the object on the server. The .NET Frame work provides three types of channels: HTTP, TCP, and IPC.
■
Before a remote object can be accessed, it must be activated. The .NET Frame work provides two types of activation: server activation and client activation. Server-activated objects can be configured to be Singleton or SingleCall.
192
Chapter 5
Creating a Remoting Client Application
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Creating a Client Application to Access a Remote Object.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which channel offers the best performance if the remote object and the client reside on the same computer? (Select the best answer.) A. The IPC channel B. The HTTP channel C. The TCP channel D. The FTP channel 2. What methods does the .NET Framework provide for activating remote objects? (Select all that apply.) A. Server-activated Singleton B. Client-activated C. Server-on-demand activation D. Server-activated SingleCall 3. How do marshal-by-value objects compare to marshal-by-reference objects? (Select all that apply.) A. Marshal-by-value objects maintain state between client calls. B. A proxy object is created for marshal-by-value objects. C. Marshal-by-reference objects can directly access resources on the server. D. A proxy object is created for marshal-by-reference objects. E. Marshal-by-value objects can directly access resources on the server.
Lesson 2: How to Configure a Client Application Using a Configuration File
193
Lesson 2: How to Configure a Client Application Using a Configuration File In Lesson 1, we focused on how to programmatically configure a client application to be able to access a remote object. Programmatically configuring a client application is perfectly viable, but client applications can also be configured using .NET Framework configuration files. To add a configuration file to a project using Visual Studio, rightclick the project in Solution Explorer and click Add, New Item, Application Configu ration File. By default, if your application is an ASP.NET application, the configuration file is named Web.config; in all other application types, the configuration file is named App.config. After this lesson, you will be able to: ■
Create and configure an application to serve as a client that consumes services of a remote object by using an application configuration file.
■
Identify and configure communication channels and the benefits inherent in each type of channel.
Estimated lesson time: 60 minutes
The .NET Framework provides several classes that comprise an entire infrastructure to work with configuration files. .NET Framework configuration files utilize a custom XML grammar that is fully documented in the MSDN Library. The primary advantage of configuring .NET remoting applications using configuration files is that many of the options can be modified without recompiling the application. Additionally, if your application includes .NET remoting clients that are written using different languages (such as Visual Basic or C#), a single configuration file can be used for all languages. MORE INFO
.NET configuration files
For more information on .NET configuration files, visit the topic titled “Configuration Files” at http://msdn2.microsoft.com/.
The XML grammar, or schema, implemented by the standard .NET Framework con figuration file includes a topmost element named configuration. There are many pos sible child elements that exist under the element, including custom elements; however, Table 5-1 lists the commonly used child elements related to .NET remoting.
194
Chapter 5
Creating a Remoting Client Application
Table 5-1
.NET Remoting Configuration File Commonly Used Elements
Element
Description
This is the root element for .NET remoting configuration settings. This element can appear only once per configuration file. The attribute of the element is listed below. ■
Identifies the .NET remoting version to which the settings apply. version
This element includes application-specific information. This ele ment is a child of the element. This ele ment can appear only once per configuration file. The attribute of the element is listed below. ■
Identifies the name of the application to which the settings apply.
name
This element is used to define the lifetime of all client-activated objects. This element is a child of the element. This element can appear only once per configuration file. The attributes of the element are listed below. Identifies the amount of time that a client-acti vated object is leased for, or the extent of its lifetime. The default lease time is 5 minutes.
■ leasTime
Identifies the length of time that the lease manager waits for a lease to be renewed after it has expired. The default timeout is 2 minutes.
■ sponsorshipTimeout
Identifies the lease time for a client-acti vated object where the lease is extended by this amount on each call to a method on the object. The default timeout is 2 minutes.
■ renewOnCallTime
Identifies how often the lease man ager checks for expired client-activated object leases. The default poll time is 10 seconds.
■ leaseManagerPollTime
Lesson 2: How to Configure a Client Application Using a Configuration File
Table 5-1
195
.NET Remoting Configuration File Commonly Used Elements
Element
Description
This element identifies all services hosted by this application. This element is a child of the element. This element can appear zero or more times per configuration file.
This element identifies the objects that the application con sumes. This element is a child of the element. This element can appear zero or more times per configuration file. The attributes of the element are listed below. Identifies the URL for a client-activated object and is required.
■ url
■ displayName
Identifies one client object from another cli
ent object.
This element identifies the well-known objects provided by the service. This element is a child of the element or the element. This element can appear zero or more times per configuration file. The attributes of the element are listed below. Identifies the type of server activation: SingleCall or Singleton. This attribute is required.
■ mode
Identifies the type name and the assembly that con tains the type. This attribute is required.
■ type
Identifies the URI that will be used to connect to an object. This attribute is required and is only allowed in elements under elements.
■ objectUri
Identifies the URL that will be used to connect to a ser vice. This attribute is required and is only allowed in elements under elements.
■ url
■ displayName
ent object.
Identifies one client object from another cli
196
Chapter 5
Creating a Remoting Client Application
Table 5-1
.NET Remoting Configuration File Commonly Used Elements
Element
Description
This element identifies the client-activated objects provided by the service. This element is a child of the element or the element. This element can appear zero or more times per configuration file. The attribute of the element is listed below. ■
Identifies the type name and the assembly that con tains the type. This attribute is required. type
This element is used to configure existing channels or define new channels. This element is a child of the element or the element.
This element is used to identify a channel to be created or config ured. This element is a child of the element. This ele ment can appear zero or more times per configuration file. The attributes of the element are listed below. Identifies the ID used to refer to the channel definition. This attribute is required.
■ id
Identifies the full type name of the channel. This attribute is required.
■ type
Identifies the channel being configured, if one already exists.
■ ref
■ name
Identifies the name of the channel.
Identifes a priority of channels to be used. A higher priority channel will be used for communication, if possible.
■ priority
■
displayName Identifies one channel from another channel.
The .NET remoting section of the configuration file can contain more elements and attributes than those listed here. For a complete list of possible elements and attributes, see the MSDN article titled “Remoting Settings Schema” at http:// msdn2.microsoft.com/en-us/library/z415cf9a.aspx.
Lesson 2: How to Configure a Client Application Using a Configuration File
197
When an application is configured using a configuration file, you must instruct your code to retrieve configuration information from the file. The RemotingConfiguration class is used to manage the configuration of the .NET remoting system. The Configure method of the RemotingConfiguration class is used to load a configuration file in code. Using the most common overload of the method, the method accepts two parame ters: the name of the configuration file to load and a Boolean value indicating whether to enable security.
Configuring the Communication Channel In Lesson 1, we defined channels and how they are used to form a communication conduit between a calling client and a hosting server in a .NET remoting environ ment. The .NET Framework provides three prebuilt channels that implement the IChannel interface. The IChannel interface can be implemented to create custom channels as well. Each of the channel types, HTTP, TCP, and IPC, can be programmatically configured, as in Lesson 1. Each type of communication channel can also be configured using a .NET configuration file.
HTTP Channel The HTTP channel is used to serialize, deserialize, and transport data using HTTP. HTTP is primarily used to communicate over the Web. The next code example is iden tical to the code example used to illustrate the HTTP channel in Lesson 1. However, the code example here is somewhat simplified and utilizes the configuration file shown here. Instantiating the HttpClientChannel Class Using a Configuration File CONFIGURATION FILE
'VB Imports System
198
Chapter 5
Imports Imports Imports Imports
Creating a Remoting Client Application
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Http
Namespace MSLearning.Chapter5.Standard.ClientHttp Module HttpModule Sub Main() ' Load the configuration file. RemotingConfiguration.Configure( _ "RemoteClientHttpCS.exe.config", False) ' more code to follow...
End Sub
End Module
End Namespace
//C# using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Http;
namespace MSLearning.Chapter5.Standard.ClientHttp {
class Program
{
static void Main(string[] args)
{
// Load the configuration file. RemotingConfiguration.Configure( "RemoteClientHttpCS.exe.config", false); // more code to follow...
}
}
}
TCP Channel The TCP channel is used to serialize, deserialize, and transport data using TCP. TCP is primarily used to communicate over the Web and networks. The following code example is identical to the code example used to illustrate the TCP channel in Lesson 1. However, the code example here is somewhat simplified and utilizes the configura tion file shown here.
Lesson 2: How to Configure a Client Application Using a Configuration File
Instantiating the TcpClientChannel Class Using a Configuration File CONFIGURATION FILE
'VB Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.PatientClasses
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Load the configuration file.
RemotingConfiguration.Configure( _
"RemoteClientTcpCS.exe.config", False)
' more code to follow... End Sub End Module End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
namespace MSLearning.Chapter5.ClientTcp
{ class Program { static void Main(string[] args)
{
199
200
Chapter 5
Creating a Remoting Client Application
// Load the configuration file. RemotingConfiguration.Configure( "RemoteClientTcpCS.exe.config", false); // more code to follow...
}
}
}
IPC Channel The IPC channel is used to serialize, deserialize, and transport data using the Win dows interprocess communication. IPC is used to consume remotable objects resid ing on the same machine and, in this scenario, the IPC channel offers better performance than the HTTP channel or TCP channel. The following code example is identical to the code example used to illustrate the IPC channel in Lesson 1. However, the code example here is somewhat simplified and utilizes the configuration file shown here. Instantiating the IpcClientChannel Class Using a Configuration File CONFIGURATION FILE
'VB Imports Imports Imports Imports Imports
System
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Ipc
Namespace MSLearning.Chapter5.Standard.ClientIpc Module IpcModule Sub Main() ' Load the configuration file. RemotingConfiguration.Configure( _ "RemoteClientIpcVB.exe.config", False)
Lesson 2: How to Configure a Client Application Using a Configuration File
201
' more code to follow...
End Sub
End Module
End Namespace
//C# using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Ipc;
namespace MSLearning.Chapter5.Standard.ClientIpc {
class Program
{
static void Main(string[] args)
{
// Load the configuration file. RemotingConfiguration.Configure( "RemoteClientIpcCS.exe.config", false); // more code to follow...
}
}
}
Configuring the Activation Mode Just as the communication channel can be configured via a configuration file, the remote object activation mode can also be configured via a configuration file. The .NET Framework provides two methods for activating an object: server activation and client activation. Each activation mode can be configured using a .NET configuration file.
Server-Activated Objects Server-activated objects can be in the form of a Singleton object or a SingleCall object. A Singleton object is one where only a single instance of the object is created to service all client calls. The lifetime of a Singleton object can span multiple client calls, hence a Sin gleton object can maintain state between client calls. A SingleCall object is one where a new instance of the object is created to handle each client call. Each instance of the object is destroyed and released from memory after it services a client call. SingleCall objects do not maintain state between client calls. The client making calls only needs to be aware that the object is a server-activated object but not how the object is handled on the server.
202
Chapter 5
Creating a Remoting Client Application
The following code example is identical to the code example used to illustrate regis tering a server-activated object in Lesson 1, but it illustrates configuring the object activation mode using a .NET configuration file. As you can see, when using a config uration file, the client calling code becomes much simpler. Registering a Server-Activated Object on Client Using a Configuration File CONFIGURATION FILE
'VB Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.PatientClasses
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Load the configuration file.
RemotingConfiguration.Configure( _
"RemoteClientTcpCS.exe.config", False)
' Create an instance of the remote Patient class.
Dim newPatient As Patient = New Patient()
' Call the PersonalInformation method on the remote object. Console.WriteLine(newPatient.PersonalInformation()) End Sub End Module End Namespace
Lesson 2: How to Configure a Client Application Using a Configuration File
//C# using using using using using using
203
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
namespace MSLearning.Chapter5.ClientTcp
{ class Program { static void Main(string[] args)
{
// Load the configuration file.
RemotingConfiguration.Configure(
"RemoteClientTcpCS.exe.config", false);
// Create an instance of the remote Patient class.
Patient newPatient = new Patient();
// Call the PersonalInformation method on the remote object. Console.WriteLine(newPatient.PersonalInformation()); } } }
Client-Activated Objects Client-activated objects are remote objects that are instantiated local to the client. Thus, the client treats the object as any other locally defined object and controls the lifetime of the object. Calls made to the object are serialized, transported to the server, and deserialized for processing. The lifetime of a client-activated object might span multiple client calls, hence it can maintain state between client calls. The following code example is identical to the code example used to illustrate regis tering a client-activated object in Lesson 1, but it illustrates configuring the object acti vation mode using a .NET configuration file. The element used for server activations has been replaced here with the element used for client activa tions. As you can see, when using a configuration file, the client calling code becomes much simpler. Registering a Client-Activated Object on Client Using a Configuration File CONFIGURATION FILE
204
Chapter 5
Creating a Remoting Client Application
'VB Imports Imports Imports Imports Imports Imports
System
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter5.PatientClasses
Namespace MSLearning.Chapter5.Standard.ClientTcp Module TcpModule Sub Main() ' Load the configuration file. RemotingConfiguration.Configure( _ "RemoteClientTcpCS.exe.config", False) ' Create an instance of the remote Patient class. Dim newPatient As Patient = New Patient() ' Call the PersonalInformation method on the remote object. Console.WriteLine(newPatient.PersonalInformation()) End Sub End Module End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
namespace MSLearning.Chapter5.ClientTcp {
class Program
{
static void Main(string[] args)
Lesson 2: How to Configure a Client Application Using a Configuration File
205
{ // Load the configuration file. RemotingConfiguration.Configure( "RemoteClientTcpCS.exe.config", false); // Create an instance of the remote Patient class. Patient newPatient = new Patient(); // Call the PersonalInformation method on the remote object.
Console.WriteLine(newPatient.PersonalInformation());
}
}
}
Lab 2: Creating a Client Application This lab is a simplified simulated version of an application that manages patient data. The lab walks you through the process of creating and configuring a .NET remoting client using a configuration file. The client can access the server hosting a remote object. The remote object includes methods to retrieve data for a sample patient. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Using Visual Studio 2005, open the LabServer solution. On the Build menu, click Build LabServer to recompile the lab server. After the server successfully builds, press Ctrl+F5 to start the server without debugging. A console window should be displayed for the server; minimize this window. 2. On the File menu, click New, Project to create a new project that will serve as the client application to consume the Patient remote object from the LabServer. a. In the Project Types pane, select your language of choice (Visual Basic or Visual C#). b. In the Templates pane, click Console Application. c. In the Name text box, type LabConsumer. d. In the Location drop-down list box, type or browse to the location where you would like to create the new project. e. Click OK.
206
Chapter 5
Creating a Remoting Client Application
3. Right-click the LabConsumer project in Solution Explorer and click Add Refer ence to add references to the Remoting namespace and the Patient remote object. a. On the .NET tab, scroll to the System.Runtime.Remoting namespace and double-click it. b. Right-click the project in Solution Explorer and click Add Reference again. c. On the Browse tab, navigate to the RemotePatient\Bin\Debug directory and double-click the RemotePatient.dll file. 4. Right-click the LabConsumer project in Solution Explorer and click Add, New Item, Application Configuration File to add a new configuration file to the project. Modify the configuration file as follows:
5. In the Program.cs file (Visual C#) or the Module1.vb file (Visual Basic), add the following namespace references: 'VB Imports Imports Imports Imports Imports //C# using using using using using
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter5.PatientClasses
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
Lesson 2: How to Configure a Client Application Using a Configuration File
207
6. In the Main method (Visual C#) or Sub Main (Visual Basic), type the following code. This code is used to load the configuration file. 'VB RemotingConfiguration.Configure("LabConsumer.exe.config", False) //C# RemotingConfiguration.Configure("LabConsumer.exe.config", false);
7. Below the channel registration, type the following code to create an instance of the remote Patient type: 'VB Dim newPatient As Patient = New Patient() //C# Patient newPatient = new Patient();
8. Below the code that creates an instance of the Patient object, type the following code or something similar to utilize and test the PersonalInformation method on the remote object: 'VB Console.WriteLine(newPatient.PersonalInformation())
Console.WriteLine(newPatient.History())
//C# Console.WriteLine(newPatient.PersonalInformation());
Console.WriteLine(newPatient.History());
9. On the Build menu, click Build LabConsumer to compile the project. After the project successfully builds, press Ctrl+F5 to start the program without debug ging. The console output should render something similar to this: Patient ID: 001 :: John Doe :: 123 Main Street :: Someplace, AZ 85000 01/12/2001; Diagnosis: cold | Treatment: take 2 and call me in the morning. 03/04/2005; Diagnosis: broken toe | Treatment: nothing.
10. Close the console window for the LabConsumer project and the LabServer project.
Lesson Summary ■
Most facets of a .NET remoting client application can be configured both pro grammatically as well as by using configuration files.
■
.NET Framework configuration files implement a custom XML grammar, or schema.
208
Chapter 5
Creating a Remoting Client Application
■
Server-activated objects are configured using the element in the configuration file.
■
Client-activated objects are configured using the element in the con figuration file.
■
The RemotingConfiguration.Configure method is used to load an application con figuration file for .NET remoting.
Lesson Review You can use the following questions to test your knowledge of the information in Lesson 2, “How to Configure a Client Application Using a Configuration File.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which class is used to load a configuration file for .NET remoting? (Select the best answer.) A. WellKnownClientTypeEntry B. ChannelServices C. RemotingConfiguration D. RemotingServices 2. What is the root element for .NET remoting configuration information? (Select the best answer.) A. B. C. D.
Lesson 3: How to Access a Remote Method
209
Lesson 3: How to Access a Remote Method In Lessons 1 and 2, we illustrated how to create an instance of a remote object using the new (New) operator. This is the same approach you would use to create a new instance of any local object and is a simple solution if the client application has already been configured to connect to the remote object. However, the .NET Framework also provides the Activator object to activate various types. The Activator object includes a method named GetObject that can be used to cre ate an instance of a remote object. The GetObject method does not require that the remoting client be configured first as you pass the configuration information to the GetObject method. After this lesson, you will be able to: ■
Create a client instance of a remote object.
■
Synchronously call methods on an instance of a remote object.
Estimated lesson time: 30 minutes
After an instance of a remote object is successfully created, you can call methods on that object just as you would with any local object. The .NET Framework provides the ability to call remote methods both synchronously and asynchronously. Asynchro nous calls to remote object methods are a bit complex and are covered in Chapter 8, “Method Invocations and Event Management with .NET Remoting.” Because we’ve already illustrated how to create an instance of a remote object and syn chronously calling methods using the new operator, we focus here on using the Activator .GetObject method. The following code illustrates using the Activator.GetObject method to create an instance of the Patient remote object used in Lessons 1 and 2 and then call the PersonalInformation method. As you can see from the example code, if you prefer to write less code, the Activator.GetObject method is the way to go. Create an Instance of a Remote Object Using Activator.GetObject 'VB Imports Imports Imports Imports Imports
System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter5.PatientClasses
Namespace MSLearning.Chapter5.ActivatorGetObject Module GetObjectModule
210
Chapter 5
Creating a Remoting Client Application
Sub Main() ' Create an instance of the Patient class. Dim newPatient As Patient = _ CType(Activator.GetObject(GetType(Patient), _ "tcp://localhost:9000/Patient.rem"), Patient) ' Call a remote method.
Console.WriteLine(newPatient.PersonalInformation())
End Sub
End Module
End Namespace
//C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
namespace MSLearning.Chapter5.ActivatorGetObject {
class Program
{
static void Main(string[] args)
{
// Create an instance of the Patient class. Patient newPatient = (Patient)Activator.GetObject(typeof(Patient), "tcp://localhost:9000/Patient.rem"); // Call a remote method.
Console.WriteLine(newPatient.PersonalInformation());
}
}
}
Lab 3: How to Access a Remote Method The labs for Lessons 1 and 2 walked you through creating an instance of a remote object using the new (New) operator. This lab walks you through creating an instance of a remote object using the Activator.GetObject method. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Using Visual Studio 2005, open the LabServer solution. On the Build menu, click Build LabServer to recompile the lab server. After the server successfully
Lesson 3: How to Access a Remote Method
211
builds, press Ctrl+F5 to start the server without debugging. A console window should be displayed for the server; minimize this window. 2. On the File menu, click New, Project to create a new project that will serve as the client application to consume the Patient remote object from the LabServer. a. In the Project Types pane, select your language of choice (Visual Basic or Visual C#). b. In the Templates pane, click Console Application. c. In the Name text box, type LabConsumer. d. In the Location drop-down list box, type or browse to the location where you would like to create the new project. e. Click OK. 3. Right-click the LabConsumer project in Solution Explorer and click Add Refer ence to add references to the Remoting namespace and the Patient remote object. a. On the .NET tab, scroll to the System.Runtime.Remoting namespace and double-click it. b. Right-click the project in Solution Explorer and click Add Reference again. c. On the Browse tab, navigate to the RemotePatient\Bin\Debug directory and double-click the RemotePatient.dll file. 4. In the Program.cs file (Visual C#) or the Module1.vb file (Visual Basic), add the following namespace references: 'VB Imports Imports Imports Imports Imports //C# using using using using using
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter5.PatientClasses
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter5.PatientClasses;
5. In the Main method (Visual C#) or Sub Main (Visual Basic), type the following code. This code creates an instance of the remote Patient object. 'VB Dim newPatient As Patient = _
CType(Activator.GetObject(GetType(Patient), _
212
Chapter 5
Creating a Remoting Client Application
"tcp://localhost:9000/Patient.rem"), Patient) //C# Patient newPatient =
(Patient)Activator.GetObject(typeof(Patient),
"tcp://localhost:9000/Patient.rem");
6. Below the code that creates an instance of the Patient object, type the following code or something similar to utilize and test the PersonalInformation method on the remote object: 'VB Console.WriteLine(newPatient.PersonalInformation())
Console.WriteLine(newPatient.History())
//C# Console.WriteLine(newPatient.PersonalInformation());
Console.WriteLine(newPatient.History());
7. On the Build menu, click Build LabConsumer to compile the project. After the project successfully builds, press Ctrl+F5 to start the program without debug ging. The console output should render something similar to this: Patient ID: 001 :: John Doe :: 123 Main Street :: Someplace, AZ 85000 01/12/2001; Diagnosis: cold | Treatment: take 2 and call me in the morning. 03/04/2005; Diagnosis: broken toe | Treatment: nothing.
8. Close the console window for the LabConsumer project and the LabServer project.
Lesson Summary ■
Before methods can be called on a remote object, an instance of the remote object must be created.
■
The .NET Framework provides the new (New) operator and the Activator.GetObject method to create an instance of a remote object.
■
Activator.GetObject is passed the configuration information directly so it requires fewer lines of code to be written.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “How to Access a Remote Method.” The questions are also available on the companion CD if you prefer to review them in electronic form.
Lesson 3: How to Access a Remote Method
NOTE
213
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What approach to creating an instance of a remote object requires the fewest lines of code to be written? (Select the best answer.) A. new operator in C# B. Activator.GetObject method C. New operator in Visual Basic D. Activator.Create method 2. What approach to creating an instance of a remote object requires programmatic configuration or configuration via a configuration file? (Select all that apply.) A. new operator in C# B. Activator.GetObject method C. New operator in Visual Basic D. Activator.Create method
214
Chapter 5 Review
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
A server can host and expose the services of a remote object. Client applications of any type can consume the services exposed by remote objects.
■
Creating a client application to consume a remote object can be fairly straight forward if all required information is known about the remote object.
■
Information about the remote object that might be required includes the URL where the object is located, the communication channel being used by the remote object, and the method of activation implemented by the remote object.
■
Remote objects can be marshaled to the client by value or reference. Remote objects can be activated on the server or the client. Remote objects that are acti vated on the server can be activated as Singleton objects or SingleCall objects.
■
Client applications that consume remote objects can be configured and man aged programmatically or by using .NET Framework configuration files.
■
The methods exposed by remote objects can be called by client applications either synchronously or asynchronously.
■
There are two approaches for creating an instance of a remote object: using the new (New) operator or using the Activator.GetObject method.
Chapter 5 Review
215
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
application URL
■
channel
■
marshal-by-reference (MBR)
■
marshal-by-value (MBV)
■
proxy object
■
remote object activation
Case Scenarios In the following case scenarios, you apply what you’ve learned about how to create cli ent applications that consume remote objects. You can find answers to these ques tions in the “Answers” section at the end of this book.
Case Scenario 1: Creating a Secure Globally Distributed Application You are the lead developer for the AdventureWorks organization. AdventureWorks is in the business of selling outdoor gear and sporting equipment globally. AdventureWorks is looking to create a centralized data entry application and data warehouse at its New York headquarters. To increase security, the data entry application should not be available through a Web interface but will use the Web to transport data. Data will be entered into the application using a custom Windows application created using the .NET Framework. The data entry application will be deployed to approximately 40 workstations at satellite offices globally. Because the application will not be pub licly available, you have decided to use .NET remoting and host a remote object on the server using IIS. The remote object will provide services to remote client applications.
216
Chapter 5 Review
Questions Before beginning application development, you must answer questions posed by your project manager as follows: 1. What communication channel should you use with the remote object? 2. What mode should you use when activating the remote object?
Case Scenario 2: Improving the Remoting Client Using Interfaces You are a developer for an application service provider that provides secure health ser vices to hospitals and insurance companies. The services provided must be HIPAAcompliant. HIPAA compliance requires the most secure environment available. To provide the most secure environment, you decided to provide services through .NET remoting and have created server-activated, marshal-by-reference objects. You suc cessfully deployed services to clients that include a copy of the remote object so that the client application can compile. However, you now realize that each client applica tion includes a full copy of the source code for the remote object.
Questions You have decided to redesign your application model somewhat to improve security. ■
How can you modify your design to best secure your remote object source code?
Suggested Practices ■
Use the HTTP channel if consuming an object over the Web.
■
Use the TCP channel if consuming an object on an intranet or internal network.
■
Use the IPC channel if consuming an object on the same machine as the client.
■
Configure objects to be SingleCall if your object is performing many requests and maintaining state is not important.
■
Configure objects to be Singleton if the object must directly access resources on the server and maintaining state is important.
■
Configure objects to be client-activated if maintaining state is important and your application must control the lifetime of each independent object.
■
Use the Activator.GetObject method to simplify the client coding process.
Chapter 5 Review
217
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 6
Debugging and Deploying Remote Applications This chapter illustrates using Microsoft Visual Studio 2005 to debug and deploy a .NET remoting application. You learn how to deploy a .NET remoting application to various hosting environments. You also learn how to debug remoting applications and monitor them by utilizing performance counters. Finally, you will learn about remote object lifetimes and how to manage them.
Exam objectives in this chapter: ■
■
Debug and deploy a remoting application. ❑
Use performance counters to monitor a remoting application.
❑
Debug a remoting application.
❑
Host and deploy a remoting application.
Manage the lifetime of remote objects. ❑
Initialize the lifetime of a remote object.
❑
Renew the lifetime of a remote object.
Lessons in this chapter: ■
Lesson 1: How to Deploy a Remoting Application . . . . . . . . . . . . . . . . . . . . . . 222
■
Lesson 2: How to Debug a Remoting Application . . . . . . . . . . . . . . . . . . . . . . 239
■
Lesson 3: How to Manage the Lifetime of Remote Objects . . . . . . . . . . . . . . . 255
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction at the beginning of the book.
■
Visual Studio 2005 and the .NET Framework 2.0.
219
220
Chapter 6
Debugging and Deploying Remote Applications
■
Familiarity with using the Visual Studio 2005 debugger.
■
Familiarity with using performance counters and managing them using the .NET Framework 2.0.
■
Familiarity with creating console applications using Visual Studio 2005.
Real World Shannon Horn One of my clients creates and markets software that is used by schools, grades K–12, to align curriculum with objectives. Most states now require students to pass an exam prior to graduation that represents minimum educational stan dards that must be met in that state. My client’s software allows school officials to easily define the necessary standards that must be met. Teachers can then use the software to plan curriculum accordingly to teach in line with the defined standards. A primary requirement for the software is that it be capable of sharing data and synchronizing student personal information with the existing student informa tion system used by the school. Initially, my client considered creating the appli cation to fully integrate with existing student information systems used by schools. However, the student information system software industry is large and includes many competitors; hence creating a software package capable of inte grating with all possible systems was not feasible. My client had to come up with a solution to allow its own alignment software to synchronize with existing stu dent information systems. Education is the fourth largest industry in the United States, and the scenario just described proliferates through most K–12 schools. Microsoft realized this and joined in an industry effort to attempt to correct this problem. The industry effort is called the Schools Interoperability Framework (SIF). One way that Microsoft has contributed to the effort is by providing the plumbing used to cre ate the framework. The framework is built on Microsoft Windows 2003 Server, Microsoft SQL Server, Microsoft BizTalk Server, and the .NET Framework. The specialized collection of these items for this purpose is called a Zone Integration Server (ZIS).
221
The SIF is used to accommodate multiple student information systems to trans port data among themselves. This arrangement seemed to be a perfect solution for integrating my client’s alignment application with other systems. To use the framework, clients must create a SIF software agent that is responsible for per forming synchronization. This task proved a challenge when attempted a few years ago as my client (through me) created the first SIF agent on the market. Due to a collection of factors that included security concerns and performance, we decided to create the SIF agent using .NET remoting and host it using a Win dows service application. As a Windows service hosted object, our SIF agent was easily accessible to the entire school while providing high performance and tight security. Deploying the SIF agent correctly was initially a bit tricky because Visual Stu dio does not provide a direct means for packaging a Windows service applica tion for deployment. We selected the deployment method that has become the standard method used in the industry for deploying Windows service applica tions created using the .NET Framework, a Visual Studio setup project with custom actions defined. The remote objects hosted by our Windows service were fairly easy to deploy in themselves because they were just an object used by the service.
MORE INFO
Schools Interoperability Framework
For more information on the SIF, visit http://www.sifinfo.org/index.asp.
222
Chapter 6
Debugging and Deploying Remote Applications
Lesson 1: How to Deploy a Remoting Application This lesson describes using Visual Studio 2005 to deploy a .NET remoting applica tion. There are multiple deployment options available depending on how secure the source code contained in the remote object must be, as well as how often the remote object is likely to be updated. Furthermore, the method of deployment selected will differ based on the target hosting environment. After this lesson, you will be able to: ■
Evaluate and determine the appropriate hosting environment.
■
Identify the correct method of deployment.
■
Describe how to create and configure Visual Studio 2005 Web setup projects.
Estimated lesson time: 60 minutes
.NET Remoting Deployment When we discuss deployment in terms of .NET remoting, we are typically refering to deployment of a server application that hosts a remote object or deployment of a remote object to a client or server. A server application that hosts a remote object might be deployed from a development or testing environment to a production envi ronment. Likewise, a remote object might be deployed from a development or testing environment to a production environment. A remote object might also be deployed from a server to a client.
Hosting Remote Objects You should have an idea of the environment that will host a remote object in the early stages of development. A remote object should be thoroughly tested in the hosting envi ronment prior to deployment. The remote object should not be tested in the production version of the hosting environment, but rather in a development version of the hosting environment that resembles the production version as closely as possible. Tests should include security testing and performance testing under estimated production loads. A hosting environment is comprised of the operating system, memory, disk space, con nectivity, software and applications that might include SQL Server, Microsoft Active Directory directory service, Microsoft Internet Information Services (IIS), and Microsoft Message Queuing (MSMQ), as well as the application type used to create the remote server. There are four common application types used to create a remote server.
Lesson 1: How to Deploy a Remoting Application
223
Console Application Console applications are the simplest type of application that can be created using Visual Studio 2005 and can execute at the command prompt. As such, they are the easiest method available for creating a .NET remoting client or server. Console appli cations are also the easiest type of .NET remoting server to deploy. However, as described in Chapter 4, “Creating a Remoting Server Application,” console applica tions require a user to start the application if it is not executing and, by default, con sole applications execute using the security context of the user that starts the application. When manually starting the application is acceptable, console applica tions are a common solution to creating a .NET remoting server. If a console application is not currently executing, it can simply be copied to a new location. The simplest method of deployment utilized in the .NET Framework is deployment using the xcopy command at the command prompt. If the xcopy com mand is used to deploy a console application, the application folder containing the console application should be copied, the bin subfolder should be copied, and any other subfolders containing dependent files should also be copied. When a console application is created using Visual Studio 2005 and a reference is added to a remote object, a copy of the remote object is copied to the bin subfolder of the con sole application. Hence, if the bin subfolder is copied when the application is deployed, the remote object is deployed with the application. Deployment using the xcopy com mand as previously described might not be a practical solution if the console application contains dependencies located outside the application folder such as references to cus tom assemblies that reside in the global assembly cache (GAC). In cases such as this, a deployment solution more advanced than the xcopy command might be better suited.
Windows Executable Application Windows executable applications are comprised of Windows forms and accommo date better usability than console applications through the Windows user interface. However, in most scenarios, after a server that hosts a remote object is executing, it does not require much user interactivity. However, as stated in Chapter 4, Windows executable applications require a user to start the application if it is not executing and, by default, Windows executable applications execute using the security context of the user who starts the application. Windows executable applications are not as common a solution as a console application is for creating a .NET remoting server. The primary method of deploying a Windows executable application is to use a Windows setup project. Windows setup projects offer configuration options almost
224
Chapter 6
Debugging and Deploying Remote Applications
identical to those of Web setup projects (described later) with the exception that some of the configuration options are specific to Windows applications instead of Web applications.
Windows Service Application A Windows service application is an application that can be automatically started when Windows starts and can execute under its own security context. Examples of Windows service applications are SQL Server and IIS. Although a Windows service application does overcome the need to manually start the application and offer a dif ferent security context, .NET remoting servers created using Windows service appli cations are not as common a solution as a console application is for creating a .NET remoting server. The primary method of deploying a Windows service application is to use a Windows setup project. Windows setup projects offer configuration options almost identical to those of Web setup projects (described later) with the exception that some of the con figuration options are specific to Windows applications instead of Web applications. When a Windows service application is deployed using a Windows setup project, the project must be configured to take some custom actions while installing the applica tion. Custom installation programs can be created using the .NET Framework and might be better suited to installing a Windows service in some scenarios.
ASP.NET Web Application The most common solution for creating a .NET remoting server is to create it as an ASP.NET application. ASP.NET applications are hosted by IIS. The .NET remoting infrastructure built into the .NET Framework is comprehensive, but it does lack secu rity features. When designing a .NET remoting application, care should be taken to utilize all the security features of the .NET Framework. Because the Web is one of the primary communication platforms used today, there are also many security features available to Web applications. Hosting a remote object using IIS allows you to imple ment Web application security features in your .NET remoting applications. An appli cation created using ASP.NET to serve as a .NET remoting server is automatically started when IIS starts and can execute using its own security context. Generally, .NET remoting applications are designed for use in intranets and are not exposed to the Web. Another benefit of hosting a remote object using IIS is that it accommodates exposing your remote objects over the Web. An application created using ASP.NET to serve as a .NET remoting server utilizes the Hypertext Transfer
Lesson 1: How to Deploy a Remoting Application
225
Protocol (HTTP) communication channel but might use a Simple Object Access Protocol (SOAP) formatter, a binary formatter, or a custom formatter. However, the SOAP formatter is used by default. The easiest method for deploying a .NET remoting server created as an ASP.NET application is to use a Web setup project (described later).
Deploying Remote Objects Remote objects are created as classes. A common practice in object-oriented program ming languages is to place each class in a separate physical file that is assigned the same name as the class definition that it contains. A remote object can contain one or more classes and each remote object is generally stored in a separate Visual Studio 2005 project. Each Visual Studio 2005 project compiles to a single DLL file located in the bin subfolder of the project. The .NET remoting server and any clients that con sume the object must add a reference to the object in the Visual Studio 2005 Solution Explorer. When a reference is added in Visual Studio 2005, a copy of the remote object is copied to the bin subfolder of the project to which the reference was added.
Deploying a Remote Object to the Server Remote objects must be deployed to both the server that hosts them as well as to each client that references them. Servers must reference a copy of a remote object so that the server can call methods contained in the remote object when requests are made by client applications. Client applications must reference a copy of a remote object so that the client code can compile. Deploying a copy of a remote object with the server that hosts the remote object is a simple process. As described earlier, when a reference to the remote object is added to the server, a copy of the remote object is copied to the bin subfolder of the server. When the server is deployed, the copy of the remote object is deployed as well. However, deploying a remote object to each client requires a bit more forethought.
Deploying a Remote Object to the Client There are three common approaches to deploying a remote object to a client: deploy the entire remote object assembly, deploy an interface implemented by the remote object, or use the .NET Framework SoapSuds utility to configure the remote object for deployment. The easiest method of deploying a remote object to a client is to deploy the entire remote object assembly. This method is the same as that used to deploy a remote
226
Chapter 6
Debugging and Deploying Remote Applications
object to a .NET remoting server application. A disadvantage to deploying an entire remote object assembly is that the code contained in the assembly is also copied to the client machine. Exposing the code to all clients to which the remote object is deployed could be a significant security risk and could expose intricate server details such as database connection information. As mentioned in Chapter 4 and Chapter 5, “Creating a Remoting Application,” there are two types of remote objects, marshal-by value (MBV) and marshal-by-reference (MBR). If you are creating an MBV remote object, the entire remote object assembly is serialized and copied to the client machine when a request is made by the client. Hence there is no way to really protect the code in the remote object assembly, and you should opt to copy the entire remote object assembly to improve performance. Another option for deploying a remote object is to deploy only an interface that the remote object implements. If you are creating an MBR remote object, this solution is perfect. When a class implements an interface, the class must override the function members declared in the interface. Thus the interface describes the function mem bers declared by any classes that implement it. A class can declare more function members than those that are declared by an interface. However, if you intend to use an interface for deployment, be sure that the interface accurately reflects the function members declared in any classes that implement the interface. To deploy an interface, declare the interface in its own project in Visual Studio 2005. This arrangement isolates the interface from any classes that implement it. When classes are created that implement the interface using Visual Studio 2005, a reference must be added to the assembly that contains the interface. Client applications must add a reference to the assembly that contains the interface using Visual Studio 2005 as well. Client applications are then able to make calls to function members declared in the interface from client code and successfully compile. However, the benefit offered by deploying an interface is that the interface contains no code, only function member signatures. Thus the code contained in the remote object is not exposed if an interface implemented by the remote object is deployed. Finally, the SoapSuds.exe (or SoapSuds) .NET Framework utility can be used to extract metadata from a remote object. In the previous two methods described for deploying a remote object—deploying the entire remote object assembly and deploying an interface implemented by the remote object assembly—deployment is being pushed from the server to the client. If you use the SoapSuds.exe utility, you can pull meta data about a remote object from the server and initiate deployment from the client. The SoapSuds.exe utility can be used to extract and re-create the entire remote object
Lesson 1: How to Deploy a Remoting Application
227
assembly on the client, extract and re-create a metadata-only remote object assembly on the client, extract a Web Services Description Language (WSDL) file describing the remote object assembly, and convert a WSDL file into source code on the client or into an assembly on the client. Extracting a WSDL file and converting it in a code file or assembly is more often used with Web services than with remote objects. The SoapSuds.exe utility is included in the .NET Framework Software Development Kit. Assuming we open the command prompt and navigate to the folder containing the RemotePatient.dll remote object assembly, the utility can be executed as shown here. SoapSuds Utility soapsuds -types:MSLearning.Chapter5.PatientClasses.Patient,RemotePatient -oa:Sample.dll
In this example, the –types switch is used to identify the class and remote object assembly to be analyzed. The –oa switch is used to identify the output assembly to be generated. The most commonly used switches of the SoapSuds.exe utility are described in Table 6-1. Table 6-1
SoapSuds.exe .NET Framework Utility Commonly Used Switches
Switch
Description
–inputassemblyfile: assemblyfile
This switch is used to identify the assembly for the utility to analyze and extract meta data from.
(–ia:assemblyfile) –inputdirectory:directory (–id:directory) –outputassemblyfile:assemblyfile (–oa:assemblyfile) –outputdirectory:outputdirectory (–od:outputdirectory)
This switch is used to identify the directory that contains the input assembly. This switch is used to identify the name of the output assembly file generated. This switch is used to identify the directory where the output assembly file will be stored.
–types: type1,assemblyname
This switch is used to identify the type and assembly to extract metadata from.
–domain:domain
This switch is used to identify the domain to be used for authentication.
(–d:domain)
228
Chapter 6
Debugging and Deploying Remote Applications
Table 6-1
SoapSuds.exe .NET Framework Utility Commonly Used Switches
Switch
Description
–username:username
This switch is used to identify the user name to be used for authentication.
(–u:username) –password:password (–p:password)
This switch is used to identify the password to be used for authentication.
Creating a Web Setup Project As mentioned earlier, the two most common targets to deploy a .NET remoting server to are a console application and an ASP.NET Web application hosted using IIS. Deploying to a console application is very easy, but deploying to IIS as a Web application can be a bit more challenging. Although a Web application can be deployed and configured manually, using a Visual Studio 2005 Web setup project automates the process. A Web setup project is used to package a Web project for deployment. When you create a Web setup project using Visual Studio 2005, you are presented with six editors. Each editor accommodates configuring an aspect of the setup project. After the setup project is configured, you build it using Visual Studio 2005. The result of building the setup project is either an executable or a Microsoft Installer file that can be used to install and configure the Web project when it is deployed. Web setup projects are typically added as an additional project to the solution that contains the Web project you are deploying. To create a Web setup project using Visual Studio 2005 follow this procedure: 1. Open the solution that contains the Web project you are deploying and click File, Add, New Project. 2. In the Add New Project dialog box, click Other Project Types, Setup And Deploy ment, Web Setup Project. 3. Assign the project a name and location, and click OK. The Web setup project is added to the open solution, and you are presented with the File System editor. The additional editors are accessible from the View menu by clicking Editor when the Web setup project is selected in Solution Explorer, right
Lesson 1: How to Deploy a Remoting Application
229
clicking the Web setup project in Solution Explorer and clicking View, or by click ing the toolbar button for each editor at the top of Solution Explorer when the Web setup project is selected.
File System Editor The File System editor is used to configure how the file system of the destination sys tem is affected by installing the Web application. Web folders, project output, files, and assemblies are added to the Web setup project by right-clicking the Web Applica tion Folder icon in the File System editor and clicking Add or from the Project menu by clicking Add when the File System editor is displayed. Project output includes the primary assembly created when the Web project is built; satellite assemblies used for localization; debug symbol files created when the Web project is built in Debug mode; and project content files such as images, source code files, Extensible Markup Lan guage (XML) documentation, and serialization files. Shortcuts to start the Web appli cation can also be added to various locations, such as the Windows desktop, when the application is installed. Additionally, when the File System editor is displayed, the Properties dialog box is used to configure settings for the destination virtual directory created when the Web application is installed. The Visual Studio 2005 Web Setup Project File System editor is shown in Figure 6-1.
Figure 6-1
The Visual Studio 2005 Web Setup Project File System editor
230
Chapter 6
Debugging and Deploying Remote Applications
Registry Editor The Registry editor is used to configure how the registry of the destination system is affected by installing the Web application. New keys and values are added to the Web setup project by right-clicking one of the registry node icons in the Registry editor. The Visual Studio 2005 Web Setup Project Registry editor is shown in Figure 6-2.
Figure 6-2
The Visual Studio 2005 Web Setup Project Registry editor
File Types Editor The File Types editor is used to configure how the file types of the destination system are affected by installing the Web application. Windows associates files with the appli cations used to manage them by using the file extension. For instance, if Microsoft Office is installed and you double-click a file with a .doc extension, Windows attempts to open the file using Microsoft Word. When you install an application, you can asso ciate file extensions and the actions taken on the files in Windows by your application using the File Types editor. File extensions and actions are added to the Web setup project by right-clicking the Files Types On Target Machine icon in the File Types edi tor and clicking Add File Type. The Visual Studio 2005 Web Setup Project Files Types editor is shown in Figure 6-3.
Lesson 1: How to Deploy a Remoting Application
Figure 6-3
231
The Visual Studio 2005 Web Setup Project File Types editor
User Interface Editor The User Interface editor is used to configure the user interface of the installation pro gram. The User Interface editor accommodates configuring both a standard installa tion interface and a separate administrative installation interface where you can give more detailed information and options to administrators. You can add, remove, and customize the dialog boxes displayed to the user as the application is installed by right-clicking a process step or dialog box in the User Interface editor. The Visual Stu dio 2005 Web Setup Project User Interface editor is shown in Figure 6-4.
232
Chapter 6
Figure 6-4
Debugging and Deploying Remote Applications
The Visual Studio 2005 Web Setup Project User Interface editor
Custom Actions Editor The Custom Actions editor is used to define any custom actions you would like to be performed when the Web application is installed. For instance, setup applications commonly display a text file after setup is complete that informs the user of updates to the application or how to get started. You can define a custom action to perform by right-clicking an icon in the Custom Actions editor and clicking Add Custom Action. The Select Item In Project dialog box is displayed, which allows you to add a file, out put, or assembly as a custom action definition. You can define a custom action to be performed prior to installation, on successful installation, on a failed installation, or on uninstallation. The Visual Studio 2005 Web Setup Project Custom Actions editor is shown in Figure 6-5.
Lesson 1: How to Deploy a Remoting Application
Figure 6-5
233
The Visual Studio 2005 Web Setup Project Custom Actions editor
Launch Conditions Editor The Launch Conditions editor is used to define any conditions that must be met prior to the Web application being installed. For instance, you might need to verify a par ticular version of IIS or the .NET Framework 2.0 to support the functionality enabled in your Web application. You can add a new launch condition to perform prior to installation beginning by right-clicking the Launch Conditions folder icon in the Launch Conditions editor and clicking Add Launch Condition. Launch conditions are typically used to verify a configuration setting or version. You can verify that a file, registry entry, or other application exists on the target machine by right-clicking the Search Target Machine folder icon in the Launch Conditions editor and selecting a search type. The Visual Studio 2005 Web Setup Project Launch Conditions editor is shown in Figure 6-6.
234
Chapter 6
Figure 6-6
Debugging and Deploying Remote Applications
The Visual Studio 2005 Web Setup Project Launch Conditions editor
Build, Install, and Uninstall After you configure the Web setup project, the next step is to build the project to gen erate the setup executable and Microsoft Installer (.msi) file. To build the Web setup project, select the option to build it from the Build menu or right-click the Web setup project in Solution Explorer and click Build. As with any other project type in Visual Studio 2005, if build errors are encountered, they must be corrected until the build is successful. When the build is successful, you can navigate to the folder where you created the Web setup project to locate the setup executable and Microsoft Installer file. If you built the project in Debug mode, you’ll find the files in the Debug subfolder; other wise you’ll find the files in the Release subfolder. You can double-click the Setup.exe file or the Microsoft Installer file to install and test the Web application. You can also install the Web application by right-clicking the Web setup project in Solution Explorer and clicking Install. Applications installed using a Web setup project and any dependent actions taken during installation are registered in the Add/Remove Applications Control Panel utility for easy uninstallation.
Lesson 1: How to Deploy a Remoting Application
235
The setup executable and Microsoft Installer files can be easily deployed to accommo date installing your Web application on a target machine. If the target machine has the latest Microsoft Installer updates applied, the Microsoft Installer file should be deployed; otherwise the setup executable should be deployed. Deployment of the setup files might include any method of copying the files from one location to another such as download, e-mail, direct file copy, and removable media.
Lab 1: Creating and Installing a Web Setup Project This lab walks you through the process of creating, building, and installing a Web setup project that will install a remote object to be hosted using IIS. The lab utilizes the RemotePatient remote object utilized in Chapter 5. �
Exercise 1: Creating a Web Setup Project
1. Add a Web Setup Project to the RemotePatient solution. a. Start Visual Studio 2005 and open the RemotePatient solution included with Lesson 1 of Chapter 6. b. On the File menu, click Add, New Project. c. In the Add New Project dialog box, click Other Project Types, Setup And Deployment, Web Setup Project. Assign the project a name such as RemotePatientSetup and click OK. 2. Add the remote object to the setup project. a. In the File System editor, in the Web Application Folder icon, right-click the bin subfolder. Click Add, Project Output. b. In the Add Project Output Group dialog box, click Primary Output and click OK. �
Exercise 2: Build and Install a Web Setup Project
1. Build the Web setup project. a. In Visual Studio 2005 Solution Explorer, right-click the bin subfolder and click Build. b. Be sure that the project builds successfully. If any build errors are encoun tered, resolve them and rebuild the project until it builds successfully.
236
Chapter 6
Debugging and Deploying Remote Applications
2. Install the Web setup project. a. The Web setup project can be installed in Solution Explorer by right-click ing the project and clicking Install. However, to better simulate an actual deployment, navigate to the location where the Web setup project was cre ated. In the Debug (or Release depending on the mode you built the project in) subfolder, double-click the .msi file to install the project. b. Work through the dialog boxes presented by the installation program to complete the installation. 3. Verify that the project was successfully installed. a. Open IIS by clicking Start, Control Panel, Administrative Tools, Internet Information Services (IIS) Manager. Using the IIS Manager, browse into the Default Website to the virtual folder created by the Web setup project installation as shown in Figure 6-7.
Figure 6-7 Services
The RemotePatientSetup virtual folder hosted by Internet Information
If you want to uninstall the Web setup project, use the Add/Remove Pro grams Control Panel utility or right-click the Web setup project in Visual Studio 2005 Solution Explorer and select Uninstall.
Lesson 1: How to Deploy a Remoting Application
237
Lesson Summary ■
.NET remoting server applications are typically deployed from a development environment to a testing environment to a production environment.
■
.NET remote objects are typically deployed from a development environment to a testing environment to a production environment and can be deployed to both the server and the client, depending on the type of remote object created.
■
.NET remote objects are hosted using a console application, a Windows execut able application, a Windows service application, or an ASP.NET Web applica tion. The most common hosts are either a console application or an ASP.NET Web application.
■
When you deploy a remote object, you can deploy the entire remote object assembly or an interface implemented by the remote object assembly, or you can use the SoapSuds.exe .NET Framework utility to read metadata from the remote object and generate an assembly on the client.
■
If you deploy a remote object as an ASP.NET Web application, you should deploy it using a Web setup project.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “How to Deploy a Remoting Application.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which application types are used to host .NET remote objects? (Select all that apply.) A. Windows service application B. Class library application C. ASP.NET Web application D. Smart device application 2. Which method should be used to deploy a remote object to a client if security of the remote object source code is a primary concern and the remote object is
238
Chapter 6
Debugging and Deploying Remote Applications
hosted using a console application on the server? (Select the best answer.) A. Deploy the entire remote object assembly. B. Deploy an interface implemented by the remote object assembly. C. Extract and re-create the entire remote object assembly using SoapSuds. D. Extract and re-create a metadata-only remote object assembly using SoapSuds. 3. What type of file is generated when a Web setup project is built? (Select the best answer.) A. Microsoft Installer file (msi) B. .NET managed assembly (dll) C. .NET managed assembly (exe) D. .NET configuration file (config)
Lesson 2: How to Debug a Remoting Application
239
Lesson 2: How to Debug a Remoting Application It is nearly impossible to write more than a few lines of code without there being some type of error in the execution of the code. There are three types of errors in software: syntax and compilation errors, runtime errors, and logic errors. Syntax and compila tion errors occur due to incorrect language syntax and command usage and normally prevent compilation. Runtime errors are errors that do not prevent compilation and are due to some element that is not detectable until runtime, such as the effect of invalid user input that is not validated and causes an error to occur. Another example of a runtime error could be an expected resource not being available at run time. Logic errors are sometimes categorized as runtime errors and normally do not prevent com pilation. Logic errors are commonly associated with if statements or loops where the logic driving the statement is not accurate. After this lesson, you will be able to: ■
Use the Visual Studio 2005 debugger to debug .NET remoting applications.
■
Handle .NET remoting exceptions using the RemotingException class.
■
Track the performance of a .NET remoting application using performance counters.
■
Monitor calls made to methods on a remote object using the .NET remoting track ing services.
Estimated lesson time: 60 minutes
Debugging is the process of identifying the causes of errors in software so that they can be corrected. Depending on the type of application created, debugging the appli cation might be relatively easy or it might be complex. Debugging .NET remoting applications is generally considered complex due to the distributed nature of the application. There are multiple options available for debugging and monitoring .NET remoting components.
Visual Studio 2005 Debugger Visual Studio 2005 is a comprehensive development environment, particularly in its full rendition, Visual Studio Team System. However, all editions of Visual Studio 2005 include the most robust visual debugger available on the market. The Visual Studio 2005 debugger can be used to fully analyze executing code including the ability to step line by line through source code, inspect memory registers in use, and manage
240
Chapter 6
Debugging and Deploying Remote Applications
unlimited breakpoints. The debugger can also be used to analyze code executing out side of Visual Studio 2005 by attaching to the process executing the code. When the debugger is attached to a process, provided you have access to the source code being executed by the process, you can control what the process is doing using the debug ger. Some application types cannot be debugged directly within Visual Studio 2005 but must be debugged by attaching the debugger to the process executing the appli cation code after the application is running. These applications include Windows ser vices and .NET remoting applications. Bear in mind that .NET remoting applications are composed of multiple components that include one or more remote objects, a server, and one or more clients. A remote object typically is created using a class library. Class libraries cannot be executed directly but must be executed by another process. Thus there is no way to debug a remote object directly without involving another process. In terms of .NET remoting, the process that acts as the server executes a remote object. Client applications then make calls to the server to access the remote object. To begin debugging a .NET remoting application, the server application must first be started. Starting the server, in turn, accommodates debugging remote objects hosted by the server. However, the server typically does not make calls to remote object meth ods on its own behalf but makes calls to remote object methods to fulfill client requests. Hence, to test and debug a .NET remoting application, you should simulate client applications by creating test scripts or a simple application, such as a console application, to make calls to remote object methods. There is essentially a single point from which to initiate debugging in a .NET remoting application: the client. A client application might require no special debug handling until a call is made to the remote object. At the point where a call is made to a remote object, execution transfers to another process, the server process. Typically, if you are debugging .NET remoting using the Visual Studio 2005 debugger, you debug it from the client. The Visual Studio 2005 debugger is capable of debugging multiple pro cesses, but only a single process can be displayed in the debugger at a given time. To debug a .NET remoting server from a client, you should attach to the server prior to executing the client. The server must be executing and listening for client requests. If you attach to the server process when it is listening for requests and not fulfilling requests, the debugger might have no activity to display. However, after a client request is made, you should be able to follow application execution in the server using
Lesson 2: How to Debug a Remoting Application
241
the debugger. To attach to the server process, open the client application project in Visual Studio 2005 and on the Debug menu, click Attach To Process. The Attach To Process dialog box is displayed in Figure 6-8.
Figure 6-8
The Visual Studio 2005 Attach To Process dialog box
The Attach To Process dialog box initially displays processes running on the local machine. If the .NET remoting server is executing on another machine, you need to select the process by connecting to the other machine. You can locate the executing process in the Available Processes list box and click Attach. After you attach to the pro cess, execute the client application. Be sure to set breakpoints at the location where you would like to break in the debugger, build all components in Debug mode, and configure all machines for remote debugging, if necessary. Furthermore, after execu tion is transferred to the server, you need to select the server as the process to display in the debugger by double-clicking the process to display in the Processes window. MORE INFO
Debugging multiple processes
For more information on debugging multiple processes using Visual Studio 2005, visit the topic titled “Attaching to Running Processes” at http://msdn2.microsoft.com/en-us/library/3s68z0b3.aspx.
242
Chapter 6
Debugging and Deploying Remote Applications
The RemotingException Class You should always expect the unexpected. When writing code, never assume that everything will go smoothly and all resources will be available. All code written using any programming language should be designed to adequately handle errors that could be encountered. Object-oriented programming languages, particularly .NET-compliant languages, handle errors through structured exception handling. When an error is encountered, an object is instantiated that represents the error, application execution halts, and the Common Language Runtime (CLR) begins searching for a catch statement to handle the exception. When errors are encountered in a .NET remoting application, the RemotingException class is instantiated to represent the error. Typically, the only code that might possibly throw an exception in a .NET remoting client application is the code that attempts to connect to the server and any code that makes calls to remote object methods. In the following code example, the catch statement is used to handle any remoting excep tions encountered. Handling Remoting Exceptions 'VB Imports Imports Imports Imports Imports
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter6.PatientClasses
Namespace MSLearning.Chapter6.ActivatorGetObject Module GetObjectModule Sub Main() Try ' Create an instance of the Patient class. Dim newPatient As Patient = _ CType(Activator.GetObject(GetType(Patient), _ "tcp://localhost:9000/Patient.rem"), Patient) ' Call a remote method. Console.WriteLine(newPatient.PersonalInformation()) Catch ex As RemotingException Console.WriteLine(ex.Message)
End Try
End Sub
Lesson 2: How to Debug a Remoting Application
243
End Module
End Namespace
//C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter6.PatientClasses;
namespace MSLearning.Chapter6.ActivatorGetObject {
class Program
{
static void Main(string[] args)
{
try { // Create an instance of the Patient class. Patient newPatient = (Patient)Activator.GetObject(typeof(Patient), "tcp://localhost:9000/Patient.rem"); // Call a remote method. Console.WriteLine(newPatient.PersonalInformation()); } catch (RemotingException ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
Using Performance Counters Windows includes a utility to monitor application performance called the Perfor mance Monitor. The Performance Monitor can be started by using the Control Panel shortcut under Administrative Tools or by using the console utility, Perfmon.exe. The Performance Monitor tracks application performance through the use of performance counters. A counter is updated periodically to reflect an updated status. An application might maintain many counters to track different performance aspects. Counters can
244
Chapter 6
Debugging and Deploying Remote Applications
be grouped together into categories to make locating them easier when many are available for tracking. Many applications install Performance Monitor counters when they are installed. For instance, SQL Server 2005 installs several categories of counters to track performance of the database including the number of transactions committed per second and the number of deadlocks encountered. The .NET Framework is another example of an application that installs several categories of Performance Monitor counters. Counters can also be added to the Performance Monitor programmatically using the classes in the System.Diagnostics namespace. The Performance Monitor utility is shown in Figure 6-9.
Figure 6-9
The Windows Performance Monitor utility
The .NET Framework provides a category of counters specifically designed to track the performance of .NET remoting operations. As with all other counters, the .NET remoting counters can be added to the Performance Monitor and tracked manually or programmatically. To manually add counters to track, in the Performance Monitor, click the Add button in the toolbar. In the Add Counters dialog box, select the cate gory of counters to track from the Performance Object drop-down list box, select the counter type from the list box on the left, select the counter instance from the list box on the right, and click Add. The Add Counters dialog box is shown in Figure 6-10.
Lesson 2: How to Debug a Remoting Application
245
Figure 6-10 The Windows Performance Monitor Add Counters dialog box
The counters included in the .NET Framework for tracking .NET remoting operations are described in Table 6-2. Table 6-2
.NET Remoting Performance Counters
Counter
Description
Channels
This counter tracks the total number of chan nels registered across all application domains for a particular application.
Context Proxies
This counter tracks the total number of proxies created in a particular process.
Context-Bound Classes Loaded
This counter tracks the current number of context-bound classes that are loaded.
Context-Bound Objects Alloc/sec
This counter tracks the current number of context-bound objects allocated per second.
Contexts
This counter tracks the current number of con texts in a particular application.
246
Chapter 6
Debugging and Deploying Remote Applications
Table 6-2
.NET Remoting Performance Counters
Counter
Description
Remote Calls/sec
This counter tracks the current number of remote procedure calls (RPC) invoked per second.
Total Remote Calls
This counter tracks the total number of RPCs invoked for a particular application.
MORE INFO
Performance counters in the .NET Framework
For more information on performance counters, visit the topic titled “Performance Counters in the .NET Framework” at http://msdn2.microsoft.com/en-us/library/w8f5kw2e.aspx.
.NET Remoting Tracking Services Although performance counters are extremely useful, the .NET Framework includes .NET remoting tracking services to provide more granular control to define custom behavior each time a .NET remoting operation is performed. The tracking services are located in the System.Runtime.Remoting.Services namespace. There are basically two facets involved in utilizing the .NET remoting tracking services: the TrackingServices class and the ITrackingHandler interface. The TrackingServices class is used to register user-defined classes with the remoting system. The user-defined classes implement the ITrackingHandler interface and are notified when particular remoting operations occur. The TrackingServices class includes the two methods described in Table 6-3 for managing user-defined classes that implement ITrackingHandler. Table 6-3
TrackingServices Methods
Method
Description
RegisterTrackingHandler
This method is used to register a user-defined class with the remoting services as a class that should be notified when remoting operations occur.
UnregisterTrackingHandler
This method is used to unregister a user-defined class that is currently registered with the remoting services.
Lesson 2: How to Debug a Remoting Application
247
To utilize tracking services, one or more user-defined classes are created that imple ment the ITrackingHandler interface. The ITrackingHandler interface includes three methods, as described in Table 6-4. These methods are called on all registered classes when the associated operation occurs. Table 6-4
ITrackingHandler Methods
Method
Description
DisconnectedObject
This method is called when an object is disconnected from its proxy.
MarshaledObject
This method is called when an object is marshaled.
UnmarshaledObject
This method is called when an object is unmarshaled.
The following code example illustrates a user-defined class that implements ITrackingHandler and simply writes to the console when remoting operations are performed. ITrackingHandler Interface Implementation 'VB Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Services
Namespace MSLearning.Chapter6.Server Class Tracker
Implements ITrackingHandler
Public Sub DisconnectedObject(ByVal obj As Object) Implements _
System.Runtime.Remoting.Services.ITrackingHandler.DisconnectedObject
Console.WriteLine("Object disconnected...")
End Sub
Public Sub MarshaledObject(ByVal obj As Object, _ ByVal [or] As System.Runtime.Remoting.ObjRef) Implements _ System.Runtime.Remoting.Services.ITrackingHandler.MarshaledObject Console.WriteLine("Object marshaled...")
End Sub
Public Sub UnmarshaledObject(ByVal obj As Object, _ ByVal [or] As System.Runtime.Remoting.ObjRef) Implements _ System.Runtime.Remoting.Services.ITrackingHandler.UnmarshaledObject
248
Chapter 6
Debugging and Deploying Remote Applications
Console.WriteLine("Object unmarshaled...")
End Sub
End Class
End Namespace
//C# using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Services;
namespace MSLearning.Chapter6.Server {
class Tracker : ITrackingHandler
{
#region ITrackingHandler Members public void DisconnectedObject(object obj)
{
Console.WriteLine("Object disconnected...");
}
public void MarshaledObject(object obj, ObjRef or) { Console.WriteLine("Object marshaled...");
}
public void UnmarshaledObject(object obj, ObjRef or) { Console.WriteLine("Object unmarshaled...");
}
#endregion
}
}
After a class is created that implements the ITrackingHandler interface, it can be regis tered to be notified when remoting operations occur using the TrackingServices class as shown in the following code example. TrackingServices Class 'VB Imports Imports Imports Imports Imports
System
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
System.Runtime.Remoting.Services
Lesson 2: How to Debug a Remoting Application
249
Namespace MSLearning.Chapter6.Server Class Program Shared Sub Main() RemotingConfiguration.Configure( _ "StandardServer.exe.config", False) TrackingServices.RegisterTrackingHandler(New Tracker()) Console.WriteLine("Press return to exit...\n")
Console.ReadLine()
End Sub
End Class
End Namespace
//C# using using using using using
System;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
System.Runtime.Remoting.Services;
namespace MSLearning.Chapter6.Server {
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure(
"StandardServer.exe.config", false);
TrackingServices.RegisterTrackingHandler(new Tracker()); Console.WriteLine("Press return to exit...\n");
Console.ReadLine();
}
}
}
Now that a handler is registered, when a client makes a call to a method in the class used in the preceding code, the handler class is notified. In the preceding example, the handler class simply writes status updates to the console.
Lab 2: Debugging a Remoting Application This lab illustrates handling .NET remoting exceptions and using the Visual Studio 2005 debugger to attach to and debug a remoting application. Exception handling
250
Chapter 6
Debugging and Deploying Remote Applications
should be included in all application code, and proper use of the debugger is essential knowledge for all .NET developers. �
Exercise 1: Handle Remoting Exceptions
1. Open the LabConsumer project. a. Start Visual Studio 2005 and open the LabConsumer project included with Lesson 2 of Chapter 6. b. Open the Main method. The Main method is located in Module.vb for the Visual Basic version of the project and Program.cs for the C# version of the project. 2. Add exception handling code to the consumer. a. Wrap the code that creates an instance of the Patient class and the code that calls methods on the Patient class in a try statement. b. Create at least one catch statement to handle any RemotingException instances that are encountered. A generic catch can also be created to catch any other exceptions that are encountered. The following code illustrates the exception handling code. Exception Handling Example 'VB Imports Imports Imports Imports Imports Imports
System
System.Runtime
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter6.PatientClasses
Namespace LabConsumer Class Program Shared Sub Main() RemotingConfiguration.Configure( _
"LabConsumer.exe.config", False)
Try Dim newPatient As Patient = New Patient() Console.WriteLine(newPatient.PersonalInformation()) Console.WriteLine(newPatient.History()) Catch ex As RemotingException
Lesson 2: How to Debug a Remoting Application
Console.WriteLine(ex.Message) Catch ex As Exception Console.WriteLine(ex.Message) End Try End Sub End Class End Namespace //C# using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter6.PatientClasses;
namespace LabConsumer
{ class Program { static void Main(string[] args)
{
RemotingConfiguration.Configure(
"LabConsumer.exe.config", false);
try
{
Patient newPatient = new Patient(); Console.WriteLine(newPatient.PersonalInformation()); Console.WriteLine(newPatient.History()); }
catch (RemotingException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); } } } }
251
252
Chapter 6
�
Debugging and Deploying Remote Applications
Exercise 2: Debug a Remoting Application
1. Set breakpoints in the RemotePatient solution. a. Using Visual Studio 2005, open the RemotePatient solution. b. Navigate to the location in code at which you would like to break. The RemotePatient example object used in the provided solution contains two methods, PersonalInformation and History. Set breakpoints in the code in the remote object. c. Build the object in Debug mode. 2. Start the server. a. Open the LabServer solution. b. Start the server without debugging by pressing Ctrl+F5. If you start the server in Debug mode, the instance of the debugger in use is attached to the server, and only a single instance of a debugger can be attached to a process at a given time. 3. Start the remote consumer. a. Open the LabConsumer solution. b. Set a breakpoint in the consumer code prior to the code that creates an instance of the remote object. c. Start debugging the consumer by pressing F5. The consumer should break at the breakpoint. d. Prior to stepping through the consumer code, attach the debugger to the server process on the Debug menu by clicking Attach To Process and select ing the server process. 4. Step into the remote object code. a. In the consumer, step into the code that creates an instance of the remote object and calls methods on the remote object. b. When a method on the remote object is called, display the remote object code by selecting the process in the Processes window. If the Processes win dow is now displayed in the debugger, display it from the Windows sub menu of the Debug menu by clicking Processes. c. Step through the remainder of the code to complete the consumer code and then press Enter twice in the server window to close it.
Lesson 2: How to Debug a Remoting Application
253
Lesson Summary ■
Debugging .NET remoting applications can be challenging. A remote object can not be executed on its own but is executed by a server application. However, a server does not call methods on a remote object that it hosts. Consumers call methods on remote objects and, hence, are the point where debugging occurs.
■
A server process is remote from a client process. The Visual Studio 2005 debugger must be attached to the remote process to be able to debug the remote process.
■
The Visual Studio 2005 debugger can debug multiple processes concurrently but can only display a single process at a time. The Processes window is used to tog gle between processes being debugged using the Visual Studio 2005 debugger.
■
The RemotingException class is used to represent exceptions thrown by .NET remoting applications.
■
The .NET Framework includes and installs several performance counters that are used to track the performance of .NET remoting applications.
■
The .NET Framework includes a tracking services class that is used to register user-defined classes that implement the tracking service interface for notifica tion of .NET remoting operations.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “How to Debug a Remoting Application.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. At which point(s) in a .NET remoting application is debugging initiated? (Select the best answer.) A. Server application B. Remote object C. Proxy object D. Client application
254
Chapter 6
Debugging and Deploying Remote Applications
2. Which of the following performance counters are used to track .NET remoting application performance? (Select all that apply.) A. Total Remote Calls B. Proxies Instantiated C. Context Proxies D. Channels 3. Which .NET remoting operations is an object registered using tracking services notified about? (Select all that apply.) A. Marshaled B. Disconnected C. Connected D. Unmarshaled
Lesson 3: How to Manage the Lifetime of Remote Objects
255
Lesson 3: How to Manage the Lifetime of Remote Objects A foundational behavioral principle of the .NET Framework CLR is the use of the gar bage collector (GC) to manage memory. The GC functions by automatically and nondeterministically cleaning and compacting memory allocated to applications managed by the CLR. The GC prevents memory leaks that are prevalent in many runt ime environments that are not managed by the CLR. In object-oriented programming languages, the duration an instance of an object exists in memory is called the object’s lifetime. After this lesson, you will be able to: ■
Understand how the lifetime of a remote object is managed.
■
Initialize the lifetime of a remote object programmatically and by using a configu ration file.
■
Renew the lifetime of a remote object.
Estimated lesson time: 60 minutes
The CLR manages both value types and reference types. The GC manages the lifetime of reference types by monitoring all references to an object. When all references to an object have released the object, the GC flags the object for collection and eventually destroys the instance of the object. The GC behavior just described is a perfect solu tion for most applications created using the .NET Framework. However, the GC is only able to monitor references to a remote object that exist in the same application domain and process as the instance of the remote object. How does this behavior affect .NET remoting applications? Client applications that consume remote objects reside in processes and application domains that are separate from the process and application domain where the remote object resides. Hence, even if there are many client applications making calls to meth ods contained in a remote object, the GC cannot see these client applications that ref erence the remote object and flag the remote object instance for collection. Eventually, the remote object is destroyed by the GC, possibly while it is fulfilling client requests. .NET remoting applications are distributed applications where the components that comprise the application can reside on opposite sides of the world. The .NET Frame work is designed to simplify distributed environments by providing components that act as the glue to hold distributed components together. For instance, depending on
256
Chapter 6
Debugging and Deploying Remote Applications
how the remote object is activated, a client application might require a proxy object to be created that represents the remote object. Likewise, on the server side, an instance of a remote object must have at least one reference to it maintained; otherwise the GC collects the remote object. However, all objects that hold a reference to an instance of a remote object typically do not reside on the server. To remedy this situation, an object similar to a proxy object is created on the server that represents a client application and holds a reference to a remote object on the server for the client application. Thus, a reference to an instance of a remote object is detected by the GC and the instance of the remote object is not collected by the GC. The proxy-type object created on the server to represent a client application and hold a reference to the instance of the remote object is called a lease object. A server can host many remote objects, and multiple instances of a remote object can exist in memory. Each instance of a remote object is assigned its own lease object. All lease objects on a server are managed by another object called the lease manager. A lease object is assigned a duration to determine how long to hold the reference to the instance of the remote object. When a lease expires, the instance of the remote object is collected by the GC. However, each client application can register a sponsor object that allows the client application to extend the duration of the lease. When a lease expires, prior to a remote object being made available for collection, the lease manager determines whether any sponsors want to extend the lifetime of the lease.
Initializing the Lifetime of a Remote Object Lease objects are assigned default values that determine their behavior. However, default values can be overridden either programmatically or through an application configuration file. Modifications to configuration values for a lease object must be made when the lease object is initialized; otherwise the configuration value modifica tions have no effect. There are several properties that are used to modify the configuration of a lease object. Table 6-5 lists commonly used lease object configuration properties. Table 6-5
Lease Lifetime Properties
Property
Description
CurrentLeaseTime
This property is used to specify the amount of time until a lease object expires.
Lesson 3: How to Manage the Lifetime of Remote Objects
Table 6-5
257
Lease Lifetime Properties
Property
Description
InitialLeaseTime
This property returns the initial lease time and is used to specify the lifetime duration for a lease object. The default value is 5 minutes. To specify that the lease does not expire, set this property to 0.
LeaseManagerPollTime
This property is used to determine how often the lease manager should check for expired leases. The default value is 10 seconds.
RenewOnCallTime
This property returns the time remaining on the lease and is used to extend the lifetime of a lease each time a call is made to a method contained in the remote object referenced by the lease. The default value is 2 minutes. However, the lifetime of the lease is extended only if the amount of time remaining in the lease object lifetime duration is less than the RenewOnCallTime. For instance, if a lease still has 3 minutes until it expires, a call with a RenewOnCallTime does not extend its duration. However, if a lease only has 1 minute until it expires, a call with a RenewOnCallTime extends the duration of the lease.
SponsorshipTimeout
This property is used to determine how long the lease manager should wait for a sponsor to respond when it attempts to determine if a sponsor wants to extend a lease. The default value is 2 minutes.
To modify the configuration of a lease object programmatically, the InitializeLife timeService method must be overridden as shown in the following code example. Initializing a Lease Programmatically 'VB Imports Imports Imports Imports
System System.Runtime.Remoting System.Runtime.Remoting.Lifetime ControlChars = Microsoft.VisualBasic.ControlChars
Namespace MSLearning.Chapter6.PatientClasses
258
Chapter 6
Debugging and Deploying Remote Applications
Public Class Patient
Inherits MarshalByRefObject
Public Overrides Function InitializeLifetimeService() As Object Dim lease As ILease = CType( _ MyBase.InitializeLifetimeService(), ILease) If lease.CurrentState = LeaseState.Initial Then lease.InitialLeaseTime = TimeSpan.FromMinutes(15) lease.RenewOnCallTime = TimeSpan.FromMinutes(5) End If Return lease
End Function
Public Function PersonalInformation() As String Return "Patient ID: 001 :: Demo Patient" End Function Public Function History() As String Return "01/12/2001; Diagnosis: cold | Treatment: take " & _ "2 and call me in the morning. " & ControlChars.CrLf & _ "03/04/2005; Diagnosis: broken toe | Treatment: nothing." End Function
End Class
End Namespace
//C# using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
namespace MSLearning.Chapter6.PatientClasses {
public class Patient : MarshalByRefObject
{
public override object InitializeLifetimeService() { ILease lease = (ILease) base.InitializeLifetimeService(); if (lease.CurrentState == LeaseState.Initial) { lease.InitialLeaseTime = TimeSpan.FromMinutes(15); lease.RenewOnCallTime = TimeSpan.FromMinutes(5); }
Lesson 3: How to Manage the Lifetime of Remote Objects
259
return lease;
}
public string PersonalInformation()
{
return "Patient ID: 001 :: Demo Patient";
}
public string History()
{
return "01/12/2001; Diagnosis: cold | Treatment: take " + "2 and call me in the morning.\n\r03/04/2005; " + "Diagnosis: broken toe | Treatment: nothing."; } } }
To modify the configuration of a lease object using an application configuration file, use the element of the configuration file. The element contains attributes with the same name and functionality as their programmatic counterparts as shown in the following example. Initializing a Lease Using a Configuration File
Renewing the Lifetime of a Remote Object After a lease has been created, modifying the properties of the lease has no effect on the lease. The lease duration can be renewed by a sponsor object or by manually call ing the Renew method of the ILease interface from a client application as shown in the following code example. Renewing a Lease 'VB Imports Imports Imports Imports Imports Imports Imports
System System.Runtime System.Runtime.Remoting System.Runtime.Remoting.Lifetime System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter6.PatientClasses
Namespace LabConsumer
260
Chapter 6
Debugging and Deploying Remote Applications
Class Program Shared Sub Main() RemotingConfiguration.Configure( _ "LabConsumer.exe.config", False) Dim newPatient As Patient = New Patient() Console.WriteLine(newPatient.PersonalInformation()) Console.WriteLine(newPatient.History()) ' Renew the lease. Dim lease As ILease = CType( _ RemotingServices.GetLifetimeService(newPatient), ILease) Dim expireTime As TimeSpan = _ lease.Renew(TimeSpan.FromMinutes(5)) Console.WriteLine(expireTime.ToString())
End Sub
End Class
End Namespace
//C# using using using using using using using
System;
System.Runtime;
System.Runtime.Remoting;
System.Runtime.Remoting.Lifetime;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter6.PatientClasses;
namespace LabConsumer {
class Program
{
static void Main(string[] args) { RemotingConfiguration.Configure( _ "LabConsumer.exe.config", false); Patient newPatient = new Patient(); Console.WriteLine(newPatient.PersonalInformation()); Console.WriteLine(newPatient.History()); // Renew the lease. ILease lease = (ILease)RemotingServices.GetLifetimeService(newPatient); TimeSpan expireTime = lease.Renew(TimeSpan.FromMinutes(5)); Console.WriteLine(expireTime.ToString()); } } }
Lesson 3: How to Manage the Lifetime of Remote Objects
261
Lab 3: Managing the Lifetime of Remote Objects This lab illustrates configuring the lease object for a remote object. �
Exercise 1: Initializing a Lease
1. Open the RemotePatient project. a. Start Visual Studio 2005 and open the RemotePatient project included with Lesson 3 of Chapter 6. b. The Patient class already extends the MarshalByRefObject class, so now it just needs to override the necessary method. 2. Override the InitializeLifetimeService function. a. Declare a new instance of the ILease interface to represent the lease for the RemotePatient object. b. Modify the configuration property values to extend the length of the lease duration when the lease is in its initial state.
Lesson Summary ■
Lease objects are used to hold a reference to a remote object on the server in place of a client application.
■
A lease object is initialized by overriding the InitializeLifetimeService function in the remote object.
■
Lease object configuration properties must be configured before the lease is ini tialized.
■
A lease object duration can be extended by calling the ILease.Renew method from a client application.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “How to Manage the Lifetime of Remote Objects.” The questions are also avail able on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
262
Chapter 6
Debugging and Deploying Remote Applications
1. Which function must be overridden to initialize a lease? (Select the best answer.) A. InitializeLease B. InitializeLifetimeService C. InitializeLeaseService D. InitializeLifetime 2. What is the default value for the InitialLeaseTime property? (Select the best answer.) A. 5 minutes B. 0 minutes C. 15 minutes D. 2 minutes 3. How can a client application extend the duration of a lease? (Select the best answer.) A. Instantiate a new lease object on the server. B. Register a sponsor for the object on the server. C. Register a new lease object in the lease manager programmatically. D. Register a new lease object in the lease manager by using a configuration file.
Chapter 6 Review
263
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
There are four common .NET application types used to host .NET remoting applications: ASP.NET Web applications, console applications, Windows exe cutable applications, and Windows service applications.
■
The most common host application type is an ASP.NET Web application. A Web setup project is the easiest way to deploy an ASP.NET Web application.
■
The Visual Studio 2005 debugger must be attached to a remote process to be able to debug the remote process. The Visual Studio 2005 debugger can attach to and debug multiple processes simultaneously but can only display a single process at a time.
■
Debugging .NET remoting applications can be complex. Debugging is initiated from a calling client application.
■
The RemotingException class is used to describe .NET remoting exceptions.
■
The .NET Framework installs several performance counters to track the perfor mance of .NET remoting applications.
■
The .NET Framework includes services for tracking .NET remoting operations.
■
A lease is used to maintain a reference to a remote object on a server in place of a client application.
■
A lease can be initialized by overriding the InitializeLifetimeService function.
■
A lease can be manually renewed by calling the ILease.Renew method.
264
Chapter 6 Review
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
lease
■
Microsoft Installer
■
performance counter
■
SoapSuds
■
sponsor
■
Web setup project
Case Scenarios In the following case scenarios, you apply what you’ve learned about how to debug and deploy remote objects. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Tracking and Improving the Performance of a Distributed Application You are the chief software architect for the AdventureWorks organization. AdventureWorks is in the business of selling outdoor gear and sporting equipment globally. You have created a distributed order tracking system that is used across AdventureWorks so that all orders are entered directly into a central database. Your order tracking sys tem utilizes remote objects to serve as its business and data components. The client base and order demand at AdventureWorks have been growing exponentially and you need to ensure that there are enough servers hosting your remote objects to sup port loads being placed on the objects as orders are placed.
Questions To accurately gauge the resources needed to support order loads, you must answer the following questions: 1. How can you track how many instances of your remote objects are being created and which methods are being called most often? 2. How can you ensure that order loads are being balanced across your remote objects as efficiently as possible?
Chapter 6 Review
265
Case Scenario 2: Simplifying Remote Object Deployment You are the chief software architect for the Baldwin Museum of Science. You are cre ating a remote object that will allow other partner museums to search your inventory of exhibits. You have new museums partnering with your museum on a continual basis. New partners will need to be able to search your inventory. You are hosting the remote objects using IIS and have implemented authentication for each partner.
Questions When creating the enterprise architecture for the museum, you need to answer the fol lowing question so that others can maintain the application you are creating in the future. ■
How can you simplify the deployment of your remote objects to trusted partner museums in the future?
Suggested Practices ■
Host remote objects using either IIS or a Windows service application. .NET remoting applications are typically only hosted using a console application in teaching and testing environments for simplicity.
■
Deploy .NET remoting applications to an IIS host using a Visual Studio 2005 Web setup project.
■
Deploy remote objects to client applications using an interface implemented by the remote object.
■
Be sure that remote objects have been thoroughly tested and debugged prior to deployment.
■
Ensure that all remote object code includes exception handling, generally using the RemotingException class.
■
Test remote objects to verify the necessary lifetime and lease durations needed for normal operation. You want remote objects to remain in memory while in use but not longer than necessary.
■
Configuring lease properties using a configuration file will be much easier to maintain in the future if modifications are necessary.
266
Chapter 6 Review
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 7
Method Invocations and Event Management with .NET Web Services The Microsoft .NET Framework provides two primary mechanisms for created dis tributed applications, .NET Web services and .NET remoting. Both technologies will be consolidated into the Windows Communication Foundation (WCF) in the near future, but the need to create and manage .NET Web services (and remoting compo nents) will only increase as applications move toward distributed architectures. This chapter is concerned with the process of creating and using .NET Web services. MORE INFO
Windows Communication Foundations (WCF)
For more information on the WCF, visit the WCF section of MSDN Online at http:// www.msdn.microsoft.com/webservices/indigo/default.aspx.
Exam objectives in this chapter: ■
Call Web methods asynchronously. ❑
Call a Web method.
❑
Poll for the completion of a Web method.
❑
Get Web method results.
❑
Implement callback.
❑
Call a OneWay Web method.
Lessons in this chapter: ■
Lesson 1: Calling Web Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
■
Lesson 2: Polling Web Methods for Completion . . . . . . . . . . . . . . . . . . . . . . . 284
267
268
Chapter 7
Method Invocations and Event Management with .NET Web Services
Before You Begin To complete the lessons in this chapter, you must must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Successfully completed all lessons in Chapters 1 though 6.
You should also be familiar with Visual Basic or C# and be comfortable with the fol lowing tasks: ■
Creating a console application in Visual Studio using Visual Basic or C#.
■
Adding references to system class libraries to a project.
■
Adding a simple Web reference to a project.
■
Having at least a basic understanding of remoting methodologies (XML Web services, DCOM, .NET remoting, CORBA, and so on). NOTE
The StockLookupService project
For each exercise, we use the StockLookupService project located on the companion CD in the Chapter 7 – Web Service folder.
Real World William Ryan Back in 2002, the company I was with had quickly grown beyond what its tech nological infrastructure could support. The company decided to create a totally new management system using the.NET Framework 1.0. Because it was a fairly straightforward in-house application, a decision was made to architect it as a standard client/server application. This structure worked wonderfully for a while, but as business grew, so did customer demands. Little by little, the com pany needed to expose more and more functionality to the outside world. Because the .NET Framework was being used as the existing platform, creating components that customers could consume (via .NET Web services) externally was a fairly straightforward endeavor. Four years after the original application was built, we now have quite a few customers that access our products via Web services, and the application has turned into one of our major selling points.
Lesson 1: Calling Web Methods
269
Lesson 1: Calling Web Methods In many respects, calling a Web method is no different from calling any other method. For instance, the following procedures are common to both tasks: ■
Add a reference to the library that contains the application logic you want to invoke.
■
Declare a new instance of the object.
■
Call the method belonging to that object.
The only substantive difference between traditional method invocation and Web method invocation is in how the library is referenced and that the data is transferred to the client in the form of XML. It’s worth noting, however, that Visual Studio 2005 does much of the grunt work associated with adding Web references for you; hence, if you can add a project reference to an ordinary dynamic link library (DLL), you can do the same for a Web library. Behind the scenes, a lot has to happen to allow you to call a Web method, but this process is almost totally abstracted from the developer. If you use Visual Studio 2005 and if you were only looking at the instantiation of the object and the method call to it, there’s no way you could distinguish whether a method call was to a Web method or a traditional method. After this lesson, you will be able to: ■
Call a Web method synchronously.
■
Call a Web method asynchronously.
■
Use the built-in CancelAsync delegate.
Estimated lesson time: 20 minutes
Calling a Web Method Synchronously To explain how to call a Web method synchronously, it’s beneficial to just show the code to call a Web method first, and then move on to the discussion. 'VB Public Sub GetTickerSymbol()
Dim Lookup As New StockLookupService()
Console.WriteLine(Lookup.GetCompanyName("MSFT"))
End Sub //C# public static void GetTickerSymbol()
{
270
Chapter 7
Method Invocations and Event Management with .NET Web Services
StockLookupService Lookup = new StockLookupService();
Console.WriteLine(Lookup.GetCompanyName("MSFT"));
}
Now, to call these methods, you would do the following: 'VB Sub Main()
GetTickerSymbol()
Console.ReadLine()
End Sub //C# static void Main(string[] args) {
GetTickerSymbol();
Console.ReadLine();
}
Unless you have some supernatural skills heretofore unknown, you can’t tell that there’s a Web object being instantiated or a Web method being called. This abstrac tion is by design. A brief explanation of what is going on behind the scenes is in order. When you add a Web reference to your project using the Add Web Reference dialog, your code looks pretty much like it would if you were just adding a traditional library reference. In this case, however, looks are deceiving. Visual Studio 2005 creates what is known as a proxy class that for all outward appearances causes the object to behave just like any other object. NOTE
Dissecting a Web reference
If you open the Web References node in Solution Explorer and click Show All Files, you’ll see a tree of items appear under the node. One of those items is named Reference.map. If you expand this node, you’ll see a Reference.vb file if you’re using Visual Basic .NET or a Reference.cs file if you’re using C#. Inside this class is a copy of every property and method of the Web service to which you added a reference. If you have never done so, you should examine the class just so you see what is going on behind the scenes.
When you add a Web reference, Visual Studio 2005 creates what is known as a proxy class that, for all outward appearances, causes the object to behave just like any other object. This class is generated in the language that’s being used to consume the web service, so you can create and consume web services in any language you can create projects in with Visual Studio .NET 2005. If you examine the proxy, this mechanism will probably start making more sense quite quickly.
Lesson 1: Calling Web Methods
BEST PRACTICES
271
Keep Web references current!
Change is inevitable in most applications. Because a Web reference is based on a snapshot of the Web service at the time this reference was created, the reference doesn’t know about any changes that might have occurred after it was added. Before doing a production build, it’s a good idea to right-click the Web reference and click Update Web Reference. This command causes the discovery process to commence, and the proxy class will be updated. Don’t assume that just because your method takes, for instance, one string parameter and returns a string that such will always be the case. Like anything else, introducing breaking changes to a Web service can cause a lot of prob lems, but it does happen and you need to be prepared if it does.
I’ll leave it up to you to examine the entire proxy class that Visual Studio 2005 gener ated for the StockSymbolConsumer project, although the specific method that was invoked in the preceding example is shown here. (Visual Studio generates slightly dif ferent code depending on whether your project is written in Visual Basic .NET or C#. As you’ll see shortly, a lot more code was generated for the GetCompanyName method than what’s shown here, but this is the only code that was needed to make that par ticular Web method call.) 'VB _ Public Function GetCompanyName(ByVal tickerSymbol As String) As String Dim results() As Object = Me.Invoke("GetCompanyName", _ New Object() {tickerSymbol}) Return CType(results(0),String) End Function //C# [System.Web.Services.Protocols.SoapDocumentMethodAttribute( "http://tempuri.org/GetCompanyName", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle= System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public string GetCompanyName(string tickerSymbol) { object[] results = this.Invoke("GetCompanyName", new object[] { tickerSymbol}); return ((string)(results[0])); }
272
Chapter 7
Method Invocations and Event Management with .NET Web Services
This might seem simple and that’s because, in its simplest form, it is simple. Yet this is far from an exhaustive summary of what can be done with Web methods. Suffice to say, however, that for synchronous calls, this is pretty much all there is to it.
Calling a Web Method Asynchronously There are a lot of potential problems associated with synchronous method calls that can severely affect the end user experience. A few of the major ones are listed here: ■
The Web method might end in an error. If this happens, you will only learn of the error after the Timeout period expires, which might be quite a long time. (Most people consider an application freeze for even five seconds a long time.)
■
The Web method might complete successfully but take a long time. Again, with synchronous invocations, the end user application freezes up, which is disturb ing to end users.
■
In most instances you will call more than one Web method, and waiting for each call to complete individually is potentially wasteful. (Imagine a case where the first method doesn’t return properly. The user might wait 30 seconds or so for this method to return and the next method to be called. If the methods were called asynchronously, both requests would be fired at close to the same time and the overall wait time could be drastically reduced.)
A nonresponsive user interface might have been acceptable 20 years ago when there was little competition in the marketplace, but today users expect more from their soft ware. Few things annoy users more than having the user interface freeze up. This sit uation often results in users killing the application process, which has the added negative externality of possibly leaving your application in an unknown state. Consid ering how simple it is to work around this issue, it’s unacceptable to do otherwise in most cases. As mentioned in the last section, there’s a lot more that can be done with respect to calling Web methods. Again, however, calling a Web method doesn’t differ in any sub stantive way from calling a regular method, although there’s a little more behind-the scenes work done for you. To call a Web method asynchronously, you have the follow ing choices: ■
Create a new thread and call the method from there. (The subject of threading is complex and beyond the scope of this particular subject matter, so it is not cov ered here.) Suffice it to say that calling a Web method from a new thread is done identically to the way it would be done with any other method.
Lesson 1: Calling Web Methods
273
■
Create a delegate object that matches the Web method signature and call it from there.
■
Use one of the delegates that the proxy class provides for you.
Again, to show how these mechanisms work, it is probably best to start with a code example. The following is all of the code that Visual Studio generated for the GetTickerSymbol method: 'VB Public Event GetCompanyNameCompleted As GetCompanyNameCompletedEventHandler _ Public Function GetCompanyName(ByVal tickerSymbol As String) As String Dim results() As Object = Me.Invoke("GetCompanyName", _ New Object() {tickerSymbol}) Return CType(results(0), String) End Function ''' Public Overloads Sub GetCompanyNameAsync(ByVal tickerSymbol As String) Me.GetCompanyNameAsync(tickerSymbol, Nothing) End Sub ''' Public Overloads Sub GetCompanyNameAsync(ByVal tickerSymbol As String, _ ByVal userState As Object) If (Me.GetCompanyNameOperationCompleted Is Nothing) Then Me.GetCompanyNameOperationCompleted = _ AddressOf Me.OnGetCompanyNameOperationCompleted
End If
Me.InvokeAsync("GetCompanyName", New Object() {tickerSymbol}, _
Me.GetCompanyNameOperationCompleted, userState) End Sub Private Sub OnGetCompanyNameOperationCompleted(ByVal arg As Object) If (Not (Me.GetCompanyNameCompletedEvent) Is Nothing) Then Dim invokeArgs As _ System.Web.Services.Protocols.InvokeCompletedEventArgs = _ CType(arg, _ System.Web.Services.Protocols.InvokeCompletedEventArgs) RaiseEvent GetCompanyNameCompleted(Me, _
New GetCompanyNameCompletedEventArgs(invokeArgs.Results, _
invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState))
End If End Sub
274
Chapter 7
Method Invocations and Event Management with .NET Web Services
Public Shadows Sub CancelAsync(ByVal userState As Object) MyBase.CancelAsync(userState) End Sub //C# public event GetCompanyNameCompletedEventHandler GetCompanyNameCompleted; [System.Web.Services.Protocols.SoapDocumentMethodAttribute( "http://tempuri.org/GetCompanyName", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle= System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public string GetCompanyName(string tickerSymbol) { object[] results = this.Invoke("GetCompanyName", new object[] { tickerSymbol}); return ((string)(results[0])); } /// public void GetCompanyNameAsync(string tickerSymbol) { this.GetCompanyNameAsync(tickerSymbol, null); } /// public void GetCompanyNameAsync(string tickerSymbol, object userState) { if ((this.GetCompanyNameOperationCompleted == null)) { this.GetCompanyNameOperationCompleted = new System.Threading.SendOrPostCallback( this.OnGetCompanyNameOperationCompleted); } this.InvokeAsync("GetCompanyName", new object[] { tickerSymbol}, this.GetCompanyNameOperationCompleted, userState); } private void OnGetCompanyNameOperationCompleted(object arg) { if ((this.GetCompanyNameCompleted != null)) { System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs) (arg)); this.GetCompanyNameCompleted(this, new GetCompanyNameCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); } } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.42")] public delegate void GetCompanyNameCompletedEventHandler( object sender, GetCompanyNameCompletedEventArgs e);
Lesson 1: Calling Web Methods
275
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.42")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class GetCompanyNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { private object[] results; internal GetCompanyNameCompletedEventArgs(object[] results, Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState) {
this.results = results;
} ///
public string Result {
get {
this.RaiseExceptionIfNecessary();
return ((string)(this.results[0]));
} } }
If you examine this code closely, you’ll probably see the specific code that allows for asynchronous invocation. (Hint: look for async.) Now, change the original code defi nition slightly to call the GetCompanyNameAsync method: 'VB Public Sub GetTickerSymbol() Dim Lookup As New StockLookupService() Console.WriteLine(Lookup.GetCompanyNameAsync("MSFT")) End Sub //C# public static void GetTickerSymbol() { StockLookupService Lookup = new StockLookupService(); Console.WriteLine(Lookup.GetCompanyNameAsync("MSFT")); }
If you try to compile and run this code, it fails, indicating that the return type from the method call isn’t valid. Lest there be any confusion, this modified code won’t work. That’s because calling an asynchronous method is a little more involved. The answer to why the return type from the method call is no longer valid rests in the proxy class, the relevant portions of which are provided here: 'VB Public Overloads Sub GetCompanyNameAsync(ByVal tickerSymbol As String) Me.GetCompanyNameAsync(tickerSymbol, Nothing)
276
Chapter 7
Method Invocations and Event Management with .NET Web Services
End Sub Public Overloads Sub GetCompanyNameAsync(ByVal tickerSymbol As String, _
ByVal userState As Object)
If (Me.GetCompanyNameOperationCompleted Is Nothing) Then
Me.GetCompanyNameOperationCompleted = _ AddressOf Me.OnGetCompanyNameOperationCompleted End If Me.InvokeAsync("GetCompanyName", New Object() {tickerSymbol}, _ Me.GetCompanyNameOperationCompleted, userState)
End Sub
//C# public void GetCompanyNameAsync(string tickerSymbol) {
this.GetCompanyNameAsync(tickerSymbol, null);
}
public void GetCompanyNameAsync(string tickerSymbol, object userState) {
if ((this.GetCompanyNameOperationCompleted == null)) {
this.GetCompanyNameOperationCompleted =
new System.Threading.SendOrPostCallback(
this.OnGetCompanyNameOperationCompleted);
}
this.InvokeAsync("GetCompanyName", new object[] {
tickerSymbol}, this.GetCompanyNameOperationCompleted,
userState);
}
The most glaring difference is the return type. Notice that a string is no longer returned. In fact, the Visual Basic .NET method signature now specifies a Sub (which indicates there is no return type) and the C# return type now specifies void (which also indicates lack of a return type). How do you handle this situation and make an asynchronous call? CAUTION
Be careful when introducing changes that break existing code
One adage of object-oriented design is that classes should be closed for modification but open for extension. Although I could write a few chapters on this principle alone, it essentially means that after you create a class, the interface for it shouldn’t change. If you have a method named GetStockSymbol that accepts a single string argument and returns a string, you should not change the return type, change the parameter type, or add or remove parameters. People incorrectly assume that this principle means that the actual implementation of the method should never be changed. If this were the case, then every time you fixed a bug you’d be violating good object-oriented pro gramming design principles, which clearly isn’t the case. For some reason, many developers who are otherwise careful not to change the interface of a tra ditional class have no such compunction when it comes to Web services. Keep in mind that from the client’s perspective, there is literally no difference between calling a Web service’s method and any other method. Remember that a proxy class is created that matches the Web service, and objects instantiated from this proxy class contain the methods that are invoked. Any changes that
Lesson 1: Calling Web Methods
277
break existing code should be approached with great caution. If you must introduce such changes (typically due to changing requirements or design flaws), make sure you give any consumers of the service enough advance notice to allow them to respond. Make sure as well that you don’t violate any contractual obligations, or you might end up with legal complications.
When Visual Studio creates the proxy, it automatically creates an event for the Com pleted event of each of your methods. This proxy creation is done by default and requires no work on the part of the developer. Basically you simply need to create an event handler to respond to the event and then wire it up, as shown here. (Again, the Visual Basic .NET code is markedly different from the C# code. These differences are due to differences in the language. Semantically, these code snippets behave the same way and the output is identical.) 'VB Private WithEvents AsyncLookup As StockLookupService Sub Main() AsyncLookup = New StockLookupService() AsyncLookup.GetCompanyNameAsync("MSFT") Console.ReadLine() End Sub Public Sub GetTickerSymbolCompletedHandler(ByVal sender As Object, _ ByVal args As GetCompanyNameCompletedEventArgs) _ Handles AsyncLookup.GetCompanyNameCompleted If Not args.Error Is Nothing Then
Console.WriteLine("Error: {0} Message: {1}", args.UserState, _
args.Error.Message)
End If
If args.Cancelled Then
Console.WriteLine("Method invocation was cancelled") Else Console.WriteLine("Method completed: {0}", args.UserState) End If End Sub //C# static void Main(string[] args) { GetTickerServiceAsyncGood(); Console.ReadLine(); } static void GetTickerServiceAsyncGood() { StockLookupService Lookup = new StockLookupService(); Lookup.GetCompanyNameCompleted += new GetCompanyNameCompletedEventHandler(
278
Chapter 7
Method Invocations and Event Management with .NET Web Services
GetTickerSymbolCompletedHandler);
Lookup.GetCompanyNameAsync("MSFT");
}
private static void GetTickerSymbolCompletedHandler(object sender,
GetCompanyNameCompletedEventArgs args)
{
if (args.Error != null)
{
Console.WriteLine("Error: {0} Message: {1}", args.UserState, args.Error.Message);
}
if (args.Cancelled)
{
Console.WriteLine("Method invocation was cancelled");
}
else {
Console.WriteLine("Method completed: {0}", args.UserState);
}
}
So what’s important in this code? ■
The GetTickerSymbolCompletedHandler method handles the Completed event from the asynchronous call.
■
GetTickerSymbolCompletedHandler is wired to the Completed event of the GetTickerSymbolCompleted event.
■
The GetTickerSymbolAsync method invokes the method asynchronously.
Getting data back from asynchronous calls and responding to the various events asso ciated with such calls is discussed in depth in the following lesson. One item remains to be discussed: canceling a call. After you call a method asynchro nously, you can simply call its Cancel method and it cancels the call. Let’s review the previous code sample; the relevant portions are highlighted in bold: 'VB Private WithEvents AsyncLookup As StockLookupService Sub Main()
AsyncLookup = New StockLookupService()
AsyncLookup.CancelAsync() Console.ReadLine()
End Sub
Public Sub GetTickerSymbolCompletedHandler(ByVal sender As Object, _
ByVal args As GetCompanyNameCompletedEventArgs) _
Handles AsyncLookup.GetCompanyNameCompleted
Lesson 1: Calling Web Methods
279
If Not args.Error Is Nothing Then
Console.WriteLine("Error: {0} Message: {1}", args.UserState, _
args.Error.Message)
End If
If args.Cancelled Then
Console.WriteLine("Method invocation was cancelled") Else Console.WriteLine("Method completed: {0}", args.UserState) End If End Sub //C# static void GetTickerServiceAsyncGood() { StockLookupService Lookup = new StockLookupService(); Lookup.GetCompanyNameCompleted += new GetCompanyNameCompletedEventHandler(
GetTickerSymbolCompletedHandler);
Lookup.CancelAsync(); Console.ReadLine(); } private static void GetTickerSymbolCompletedHandler(object sender, GetCompanyNameCompletedEventArgs args) { if (args.Error != null) { Console.WriteLine("Error: {0} Message: {1}", args.UserState, args.Error.Message);
}
if (args.Cancelled)
{
Console.WriteLine("Method invocation was cancelled");
}
else {
Console.WriteLine("Method completed: {0}", args.UserState); } }
Cancelling the call is particularly relevant because there are times when you might decide that you don’t want to make the user wait longer for a method to complete, so you decide to cancel execution. Polling, a system that checks the execution status of an asynchronous method and responds accordingly, is discussed in the next lesson, but for the time being, assume that you have somehow made a determination that you want to cancel execution. All that is needed is a call to the built-in CancelAsync method. If the event handler is set up properly (this is an automatic process) and you have code to check for a cancellation as shown in the previous code example, there’s really nothing more that needs to be done to handle this situation.
280
Chapter 7
Method Invocations and Event Management with .NET Web Services
Lab 1: Calling a Web Method In this lab, you create add a Web reference to your project and then call one of its Web methods from a client application. �
Exercise: Calling a Web Method
In this exercise, you create a console application that calls the StockLookupService project’s GetCompanyName method. 1. Open Visual Studio 2005 and create an empty project. 2. Add a new C# or Visual Basic .NET console application project named StockSymbolConsumerCS or StockSymbolConsumerVB, depending on which lan guage you choose to write in. 3. Select File, Add, Existing Project and add the StockLookupService project to this solution. 4. Build the StockLookupService project. 5. Right-click the StockSymbolConsumer project and select Add Web Reference. You should see a dialog box similar to the one shown in Figure 7-1.
Figure 7-1
Use the Add Web Reference dialog box to find a Web service
6. Click Web Services In This Solution, and then click Service for the StockLook upService project. 7. Use the default value of localhost in the Web Reference Name text box. 8. Click Add Reference.
Lesson 1: Calling Web Methods
281
9. Open the StockSymbolConsumer project’s Program.cs file if you’re using C# or Module1.vb if you’re using Visual Basic .NET. 10. At the top of the module or class, add the following: 'VB Imports StockSymbolConsumerVB.localhost //C# using StockSymbolConsumerCS.localhost;
11. Add the following code to the Main method of the respective project: 'VB GetTickerSymbol()
Console.ReadLine()
//C# GetTickerSymbol();
Console.ReadLine();
12. Add the following methods to the class: 'VB Public Sub GetTickerSymbol()
Dim Lookup As New StockLookupService
Console.WriteLine(Lookup.GetCompanyName("MSFT"))
End Sub //C# static void GetTickerSymbol() { StockLookupService Lookup = new StockLookupService(); Console.WriteLine(Lookup.GetCompanyName("MSFT")); }
13. Build the project, and resolve any errors. Run the application and you should see the word Microsoft in the console window.
Lesson Summary ■
The Add Web Reference feature of Visual Studio allows you to add a reference to a Web service to your project.
■
If the Web service is contained in the same solution, you can use the Web Services In This Solution command to add a Web service to your project.
■
If the Web service is contained on the local machine but not in the same solu tion, the Web Services On The Local Machine option can be used to add a Web ref erence to your project.
282
Chapter 7
Method Invocations and Event Management with .NET Web Services
■
If the Web service is located on a remote server, you can specify the address in the Uniform Resource Locator (URL) address box of the Add Web Reference dia log box.
■
When a Web reference is added, Visual Studio 2005 adds a proxy class to the program for you.
■
Client code creates and calls an instance of the proxy class, which in turn han dles the calls to the Web service. The Web service itself is not called directly by the client code.
■
Depending on the circumstances, the Web service for which a reference is cre ated is likely to change after it has first been referenced. Right-click the Web ref erence and click Update Web Reference to generate a proxy matching the Web service.
■
Be careful not to introduce breaking changes (in other words, don’t change the method signatures) on existing Web services. If you must introduce breaking changes, ensure that the customer is notified early enough to respond to the change.
■
Asynchronous methods are provided by default. They use the syntax of asnyc.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Calling Web Methods.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What needs to be done to call a Web method asynchronously? (Select all that apply.) A. Add a Web reference to the service that contains the method you want to call. B. Declare and instantiate an instance of the service object. C. Call the method by name. D. Call the method that contains the name postfixed by the word async.
Lesson 1: Calling Web Methods
283
2. How do asynchronous methods differ from traditional ones? (Select all that apply.) A. They have a different signature and return type in most cases. B. Other methods can be processed while the call to the Web method is processing. C. The Completed event must be handled to get the results back. D. The method call is for all intents and purposes identical to the synchronous counterpart.
284
Chapter 7
Method Invocations and Event Management with .NET Web Services
Lesson 2: Polling Web Methods for Completion The previous lesson introduced both synchronous and asynchronous invocations of Web services. In this lesson, we delve a little deeper into the process of asynchronous invocations. After this lesson, you will be able to: ■
Use a delegate to invoke a Web service.
■
Use polling to check the state of completion and respond accordingly.
■
Use built-in delegates.
Estimated lesson time: 20 minutes
Polling When a method is called asynchronously, you don’t really know when it has finished. Typically, programs execute in a linear fashion, but that’s not the case with asynchro nous calls. Consider the following situation: ■
A program calls the GetTickerSymbol method of a Web service to look up a com pany’s stock ticker symbol.
■
The program next calls another method of the Web service, passing a second company’s stock ticker symbol, to retrieve the company’s closing stock price.
■
When the first method returns, the program uses the results to call to retrieve the first company’s closing stock price.
In a synchronous scenario, you can be sure that the second and third calls will not execute until the first call is completed. You can also be sure that the third call won’t complete until the second call is completed. In an asynchronous scenario, you don’t know when any of the calls are going to return and you certainly can’t count on them finishing in the sequence in which they were called. (If the calls do finish in the sequence in which they were issued it’s only due to random chance.)
Lesson 2: Polling Web Methods for Completion
285
Real World William Ryan Many people are intimidated by threading and asynchronous invocation. How ever, the difference between applications that users enjoy and ones that anger users is often asynchronous invocation. In the previous Real World example, I spoke of our move to Web services. In the beginning we had a few problems. We typically built customized client applications and used standard invocations. However, the Web isn’t always stable and available, so our applications would often freeze up while waiting for methods to return. Fortunately, changing from a synchronous application model to an asynchronous application model was very simple. Using asynchronous delegates made everything a lot easier, and, fortunately, it was an easy port in most cases.
Begin and IAsyncResult Without any extra work, there are two items that are of great use when performing asynchronous invocations. In the first lesson we saw one way to determine when the method completed. However, that example was a bit of a simplified version. Each asynchronous Web method has a Begin method associated with it. The Begin methods have a return type of IAsyncResult. Follow these steps to call a Begin method, check its execution status, and respond accordingly. 1. Create an IAsyncResult variable and set it to the return value of the Web service’s Begin method. 2. Poll the IsCompleted property of the IAsyncResult variable until it turns true. 3. Call the End method. This process might sound complex but it’s actually quite simple, as the following code illustrates: 'VB Public Sub BeginGetTickerSymbol()
Dim Lookup As New StockLookupService()
Dim CompanyName As IAsyncResult = _
Lookup.BeginGetCompanyName("MSFT", Nothing, Nothing)
While Not CompanyName.IsCompleted
'Do Whatever you need here
End While
286
Chapter 7
Method Invocations and Event Management with .NET Web Services
Console.WriteLine(Lookup.EndGetCompanyName(CompanyName)) End Sub //C# static void BeginGetTickerSymbol() { StockLookupService Lookup = new StockLookupService(); IAsyncResult CompanyName = Lookup.BeginGetCompanyName("MSFT", null, null); while (!CompanyName.IsCompleted) { //Do whatever you need here } Console.WriteLine(Lookup.EndGetCompanyName(CompanyName)); }
CAUTION
Avoid passing only null parameters in delegates
In most real-world scenarios, you’ll want to avoid passing null or Nothing as both parameters. It’s done here only because at this point we won’t cover the concepts of dealing with null values.
This method isn’t as elegant in most respects as wiring up the event handler as we did in the previous lesson because we have to poll for the results. This polling is running in the same thread, so it does block execution on that thread. (Blocking is the inter ruption of a thread until a value is returned.) A more elegant solution, similar to the first method that was illustrated, is using a call back method. Callback methods are exactly what their name implies: They call back to the application, metaphorically saying “I’m done.” Using them is equally simple. In this case, you just need to specify an AsyncCallBack object and specify a target for it. Processing occurs asynchronously, and when it’s completed, the callback notifies the application that it’s finished. At that point, any return values can be retrieved: 'VB Public Sub GetTickerSymbolCallBack() Dim Lookup As New StockLookupService() Dim Callback As New AsyncCallback(AddressOf CompanyReturned) Dim Result As IAsyncResult = _ Lookup.BeginGetCompanyName("MSFT", Callback, Nothing) End Sub Public Sub CompanyReturned(ByVal result As IAsyncResult) Dim Lookup As New StockLookupService() Console.WriteLine(Lookup.EndGetCompanyName(result)) End Sub
Lesson 2: Polling Web Methods for Completion
287
//C# static void GetTickerSymbolCallBack() { StockLookupService Lookup = new StockLookupService(); AsyncCallback Callback = new AsyncCallback(CompanyReturned); IAsyncResult Result = Lookup.BeginGetCompanyName("MSFT", Callback, null); } static void CompanyReturned(IAsyncResult result) { StockLookupService Lookup = new StockLookupService(); Console.WriteLine(Lookup.EndGetCompanyName(result)); }
If you invoked the GetTickerSymbolCallBack method with the following code, you’d see the output I’m running asynchronously before you’d see the return value in the con sole window. 'VB GetTickerSymbolCallBack() Console.WriteLine("I'm running asynchronously") Console.ReadLine() //C# GetTickerSymbolCallBack(); Console.WriteLine("I'm running asynchronously"); Console.ReadLine();
In the CompanyReturned method we’re using the End to retrieve the result of the method call. Although the signature of Begin is totally dif ferent from the method it covers, the End is of the same return type and in fact, returns the value of the method. However, in the first lesson we didn’t see the details of the retrieval of values from the Web method. We wired up an event handler to respond when the method was fin ished executing, but we didn’t respond with respect to the value returned by the method. Fortunately, it’s trivial to get the return value using the event handler method. Using virtually identical code to the event handler example in Lesson 1, retrieving the return value of the method is shown here in bold: 'VB Private WithEvents AsyncLookup As StockLookupService Sub Main() AsyncLookup = New StockLookupService() AsyncLookup.GetCompanyNameAsync("MSFT") Console.ReadLine()
288
Chapter 7
Method Invocations and Event Management with .NET Web Services
End Sub Public Sub GetTickerSymbolCompletedHandler(ByVal sender As Object, _ ByVal args As GetCompanyNameCompletedEventArgs) _ Handles AsyncLookup.GetCompanyNameCompleted If Not args.Error Is Nothing Then Console.WriteLine("Error: {0} Message: {1}", args.UserState, _ args.Error.Message)
End If
If args.Cancelled Then
Console.WriteLine("Method invocation was cancelled") Else Console.WriteLine("Method completed: {0} Value: {1}", _ args.UserState, args.Result) End If End Sub //C# static void Main(string[] args) {
GetTickerServiceAsnycGood();
Console.ReadLine();
} static void GetTickerServiceAsnycGood() { StockLookupService Lookup = new StockLookupService(); Lookup.GetCompanyNameCompleted += new GetCompanyNameCompletedEventHandler(
GetTickerSymbolCompletedHandler);
Lookup.GetCompanyNameAsync("MSFT");
}
private static void GetTickerSymbolCompletedHandler(object sender, GetCompanyNameCompletedEventArgs args) {
if (args.Error != null)
{
Console.WriteLine("Error: {0} Message: {1}", args.UserState, args.Error.Message);
}
if (args.Cancelled)
{
Console.WriteLine("Method invocation was cancelled"); } else { Console.WriteLine("Method completed: {0} Value: {1}", args.UserState, args.Result); } }
Lesson 2: Polling Web Methods for Completion
289
Essentially all that needs to be done is to check that the value isn’t null and that it’s not cancelled (if it is, trying to retrieve the Result property will probably result in an exception or unpredictable behavior at best) and simply use the Result property of the specific EventArgs object that’s being trapped. To summarize, there are essentially three primary methods for using delegates to asynchronously invoke a Web method: ■
Use a CompletedHandler. Check that the return value is not null and that the method wasn’t cancelled. If neither condition is true, interrogate the Result property of the EventArgs argument.
■
Use a Begin delegate and poll for completion.
■
Use a Callback and let the callback notify you on completion.
There’s one other case, however, that doesn’t really fit in with any of the discussions thus far. Imagine a scenario in which you want to “fire and forget,” meaning that you want to call the method and, irrespective of the results, you just want to continue pro cessing. This situation is common when dealing with Web services because some methods don’t have return values, so there’s sometimes no reason to know when the services have completed. Again, because the proxy is generated for you, handling this scenario is extremely simple. Web services (and, as we’ll see in the next chapter, remoting methods) can be called in a unilateral fashion. To do this, a given method simply needs to be decorated with the OneWay attribute. Assume that you have the following Web method definition: [WebMethod] [SoapDocumentMethod(OneWay = true)] public void ThrowException() { throw new ApplicationException("You'll never know I was thrown"); }
If you don’t use the OneWay attribute and you call this method, the .NET Framework propagates a SoapException to the client that calls this method. However, if you actu ally call this method as it’s shown here, processing continues in your program with out interruption, proving that everything in the Web method was ignored. The following code uses a hypothetical service to demonstrate that a one-way method is truly “fire and forget”: 'VB Dim DemoService As New Service() DemoService.ThrowException()
290
Chapter 7
Method Invocations and Event Management with .NET Web Services
Console.WriteLine("I worked as expected")
Console.ReadLine()
//C# Service DemoService = new Service();
DemoService.ThrowException();
Console.WriteLine("I worked as expected");
Console.ReadLine();
If you compile and run the preceding code it will show I worked as expected in the con sole window, proving it worked as expected. If this doesn’t prove it to you, remove the OneWay attribute (or set it to false) and rerun the application.
Lab 2: Calling a Web Method Asynchronously In this lab, you create and add a Web reference to your project and then call one of its Web methods from a client application asynchronously. In the next exercise you make use of the OneWay attribute to verify that a call is working correctly. �
Exercise 1: Calling a Web Method Asynchronously
In this exercise, you’ll create a console application that asynchronously calls the StockLookupService project’s GetCompanyName method. 1. Follow steps 1 through 10 in the lab from Lesson 1. 2. Add the following code to the Programs.cs class if you’re using C# or to Module1.vb if you’re using Visual Basic .NET: 'VB Private WithEvents AsyncLookup As StockLookupService Sub Main()
AsyncLookup = New StockLookupService()
AsyncLookup.GetCompanyNameAsync("MSFT")
Console.WriteLine("I'm running async")
Console.ReadLine()
End Sub Public Sub GetTickerSymbolCompletedHandler(ByVal sender As Object, _ ByVal args As GetCompanyNameCompletedEventArgs) _ Handles AsyncLookup.GetCompanyNameCompleted If Not args.Error Is Nothing Then Console.WriteLine("Error: {0} Message: {1}", args.UserState, _ args.Error.Message)
End If
If args.Cancelled Then
Console.WriteLine("Method invocation was cancelled") Else Console.WriteLine("Method completed: {0} Value: {1}", _
Lesson 2: Polling Web Methods for Completion
291
args.UserState, args.Result)
End If
End Sub
//C# static void Main(string[] args) {
GetTickerServiceAsyncGood();
Console.WriteLine("I'm running async");
Console.ReadLine();
}
static void GetTickerServiceAsyncGood()
{
StockLookupService Lookup = new StockLookupService();
Lookup.GetCompanyNameCompleted +=
new GetCompanyNameCompletedEventHandler(
GetTickerSymbolCompletedHandler);
Lookup.GetCompanyNameAsync("MSFT");
}
private static void GetTickerSymbolCompletedHandler(object sender,
GetCompanyNameCompletedEventArgs args)
{
if (args.Error != null)
{
Console.WriteLine("Error: {0} Message: {1}", args.UserState, args.Error.Message);
}
if (args.Cancelled)
{
Console.WriteLine("Method invocation was cancelled"); } else { Console.WriteLine("Method completed: {0} Value: {1}",
args.UserState, args.Result);
}
}
3. Build the project, and resolve any errors. Run the application and you should see the words I’m running async output to the console window followed by the word Microsoft. �
Exercise 2: Calling a Web Method Decorated with the OneWay Attribute
In this exercise, you create a console application that calls the StockLookupService project’s GetCompanyName method but uses the OneWay attribute. 1. Open Visual Studio 2005 and create an empty project. 2. Add a new C# or Visual Basic .NET console application named StockSymbolConsumerCS or StockSymbolConsumerVB, depending on which language you choose to write in.
292
Chapter 7
Method Invocations and Event Management with .NET Web Services
3. Select File, Add, Existing Project and add the StockLookupService project to this solution. 4. Build the StockLookupService project. 5. Right-click the project and click Add Web Reference. You should see a dialog box similar to the one shown earlier in Figure 7-1. 6. Click Web Services In This Solution, and then click Service for the StockLook upService project. Use the default value of localhost in the Web Reference Name text box. 7. Click Add Reference. 8. Open the StockSymbolConsumer project’s Program.cs file if you’re using C#, or Module1.vb if you’re using Visual Basic .NET. 9. At the top of the module or class, add the following: 'VB Imports StockSymbolConsumerVB.localhost //C# using StockSymbolConsumerCS.localhost;
10. Add the following code to the Main method of the respective project: 'VB Dim DemoService As New Service()
DemoService.ThrowException()
Console.WriteLine("I made it so the OneWay attribute worked!")
//C# Service DemoService = new Service();
DemoService.ThrowException();
Console.WriteLine("I made it so the OneWay attribute worked!");
11. Build the project, and resolve any errors. Run the application and you should see the word Microsoft in the console window.
Lesson Summary ■
Asynchronous invocation should be used whenever an application cannot wait for a method to finish processing.
■
Methods can be invoked asynchronously by using either a delegate or a separate thread.
Lesson 2: Polling Web Methods for Completion
293
■
The Begin and End methods are used to start and complete an asynchronous invocation.
■
By default, Web methods can be invoked asynchronously by using the CompletedEventHandler.
■
The CancelAsync method of a Web service can be used to cancel an asynchro nous call.
■
Polling can be performed by either using an IAsyncResult object and waiting for its IsCompleted property to turn true, or via a callback method that notifies the cli ent when it has completed.
■
The OneWay attribute can be used to provide true “fire and forget” functionality.
■
Care must be taken with the OneWay attribute because the method will not be able to retrieve any return values. Therefore, serious problems can be masked using the attribute.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Polling Web Methods for Completion.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which method is an appropriate means to poll for a Web method’s completion? (Select the best answer.) A. Use an IAsyncResult object in conjunction with a standard invocation and poll for the IsCompleted property to turn true. B. Use an IAsyncResult object in conjunction with an asynchronous invocation and poll for the IsCompleted property to turn true. C. Use a callback method and wait for its IsCompleted property to turn true. D. Mark the method with a OneWay attribute.
294
Chapter 7
Method Invocations and Event Management with .NET Web Services
2. How do calls through a delegate differ from traditional ones? (Select all that apply.) A. They have a different signature and return type in most cases. B. Other methods can be processed while the call to the Web method is processing. C. The Completed event must be handled to get the results back. D. The method call is for all intents and purposes identical to the synchronous counterpart. 3. Which of the following characterize Web method calls? (Select all that apply.) A. Client code calls the Web service directly. B. Client code calls the proxy class that corresponds to the Web service. C. Web services can only be called asynchronously by using separate threads. D. Asynchronous calls can be implemented using delegates or separate threads.
Chapter 7 Review
295
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
.NET Web services allow you to expose data to outside consumers as Extensible Markup Language (XML).
■
Web methods of those Web services behave virtually identically to how normal methods behave.
■
.NET Web services can be created and consumed in any .NET language.
■
.NET Web services can be consumed by anything that can parse XML, which is how the data is returned.
■
A Web reference is needed to consume a Web service.
■
After a Web reference is added to a project, Visual Studio 2005 creates a class that maps to the Web service’s methods and properties, which allows you to interact with the Web service as though it were local.
■
Web methods can be called just like traditional methods. Invocations can be done either asynchronously or synchronously.
■
To implement “fire and forget” functionality, you can use the OneWay attribute on Web methods.
■
The two methods you can use to determine when a Web method has finished executing are polling and callbacks.
■
Semantically, callbacks are much more elegant than polling.
296
Chapter 7 Review
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
asynchronous
■
blocking
■
callback
■
fire and forget
■
synchronous
■
Web method
■
Web service
Case Scenarios In the following case scenarios you apply what you’ve learned about how to use Web methods and Web services. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Exposing Functionality Through .NET Web Services Many companies expand operation over time and need much of their functionality exposed to external customers. .NET Web services and .NET remoting are two of the primary vehicles that make this available. The following case study concerns itself with developing a Web services strategy.
Interviews Following is a list of company personnel interviewed and their statements: “This company has been around for awhile and the original IT infrastructure was comprised of many different vendors’ proprietary prod ucts. This legacy has been one of the biggest obstacles we’ve faced in moderniz ing operations. None of the systems talk to each other and that causes a lot of manual data entry, not to mention data entry errors. We’ve consolidated a lot of this information into a SQL Server database, but a few of our products still run on OleDb databases. We need to expose this functionality to our trading part ners and customers so they can see real-time data and enter data as well. We started trying to use Java to fix these problems, but the solution was riddled with
■ IT Department Head
Chapter 7 Review
297
problems. We needed this fixed last year and would love to move to the .NET Framework, but only if it can help us with this problem.” “Because we have a lot of shortcomings with real-time sys tems, we end up having to do a lot of extra things, which typically involve giving stuff away or selling it at a discount, not to mention having to keep a lot of extra data entry personnel on staff. This is a problem but we can live with it. However, we can’t live with customers leaving our company because other companies have real-time tracking and transmission information available to them. And a reason this is happening is because other companies have updated their pro curement and delivery systems with their trading partners so a lot can be done without manual intervention. Without a doubt, this is the most pressing issue we face and it needs to be addressed as soon as possible.”
■ Lead Business Analyst
“We’re still stuck in the ’90s in many respects; heck, we’re in the ’80s in a few respects. This situation needs to be fixed. We tried a huge Java initiative a while back, but it was nothing but problems. Most developers in the area didn’t know it so we had to hire a bunch of really expensive consultants. A few issues were fixed but it ran slow and nothing was accomplished in exposing our sys tems externally. To be honest, external exposure was the only reason I was will ing to sink the resources into trying it in the first place and I lost my shirt on this. I’ve got one last chance to fix this but I’ll be gambling everything on it. Yes, I’m skeptical, very skeptical in some respects, that fixing it is even possible. Well, I know it can be, but not without causing downtime and so many problems that it isn’t viable.”
■ CIO
Questions Answer the following questions for your manager: 1. CORBA fixed a lot of their problems but the main one they need fixed is expos ing their data externally. What’s the best technology to use to give them this? 2. Their office is in a small, secluded town and they don’t have a lot of cutting-edge developers. No matter what we come up with, it has to be something that an average Joe can learn. Will .NET remoting or Web services fit the bill? 3. How can we consolidate all of their data into one place so that people can get to it externally?
298
Chapter 7 Review
Case Scenario 2: Refining the Use of Web Services After getting the Web services in place and usable, refinement needs to be performed. Only after deployment will many issues come up, performance in particular. The main focus now is getting a responsive client that has predictable and consistent behavior, and that’s the focus of this case study.
Interviews The following is a list of company personnel interviewed and their statements: “Now that we’ve got our functionality moved to Web ser vices, things are a lot better. But, and this is a big but, we still haven’t worked out our bandwidth issues, and the client applications we’ve distributed often hang up. We are getting so many support calls that it’s starting to be as big of a prob lem as not having the functionality exposed in the first place.”
■ IT Department Head
“It’s hard to believe that 6 months ago our biggest issue was that data wasn’t available to customers. Now that is hardly ever mentioned but we sure do get a lot of complaints about performance. We’ve had a ton of unhandled exceptions and the application hangs all the time. This is the biggest problem I hear about and the biggest one that needs to be fixed.”
■ Lead Business Analyst
“Our support calls are going through the roof and it’s costing us a fortune. What’s more, we get so many calls that our support people don’t have much time to do anything else. We need this to stop and stop immediately.”
■ CIO
Questions Answer the following questions for your manager: 1. How can we keep the application from hanging up? 2. How can the application be developed so that noncritical methods never throw exceptions?
Suggested Practices To successfully master the objectives covered in this chapter, complete the following tasks. You should complete at least Practices 1 and 2. You can complete Practice 3 for a more in-depth understanding of interoperation.
Chapter 7 Review
299
Create a Web service project and add a console application project. In the console application, add a Web reference to the Web service and examine the contents of the proxy class.
■ Practice 1
Use the console application created in Practice 1 and call a Web method in a regular fashion. Then, invoke the same method asynchronously.
■ Practice 2
Add the OneWay attribute to one of the Web methods in the Web ser vice you created in Practice 1. Modify the method so that it intentionally throws an exception. Call the Web method from the console application and ensure that no exception is thrown back to the client.
■ Practice 3
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 8
Method Invocations and Event Management with .NET Remoting It’s been noted that there are two primary technologies that the .NET Framework pro vides for implementing a communications layer in distributed applications, .NET XML Web Services and .NET Remoting. With respect to the client code, there are many similarities to using either technology because of the nature of the distributed communications. For instance, both typically require an additional machine to host a separate application. Because of latency inherent in network communications, issues regarding responsive user interfaces need to be addressed. And, as with all applica tions, asynchronous invocations may be necessary to enhance usability. This chapter will address remote method invocations and event management in .NET Remoting.
Exam objectives in this chapter: ■
■
Call remoting methods asynchronously. ❑
Implement one-way methods by using the OneWay attribute.
❑
Call a remote method asynchronously.
❑
Implement a callback.
Implement events in remoting. ❑
Create and fire events.
❑
Implement an event handler for events of the remote object.
Lessons in this chapter: ■
Lesson 1: Calling Remoting Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
■
Lesson 2: Callbacks and Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
■
Lesson 3: Implementing and Responding to Events . . . . . . . . . . . . . . . . . . . . 336
301
302
Chapter 8
Method Invocations and Event Management with .NET Remoting
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction at the beginning of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Successfully completed all lessons in Chapters 1 through 6.
You should be familiar with Microsoft Visual Basic or C# and be comfortable with the following tasks: ■
Creating a console application in Visual Studio using Visual Basic or C#.
■
Adding references to system class libraries to a project.
■
Adding a simple Web reference to a project.
■
A basic understanding of remoting methodologies (XML Web services, DCOM, .NET remoting, CORBA, and so on).
■
A familiarity with formatters and serialization in the .NET Framework.
NOTE
Ensure that a server application is running before attempting to use client code samples.
The server project for each exercise, included on the companion CD, must be running for the processes to work correctly.
Real World William Ryan A few years ago, my company implemented a fairly straightforward client/server application in ASP.NET. The application was implemented and customers were happy, but we received some new security guidelines from the government that involved implementing a new firewall. The application connected directly to the database from the Web server, which forced us to poke a hole in the firewall and opened up some potential security concerns. We decided that we should use .NET remoting to implement an application server. The Web server would only talk to the application server and the application server would talk to the database. This way, the database could never be accessed directly from the Web server, so even if the Web server were ever compromised, the attack surface would be greatly reduced. This solution was the single best enhancement that was made in the application, and we have used .NET remoting extensively since then.
Lesson 1: Calling Remoting Methods
303
Lesson 1: Calling Remoting Methods On the surface, calling a method using .NET remoting might not look any different from calling any other traditional method. However, looks are very deceiving in this case because the mechanics of calling a remote method differ greatly (and for the most part, these mechanics are hidden from the developer) from traditional method invoca tion or even Web method invocation. The following are some of the major differences: ■
Each time you call a remote method, the server must be contacted so it can pro cess the request.
■
With the exception of methods decorated with the OneWay attribute (discussed later), the developer cannot know at the time of invocation whether or not the method will complete successfully.
■
Much more care must be taken with respect to the passing of parameters and the size of the returned value because remoting methods involve network traffic and, depending on bandwidth availability, operations that would otherwise be trivial might cause performance concerns.
These issues are quite serious and need to be considered in depth before using .NET remoting. For instance, assume that your application had a Person object with a FirstName and LastName property, both of which are of type String. Provided that the prop erties were set properly, each could be referenced from calling code without any possibility of an exception being thrown. Yet if the object was remote, several factors, such as a server failure, would cause the method to fail. Similarly, on client machines, developers often take copious amounts of random access memory (RAM) on client machines for granted. Passing large objects around often makes sense, and most peo ple take the ability to do so for granted. However, in remoting scenarios, each param eter that is passed in, as well as each value that is returned, consumes bandwidth. This bandwidth might not be readily available, and things that used to work fine might suddenly start performing sluggishly (or worse, failing). After this lesson, you will be able to: ■
Call a remoting method.
■
Call a remoting method asynchronously.
■
Use events with remote objects.
Estimated lesson time: 20 minutes
304
Chapter 8
Method Invocations and Event Management with .NET Remoting
Calling a Remoting Method Synchronously In most cases, developers create classes and use those classes to create objects. A sim ple Person class with a FirstName method and a LastName method might look some thing like the following code: 'VB Sub ShowNormalInstantiation()
Dim SomePerson As New Person()
Console.WriteLine(SomePerson.LastName() + ", " + _
SomePerson.FirstName())
End Sub
//C# static void ShowNormalInstantiation() {
Person SomePerson = new Person();
Console.WriteLine(SomePerson.LastName() + ", " +
SomePerson.FirstName());
}
Depending on the exact approach you are using to create a given remote object, the invocation might look something like the following: 'VB Sub Main()
RemotingConfiguration.Configure("StandardClient.exe.config", False)
Dim person As IPerson = _
CType(Activator.GetObject(GetType(IPerson), _
"tcp://localhost:9000/Person.rem"), IPerson)
Console.WriteLine(person.LastName() & ", " & person.FirstName())
End Sub
//C# static void Main(string[] args) {
RemotingConfiguration.Configure("StandardClient.exe.config", false);
IPerson person = (IPerson)Activator.GetObject(typeof(IPerson),
@"tcp://localhost:9000/Person.rem");
Console.WriteLine(person.LastName() + ", " + person.FirstName());
}
The output for the preceding code should approximate that in Figure 8-1.
Lesson 1: Calling Remoting Methods
Figure 8-1
305
Console output of call to LastName and FirstName
The preceding example is just one way to create a remote object, and how an object is created isn’t really important to knowing how to invoke methods off of it. After the remote object is created, calls to its methods are identical, irrespective of how the object is instantiated (client-activated or server-activated instantiation). Hence, as far as the actual method call is concerned, there is no syntactical difference between local and remote calls. Although syntactically remote method calls might look no different from their nonre mote counterparts, operationally and architecturally they are very different. Accord ingly, there is an issue with the preceding code that the developer should be aware of. Notice that there is a call to both the FirstName method and the LastName method. As you might now realize, these calls, even if combined on one line as they are in this example, require two trips to the server. This fact greatly complicates traditional object-oriented usage because now referencing these two methods is not necessarily a trivial endeavor. The following issues arise here: ■
If you wrap the entire line in a try/catch block, the first call might succeed and the second call might fail. This situation requires more involved exception man agement and logging to be performed on the client so that the nature of any problems can be accurately discerned.
■
Instead of calling the two methods, it might be preferable to add another method to the class that performs the concatenation on the server instead of on the client. However, this preference isn’t always the case. After all, if you rarely use the methods in a combined format, you might just be adding unnecessary or confusing logic to your design.
■
Good design in a nonremoting environment might make for a terrible design in a remoting environment and vice versa. (This situation is often the case, partic ularly with respect to events, which are discussed later.)
306
Chapter 8
Method Invocations and Event Management with .NET Remoting
Stateless Invocation Using One-Way Calls Precisely because so many different things can go wrong when calling remote meth ods, you need to take much care in handling and responding to exceptions. Yet there are many times when a decision is made that something should be called in a fire and forget method. That effectively means that irrespective of what happens on the server side, processing should neither be delayed nor fail due to an exception. To provide this behavior, the System.Runtime.Remoting.Messaging namespace provides the OneWay attribute. The behavior that this attribute causes is functionally identical to the behavior observed when the OneWay attribute is used in a Web method. The following are the modifications to the IPerson interface and the Person class that are necessary to use the OneWay attribute: 'VB Public Interface IPerson
_
Function FirstName() As String
_
Function LastName() As String
End Interface Public Class Person
Inherits MarshalByRefObject
Implements IPerson
_
Public Function FirstName() As String _
Implements Interfaces.IPerson.FirstName Throw New ArgumentException("Intentionally thrown exception") End Function _
Public Function LastName() As String Implements _
Interfaces.IPerson.LastName
Throw New ArgumentException("Intentionally thrown exception")
End Function
End Class
//C# public interface IPerson
{
[OneWay()]
String FirstName();
[OneWay()]
String LastName();
}
Lesson 1: Calling Remoting Methods
307
public class Person : MarshalByRefObject, IPerson { #region IPerson Members
[OneWay()]
public string FirstName()
{
throw new ArgumentException("Intentionally thrown exception");
}
[OneWay()]
public string LastName()
{
throw new ArgumentException("Intentionally thrown exception");
}
#endregion }
Before I introduce the calling code, note what has changed here. ■
A reference to import the System.Runtime.Remoting.Messaging namespace was included in both the IPerson interface and the Person class.
■
The OneWay attribute was added to both the FirstName and LastName methods of the IPerson interface.
■
The OneWay attribute was added to both the FirstName and LastName methods of the Person class.
■
Instead of returning values in the FirstName and LastName methods, an Argu mentException is intentionally thrown.
Now, just to make the behavior here absolutely clear, note the following changes (in bold) to the previous code Main: 'VB Sub Main() RemotingConfiguration.Configure("StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _
"tcp://localhost:9000/Person.rem"), IPerson)
Dim FirstName As String = person.FirstName
Dim LastName As String = person.LastName
'If these calls were not marked as OneWay, we would never get to this
'line because an unhandled exception would interrupt processing.
Console.ReadLine() End Sub //C# static void Main(string[] args)
308
Chapter 8
Method Invocations and Event Management with .NET Remoting
{
RemotingConfiguration.Configure("StandardClient.exe.config", false);
IPerson person = (IPerson)Activator.GetObject(typeof(IPerson),
@"tcp://localhost:9000/Person.rem"); String FirstName = person.FirstName(); String LastName = person.LastName(); //If these calls were not marked as OneWay, we would never get to this //line because an unhandled exception would interrupt processing. Console.ReadLine();
}
Note that now, the application is calling the FirstName and LastName methods indi vidually, just to reinforce the point that execution will continue regardless of whether something goes wrong on the server. To verify this point, run the client application (such as the Lesson 1 StandardClient application on the companion disk) without starting the server application. After you run the application, you should notice that processing occurs through both methods without interruption, even though there isn’t a server running to actually return anything. If the OneWay attribute was missing (feel free to remove the OneWay attributes and rerun the application) on either or both of the methods, an exception would immediately be raised. Now run the client program, making sure that the server application has been started. After a call to the FirstName method, the server application will either crash (if it’s in Release mode) or break into the debugger (if it’s in Debug mode). How can this be if the OneWay attribute is supposed to protect against crashes? The answer is that the OneWay attribute does in fact protect the client against any exceptions (and every thing else) that might occur on the server, but it does not guard the server against unhandled exceptions or failures. This behavior is entirely desirable. Why? Assume that you have a client that runs some fire and forget procedure every 15 minutes. Imagine that the client machines become disconnected from the network or that the server code references a drive that doesn’t exist or performs some other operation that necessarily fails. If the OneWay attribute in the server code shielded the server application from all failures, how would you ever know of the problem? You’d proba bly figure it out after a while, but if the OneWay attribute subdued exceptions on the server, it would unquestionably cause many more problems than it ever solved. Hence, the price of a fire and forget method would far exceed any benefit you might get from it.
Lesson 1: Calling Remoting Methods
309
Calling a Remoting Method Asynchronously There are a lot of potential problems associated with synchronous method calls that can severely affect the end user experience. A few of the major ones are listed here: ■
The remoting method might end in an error. If this happens, you will only learn of the error after the Timeout period expires, which might be quite a long time. (Most people consider an application freeze for even 5 seconds a long time.)
■
The remoting method might complete successfully but take a long time to com plete. If the application is waiting for this method to complete, it might interfere with the user experience.
■
In most instances you call more than one remoting method, and waiting for each call to complete individually is potentially wasteful. (Imagine a case where the first method doesn’t return properly. The user might wait 30 seconds or so for the first method to return and the next method to be called. If the methods were called asynchronously, both requests would be fired at close to the same time and the overall wait time could be drastically reduced.)
This lesson isn’t intended to be an advertisement for asynchronous processing, but suffice it to say that in most professional applications, at least some degree of asyn chronous processing is called for. With this in mind, the choices available for asynchronous remoting calls are effec tively the same ones available with any other method (again, the notable differences are transparent to the developer): ■
Create a new thread and call the method.
■
Create a delegate object that matches the remoting method’s signature and use the delegate in place of the normal invocation.
Before we continue, a note of caution is needed. Although an asynchronous invoca tion using a delegate is fairly straightforward in its simplest form, it can be quite involved. For the purposes of this discussion, a simple example is used at first and the nuances are discussed in the following lessons. Using the same methods that were employed in the previous example, the following code adds asynchronous support: 'VB Module Module1
Public Delegate Function FirstNameDelegate() As String
Public Delegate Function LastNameDelegate() As String
Sub Main()
310
Chapter 8
Method Invocations and Event Management with .NET Remoting
RemotingConfiguration.Configure("StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _ "tcp://localhost:9000/Person.rem"), IPerson) Dim first_name As New FirstNameDelegate(AddressOf person.FirstName) Dim last_name As New LastNameDelegate(AddressOf person.LastName) Dim FirstNameResult As IAsyncResult = _ first_name.BeginInvoke(Nothing, Nothing) Console.WriteLine("I will probably process before " & _ "[firstNameResult] does") Dim LastNameResult As IAsyncResult = _ last_name.BeginInvoke(Nothing, Nothing) Console.WriteLine("I will probably process before " "[lastNameResult] does") Console.ReadLine() End Sub End Module //C# class Program {
delegate String GetFirstNameDelegate();
delegate String GetLastNameDelegate();
static void Main(string[] args) { RemotingConfiguration.Configure("StandardClient.exe.config", false); IPerson person = (IPerson)Activator.GetObject(typeof(IPerson), @"tcp://localhost:9000/Person.rem"); GetFirstNameDelegate first_Name = new GetFirstNameDelegate(person.FirstName); GetLastNameDelegate last_Name = new GetLastNameDelegate(person.LastName); IAsyncResult firstNameResult = first_Name.BeginInvoke(null, null); Console.WriteLine("I will probably process before " + "[firstNameResult] does"); IAsyncResult lastNameResult = last_Name.BeginInvoke(null, null); Console.WriteLine("I will probably process before " + "[lastNameResult] does");
Console.ReadLine();
}
}
The output from the preceding code should look like Figure 8-2.
Lesson 1: Calling Remoting Methods
Figure 8-2
311
Console output of asynchronous call to LastName and FirstName
So what just happened? These are the important points: ■
A delegate object was created that matches the signature of the FirstName method of the Person class.
■
A delegate object was created that matches the signature of the LastName method of the Person class.
■
A new instance of each delegate was created.
■
A new IAsyncResult object was created for each delegate.
■
The BeginInvoke method of each respective IAsyncResult object was called, pass ing in null (in C#) or Nothing (in Visual Basic .NET).
Getting data back from asynchronous calls and responding to the various events asso ciated with such calls is discussed in depth in the following lessons.
Lab 1: Invoking a Remoting Method In this lab, you create a console application that will call the FirstName and LastName methods of the Person class shown previously. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005 and create a new empty project. Name this solution StandardCallDemo. 2. Add a new C# or Visual Basic .NET console application named StandardClient. 3. In Solution Explorer, right-click the Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8.Standard.Client. 4. On the File menu, select Add, New Project. Click the Class Library template, enter the name StandardInterfaces, and click OK.
312
Chapter 8
Method Invocations and Event Management with .NET Remoting
5. In Solution Explorer, right-click the StandardInterfaces project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8 .Standard.Interfaces. 6. In Solution Explorer, select the StandardInterfaces project. On the Project menu, select Add New Item. Click the Interface template, name the interface IPerson, and click Add. 7. Add the code shown in bold here to the IPerson interface: 'VB Public Interface IPerson
Function FirstName() As String
Function LastName() As String
End Interface //C# namespace MSLearning.Chapter8.Standard.Interfaces {
public interface IPerson
{
String FirstName();
String LastName(); }
}
8. Add another C# or Visual Basic .NET console application to the solution and name it StandardServer. 9. In Solution Explorer, right-click the StandardServer project’s Properties folder and click Open. In the Default Namespace text box, type MSLearning.Chapter8 .Standard.Server. 10. Right-click the StandardClient project’s References folder and select Add Refer ence. In the Add Reference dialog box, click the Projects tab, click the Stan dardInterfaces project, and click OK. Repeat this process to add a reference in the StandardInterfaces project to the StandardServer project. 11. Right-click each project, select Add Reference, and add a reference to System.Run time.Remoting. 12. Right-click the StandardClient project and select Add, New Item. Click Applica tion Configuration File, and click Add. 13. Edit the App.config application configuration file to look like the following:
Lesson 1: Calling Remoting Methods
313
14. Right-click the StandardServer project and click Add, New Item. Click Applica tion Configuration File and click Add. 15. Edit the App.config application configuration file to look like the following:
16. Open the StandardServer project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic .NET). Modify the file so that it looks like the following: 'VB Imports Imports Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
Module Module1 Sub Main() RemotingConfiguration.Configure("StandardServer.exe.config", _ False)
Console.WriteLine("Press return to exit...\n")
Console.ReadLine()
314
Chapter 8
Method Invocations and Event Management with .NET Remoting
End Sub
End Module
//C# using using using using using using
System;
System.Collections.Generic;
System.Text;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
namespace MSLearning.Chapter8.Standard.Server {
class Program
{
static void Main(string[] args) { RemotingConfiguration.Configure("StandardServer.exe.config", false); Console.WriteLine("Press return to exit...\n"); Console.ReadLine(); }
}
}
17. Right-click the StandardServer project and click Add, Class. Name the class Person and click Add. The class needs to implement the IPerson interface. (This project should already have a reference to the StandardInterfaces project, which you added in step 9.) Edit the Person class so that it looks like the following: 'VB Imports Imports Imports Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter8.Standard.Interfaces
Public Class Person
Inherits MarshalByRefObject
Implements IPerson
Public Function FirstName() As String _
Implements Interfaces.IPerson.FirstName
Return "Demo"
End Function
Public Function LastName() As String _
Implements Interfaces.IPerson.LastName
Lesson 1: Calling Remoting Methods
315
Return "Person"
End Function
End Class
//C# using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MSLearning.Chapter8.Standard.Interfaces;
using System.Runtime.Remoting.Messaging;
namespace MSLearning.Chapter8.Standard.Server
{
public class Person : MarshalByRefObject, IPerson
{
#region IPerson Members public string FirstName()
{
return "Demo";
}
public string LastName()
{
return "Person";
}
#endregion
}
}
18. Open the StandardClient project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic .NET). Modify the file so that it looks like the following: 'VB Imports Imports Imports Imports
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter8.Standard.Interfaces
Module Module1 Sub Main() RemotingConfiguration.Configure("StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _ "tcp://localhost:9000/Person.rem"), IPerson) Console.WriteLine(person.LastName() & ", " & person.FirstName())
316
Chapter 8
Method Invocations and Event Management with .NET Remoting
End Sub End Module //C# using using using using
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter8.Standard.Interfaces;
namespace MSLearning.Chapter8.Standard.Client {
class Program
{
static void Main(string[] args) { RemotingConfiguration.Configure("StandardClient.exe.config", false); IPerson person = (IPerson)Activator.GetObject(typeof(IPerson), @"tcp://localhost:9000/Person.rem"); Console.WriteLine(person.LastName() + ", " + person.FirstName()); Console.ReadLine(); } } }
At this point, Solution Explorer should resemble Figure 8-3. (This figure shows all three projects being created in C#. However, the Visual Basic .NET equivalent should look similar except it will show the Visual Basic .NET project and source files.)
Figure 8-3
Solution Explorer with all three necessary projects
19. On the Visual Studio 2005 Project menu, click Build, Rebuild Solution. Resolve any build errors.
Lesson 1: Calling Remoting Methods
317
20. Right-click the StandardServer project and select Debug, Start New Instance to start an instance of the StandardServer program. 21. Right-click the StandardClient project and select Debug, Start New Instance to start an instance of the StandardClient program and make a synchronous call to the FirstName and LastName methods of the Person class. 22. Press Enter in both console windows to exit the StandardClient and StandardServer applications.
Lesson Summary ■
Methods of remote objects can be called using either Web services or .NET remoting.
■
Although the client-side usage is seemingly the same, methods called on remote objects can execute on the server instead of the client.
■
By creating a delegate with a matching signature, any method can be invoked by calling the delegate’s BeginInvoke method.
■
To use a delegate object to invoke a method, the delegate’s signature must match the signature of any method it will be used to invoke.
■
A delegate can be used to invoke different methods, but each method must have a matching return type and a matching parameter list.
■
The OneWay attribute can be used to provide fire and forget functionality.
■
Although the OneWay attribute allows a client method to process uninterrupted regardless of what happens on the server, the OneWay attribute does not shield the server-side method from failing.
■
If interfaces are used for remote objects, the OneWay attribute must be applied at both the interface and the class level.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Calling Remoting Methods.” The questions are also available on the compan ion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
318
Chapter 8
Method Invocations and Event Management with .NET Remoting
1. Which is true of objects that use the OneWay attribute? (Select all that apply.) A. Each method that requires fire and forget functionality should be deco rated with the OneWay attribute. B. If an interface is used, each method that will be implemented in a fire and forget manner should be decorated with the OneWay attribute. C. The code block containing the call to a fire and forget method must be marked with the OneWay attribute. D. The OneWay attribute is not necessary so long as the method will be invoked via a delegate. 2. How do asynchronous methods differ from traditional ones? (Select all that apply.) A. They have a different signature and return type in most cases. B. Other methods can be processed while the call to the remoting method is processing. C. The Completed event must be handled to get the results back. D. The method call is for all intents and purposes identical to the synchronous counterpart, other than the way in which it is invoked.
Lesson 2: Callbacks and Remoting
319
Lesson 2: Callbacks and Remoting In the previous lesson, we were introduced to both synchronous and asynchronous invocations of remoting calls. In this lesson, we delve a little deeper into the process of asynchronous invocations. In particular, we cover the following: ■
Checking for completion using the IsCompleted method.
■
Using an AsyncCallback object.
After this lesson, you will be able to: ■
Use a delegate to invoke a remoting method.
■
Check the state of completion and respond accordingly.
Estimated lesson time: 45 minutes
Real World William Ryan Totally changing the architecture of the application referenced in the previous Real World example was a great move, but it was not without some problems along the way. One problem was with interface responsiveness. The same appli cation server used to serve data to the ASP.NET application was also used to serve data to our internal applications. Because everything was done synchro nously, the user interface froze quite a bit. Thanks to implementing asynchro nous techniques and callbacks, we then had a much more responsive application, which users greatly appreciated.
Polling When a method is called asynchronously, you don’t really know when it has reached completion. Typically, programs execute in a linear fashion, but that’s not the case with asynchronous calls. Consider the following situation: A call is made to a given method of a remote object. Next, another call is made to a different method, one that uses the return value from the first call as a parameter for the second call. In a synchronous scenario, you can be sure that the second call will not execute until the first is completed. In an asynchronous scenario, you don’t know when any of the methods are going to return and you certainly can’t count on them finishing in the
320
Chapter 8
Method Invocations and Event Management with .NET Remoting
sequence in which they were called. (If they do finish in the sequence in which they were called, it’s only due to random chance.)
Determining Whether an Asynchronous Call Has Finished In the last part of Lesson 1, a simple example invoked the FirstName and LastName methods of the Person class. However, in that example, the client code wasn’t con cerned with the return values from either of those methods. In fact, the example essentially ignored the return values because we were trying to show that processing truly occurred asynchronously. If, however, the calling code was unable to use return values whenever it invoked a method asynchronously, the usefulness of asynchro nous calls would be severely limited. After all, methods that return values that will be consumed by the client are just as likely as ones that won’t take a long time to com plete. If you had to hold up processing every time you needed a value back from a remote method, you’d require a Herculean effort just to decide when and when not to use a method. Not only can you retrieve a value from an asynchronous call if you need it, but there are several ways to accomplish the retrieval. We saw in Chapter 7 that to use an IAsyncResult object to perform an asynchronous invocation, a delegate object that matched the method’s signature was necessary. After this matching delegate was in place, all that was necessary to perform the asyn chronous invocation was calling the BeginInvoke method of the delegate, passing in the function’s name, and in our example, two null parameters. In the simplest asyn chronous return value retrieval scenario, all that is necessary is to call the EndInvoke method of the delegate, passing in the IAsyncResult object as a parameter. Assuming the same implementation of IPerson and Person that was used in the first example in Lesson 1, all that is needed to get the return values from FirstName and LastName is the following modification (new code is highlighted in bold): 'VB Imports Imports Imports Imports
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter8.Standard.Interfaces
Module Module1
Public Delegate Function FirstNameDelegate() As String
Public Delegate Function LastNameDelegate() As String
Sub Main() RemotingConfiguration.Configure("StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _
Lesson 2: Callbacks and Remoting
"tcp://localhost:9000/Person.rem"), IPerson) Dim first_name As New FirstNameDelegate(AddressOf person.FirstName)
Dim last_name As New LastNameDelegate(AddressOf person.LastName)
Dim FirstNameResult As IAsyncResult = _
first_name.BeginInvoke(Nothing, Nothing)
Console.WriteLine("Calling first_Name didn't block me...") Dim LastNameResult As IAsyncResult = _
last_name.BeginInvoke(Nothing, Nothing)
Console.WriteLine("Calling last_Name didn't block me either...")
Dim FirstNameValue As String = _
first_name.EndInvoke(FirstNameResult)
Dim LastNameValue As String = last_name.EndInvoke(LastNameResult)
Dim Output As String = String.Format("FirstName: {0} " & _
"LastName: {1}", FirstNameValue, LastNameValue)
Console.WriteLine(Output)
Console.ReadLine() End Sub End Module //C# using using using using
System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; MSLearning.Chapter8.Standard.Interfaces;
namespace MSLearning.Chapter8.Standard.Client { class Program { delegate String GetFirstNameDelegate();
delegate String GetLastNameDelegate();
static void Main(string[] args)
{
RemotingConfiguration.Configure("StandardClient.exe.config",
false);
IPerson person = (IPerson)Activator.GetObject(typeof(IPerson),
@"tcp://localhost:9000/Person.rem");
GetFirstNameDelegate first_Name =
new GetFirstNameDelegate(person.FirstName);
GetLastNameDelegate last_Name =
new GetLastNameDelegate(person.LastName);
IAsyncResult firstNameResult =
first_Name.BeginInvoke(null, null);
Console.WriteLine("Calling first_Name didn't block me..."); IAsyncResult lastNameResult =
last_Name.BeginInvoke(null, null);
Console.WriteLine(
"Calling last_Name didn't block me either...");
321
322
Chapter 8
Method Invocations and Event Management with .NET Remoting
String FirstNameValue = first_Name.EndInvoke( firstNameResult); String LastNameValue = last_Name.EndInvoke(lastNameResult); String Output = String.Format("FirstName: {0} LastName: {1}", FirstNameValue, LastNameValue);
Console.WriteLine(Output);
Console.ReadLine(); } } }
If the code is compiled and run as it was in the previous examples, the output should look similar to that of Figure 8-4.
Figure 8-4 CAUTION
Output from calls to FirstName and LastName after EndInvoke is called Avoid passing only null parameters in delegates
In most real-world scenarios, you’ll want to avoid passing null or Nothing as both parameters. It’s done here only because at this point we haven’t introduced some of the concepts with respect to dealing with null values.
Polling for Completion Each object we create of type delegate has the properties of the base class. The method most relevant to the discussion at hand is the IsCompleted method (which, as you might have gathered from the name, has a return type of Boolean). This method is very straightforward to use. After you invoke the method with BeginInvoke, you can poll for IsCompleted to be true, which indicates that processing has completed. The fol lowing example illustrates how to poll for completion (new code is highlighted in bold): 'VB Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Lesson 2: Callbacks and Remoting
Imports System.Runtime.Remoting.Channels.Tcp Imports MSLearning.Chapter8.Standard.Interfaces Module Module1 Public Delegate Function FirstNameDelegate() As String Public Delegate Function LastNameDelegate() As String Sub Main()
RemotingConfiguration.Configure("StandardClient.exe.config", False)
Dim person As IPerson = _
CType(Activator.GetObject(GetType(IPerson), _
"tcp://localhost:9000/Person.rem"), IPerson)
Dim first_name As New FirstNameDelegate(AddressOf person.FirstName)
Dim last_name As New LastNameDelegate(AddressOf person.LastName)
Dim FirstNameResult As IAsyncResult = _ first_name.BeginInvoke(Nothing, Nothing)
Console.WriteLine("Calling first_Name didn't block me...")
Dim LastNameResult As IAsyncResult = _
last_name.BeginInvoke(Nothing, Nothing)
Console.WriteLine("Calling last_Name didn't block me either...")
While (Not FirstNameResult.IsCompleted OrElse _
Not LastNameResult.IsCompleted)
If FirstNameResult.IsCompleted Then Console.WriteLine("The call to FirstName has finished...") End If If LastNameResult.IsCompleted Then Console.WriteLine("The call to LastName has finished..")
End If
End While
Dim FirstNameValue As String = _ first_name.EndInvoke(FirstNameResult)
Dim LastNameValue As String = last_name.EndInvoke(LastNameResult)
Dim Output As String = String.Format( _
"FirstName: {0} LastName: {1}", FirstNameValue, LastNameValue)
Console.WriteLine(Output)
Console.ReadLine()
End Sub End Module //C# using using using using
System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; MSLearning.Chapter8.Standard.Interfaces;
namespace MSLearning.Chapter8.Standard.Client { class Program {
323
324
Chapter 8
Method Invocations and Event Management with .NET Remoting
delegate String GetFirstNameDelegate();
delegate String GetLastNameDelegate();
static void Main(string[] args) { RemotingConfiguration.Configure("StandardClient.exe.config", false); IPerson person = (IPerson)Activator.GetObject(typeof(IPerson), @"tcp://localhost:9000/Person.rem"); GetFirstNameDelegate first_Name = new GetFirstNameDelegate(person.FirstName); GetLastNameDelegate last_Name = new GetLastNameDelegate(person.LastName); IAsyncResult firstNameResult = first_Name.BeginInvoke(null, null); Console.WriteLine("Calling first_Name didn't block me..."); IAsyncResult lastNameResult = last_Name.BeginInvoke(null, null); Console.WriteLine( "Calling last_Name didn't block me either..."); while (!firstNameResult.IsCompleted || !lastNameResult.IsCompleted) {
if (firstNameResult.IsCompleted)
{
Console.WriteLine( "The call to FirstName has finished..."); } if (lastNameResult.IsCompleted) { Console.WriteLine( "The call to LastName has finished.."); } } String FirstNameValue = first_Name.EndInvoke(firstNameResult); String LastNameValue = last_Name.EndInvoke(lastNameResult); String Output = String.Format("FirstName: {0} LastName: {1}", FirstNameValue, LastNameValue);
Console.WriteLine(Output);
Console.ReadLine();
}
}
}
Polling Using a Callback Method A more elegant solution, similar to the first method that was illustrated, is using a call back method. Callback methods are exactly what their name implies: They call back to the application, metaphorically saying “I’m done.”
Lesson 2: Callbacks and Remoting
325
Using them is equally simple. In this case, you just need to specify an AsyncCallback object and specify a target for it. Processing occurs asynchronously, and when it’s completed, the callback notifies the application that it’s finished. At that point, any return values can be retrieved. For the sake of simplicity, this example promotes a few of the local variables to the module/class level, purely for scoping reasons. With this change, the following is all that is required to use an AsyncCallback object: ■
Create a method to handle the callback object. This method takes one IAsyncResult object as a parameter.
■
Create an AsyncCallback object for each BeginInvoke you plan to use, specifying the name of the method you created.
■
Specify this callback object as the first parameter in each BeginInvoke instance.
The following code illustrates this process: 'VB Imports Imports Imports Imports
System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter8.Standard.Interfaces
Module Module1 Public Delegate Function GetFirstNameDelegate() As String Public Delegate Function GetLastNameDelegate() As String Private demo_person As IPerson Private firstNameResult As IAsyncResult Private lastNameResult As IAsyncResult Private first_Name As GetFirstNameDelegate Private last_Name As GetLastNameDelegate Function DemoPerson() As IPerson
If demo_person Is Nothing Then
RemotingConfiguration.Configure("StandardClient.exe.config", _
False)
Dim person As IPerson = _
CType(Activator.GetObject(GetType(IPerson), _
"tcp://localhost:9000/Person.rem"), IPerson)
End If
Return demo_person
End Function
Sub Main() first_Name = _ New GetFirstNameDelegate(AddressOf DemoPerson.FirstName)
last_Name = New GetLastNameDelegate(AddressOf DemoPerson.LastName)
Dim FirstNameCallback = _
New AsyncCallback(AddressOf FirstNameReturned)
326
Chapter 8
Method Invocations and Event Management with .NET Remoting
Dim LastNameCallback = _ New AsyncCallback(AddressOf LastNameReturned) firstNameResult = first_Name.BeginInvoke( _ FirstNameCallback, first_Name) lastNameResult = last_Name.BeginInvoke(LastNameCallback, last_Name) Console.ReadLine()
End Sub
Sub FirstNameReturned(ByVal result As IAsyncResult)
Console.WriteLine("FirstNameCallback value: " & _
first_Name.EndInvoke(result))
End Sub
Sub LastNameReturned(ByVal result As IAsyncResult)
Console.WriteLine("LastNameCallback value: " & _
last_Name.EndInvoke(result))
End Sub
End Module //C# using using using using
System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; MSLearning.Chapter8.Standard.Interfaces;
namespace MSLearning.Chapter8.Standard.Client { class Program { delegate String GetFirstNameDelegate(); delegate String GetLastNameDelegate(); private static IPerson demo_person; static IAsyncResult firstNameResult; static IAsyncResult lastNameResult; static GetFirstNameDelegate first_Name; static GetLastNameDelegate last_Name; static IPerson DemoPerson() {
if (demo_person == null)
{
RemotingConfiguration.Configure( _ "StandardClient.exe.config", false); demo_person = (IPerson)Activator.GetObject( _ typeof(IPerson), @"tcp://localhost:9000/Person.rem"); }
return demo_person;
}
static void Main(string[] args)
Lesson 2: Callbacks and Remoting
327
{ first_Name = new GetFirstNameDelegate(DemoPerson().FirstName); last_Name = new GetLastNameDelegate(DemoPerson().LastName); AsyncCallback FirstNameCallback = _ new AsyncCallback(FirstNameReturned); AsyncCallback LastNameCallback = _ new AsyncCallback(LastNameReturned); firstNameResult = first_Name.BeginInvoke( _ FirstNameCallback, first_Name); lastNameResult = last_Name.BeginInvoke( _ LastNameCallback, last_Name) Console.ReadLine();
}
static void FirstNameReturned(IAsyncResult result) { Console.WriteLine("FirstNameCallback Value: " + first_Name.EndInvoke(result)); } static void LastNameReturned(IAsyncResult result) { Console.WriteLine("LastNameCallback Value: " + last_Name.EndInvoke(result)); } } }
The preceding code should result in output as shown in Figure 8-5.
Figure 8-5
Output from AsyncCallback methodology
Lab 2: Calling a Remoting Method Asynchronously In this lab, you will create a remotable object and call it asynchronously. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder.
328
Chapter 8
Method Invocations and Event Management with .NET Remoting
1. Open Visual Studio 2005 and create a blank solution. 2. Add a new C# or Visual Basic .NET console application named StandardClient. 3. In Solution Explorer, right-click the project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8.Standard.Client. 4. On the File menu, select Add, New Project. Click the Class Library template, enter the name StandardInterfaces, and click OK. 5. In Solution Explorer, right-click the StandardInterfaces project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning .Chapter8.Standard.Interfaces. 6. In Solution Explorer, select the StandardInterfaces project. On the Project menu, select Add New Item. Click the Interface template, name the interface IPerson, and click Add. 7. Add the code shown in bold to the IPerson interface: 'VB Public Interface IPerson
Function FirstName() As String
Function LastName() As String End Interface
//C# namespace MSLearning.Chapter8.Standard.Interfaces {
public interface IPerson
{
String FirstName();
String LastName();
}
}
8. Add another C# or Visual Basic .NET console application to the solution and name it StandardServer. 9. In Solution Explorer, right-click the StandardServer project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8 .Standard.Server. 10. Right-click the StandardClient project’s References folder and select Add Refer ence. In the Add Reference dialog box, click the Projects tab, click the Stan dardInterfaces project, and click OK. Repeat this process to add a reference to the StandardInterfaces project and to the StandardServer project. 11. Right-click each project, select Add Reference, and add a reference to System.Run time.Remoting.
Lesson 2: Callbacks and Remoting
329
12. Right-click the StandardClient project and select Add, New Item. Click Applica tion Configuration File, and click Add. 13. Edit the App.config application configuration file to look like the following:
14. Right-click the StandardServer project and click Add, New Item. Click Application Configuration File and click Add. 15. Edit the App.config application configuration file to look like the following:
16. Open the StandardServer project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic .NET). Modify the file so that it looks like the following: 'VB Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
System.Runtime.Remoting
330
Chapter 8
Method Invocations and Event Management with .NET Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Module Module1 Sub Main() RemotingConfiguration.Configure("StandardServer.exe.config", False) Console.WriteLine("Press return to exit...\n") Console.ReadLine() End Sub
End Module
//C# using using using using using using
System;
System.Collections.Generic;
System.Text;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
namespace MSLearning.Chapter8.Standard.Server {
class Program
{
static void Main(string[] args) { RemotingConfiguration.Configure("StandardServer.exe.config", false); Console.WriteLine("Press return to exit...\n"); Console.ReadLine(); }
}
}
17. Right-click the StandardServer project, and click Add, Class. Name the class Person and click Add. The class needs to implement the IPerson interface. (This project should already have a reference to the Standard.Interfaces project, which you added in step 9.) Edit the Person class so that it looks like the following: 'VB Imports Imports Imports Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter8.Standard.Interfaces
Public Class Person
Inherits MarshalByRefObject
Implements IPerson
Lesson 2: Callbacks and Remoting
331
Public Function FirstName() As String _
Implements Interfaces.IPerson.FirstName
Return "Demo"
End Function
Public Function LastName() As String _
Implements Interfaces.IPerson.LastName
Return "Person"
End Function
End Class
//C# using using using using using using using using
System;
System.Collections.Generic;
System.Text;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter8.Standard.Interfaces;
System.Runtime.Remoting.Messaging;
namespace MSLearning.Chapter8.Standard.Server {
public class Person : MarshalByRefObject, IPerson
{
#region IPerson Members public string FirstName()
{
return "Demo";
}
public string LastName()
{
return "Person";
}
#endregion
}
}
18. Open the StandardClient project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic .NET). Modify the file so that it looks like the following: 'VB Imports System
Imports System.Collections.Generic
Imports System.Text
332
Chapter 8
Method Invocations and Event Management with .NET Remoting
Imports Imports Imports Imports
System.Runtime.Remoting System.Runtime.Remoting.Channels System.Runtime.Remoting.Channels.Tcp MSLearning.Chapter8.Standard.Interfaces
Module Module1 Public Delegate Function GetFirstNameDelegate() As String Public Delegate Function GetLastNameDelegate() As String Private demo_person As IPerson Private firstNameResult As IAsyncResult Private lastNameResult As IAsyncResult Private first_Name As GetFirstNameDelegate Private last_Name As GetLastNameDelegate Function DemoPerson() As IPerson If demo_person Is Nothing Then RemotingConfiguration.Configure( _ "StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _ "tcp://localhost:9000/Person.rem"), IPerson) End If
Return demo_person
End Function
Sub Main() first_Name = New GetFirstNameDelegate( _ AddressOf DemoPerson.FirstName) last_Name = New GetLastNameDelegate(AddressOf DemoPerson.LastName) Dim FirstNameCallback = _ New AsyncCallback(AddressOf FirstNameReturned) Dim LastNameCallback = _ New AsyncCallback(AddressOf LastNameReturned) firstNameResult = first_Name.BeginInvoke( _ FirstNameCallback, first_Name) lastNameResult = last_Name.BeginInvoke(LastNameCallback, last_Name) Console.ReadLine()
End Sub
Sub FirstNameReturned(ByVal result As IAsyncResult) Console.WriteLine("FirstNameCallback value: " & _ first_Name.EndInvoke(result)) End Sub Sub LastNameReturned(ByVal result As IAsyncResult) Console.WriteLine("LastNameCallback value: " & _ last_Name.EndInvoke(result)) End Sub End Module
Lesson 2: Callbacks and Remoting
//C# using using using using using using using
System; System.Collections.Generic; System.Text; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; MSLearning.Chapter8.Standard.Interfaces;
namespace MSLearning.Chapter8.Standard.Client { class Program { delegate String GetFirstNameDelegate();
delegate String GetLastNameDelegate();
private static IPerson demo_person;
static IAsyncResult firstNameResult;
static IAsyncResult lastNameResult;
static GetFirstNameDelegate first_Name;
static GetLastNameDelegate last_Name;
static IPerson DemoPerson() {
if (demo_person == null)
{
RemotingConfiguration.Configure( "StandardClient.exe.config", false); demo_person = (IPerson)Activator.GetObject( typeof(IPerson), @"tcp://localhost:9000/Person.rem"); }
return demo_person;
} static void Main(string[] args) { first_Name = new GetFirstNameDelegate(DemoPerson().FirstName); last_Name = new GetLastNameDelegate(DemoPerson().LastName); AsyncCallback FirstNameCallback = new AsyncCallback(FirstNameReturned); AsyncCallback LastNameCallback = new AsyncCallback(LastNameReturned); firstNameResult = first_Name.BeginInvoke( FirstNameCallback, first_Name); lastNameResult = last_Name.BeginInvoke( LastNameCallback, last_Name); Console.ReadLine();
}
static void FirstNameReturned(IAsyncResult result) {
333
334
Chapter 8
Method Invocations and Event Management with .NET Remoting
Console.WriteLine("FirstNameCallback Value: " + first_Name.EndInvoke(result)); } static void LastNameReturned(IAsyncResult result) { Console.WriteLine("LastNameCallback Value: " + last_Name.EndInvoke(result)); } } }
At this point, the solution tree should resemble Figure 8-3, shown previously. (This figure shows all three projects being created in C#. However, the Visual Basic .NET equivalent should look similar, except it will show the Visual Basic .NET project and source files.) 19. On the Visual Studio Build menu, select Rebuild Solution. 20. Right-click the StandardServer project and select Debug, Start New Instance to start an instance of the StandardServer program. 21. Right-click the StandardClient project and select Debug, Start New Instance to start an instance of the StandardClient program and make a call to the FirstName and LastName methods of the Person class asynchronously. 22. Press Enter in both console windows to exit the StandardClient and StandardServer applications.
Lesson Summary ■
BeginInvoke can be called without any parameter values, but it’s an ill-advised methodology.
■
Polling can be performed by either using an IAsyncResult object and waiting for its IsCompleted property to turn true, or via a callback method that notifies the cli ent when it has completed.
■
AsyncCallback objects can be used to notify the calling code when processing has completed. This negates the need to poll using IsCompleted or similar methodol ogies.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Callbacks and Remoting.” The questions are also available on the companion CD if you prefer to review them in electronic form.
Lesson 2: Callbacks and Remoting
NOTE
335
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which method is an appropriate means to poll for a remote method’s comple tion? (Select the best answer.) A. Use an IAsyncResult object in conjunction with a standard invocation and poll for the IsCompleted property to be true. B. Use an IAsyncResult object in conjunction with an asynchronous invocation and poll for the IsCompleted property to be true. C. Use a callback and wait for its IsCompleted property to turn true. D. Mark the method with a OneWay attribute. 2. Which of the following are benefits of using the OneWay attribute? (Select all that apply.) A. It provides fire and forget functionality. B. Client-side processing can continue irrespective of what happens on the server. C. Client-side processing can continue irrespective of client-side exceptions. D. The server methods can be marked with this attribute without any other changes being made.
336
Chapter 8
Method Invocations and Event Management with .NET Remoting
Lesson 3: Implementing and Responding to Events So far, we’ve focused on how to remote objects and their respective methods across boundaries. One more area needs to be discussed to complete our discussion of remoting: events. Any responsible discussion of remoting and events invariably con tains quite a few cautions. In many cases, the discussion contains a lot more informa tion about avoiding events in remoting scenarios than it does on how to use them. Let’s be clear about this: There are definitely times when using events with remoting is helpful or necessary, but those times are very few and very specific. It’s entirely plausible that a developer could use remoting extensively and never come across a need to handle server-side events. A few cautionary notes about remoting events are provided in the following list: ■
The typical use case for remoting events is in scenarios where different applica tions are running, applications that reference each other and are running on the same machine.
■
Because events are only useful when listeners are wired up to respond to them, scalability is seriously decreased as the number of listeners increases. This limi tation means that an application that performs well with, for instance, 10 clients might come to a crashing halt when 30 clients are added. Due to the number of different variables that can affect this, it’s next to impossible to determine the breaking point in advance. If you know an application will be distributed to mul tiple clients, using events is ill-advised.
■
Listening to events involves a server component being coupled with a client component and vice versa. This arrangement makes the application very suscep tible to failures outside of the application. The only responsible way to address this is through complex and sophisticated exception handling. This exception handling greatly complicates the code and makes maintenance much more dif ficult.
■
Any point on the network might fail (such as the switch, the server, or the net work card); however, the client is not necessarily notified of this failure. If the cli ent application makes infrequent calls to the server this failure can be particularly problematic. The client application might be expecting notifications for events, yet the server is no longer responding. The latency between the server failure and client notification can be very troublesome. There are solutions, such as polling, but these all entail an additional layer of complexity that greatly com plicates the code logic and makes maintenance much more difficult.
Lesson 3: Implementing and Responding to Events
337
■
If the OneWay attribute is used, the client is not notified of any failures on the server. With events, these calls might be frequent and each time an event is raised, the server tries to contact each of the listening machines. If these machines are no longer running, the server tries to contact them nonetheless. These attempts can cause a huge resource leakage.
■
Code Access Security does not work across process boundaries. This limitation raises many security concerns that are often rather difficult to properly address.
After this lesson, you will be able to: ■
Wire a client to listen for remote events.
Estimated lesson time: 45 minutes
Handled Remote Events Throughout the discussion of .NET Remoting, it’s been pointed out that in many ways dealing with remote objects is very similar to dealing with their nonremote counterparts. At the same time, the discussion has highlighted the differences. Event handling in .NET Remoting definitely falls into the same-but-different category. It’s the same as traditional event management in the semantic sense, as far as the code is concerned, and it appears to be done the same way other event management is. But it’s different in the underlying mechanics. Intuitively, if you wanted to add an event handler, you would assume that you could do something like the following: 'VB Module Module1
Public Delegate Function FirstNameDelegate() As String
Public Delegate Function LastNameDelegate() As String
Sub Main() RemotingConfiguration.Configure("StandardClient.exe.config", False) Dim person As IPerson = _ CType(Activator.GetObject(GetType(IPerson), _ "tcp://localhost:9000/Person.rem"), IPerson) AddHandler person.NameChange, AddressOf person_NameChange Console.ReadLine() End Sub Private Sub person_NameChange(ByVal sender As Object, _
ByVal e As NameChangeEventArgs)
Console.Write(e.ToString())
338
Chapter 8
Method Invocations and Event Management with .NET Remoting
End Sub
End Module
//C# class Program {
delegate String GetFirstNameDelegate();
delegate String GetLastNameDelegate();
static void Main(string[] args) { RemotingConfiguration.Configure( "StandardClient.exe.config", false); IPerson person = (IPerson)Activator.GetObject(typeof(IPerson), @"tcp://localhost:9000/Person.rem"); person.NameChange += new NameChangeEvent(person_NameChange); Console.ReadLine(); } private static void person_NameChange(object sender,
NameChangeEventArgs e)
{
Console.WriteLine(e.ToString());
}
}
Essentially you’d expect that you’d just create a handler for the remote object on the client and proceed from there. While this approach seems correct (and will compile without any problems), it won’t work as expected in the 2.0 Framework. The reason is that, in order to handle events on the client, two-way communication needs to occur. When just invoking remote methods, one-way communication is all that’s nec essary (from the server to the client), but in order to process events remotely, two-way communication must occur. Hence, a MarshalByRef object must be shared between the client and the server. Once this is done, however, event processing is handled exactly how it would otherwise. In short, to consume events in a remoting scenario, the following steps need to be performed: 1. Create a server project to host the remote object. 2. Create a client project to consume the object. 3. Create a shared assembly referenced in both the client and the server. 4. Define an event in the class created in the shared assembly. 5. Wire up a handler on the client to handle the event. If the point wasn’t made clearly at the beginning of this lesson, consuming events in a Remoting scenario carries many potential complications and should be approached
Lesson 3: Implementing and Responding to Events
339
with a fair degree of caution. While there’s nothing necessarily wrong with doing so, and there are times where it may be warranted, caution should be used before one implements remote events.
Lab 3: Handle Events from a Remote Object In this lab, you create a remotable object and respond to events it raises. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005 and create a blank solution. 2. Add a new C# or Visual Basic .NET console application named StandardClient. 3. In Solution Explorer, right-click the project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8.Standard.Client. 4. On the File menu, select Add, New Project. Click the Class Library template, enter the name Shared, and click OK. 5. In Solution Explorer, right-click the Shared project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8.Standard .Shared. 6. Add another C# or Visual Basic .NET console application to the solution and name it StandardServer. 7. In Solution Explorer, right-click the StandardServer project’s Properties folder and select Open. In the Default Namespace text box, type MSLearning.Chapter8 .Standard.Server. 8. Right-click the StandardClient project’s References folder and select Add Refer ence. In the Add Reference dialog box, click the Projects tab, select the Shared project, and click OK. Repeat this process to add a reference to the Shared project and to the StandardServer project. 9. Right-click each project, select Add Reference, and add a reference to System .Runtime.Remoting. 10. Right-click the StandardClient project and click Add, New Item. Click Applica tion Configuration File and click Add. 11. Edit the App.config application configuration file to look like the following:
340
Chapter 8
Method Invocations and Event Management with .NET Remoting
12. Right-click the StandardServer project and select Add, New Item. Click Applica tion Configuration File, and click Add. 13. Edit the App.config application configuration file to look like the following:
Lesson 3: Implementing and Responding to Events
341
14. Open the StandardServer project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic). Modify the file so that it looks like the following: 'VB Imports Imports Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
Module Module1 Sub Main() RemotingConfiguration.Configure("StandardServer.exe.config", False) Console.WriteLine("Press return to exit...") Console.ReadLine() End Sub
End Module
//C# using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MSLearning.Chapter8.Standard.Shared;
namespace MSLearning.Chapter8.Standard.Server
{
class Program {
static void Main(string[] args)
{
RemotingConfiguration.Configure("StandardServer.exe.config", false); Console.WriteLine("Press return to exit...\n"); Console.ReadLine(); }
}
}
15. Right-click the StandardServer project, and click Add, Class. Name the class Person and click Add. Edit the Person class so that it looks like the following: 'VB Imports Imports Imports Imports
MSLearning.Chapter8.Standard.Shared
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
342
Chapter 8
Method Invocations and Event Management with .NET Remoting
Imports System.Runtime.Remoting.Messaging
Public Class Person
Inherits MarshalByRefObject
Public Function FirstName(ByVal first_Name) As String Return first_Name End Function Public Function LastName(ByVal last_Name) As String Return last_Name End Function Public Event NameChangeEvent As EventHandler Private _shared As SharedClass = Nothing Public Overrides Function InitializeLifetimeService() As Object Return Nothing End Function Public Sub New() RemotingConfiguration.Configure("StandardClient.exe.config", False) _shared = New SharedClass AddHandler _shared.NameChangeEvent, AddressOf HandlesMyEvent End Sub Public Sub HandlesMyEvent(ByVal sender As Object, ByVal e As EventArgs) Console.WriteLine(String.Format("Event raised by {0}", sender.ToString())) End Sub End Class _ Public Delegate Sub NameChangeEvent(ByVal sender As Object, ByVal e As EventArgs) Public Class SharedClass Inherits MarshalByRefObject Public Event NameChangeEvent As EventHandler Public Sub RaiseThisEvent() RaiseEvent NameChangeEvent(Me, EventArgs.Empty) End Sub Public Overrides Function InitializeLifetimeService() As Object Return Nothing End Function End Class
//C# using using using using using
System;
System.Collections.Generic;
System.Text;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
Lesson 3: Implementing and Responding to Events
using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Messaging; namespace MSLearning.Chapter8.Standard.Shared { [Serializable]
public delegate void NameChangeEvent(object sender, EventArgs e);
public class Shared : MarshalByRefObject
{
public event EventHandler NameChangeEvent;
public void RaiseEvent()
{
NameChangeEvent(this, EventArgs.Empty);
}
public override object InitializeLifetimeService()
{
return null;
}
}
[Serializable]
public class Person : MarshalByRefObject
{
private Shared shared = null; public override object InitializeLifetimeService()
{
return null;
}
public Person() {
RemotingConfiguration.Configure("StandardClient.exe.config", false);
shared = new Shared();
shared.NameChangeEvent += new EventHandler(HandlesMyEvent);
} public string FirstName(String firstName) {
HandlesMyEvent(this, null);
return firstName;
} public string LastName(String lastName)
{HandlesMyEvent(this, null);
return lastName;
}
343
344
Chapter 8
Method Invocations and Event Management with .NET Remoting
public void HandlesMyEvent(object sender, EventArgs e) { Console.WriteLine(string.Format("Event raised by {0}", sender.ToString())); } public event NameChangeEvent NameChange; }
}
16. Open the StandardClient project’s Program.cs file (if you’re using C#) or the Module1.vb file (if you’re using Visual Basic .NET). Modify the file so that it looks like the following: 'VB Imports Imports Imports Imports
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Tcp
MSLearning.Chapter8.Standard.Shared
Module Module1 Sub Main() Dim Demoperson As New Person AddHandler Demoperson.NameChangeEvent, AddressOf person_NameChange 'Acknowledge that the event was successfully registered Console.WriteLine("Successfully registered Name Change Event") Demoperson.LastName("Demo Person") 'Force the event to fire Console.ReadLine() End Sub Private Sub person_NameChange(ByVal sender As Object, ByVal e As EventArgs) Console.Write(e.ToString()) End Sub End Module //C# using using using using using using using
System;
System.Collections.Generic;
System.Text;
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Tcp;
MSLearning.Chapter8.Standard.Shared ;
namespace MSLearning.Chapter8.Standard.Client {
class Program
{
Lesson 3: Implementing and Responding to Events
345
static void Main(string[] args) { Person person = new Person(); person.NameChange += new NameChangeEvent(person_NameChange); //Acknowledge that the event was successfully registered Console.WriteLine("Successfully registered Name Change Event"); person.LastName("Demo Person"); //Force the event to fire Console.ReadLine(); } private static void person_NameChange(object sender, EventArgs { Console.WriteLine(e.ToString()); }
e)
} }
17. On the Visual Studio menu, select Rebuild Solution. 18. Right-click the StandardServer project and select Debug, Start New Instance to start an instance of the StandardServer program. 19. Right-click the StandardClient project and select Debug, Start New Instance to start an instance of the StandardClient program to set the LastName value of the person object and confirm that the event was registered and that it has being handled. 20. Press Enter twice in both console windows to exit the StandardClient and Stan dardServer applications.
Lesson Summary ■
When events are used, the client adds a listener to respond to the event. In this case, the client functions as a server as well as a client, because messages are sent to the client and acknowledgments are sent back.
■
Event management in remoting scenarios is very involved and should be approached with caution.
■
Any EventArgs that are created that will be consumed by both the client and the server must be decorated with the Serializable attribute.
Lesson Review You can use the following question to test your knowledge of the information in Les son 3, “Implementing and Responding to Events.” The questions are also available on the companion CD if you prefer to review them in electronic form.
346
Chapter 8
NOTE
Method Invocations and Event Management with .NET Remoting
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which is true of consuming events in remoting? (Select all that apply.) A. If the OneWay attribute is used with an event, the server continually sends notifications to clients that no longer exist. B. The EventArgs class must be marked as Serializable. C. Scalability might be severely limited. D. Events are best used in cases where different processes are running on the same machine.
Chapter 8 Review
347
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Remoting methods can be invoked synchronously like traditional methods or asynchronously.
■
The OneWay attribute allows methods to be called and to continue processing regardless of any exceptions that might occur on the server. Processing contin ues without interruption, even if the server is not available.
■
Care should be taken when using the OneWay attribute because it can lead to resource leaks.
■
A delegate that matches the method’s signature can be used to invoke a method asynchronously.
■
The IsCompleted method of a delegate can be used to determine when processing has completed.
■
The EndInvoke method of a delegate should be used whenever a return value from a remote method (that was invoked asynchronously) is needed.
■
AsyncCallback objects can be used by a called method to notify the caller when processing is completed.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
asynchronous
■
callback
Chapter 8 Review
■
fire and forget
■
one-way
■
remote method
■
synchronous
348
Case Scenarios In the following case scenario, you apply what you’ve learned about how to use Web methods and Web services. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Building Robust, Scalable Enterprise Applications In the following case scenario, you are the lead developer at a fast-growing company and you must apply what you’ve learned to move from your existing client/server application architecture to a robust, scalable enterprise application architecture.
Interviews Following is a list of company personnel interviewed and their statements: “Our company has grown substantially in a short amount of time. We are no longer able to use a simple client/server model and are look ing to expand our options. Whatever we implement, I want a centralized appli cation server from which to run our applications. We will need at least three tiers: the client tier, the application logic tier, and the data tier. We need every lit tle piece of performance we can squeeze out.”
■ IT Department Head
“We are in a situation where changes have to be made to configurations frequently. If a database goes down, we need to be able to change the database. If an application server goes down, we need to be able to change the application server the clients are using. This change needs to happen fast, without our developers having to recompile the application and redistribute it. This might be one of the biggest problems I know of.”
■ Lead Business Analyst
“Every minute of downtime costs us a fortune. And now, we have a ton of it. When we switch out an application server, our clients are down for 30 min utes. The support calls flood us. We have employees leaving for breaks who don’t know when to come back because they don’t know when things will be back up. When things go down in the middle of the night, it takes hours before we get them back up. This situation needs to be fixed as soon as possible.”
■ CIO
Chapter 8 Review
349
Questions Answer the following questions for your manager: 1. How can the application logic be centralized? 2. How can changes be made to instruct the client to use a different server with a minimum of effort? 3. How can these procedures be implemented while maximizing performance so that total downtime is limited?
Suggested Practices To successfully master the objectives covered in this chapter, complete at least Prac tices 1 and 2. Create a class that implements MarshalByRefObject. Add whatever members you think would make the class useful, then invoke those members remotely.
■ Practice 1
Use the application created in the previous practice and invoke the same methods asynchronously. Now do the same using a callback object.
■ Practice 2
Add the OneWay attribute to one of the remoting methods you cre ated in Practice 1. Modify the method so that it intentionally throws an excep tion. Call the remoting method from the console application and ensure that no exception is thrown back to the client.
■ Practice 3
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications Although Extensible Markup Language (XML) Web services have been available for a few years, they are still relatively new when compared with other mechanisms for implementing distributed applications. One of the key reasons for the high degree of adoption that XML Web services have received is their use of XML and Simple Object Access Protocol (SOAP). As with any new technology, the business community has put quite a bit of effort into standardization and, although a lot of progress has been made in this respect, no definitive standard has been adopted. The standards that do exist are still evolving. Collectively, they are referred to as WS-*. Microsoft has pub lished a list of the standards it has implemented, which is available at http:// msdn.microsoft.com/webservices/webservices/understanding/specs/default.aspx. For a generic overview of these specifications as they evolve, Wikipedia has an entry avail able at http://en.wikipedia.org/wiki/List_of_Web_service_specifications. Web Services Enhancements 3.0 (WSE 3.0) is a composite of many existing standards and, as the name implies, provides enhanced functionality to XML Web services. Ben efits of WSE 3.0 include the following: ■
Simplified message security from endpoint to endpoint
■
Content-based routing
■
Highly customizable and configurable security
■
Performance benefits
Exam objectives in this chapter: ■
Enable WSE in client and server applications. ❑
Add references to WSE assemblies in client applications.
❑
Add a element under the element in a configuration file.
❑
Add a element and a section to a configuration file. 351
352
Chapter 9
■
Web Services Enhancements 3.0 in Client and Server Applications
Add a digital signature to a SOAP message and verify an existing SOAP message signature. ❑
Digitally sign a SOAP message.
❑
Verify a signed SOAP message.
Lessons in this chapter: ■
Lesson 1: Enabling and Referencing WSE 3.0. . . . . . . . . . . . . . . . . . . . . . . . . . 354
■
Lesson 2: Using soapExtensionTypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
■
Lesson 3: Using Digital Signatures to Ensure Message Integrity . . . . . . . . . . 379
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Web Services Enhancements 3.0 installed before completing the examples in this chapter.
NOTE
Web Services Enhancements 3.0
The current version of WSE is 3.0. As of the time of writing, WSE 3.0 can be downloaded at http://www.microsoft.com/downloads/details.aspx?familyid=018a09fd-3a74-43c5-8ec1 8d789091255d&displaylang=en#Overview. The WSE developer’s center at MSDN can be found at http://msdn.microsoft.com/webservices/webservices/building/wse/default.aspx.
To complete the lessons in this chapter, you should be familiar with Visual Basic .NET or C# and be comfortable with the following tasks: ■
Creating a console application in Visual Studio 2005 using Visual Basic .NET or C#.
■
Creating and consuming a Web service using Visual Basic .NET or C#.
■
Adding both library references and Web references to a project.
■
Manipulating XML and SOAP documents.
Before You Begin
353
Real World William Ryan Web Services Enhancements can be described as an early adopter technology for many reasons. Web service adoption, although increasingly popular, is still in its early childhood. Although Web services have helped bridge many problems related to getting disparate systems to communicate with each other, features that simplify adoption invariably pose limitations on use. I worked at a company that jumped on the .NET bandwagon early on. We had a lot to get done and a really short deadline. Because we were still in the process of learning the .NET Framework when we started our first production application, we were still accustomed to doing things in a very traditional (non-.NET) manner. Eight months and 120,000 lines of code later, we launched our first large appli cation. The application worked well but we decided to do a postmortem analysis so we could document what we would have done differently with the better understanding of .NET we had gained. There was a good bit of disagreement on the specifics, but one thing everyone agreed on was that we would have changed the architecture from a two-tier, client/server application to one that used distrib uted technologies. Little by little, we started changing our components to a more service-oriented architecture approach and used remoting and Web services extensively. It wasn’t long before we were pushing the limits of what Web ser vices provided out of the box, and we moved on to Web Services Enhancements to help with performance and security. Just about the time we got everything refined using WSE 2.0, WSE 3.0 was released. Many of the features that we took advantage of in previous versions of WSE, such as Direct Internet Message Encapsulation (DIME) attachments and secu rity policy, were altogether changed or greatly enhanced. At each point, the learn ing curve got smaller and smaller, development times got shorter and shorter, and our application became faster and more secure. In terms of security and per formance, the benefits we’ve realized from the switch from WSE 2.0 to WSE 3.0 are as large as the benefits we realized when we switched to WSE in the first place. With the switch to WSE 3.0, however, we’ve released our application before a technology was released that replaced it! (In the not too distant future, Windows Communication Foundation will be released, which will ultimately replace WSE. This time, though, we’re far ahead of the curve.)
354
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Lesson 1: Enabling and Referencing WSE 3.0 WSE 3.0 is the latest version of Web Services Enhancements that Microsoft has released; however, there are objectives on the exam that cover both WSE 2.0 and WSE 3.0. The preponderance of material, however, covers WSE 3.0. As a starting point, WSE 3.0 supports the following WS-* specifications: ■
XML, SOAP, WSDL
■
WS-Security
■
WS-Trust
■
WS-SecureConversation
■
WS-Addressing
■
Message Transmission Optimization Mechanism (MTOM)
NOTE
MTOM vs. DIME
Although there are many noteworthy features in WSE 3.0, one of the most profound changes was the replacement of DIME with MTOM. The primary purpose of both of these technologies is to enable a secure and efficient mechanism for sending attachments (such as an Excel file or Word document) along with the original message.
Much of the focus of WSE 3.0 has been on security and, as you’ll see shortly, there are many powerful features now available. Furthermore, it is rumored that Web Services, Web Services Enhancements, and Remoting are going to be consolidated in the Windows Communication Foundation (WCF). MORE INFO
WCF in the .NET Framework
At the time of writing, WCF is still in beta and, as such, is subject to change between now and its release. Therefore, it will not be discussed in any substantive manner in this book. However, WCF will be an integral part of the .NET Framework, and it is probably beneficial to be familiar with it. For more information, please visit the Windows Communication Foundation site on MSDN, avail able at http://msdn.microsoft.com/winfx/technologies/communication/default.aspx.
Fortunately, one of the other major design goals of WSE 3.0 was for an easy transition from WSE 3.0 to WCF. NOTE
Why standards matter
At first glance, many people question why there is such an apparent industry obsession with stan dardization. WSE 3.0 is an implementation of several standards, so it’s helpful to understand why
Lesson 1: Enabling and Referencing WSE 3.0
355
these standards matter. If you were asked how to implement an XML document that contained a customer name, it’s doubtful you would think much about it. Perhaps you’d create an element for FirstName, one for LastName, and one for MiddleName. But would this strategy work in all scenar ios? Well, no. Many people have a need to record prefixes (Dr., Mr., Mrs., and so on) and suffixes (PhD, II, and so on). But even if you were sure of all the fields that needed to be captured, would this be an easy process to get right in every case? Again, the answer is no. You could create a Per son element and contain each field in an attribute. You could create a separate element for each. You could make Prefix an attribute of FirstName and suffix an attribute of LastName. Each field adds to the number of permutations. The ultimate point is that, without standards, something as simple as capturing a person’s name can be very complicated. Many of these standards are discussed throughout this chapter.
Although Web Services Enhancements are very powerful and flexible, setting them up and using the basic features is actually quite simple. Like any technology, gaining an in-depth understanding of how the enhancements work and how to use them is not a trivial endeavor, but an average developer can get up and running with them after only a couple hours of studying time. The reason is because, as powerful as they are, there is a very comprehensive wrapper for the application programming interface (API). The interaction with Visual Studio 2005 is also entirely consistent with other programming tasks that you are probably already familiar with, so you can use your existing knowledge as a basis for learning WSE. You might remember that, in Chapter 7, “Method Invocations and Event Management with .NET Web Services,” and Chapter 8, “Method Invocations and Event Manage ment with .NET Remoting,” it was noted that the programming interface to use Web services and remoting was very straightforward from a developer’s perspective, although what’s happening behind the scenes is anything but trivial. The same is true for WSE. Although the API that a developer works with is simple, there’s a tremen dous amount of work that has to be performed behind the scenes to execute even the simplest of tasks with WSE. After this lesson, you will be able to: ■
Add a project reference to the WSE library.
■
Inherit from WebServicesClientProtocol.
■
Edit the proxy class.
Estimated lesson time: 20 minutes
356
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Adding References to WSE Assemblies in Client Applications Before anything can be done that uses WSE 3.0, the correct version needs to be installed. After the correct version is installed, the following steps are all that’s neces sary to begin using WSE 3.0: CAUTION
Be careful to install and reference the correct WSE version
Currently, WSE is at version 3.0. As such, there are two previous versions that contain vast differ ences from version 3.0. Because the library names are very similar, it’s not hard to confuse them and reference the wrong version in your project. Make sure that you have downloaded the correct version before continuing. Also make sure that you reference the correct library and, if you are going to use any library aliases, make sure they reference WSE 3.0 as well (Microsoft.Web.Services3).
1. Add a reference to the Web Services Enhancements 3.0 library. If they were installed correctly, they will be available in the global assembly cache (GAC). They can also be referenced directly and, with a default installation and config uration, t he librar y should be available at [Drive Letter]:\Prog ram Files\Microsoft WSE\v3.0\Microsoft.Web.Services3.dll. 2. Alias the appropriate namespace. ❑
In Visual Basic .NET, this can be accomplished by typing the following at the top of a class or module: Imports Microsoft.Web.Services3
❑
In C#, this can be accomplished by typing the following at the top of a class: using Microsoft.Web.Services3;
Although aliases aren’t technically necessary to use objects in the Services3 namespace, if an alias isn’t included, each object declaration or reference needs to use fully qualified object names, which makes for much more verbose code declarations. To add a reference to the WSE 3.0 library, follow these steps: 1. Create a new project in either Visual Basic .NET or C#. (You might need to create a solution first depending on what type of project you are creating. If you’re cre ating a Windows Forms or a console application, you need to create a solution and add your project or projects to it. If you’re creating an ASP.NET Web site or a Web service, no solution is necessary.) 2. You should add a reference to the WSE 3.0 library. (Note that the process of add ing the WSE 3.0 reference to an ASP.NET Web service or ASP.NET Web site dif fers slightly from adding the reference to other project types.)
Lesson 1: Enabling and Referencing WSE 3.0
357
A. Right-click the project folder in Solution Explorer and click WSE Settings 3.0, as shown in Figure 9-1.
Figure 9-1
Selecting the WSE Settings 3.0 folder from a project’s Properties menu
B. You should see a dialog box similar to the one shown in Figure 9-2. The General tab contains two check boxes: Enable This Project For Web Ser vices Enhancements and Enable Microsoft Web Services Enhancement Soap Protocol Factory. You should select the first check box and, if your project requires it, the second check box.
Figure 9-2 box
Select the first check box and, if your project requires it, the second check
C. Click OK to add the Microsoft.Web.Services3 reference to your project.
358
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
D. The References folder that is visible in other project types isn’t available in ASP.NET Web site and Web service projects. To verify that the reference has been added correctly, right-click the project and click Properties. Click the References folder, and Microsoft.Web.Services3 should be visible in the right panel as shown in Figure 9-3.
Figure 9-3 Verify that a reference for Microsoft.Web.Services3 was correctly added to the project
Inheriting from the WebServicesClientProtocol Class As the name implies, Web Services Enhancements augment the functionality of stan dard .NET Web services. There are subtle differences in applications that use WSE functionality, but the biggest differences reside in those applications that consume Web services. In Chapter 7, we discussed what happens behind the scenes when you add a Web reference. As a refresher, here’s a summary: ■
Visual Studio 2005 generates a proxy class when you add a Web reference.
■
This proxy class mimics the Web service’s methods verbatim, and the client application actually invokes methods from the proxy.
■
The Web service can change after the proxy class is created, in which case there is a mismatch between the service and the proxy. Visual Studio 2005 provides a mechanism to regenerate the proxy to ensure that the current proxy is up to date.
There are subtle differences between the class generated by Visual Studio 2005 and the actual class, but most of those differences are additional methods to provide asyn chronous invocation support. Most noteworthy about the proxy class, however, is that it inherits from the System.Web.Services.Protocols.SoapHttpClientProtocol class. Just to reinforce the point, the following code excerpts show the outer class definition of the proxy class generated from the StockLookupService created in Chapter 7, with the relevant areas shown in bold:
Lesson 1: Enabling and Referencing WSE 3.0
NOTE
359
For illustration purposes only
The following code is provided only to show the class definition and the inheritance chain. This code, without any additional functionality, does nothing. 'VB _ Partial Public Class StockLookupService Inherits System.Web.Services.Protocols.SoapHttpClientProtocol //C# [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.42")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute( Name="StockLookupServiceSoap", Namespace="http://a-datum.org/")] public partial class StockLookupService : System.Web.Services.Protocols.SoapHttpClientProtocol {}
To use WSE 3.0 features, the inheritance chain needs to be changed. Instead of inherit ing from the System.Web.Services.Protocols.SoapHttpClientProtocol class, the proxy class needs to inherit from the Microsoft.Web.Services3.WebServicesClientProtocol class. So the same Web service definition would now look like the following if it enabled WSE 3.0: 'VB _ Partial Public Class StockLookupService Inherits Microsoft.Web.Services3.WebServicesClientProtocol //C# [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.42")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute( Name="StockLookupServiceSoap", Namespace="http://a-datum.org")] public partial class StockLookupService : Microsoft.Web.Services3.WebServicesClientProtocol {}
360
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Inheriting from this class is the entry point for your client to consume all of the WSE 3.0 functionality. Although the following list is not exhaustive, it shows the main func tional areas that can be accessed via the WebServicesClientProtocol objects: 1. The SoapContext of SOAP requests and SOAP responses from XML Web services can be accessed through WebServicesClientProtocol objects. SOAP requests can be accessed through the RequestSoapContext property of the class, and SOAP responses can be accessed through the ResponseSoapContext property of the class. 2. SOAP headers defined in the WS-Security specification can be accessed through the SoapContext mentioned in item 1. 3. SOAP headers defined in the WS-Addressing specification can be accessed through the SoapContext mentioned in item 1. 4. If a WebServicesClientProtocol object is cast to a SoapHttpClientProtocol object, members of the WebServicesClientProtocol class that don’t exist in the SoapHttpClientProtocol class will be lost. Among these are the RequestSoapContext prop erty and the ResponseSoapContext property.
Editing the Proxy Class Because Visual Studio 2005 generates the proxy class for you, the class needs to be edited to make the proxy inherit from WebServicesClientProtocol. NOTE If you’re using Visual Studio 2005, there’s no need to change the inheritance manually as shown in this section. All you need to do is ensure that the client or consumer is WSE enabled when the reference to the Web service if referenced or updated. Visual Studio 2005 will detect this and automatically create a second proxy class that inherits from WebServicesClientProtocol.
To facilitate the process, the following tasks need to be performed: 1. Create a new project and add a reference to the Microsoft.Web.Services3 library. 2. Add a Web reference to this application pointing to the Web service you want to consume. Visual Studio 2005 automatically generates a proxy class for you. 3. In Solution Explorer, expand the Web Reference folder corresponding to the Web service that was added in the previous step. 4. Click Show All Files. 5. Expand the Reference Map folder to reveal the Reference.cs or Reference.vb class.
Lesson 1: Enabling and Referencing WSE 3.0
361
6. Double-click the Reference.cs or Reference.vb file to open it in the code window. Edit the class definition so that it inherits from WebServicesClientProtocol instead of SoapHttpClientProtocol. An example of the class declaration would look like the following code: 'VB _
Partial Public Class AccountManagerServiceWse Inherits Microsoft.Web.Services3.WebServicesClientProtocol //C# [System.CodeDom.Compiler.GeneratedCodeAttribute( "System.Web.Services", "2.0.50727.42")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute( Name="AccountManagerServiceSoap", Namespace="http://a-datum.org/")]
public partial class AccountManagerServiceWse :
Microsoft.Web.Services3.WebServicesClientProtocol
7. Edit the application’s configuration file with the following modifications that are necessary to use a specific configuration section (if you haven’t added a config uration file, you need to do so first) with the following entries:
At this point, the client is configured to use all of the features of WSE 3.0.
362
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Real World William Ryan A friend of mine is the ultimate early adopter. Not only does he dive into new technologies as soon as they come out, but he quickly ends up pushing the enve lope on whatever he touches. He was using Web Services Enhancements since they first came out and went so far as to even port the technology over to the Compact Framework. One day he created one of the coolest applications I had come across. He used Web Services Enhancements to create a File Transfer Pro tocol (FTP) application that moved programs to and from his Web server. Using WSE, he designed the application so that it could move a newer version of itself to the Web server and then cause the new version to run. Because of this appli cation’s power, it needed to be both efficient and secure—after all, you wouldn’t want to just run any program on your server that could move all of your files and start running applications. Using the security features of Web Services Enhance ments and attaching the actual application as a DIME attachment (replaced with MTOM in the current version of WSE), he created an ultrasecure and efficient application that could seek out its own replacement, transfer the new applica tion, remove the attachments, and then run itself. With WSE, the possibilities are endless!
Lab 1: Adding WSE 3.0 to a Project In t his lab, you create a simple console application t hat references t he Microsoft.Web.Services3 library. 1. Open Visual Studio 2005 and create an empty project. 2. Add a new C# or Visual Basic .NET console application named WSEDemoCS or WSEDemoVB depending on which language you choose to write in. 3. In Solution Explorer, right-click the References folder and click Add Reference. 4. In the Add Reference dialog box, click the .NET tab. 5. Click Microsoft.Web.Services3 and click OK. If each step was performed correctly, the Microsoft.Web.Services3 library should be vis ible under the References folder in Solution Explorer.
Lesson 1: Enabling and Referencing WSE 3.0
363
Lesson Summary ■
Web Services Enhancements augment the default functionality of Web services.
■
Adding a reference to the WSE 3.0 library is performed the same way as adding a reference to other libraries, with the exception of Web applications. The WSE Settings 3.0 menu command is used to reference the WSE 3.0 library in Web applications.
■
The following WS-* standards are supported by WSE 3.0: XML, SOAP, WSDL, WS-Security , WS-Trust, WS-SecureConversation, WS-Addressing, and MTOM.
■
SOAP headers defined in the WS-Security specification can be accessed through the SoapContext.
■
The proxy class of any consumers that use WSE 3.0 needs to inherit from the WebServicesClientProtocol base class instead of the default SoapHttpClientProtocol base class.
■
If a WebServicesClientProtocol object is cast to a SoapHttpClientProtocol object, members of the WebServicesClientProtocol class that don’t exist in the SoapHttpClientProtocol class are lost. Among these are the RequestSoapContext property and the ResponseSoapContext property.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Enabling and Referencing WSE 3.0.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which methods are valid for enabling Web Services Enhancements 3.0? (Select all that apply.) A. Use the Add Reference feature of Visual Studio 2005 to select the Microsoft .Web.Services3 library. B. Directly reference the C:\Program Files\Microsoft WSE\v3.0\Microsoft.Web .Services3.dll file. C. In the project, select the WSE 3.0 Settings menu command.
364
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
D. Add a reference to the Web service. If WSE is enabled, the reference is auto matically created through the proxy. 2. Which is true about using the WebServiceClientProtocol class? (Select the best answer.) A. All Web services (classes corresponding to the .asmx file) that will be con sumed by clients using WSE 3.0 must inherit from WebServiceClientProtocol. B. All classes that are consuming or being consumed in a project using WSE 3.0 must inherit from the WebServiceClientProtocol class. C. Any client class that is to consume a Web service and needs to use WSE 3.0 functionality must inherit from the WebServiceClientProtocol class. D. It can be used interchangeably with SoapHttpClientProtocol. 3. What happens if a WebServicesClientProtocol object is cast to a SoapHttpClientProtocol object? (Select the best answer.) A. An invalid cast exception is thrown. B. No exception is thrown. However, the casted object is null. The behavior is identical to that of the as keyword in C# in the context of casts, and when one type can’t be cast to another, null is returned as opposed to throwing an exception. C. No exceptions are thrown. However, any properties of the WebServicesClientProtocol class that aren’t present in the SoapHttpClientProtocol class evaluate to null in C# or Nothing in Visual Basic .NET. D. They both implement the IClientProtocol interface and, as such, can be cast from one to the other. If a property exists in one that is nonexistent in the other, then everything else converts except for such properties.
Lesson 2: Using soapExtensionTypes
365
Lesson 2: Using soapExtensionTypes In the previous lesson, we were introduced to the basics of adding references to the WSE 3.0 library. The information contained in Lesson 1 provided the infrastructure needed for a developer to consume a Web service and use WSE features such as RequestSoapContext and ResponseSoapContext. In the introduction, some uses for WSE were mentioned, in particular, enhanced security and messaging. Customization of these features is one of the biggest benefits to using WSE 3.0, and customization is handled via SoapExtensions. Like many areas of the .NET Framework, SoapExtensions can be handled through any of the following three methods: Code can be written to specifically build features that expand on WSE 3.0 features.
■ Imperatively
Attributes can be used to build in aspect-oriented features that expand on WSE 3.0 features.
■ Declaratively
To make an application as flexible as possible, configuration files can be used to inform the application that it should use a certain feature (or features).
■ Configuration
After this lesson, you will be able to: ■
Add a child element using the element.
■
Specify a type.
■
Specify a priority.
■
Specify a group.
Estimated lesson time: 50 minutes
When the .NET Framework was released, it introduced the System.Configuration namespace and all the functionality that comes with it. Many developers were accus tomed to handling configuration their way, and there was a good bit of debate about whether or not to use the .NET Configuration Framework and to what extent it should be used. There are probably still some people that argue about this topic, but on the whole, the jury has returned and the verdict has been unanimous: Using the .NET con figuration mechanism is the best way to handle background information that is unknown at development time or subject to change during the application’s lifetime. Although using configuration files can be very helpful across the board in .NET Frame work development, their usefulness is nothing short of astonishing in areas such as .NET remoting, Web services, logging, diagnostics, and Web Services Enhancements. The only downside to using configuration files (and I’m hesitant to call it a downside) is that editing configuration files can be a little confusing and error-prone to the uninitiated.
366
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
However, whatever disadvantage there might be in this respect, the benefits so outnum ber the costs that developers who want to be proficient using WSE 3.0 must familiarize themselves with using configuration files. Before moving into more advanced features of Web Services Enhancements, it’s worth discussing the basic structure of configuration elements related to WSE.
Configuration File Structure Web applications use a file named Web.config to store configuration information, whereas Windows Forms and console applications use a file named App.config. When compiled, Visual Studio renames the App.config file as ApplicationName.exe.config and stores the file in the same directory as the executable file. App.config and Web.config are essentially the same, and with respect to WSE 3.0, all relevant information is identical. NOTE
Differences between App.config and Web.config files
There are some differences in the default layout of a Web.config file as opposed to an App.config file, largely because certain values are not necessary in Windows Forms and console applications that are necessary in Web applications. For instance, having a default error page to which the application navigates doesn’t make much sense in a Windows Forms or a console application, whereas it makes perfect sense in a Web application. All of the differences between a default App.config file and a default Web.config file are attributable to differences in how the applications interact with the environment. None of these differences need to be understood to understand how to configure an application consuming WSE 3.0.
The best way to discuss the structure of a configuration file and how it relates to WSE 3.0 is to show a sample configuration file and discuss each portion of it from there. The basic hierarchy for configuration elements is shown in Figure 9-4.
Figure 9-4
Hierarchy of configuration elements in a *.config file
Lesson 2: Using soapExtensionTypes
367
At the top of the hierarchy is the element. This is the outermost container element that contains all other elements and attributes that the application will use. Underneath it is the element that contains all values related to the Sys tem.Web namespace. Within the element is the element that contains all values related to Web services configuration. Elements related to Web ser vices, such as , , and , are contained within the element. Each of these elements can have a different structure (different elements or attributes) and some might contain multiple values. This structure depends on the specific item being configured. Examine the following configuration file (this is the actual configuration file used in the WSClientProtocol Web service created in Lesson 1). Sections not directly related to WSE 3.0 were removed to avoid confusion:
Within the element of the configuration file, an entry was added (in bold) for the Microsoft.Web.Services3 namespace. The library type, version, default cul ture, and public key token were added so that the library can be accurately identified. This information is critical because if multiple versions of this library were loaded on the machine, an entry could be added for each version and this structure would allow side-by-side execution. The element is self-contained and can be used for any custom sec tions that are implemented (the section was removed for simplicity). The entry serves as a declaration for the namespace and as such, a matching entry needs to be entered that matches the specified section name attribute. After this information is in place, everything related to the Microsoft.Web.Services3 namespace should be included in the section.
368
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
CAUTION
can only be safely used in Internet Information Services
(IIS) To use the element in a Web service, the service itself must be hosted in Microsoft Internet Information Services. The behavior of this feature might differ on other Web servers.
At the beginning of this lesson, I mentioned that most of the power of WSE 3.0 lies within using SoapExtensions and soapExtensionTypes in particular. After they are cre ated in your code, they are referenced within the section of the config uration file. The following format is used to add soapExtensionTypes to your application:
Table 9-1 shows each of the relevant attributes coupled with their usage. Table 9-1
Attribute Usage
Attribute
Usage
type
The fully qualified object name of the soapExtensionTypes that will be used followed by a comma and a space, followed by the assem bly name. If a space is present after the assembly name, the space is assumed to be part of the name and results in an error. There can be a space after the comma separating the object name and the assem bly but not one after the names.
priority
The priority of the extension within a group; 1 is the highest prior ity an extension can have. The lower the priority number, the higher the priority. Because priority has an inverse correlation to the number it’s assigned, it’s a common mistake to assume larger numbers have higher priorities.
group
The group extension is a member of a priority. There are two possi ble values: 0 and 1. As with priority, lower numbers have higher importance. Hence, an assignment of 0 gives a group the highest priority, and an assignment of 1 gives a group the lowest priority.
Lesson 2: Using soapExtensionTypes
369
There are three actions that can be taken when using the ele ment, represented by three child elements. The three child elements are explained in Table 9-2. Table 9-2
Child Elements
Attribute
Usage
add
Adds a soapExtension to a Web service’s list of supported extensions.
clear
Removes all supported extensions.
remove
Removes an individual extension from the list of supported extensions.
Adding a Child Element with the Element As was touched on briefly earlier, to add an element, the subtag should be used within the element of the configuration file. In the following example, a library named MSPress.DemoExtension in the MSPressExtensions assembly is added to the application (to focus only on the item at hand, the priority and group subtags are ignored and the relevant code is shown in bold):
Specifying a Priority To specify a priority, simply specify a value for the priority attribute. The main thing to keep in mind is that the lower the numeric value, the higher the priority. The group subtag is intentionally left out of this example:
Specifying a Group To specify a group, simply specify a value for the group attribute. The main thing to keep in mind is that the lower the numeric value, the higher the priority of the group:
370
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Lab 2: Creating a Class That Inherits from WebServicesClientProtocol In this lab, you create a Web service and a client consumer that use WSE 3.0. The cli ent application employs the use of a class that inherits from WebServicesClientProtocol. �
Exercise 1: Creating AuthorService Web Service
In this exercise, you create a very simple Web service that returns information about an author (return values from the Web service are hard-coded for the sake of simplic ity, but nothing would differ on the client side if this was a “hot” Web service). 1. Open Visual Studio 2005 and create an empty solution named WebServicesEnhancementsLab. 2. Right-click the solution file and select Add New, Web Site and click the ASP.NET Web Service template. 3. In the Location drop-down list box, click File System. 4. In the Language drop-down list box, click either Visual C# or Visual Basic depending on your language preference. 5. Enter WebDemo.cs or WebDemo.vb as the project name and click OK. 6. In Solution Explorer, right-click the project folder and click WSE Settings 3.0. 7. Click the General tab, select Enable This Project For Web Services Enhance ments and then click OK. 8. Right-click the solution folder and click Add, New Project. 9. Click your language of choice in the Project Types drop-down list box. 10. Click the Class Library template and in the Name text box, type WSEBusinessObjects and click OK. 11. Right-click the new WSEBusinessObjects project folder and click Properties. 12. In the Default Namespace text box, type MSPress.Chapter9.Lesson2.Lab. Close this window after setting the default namespace. 13. Right-click the new WSEBusinessObjects project folder and click WSE Settings 3.0. 14. Click the General tab and select Enable This Project For Web Services Enhance ments, then click OK. 15. Right-click the Class1.cs or Class1.vb file and click Rename. Change the class name to Authors.cs or Authors.vb. 16. Modify the class definition of the Authors class to look like the following:
Lesson 2: Using soapExtensionTypes
'VB Imports Imports Imports Imports
371
System
System.Collections.Generic
System.Text
System.Xml.Serialization
_ Public Class Author
Public FirstName As String
Public LastName As String
Public Function FullName() As String
Return String.Format("{0}, {1}", Me.LastName, Me.FirstName)
End Function
Public Public Public Public End Class //C# using using using using
WebSiteUrl As String
BlogUrl As String
BookTitles() As String
MVPAwardee As String
System;
System.Collections.Generic;
System.Text;
System.Xml.Serialization;
namespace MSPress.Chapter9.Lesson2.Lab
{
[XmlRoot(Namespace = "http://www.williamgryan.com/wse/books/529/09/Lab02")]
public class Author
{
public String FirstName;
public String LastName;
public String FullName()
{
return String.Format("{0}, {1}", this.LastName, this.FirstName);
}
public String WebSiteUrl;
public String BlogUrl;
public String[] BookTitles;
public Boolean MVPAwardee;
}
}
17. Right-click the Service.cs or Service.vb file in the Web Services project and rename it as AuthorService.cs or AuthorService.vb. Open the file and modify the class definition to look like the following:
372
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
'VB Imports System.Web Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.Xml.Serialization Imports MSPress.Chapter9.Lesson2.Lab _ _ _ Public Class AuthorService Inherits System.Web.Services.WebService _ Public Function HelloWorld() As Author Dim SomeAuthor As New Author() SomeAuthor.FirstName = "William" SomeAuthor.LastName = "Ryan" SomeAuthor.MVPAwardee = True SomeAuthor.WebSiteUrl = "http://www.williamgryan.com" SomeAuthor.BlogUrl = "http://www.msmvps.com/WilliamRyan" SomeAuthor.BookTitles = New String() { "Professional ADO.NET 2.0", _
"Professional WinFX", _
"Advanced Microsoft Speech Server Development", _
"MCTS Self-Paced Training Kit (Exam 70-536)"}
Return SomeAuthor End Function End Class //C# using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
using MSPress.Chapter9.Lesson2.Lab;
[WebService(Namespace =
"http://www.williamgryan.com/wse/books/529/09/Lab02")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class AuthorService : System.Web.Services.WebService { public AuthorService () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod]
[SoapDocumentMethod(ResponseElementName = "Authors")]
[return: XmlElement("Authors")]
public Author GetAuthorInformation() {
Lesson 2: Using soapExtensionTypes
373
Author SomeAuthor = new Author();
SomeAuthor.FirstName = "William";
SomeAuthor.LastName = "Ryan";
SomeAuthor.MVPAwardee = true;
SomeAuthor.WebSiteUrl = "http://www.williamgryan.com";
SomeAuthor.BlogUrl = "http://www.msmvps.com/WilliamRyan";
SomeAuthor.BookTitles = new String[] {
"Professional ADO.NET 2.0",
"Professional WinFX",
"Advanced Microsoft Speech Server Development",
"MCTS Self-Paced Training Kit (Exam 70-536)"};
return SomeAuthor; }
}
18. Right-click the Web Services project folder and click Add Reference. In the Add Reference dialog box, click the Projects tab, click the WSEBusinessObjects project, and then click OK. 19. In the Web Service project, right-click the Service.asmx file and rename it AuthorService.asmx. 20. Open the AuthorService.asmx file and modify it to look like the following: 'VB
//C#
21. Click Build, Rebuild Web Site. 22. Right-click the Web service project and click Set As StartUp Project. 23. Right-click the AuthorService.asmx file and click Set As Start Page. 24. Run the application. The test page for the Web service should show if everything works correctly and should look like Figures 9-5 and 9-6.
374
Chapter 9
�
Web Services Enhancements 3.0 in Client and Server Applications
Figure 9-5
AuthorService Method tester
Figure 9-6
Output from GetAuthorInformation Web service
Exercise 2: Creating a Project Referencing WSE 3.0
In this exercise, you create a simple console application that references the Microsoft .Web.Services3 library. The primary class in this application inherits from the WebSer vicesClientProtocol class.
Lesson 2: Using soapExtensionTypes
375
1. Open Visual Studio 2005 and create an empty project. 2. Add a new C# or Visual Basic .NET console application named WSEDemoCS or WSEDemoVB, depending on which language you choose to write in. 3. In Solution Explorer, right-click the project folder and click Add Reference. 4. In the Add Reference dialog box, click the .NET tab. 5. Click Microsoft.Web.Services3 and click OK. 6. Right-click the project folder and click Add Web Reference. 7. Click Web Services On This Machine and click AuthorService. 8. In the Web Reference Name text box, type localhost and click Add Reference. 9. Click Localhost in the Web References folder and in Solution Explorer, click the Show All Files button. 10. Expand localhost and expand the Reference.map item. 11. Open the Reference.cs or Reference.vb file (this file is the Web service proxy class). 12. Ensure that the proxy class inherits from the WebServicesClientProtocol class. 13. If necessary, modify the class so that the definition looks like this: 'VB Partial Public Class AuthorServiceWse
Inherits Microsoft.Web.Services3.WebServicesClientProtocol
//C# public partial class AuthorServiceWse :
Microsoft.Web.Services3.WebServicesClientProtocol
14. In the WSEDemoVB project, open the Main.cs or Main.vb file and edit the code to look like the following: 'VB Imports Imports Imports Imports Imports
System
System.Collections.Generic
System.Text
Microsoft.Web.Services3
WSEDemoVB.localhost
Module Module1 Sub Main(ByVal args As String()) 'Alias the Microsoft.Web.Services3 and 'WebDemoCS.localhost namespaces Dim DemoService As AuthorService = New AuthorService() Dim DemoAuthor As Author = DemoService.GetAuthorInformation()
376
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
Console.WriteLine("First Name: " + DemoAuthor.FirstName) Console.WriteLine("Last Name: " + DemoAuthor.LastName) Console.WriteLine("Blog URL: " + DemoAuthor.BlogUrl) Console.WriteLine("Web Site URL: " + DemoAuthor.WebSiteUrl) Console.WriteLine("MVP Awardee? " + _ DemoAuthor.MVPAwardee.ToString()) Console.WriteLine("First Name: " + DemoAuthor.FirstName) For Each book As String In DemoAuthor.BookTitles Console.WriteLine("Book Title: " + book)
Next
Console.ReadLine()
End Sub End Module //C# using using using using using
System;
System.Collections.Generic;
System.Text;
Microsoft.Web.Services3;
WebDemoCS.localhost;
namespace WebDemoCS {
class Program
{
static void Main(string[] args) { //Alias the Microsoft.Web.Services3 //and WebDemoCS.localhost namespaces AuthorService DemoService = new AuthorService(); Author DemoAuthor = DemoService.GetAuthorInformation(); Console.WriteLine("First Name: " + DemoAuthor.FirstName); Console.WriteLine("Last Name: " + DemoAuthor.LastName ); Console.WriteLine("Blog URL: " + DemoAuthor.BlogUrl ); Console.WriteLine("Web Site URL: " + DemoAuthor.WebSiteUrl); Console.WriteLine("MVP Awardee? " + DemoAuthor.MVPAwardee.ToString()); Console.WriteLine("First Name: " + DemoAuthor.FirstName); foreach (String book in DemoAuthor.BookTitles) { Console.WriteLine("Book Title: " + book); } Console.ReadLine(); }
}
}
15. Right-click the WebDemoCS or WebDemoVB project and click Set As StartUp Project.
Lesson 2: Using soapExtensionTypes
377
16. Compile and run the application. If it worked correctly, the output should look as shown in Figure 9-7.
Figure 9-7
Output from WebDemoCS or WebDemoVB project
Lesson Summary ■
SoapExtensions can be configured through the element in a configuration file.
■
SoapExtensions can be added, removed, and cleared through configuration file entries.
■
With both the group and priority subtags, lower numeric values indicate higher priority than higher values.
■
Custom configuration sections, such as Microsoft.Web.Services3, can be added through the section of the configuration file.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Using soapExtensionTypes.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
378
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
1. Which soapExtensionTypes tasks can be done with a configuration file? (Select all that apply.) A. soapExtensionTypes can be added to the project. B. soapExtensionTypes can be removed from the project. C. All soapExtensionTypes that have been added can be cleared at once. D. soapExtensionTypes cannot be managed through a configuration file. 2. Which is true with respect to soapExtensionTypes declarations in a configuration file? (Select the best answer.) A. A priority value of 2 takes higher precedence than a priority value of 1. B. A group value of 1 takes higher precedence than a group value of 0. C. A priority value of 1 takes higher precedence than a priority value of 2. D. Numeric values do not control priority in either the priority or the group tags. 3. What modifications are necessary to use a specific configuration section? (Select all that apply.) A. Add an entry to the section of the configuration file. B. The assembly name, the assembly version, and the default culture can all be specified in the custom configuration section. C. An entry matching the name specified in the entry must be included outside of this section. D. An element with the name of the assembly must be included in the config uration file. A configSection attribute should be added to this element.
Lesson 3: Using Digital Signatures to Ensure Message Integrity
379
Lesson 3: Using Digital Signatures to Ensure Message Integrity One of the biggest selling points of Web Services Enhancements and Web Services Enhancements 3.0 in particular is the enhanced security features. Like the early WSE counterparts, WSE 3.0 implements the WS-Security 1.1 specification. MORE INFO
WS-Security in depth
General information about the WS-Security specification can be found at the following Uniform Resource Locator (URL): http://en.wikipedia.org/wiki/WS-Security.
The WS-Security 1.1 specification seeks to address three primary objectives with respect to messages: Ensure that the message was not tampered with during the transmis sion from sender to receiver.
■ Integrity
■ Authentication
Verify the identity of both the sender and receiver of the mes
sage. Obscure the contents of the message so that only authorized parties can read it.
■ Confidentiality
After this lesson, you will be able to: ■
Understand the basics of messaging security concepts.
■
Use security tokens.
Estimated lesson time: 45 minutes
Digital Signature Basics Until recently, written human signatures were the main way in which contractual agreements were executed. By signing a contract, I verify that I read it and that I accept the terms of the contract. If I sign a check, I acknowledge that I in fact want to engage in the transaction and that I thereby authorize it. However, there have always been dis honest people who have been able to benefit by forging signatures. As such, most institutions such as banks have signature cards on file so that they can compare a sig nature they know is authentic with any incoming checks. This system, however, as is the case with all handwriting verifications, involves a human being checking a new signature against a signature card to determine whether the signature is authentic. In
380
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
a bank, most employees are qualified to make this determination for the bank, but in larger transactions or disputes, handwriting experts are brought in to verify signature authenticity. Signature verification is always more art than science and, because the costs of being wrong can be very high, it is potentially problematic. Now that electronic commerce has become commonplace, signature verification is not feasible in many cases. Imagine that you need $20 to eat dinner or to purchase gas oline. If a human was necessary to verify your signature, the bank would be required to be open 24 hours a day to provide this service. Instead, most of us now use auto mated teller machine (ATM) cards. Each card has a personal identification number (PIN) that, if kept private, helps ensure that only the intended user can withdraw money from a given account. An ATM card corresponds to my account specifically. Short of a really sophisticated forgery mechanism, I can only use my ATM card to withdraw money from my account. If someone gets possession of my card but doesn’t have my PIN, he or she won’t be able to withdraw money from my account unless he or she can somehow procure my PIN. Digital signatures work much the same way. When a message is digitally signed, a user name and password are usually required to create the signature. This requirement ensures that senders are who they say they are. The message itself is used to create a hash value that mathematically can correspond only to this particular message (even a small change results in a different hash value) or a very small subset of possible messages. When the message is received, the hash can be verified and if it matches the one generated when the message was signed, it’s safe to assume that the message wasn’t tampered with. Although digital signatures aren’t 100 percent guaranteed to be authentic, the chances of tampering are so small that a digital signature’s security far exceeds the security of traditional methods such as handwriting. For SOAP messages, there are four mechanisms that can be used to digitally sign mes sages: ■
A UserNameToken object containing a user name and password combination.
■
A digital certificate such as X.509.
■
A Kerberos token. Kerberos is powerful but limited in use because it can only be issued and verified on a machine running Microsoft Windows XP Service Pack 1 or later or Microsoft Windows Server 2003.
Lesson 3: Using Digital Signatures to Ensure Message Integrity
381
X.509 Certificates X.509 certificates provide a clean, fairly easy-to-use mechanism for securing messages. A synopsis of how they are employed is provided here: 1. An installed X.509 certificate is used to generate a public and a private key pair. 2. The keys are first used to digitally sign an outgoing SOAP request. 3. On the server, the keys are used to decrypt the message that was encrypted in step 2. The most difficult part of using X.509 certificates is getting them installed on a machine. After they are installed, they can be used in the manner shown here: 'VB Private Sub X509Demo()
Dim DemoService As New ServiceWse()
Dim DemoToken As X509SecurityToken 'Retrieve 509 certificate
'from store
DemoService.RequestSoapContext.Security.Tokens.Add(DemoToken)
End Sub
//C# public static void X509Demo() {
ServiceWse DemoService = new ServiceWse();
X509SecurityToken DemoToken; //Retrieve X509SecurityToken from store
DemoService.RequestSoapContext.Security.Tokens.Add(DemoToken);
}
Kerberos Token Kerberos is a proprietary Microsoft standard that can be quite useful. In the context of WSE 3.0, it’s implemented through the KerberosToken class. The KerberosToken is passed within the SOAP headers, in much the same way the following UserNameToken is passed. After the call to the Web service, the machine is verified against the Ker beros domain and if the machine is authenticated, it can be permissioned to call the methods of the Web service: 'VB Private Sub KerberosDemo() Dim DemoService As New ServiceWse() Dim DNSName As String = System.Net.Dns.GetHostName() Dim kerbToken As New KerberosToken("host/" & DNSName & "@DomainName") Dim RequestContext As SoapContext = DemoService.RequestSoapContext RequestContext.Security.Tokens.Add(kerbToken) RequestContext.Security.Timestamp.TtlInSeconds = 60 RequestContext.Security.Elements.Add(New MessageSignature())
382
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
DemoService.ValidateResult("Bill.Ryan") End Sub //C# public static void KerberosDemo() {
ServiceWse DemoService = new ServiceWse();
String DNSName = System.Net.Dns.GetHostName();
KerberosToken kerbToken = new KerberosToken("host/" +
DNSName + "@DomainName"); SoapContext RequestContext = new DemoService.RequestSoapContext; RequestContext.Security.Tokens.Add(kerbToken); RequestContext.Security.Timestamp.TtlInSeconds = 60; RequestContext.Security.Elements.Add(new MessageSignature()); DemoService.ValidateResult("Bill.Ryan"); }
UserNameToken Probably the simplest mechanism in the security library is creating using the UserNameToken. To use UserNameToken, all that needs to be done is the following: 1. Declare a UserNameToken object. 2. Instantiate the UserNameToken, specifying a user name and a password. 3. Attach the UserNameToken to the RequestSoapContext’s Tokens collection. The following code illustrates the process of using a UserNameToken: 'VB Public Sub UserNameTokenSampe()
Dim DemoService As New ServiceWse()
Dim DemoUserName As String = "BillRyan"
Dim DemoToken As UsernameToken
Dim PasswordArray As Byte() = _
System.Text.Encoding.UTF8.GetBytes(DemoUserName) Array.Reverse(PasswordArray) Dim Base64Equivalent As String = Convert.ToBase64String(PasswordArray) DemoToken = New UsernameToken(DemoUserName, _ Base64Equivalent,PasswordOption.SendHashed)
DemoService.RequestSoapContext.Security.Tokens.Add(DemoToken)
End Sub
//C# public static void UserNameTokenSample() {
ServiceWse DemoService = new ServiceWse();
UsernameToken DemoToken = new UsernameToken();
String DemoUserName = "BillRyan";
Byte[] PasswordArray =
Lesson 3: Using Digital Signatures to Ensure Message Integrity
383
System.Text.Encoding.UTF8.GetBytes(DemoUserName); Array.Reverse(PasswordArray); String Base64Equivalent = Convert.ToBase64String(PasswordArray); DemoToken = new UsernameToken(DemoUserName, Base64Equivalent, PasswordOption.SendHashed); DemoService.RequestSoapContext.Security.Tokens.Add(DemoToken); DemoService.RequestSoapContext.Security.Elements.Add(null); }
Lab 3: Creating a Policy for Digital Signatures �
Exercise 1: Create the Web Service
1. Open Visual Studio 2005 and create an empty solution named DigitalSigPolicyLab. 2. Add a new C# or Visual Basic .NET Web service named SignatureEnabledServiceCS or SignatureEnabledServiceVB depending on which language you choose to write in. 3. In Solution Explorer, right-click the project folder, and click Add Reference. 4. In the Add Reference dialog box, click the .NET tab. 5. Click Microsoft.Web.Services3, and click OK. 6. Right-click the App_Code folder, and click Add New Item. Choose Class, name the class X509ProviderDemo, and click Add. 7. Add the following Imports or using statements near the top of the file: 'VB Imports Imports Imports Imports //C# using using using using
Microsoft.Web.Services3
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
System.Security.Cryptography.X509Certificates
Microsoft.Web.Services3;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
System.Security.Cryptography.X509Certificates;
8. Add the following code to the class signature so the class inherits from SendSecurityFilter. The class definition for each should look like the following: 'VB Public Class X509ProviderDemo
Inherits SendSecurityFilter
//C# class X509ProviderDemo : SendSecurityFilter
384
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
9. Add a constructor that calls the base class’s constructor: 'VB Public Sub New()
MyBase.New("ServiceActor", True)
End Sub
//C# protected X509ProviderDemo(string serviceActor, bool isClient) : base("ServiceActor", true) { }
10. Override the SecureMessage method, and give it the following defintion: 'VB Public Overrides Sub SecureMessage( _ ByVal envelope As Microsoft.Web.Services3.SoapEnvelope, _ ByVal security As Microsoft.Web.Services3.Security.Security) Dim DemoCertificate As New X509Certificate2()
Dim DemoToken As New X509SecurityToken(DemoCertificate)
security.Tokens.Add(DemoToken)
Dim DemoSig As New MessageSignature(DemoToken)
security.Elements.Add(DemoSig)
End Sub //C# public override void SecureMessage(SoapEnvelope envelope, Security security) { X509Certificate2 DemoCertificate = new X509Certificate2(); X509SecurityToken DemoToken = new X509SecurityToken(DemoCertificate); security.Tokens.Add(DemoToken); MessageSignature DemoSig = new MessageSignature(DemoToken); security.Elements.Add(DemoSig); }
11. Compile the application. If done correctly, this should complete the first step necessary to send digitally signed messages. �
Exercise 2: Adding a Custom Policy
In this lab, you will create a custom policy to handle incoming messages that are dig itally singed. 1. Open the solution created in the previous exercise named DigitalSigPolicyLab. 2. Expand the App_Code folder in the Web service and select the Service.cs or Ser vice.vb file, depending on which language you are working in. At the top of the class, ensure that the following namespaces are included (using the using key word in C# or the Imports keyword in Visual Basic): Microsoft.Web.Services3;
System.Security.Principal;
Lesson 3: Using Digital Signatures to Ensure Message Integrity
385
Microsoft.Web.Services3.Design;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
System.Security.Cryptography.X509Certificates;
3. At the class declaration of the service, add the following line of code to specify a pol icy; this code should go under the WebService, WebServiceBinding, and DesignerGenerated attributes. (Only Visual Basic generates the DesignerGenerated attribute, so it is of no concern if you are using C#.) 'VB _ //C# [Policy(typeof(DemoPolicy))]
4. At the end of the class definition for the Web service, create another class that will define the policy. (This class could just as easily be added in a separate file, and there is no problem in doing so. However, for the sake of simplicity, add the class in the same file as the service because the service needs this class to run.) Add the following class definition after the end of the class definition of the ser vice: 'VB Public Class DemoPolicy
Inherits Policy
Public Const CERTIFICATE As String = "CERTIFICATE REFERENCE HERE" Public Sub New()
Dim DemoAssertion As UsernameForCertificateAssertion = _
New UsernameForCertificateAssertion()
DemoAssertion.X509TokenProvider = _ New X509TokenProvider( _ StoreLocation.LocalMachine, _ StoreName.My, _ CERTIFICATE, _ X509FindType.FindBySubjectDistinguishedName) Dim DemoProtection As EndpointProtectionRequirements = _ DemoAssertion.Protection Dim DemoOptions As SignatureOptions = _
SignatureOptions.IncludeAddressing Or _
SignatureOptions.IncludeTimestamp Or _
SignatureOptions.IncludeSoapBody
DemoProtection.Request.SignatureOptions = DemoOptions DemoProtection.Request.EncryptBody = True
386
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
DemoProtection.Response.SignatureOptions = DemoOptions DemoProtection.Response.EncryptBody = True DemoProtection.Fault.SignatureOptions = DemoOptions DemoProtection.Fault.EncryptBody = False DemoAssertion.MessageProtectionOrder = _ MessageProtectionOrder.SignBeforeEncrypt DemoAssertion.RequireDerivedKeys = True Me.Assertions.Add(DemoAssertion) End Sub End Class //C# public class DemoPolicy : Policy { private const String CERTIFICATE = "CERTIFICATE REFERENCE HERE"; public DemoPolicy() { UsernameForCertificateAssertion DemoAssertion = new UsernameForCertificateAssertion(); DemoAssertion.X509TokenProvider = new X509TokenProvider(StoreLocation.LocalMachine, StoreName.My, CERTIFICATE, X509FindType.FindBySubjectDistinguishedName); EndpointProtectionRequirements DemoProtection = DemoAssertion.Protection; DemoProtection.Request.SignatureOptions = SignatureOptions.IncludeAddressing | SignatureOptions.IncludeTimestamp | SignatureOptions.IncludeSoapBody; DemoProtection.Request.EncryptBody = true; DemoProtection.Response.SignatureOptions = SignatureOptions.IncludeAddressing | SignatureOptions.IncludeTimestamp | SignatureOptions.IncludeSoapBody; DemoProtection.Response.EncryptBody = true; DemoAssertion.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; DemoAssertion.RequireDerivedKeys = true; this.Assertions.Add(DemoAssertion); } }
Lesson 3: Using Digital Signatures to Ensure Message Integrity
387
5. To enable a client to use this policy, all that needs to be done is to copy the class definition to a method in the client and specify that the policy be used. If the cli ent had a method named GetPolicy, it would look like the following: 'VB Private Function GetPolicy() As SecureInvoiceServiceWse Public Const CERTIFICATE As String = "CERTIFICATE REFERENCE HERE" Dim DemoAssertion As UsernameForCertificateAssertion = _ New UsernameForCertificateAssertion() DemoAssertion.X509TokenProvider = _ New X509TokenProvider( _ StoreLocation.LocalMachine, _ StoreName.My, _ CERTIFICATE, _ X509FindType.FindBySubjectDistinguishedName) Dim DemoProtection As EndpointProtectionRequirements = _ DemoAssertion.Protection Dim DemoOptions As SignatureOptions = _
SignatureOptions.IncludeAddressing Or _
SignatureOptions.IncludeTimestamp Or _
SignatureOptions.IncludeSoapBody
DemoProtection.Request.SignatureOptions = DemoOptions DemoProtection.Request.EncryptBody = True DemoProtection.Response.SignatureOptions = DemoOptions DemoProtection.Response.EncryptBody = True DemoProtection.Fault.SignatureOptions = DemoOptions DemoProtection.Fault.EncryptBody = False DemoAssertion.MessageProtectionOrder = _
MessageProtectionOrder.SignBeforeEncrypt
DemoAssertion.RequireDerivedKeys = True
Me.Assertions.Add(DemoAssertion) End Function //C# private Policy GetPolicy() {
private String CERTIFICATE = "CERTIFICATE REFERENCE HERE";
UsernameForCertificateAssertion DemoAssertion =
new UsernameForCertificateAssertion();
DemoAssertion.X509TokenProvider =
388
Chapter 9
Web Services Enhancements 3.0 in Client and Server Applications
new X509TokenProvider(StoreLocation.LocalMachine, StoreName.My, CERTIFICATE, X509FindType.FindBySubjectDistinguishedName); EndpointProtectionRequirements DemoProtection = DemoAssertion.Protection; DemoProtection.Request.SignatureOptions =
SignatureOptions.IncludeAddressing |
SignatureOptions.IncludeTimestamp |
SignatureOptions.IncludeSoapBody;
DemoProtection.Request.EncryptBody = true; DemoProtection.Response.SignatureOptions =
SignatureOptions.IncludeAddressing |
SignatureOptions.IncludeTimestamp |
SignatureOptions.IncludeSoapBody;
DemoProtection.Response.EncryptBody = true;
DemoAssertion.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; DemoAssertion.RequireDerivedKeys = true; this.Assertions.Add(DemoAssertion);
}
6. Now before any call to the service, all that needs to be done is setting the policy: 'VB Dim DemoPolicy As Policy = GetPolicy()
proxy.SetPolicy(DemoPolicy)
//C# Policy DemoPolicy = GetPolicy();
proxy.SetPolicy(DemoPolicy);
Lesson Summary ■
Digital signatures can be used to verify a message’s integrity.
■
Authentication deals with verifying the sender and receivers of a message.
■
Confidentiality deals with ensuring that only approved entities can view a mes sage’s content.
■
Integrity deals with ensuring that a message has not been tampered with after it has been transmitted.
■
Tokens that can be attached to a message include X.509, a UserNameToken, Ker beros tokens, and custom binary tokens.
■
Tokens can be added to the Tokens collection of the RequestSoapContext of a WSE-enabled Web service or proxy.
Lesson 3: Using Digital Signatures to Ensure Message Integrity
389
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “Using Digital Signatures to Ensure Message Integrity.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which of the following are objectives of digital signatures? (Select all that apply.) A. Authentication B. Authorization C. Integrity D. Confidentiality 2. What types of tokens can be used with a WSE 3.0 file? (Select all that apply.) A. Kerberos B. X.509 C. UserNameToken objects D. Custom binary
390
Chapter 9 Review
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Web Services Enhancements provide extended functionality for Web services.
■
Web Services Enhancements build on the various WS-* specifications.
■
WSE can be used to provide powerful custom security features.
■
The WebServicesClientProtocol is the base class from which Web service proxies that use WSE functionality inherit.
■
A Web reference is needed to consume a Web service. Each proxy, however, must use the WebServicesClientProtocol instead of the SoapHttpClientProtocol.
■
Configuration files provide a powerful and flexible mechanism for using WSE 3.0.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
authentication
■
digital signature
■
Direct Internet Message Encapsulation (DIME)
■
integrity
■
Kerberos
■
Message Transmission Optimization Mechanism (MTOM)
■
WS-*
Chapter 9 Review
391
Case Scenarios In the following case scenarios, you apply what you’ve learned about how to use Web methods and Web services. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Where Does WSE Fit into My Application Development Strategy? This case scenario describes a typical deployment scenario whenever a company starts using Web services. At first, getting the services to work is first priority. But immediately afterward, issues such as security and performance become critical. This case scenario discusses how to address such concerns.
Interviews Following is a list of company personnel interviewed and their statements: “We are a little late into the game when it comes to Web ser vices. However, we’re trying to get on board as fast as possible. So far, we’ve seen so many protocols that it’s hard to decide what is hype and what is appropriate. The one thing we can definitely tell, though, is that rolling out our own solution doesn’t make much sense.”
■ IT Department Head
“The days of security by obscurity are over. Every client we have asks about our security procedures and they see right through fluff. They ask intelligent questions and demand intelligent answers. We need to have real answers for them. The only way to do this is to have flexible and exhaustive secu rity. Can WSE help here?”
■ Lead Business Analyst
“Taking security seriously is a matter of survival. I know better than anyone that security doesn’t get you any recognition until it’s not there, but I’m willing to do whatever I have to so I can sleep soundly at night knowing my customers’ data is secure. And I can’t listen to anything else about how you have to trade off security for performance. We need both!”
■ CIO
Questions Answer the following questions for your manager. 1. Do Web Service Enchancements fit into our development story? 2. If we use WSE, can we implement advanced security or performance features without taking a year to learn how to do it?
392
Chapter 9 Review
3. Can WSE provide both trusted security mechanisms and customization? Or do they employ a one-size-fits-all approach?
Case Scenario 2: Refining the Process? Assuming some enchancements were made and the process is working well, some consideration needs to be paid to maximizing performance. This scenario deals with how best to address this.
Interviews Following is a list of company personnel interviewed and their statements: “File transfers are killing us. We thought we had everything addressed, but we’re pushing some large multimedia files to the clients and it’s killed our network. Clients are complaining that everything is slow, we’re seeing a lot of network latency, and things just aren’t working as we planned from a per formance perspective.”
■ IT Department Head
“At first it seemed like once we put our business objects on the Web, our problems would all be resolved. Unfortunately, that’s not the case. It fixed many of our existing problems, but now we’ve inadvertently upped the bar for what clients expect, and performance is the key now.”
■ Lead Business Analyst
“Buy faster servers! Buy faster switches! Buy more bandwidth! This is insane. When I said I wanted these problems fixed, I didn’t mean I want them fixed even if it annihilates every bit of cash flow the company has. One of the main reasons we went with Web services is that it was supposed to be efficient, in terms of performance and cost. Yes, the new functionality has done a lot for us, but it’s bankrupting me, and “buy, buy, buy” can’t be the approach for every thing. Is there anything we can do now with the resources we have?”
■ CIO
Questions Answer the following questions for your manager. 1. Without purchasing new hardware or bandwidth, what can be used to enhance the efficiency of the data transfers? 2. Can we use one of the earlier WSE versions, or do we need WSE 3.0? 3. How much rework will any such approach entail?
Chapter 9 Review
393
Suggested Practices To successfully master the objectives covered in this chapter, complete the following tasks. Create a simple Web service and compile it. Pay close attention to the web.config file that’s generated by default. Afterward, use the WseConfigEditor3 to enable WSE and then examine what changes are made.
■ Practice 1
Using the Web service created in Practice 1, create a client application to consume it. Add a Web reference to the service and make note of the defini tion of the proxy class that is generated. Enable WSE 3.0, and refresh the Web reference. Re-examine the proxy class and note as many differences as you can.
■ Practice 2
Create a Web service that uses WSE 3.0. Create a client that con sumes it. Digitally sign a message and verify its authenticity.
■ Practice 3
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 10
WSE Security
As mentioned in the previous chapter, Web Services Enhancements (WSE) provide advanced functionality that is not readily available otherwise. Security is one of the major benefits of using WSE, and, by using it, developers have access to a feature-rich and easy-to-use application programming interface (API) that allows them to imple ment extremely granular security solutions. Additional security, however, isn’t any thing new to WSE 3.0; enhanced security has been a primary feature of WSE since version 1.0. The primary difference between WSE 3.0 and previous versions is that, in previous versions, security was applied to each Simple Object Access Protocol (SOAP) message on an individual basis. Essentially, previous versions addressed security in a message-by-message fashion. Although this system was adequate for most developers’ purposes, the very nature of the implementation made it fairly complex to use. With the advent of WSE 3.0, message-level security can be applied to the actual message exchange mechanism itself. Therefore, WSE 3.0 enables you to apply security at a higher level using a set of security operations, which are known as security assertions. WSE also provides a set of predefined security assertions that are called turnkey secu rity assertions. Security assertions are applied using policies and policy assertions. An easy way to distinguish between these two approaches is a bodyguard metaphor. Assume that your company is charged with providing security for X number of peo ple. Using the security system used by previous versions of WSE, you’d assign a body guard to each person as they went to and from wherever it was they were going. If 50 people were traveling at once, you’d need at least 50 bodyguards. In the current ver sion of WSE, you effectively secure the transport vehicle and the transportation route as well as the origination point and destination, and then let all 50 people move along this channel as they pleased. Instead of trying to secure them individually, you basi cally secure a zone or route for them to travel, and they can rest assured that as long as they are within this zone, they are safe. The metaphor isn’t perfect, but it works to illustrate the conceptual differences between WSE 3.0 and previous versions.
Exam objectives in this chapter: ■
Implement a policy for a Web service application. ❑
Create a policy file manually.
❑
Declare the set of policies in a policy file. 395
396
Chapter 10
■
■
WSE Security
❑
Map policies to SOAP endpoints.
❑
Configure a policy file in a configuration file.
❑
Create and enforce a custom policy.
❑
Create a policy file by using the WseConfigEditor3 tool.
❑
Set a policy in a client application and in a client computer.
Encrypt and decrypt a SOAP message. ❑
Encrypt a SOAP message.
❑
Decrypt an encrypted SOAP message.
Implement filters in a Web service application. ❑
Add a filter.
❑
Remove a filter.
❑
Shuffle the order of the filters.
❑
Enable the Trace filter.
❑
Create custom input and output filters.
Lessons in this chapter: ■
Lesson 1: Web Service Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
■
Lesson 2: Custom Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
■
Lesson 3: Message Filters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Knowledge of programming in Microsoft Visual Basic or C# and a basic under standing of Extensible Markup Language (XML).
In addition, each of the code examples in the chapter assumes that the following namespaces have been added at the top of the code file: 'VB Imports System
Before You Begin
Imports Imports Imports Imports Imports Imports Imports Imports //C#
using using using using using using using using
397
System.Collections.Generic
System.Text
System.Xml
System.Security.Cryptography.X509Certificates
Microsoft.Web.Services3
Microsoft.Web.Services3.Design
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
System;
System.Collections.Generic;
System.Text;
System.Security.Cryptography.X509Certificates;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Design;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
To import the Microsoft.Web.Services3 namespace and child namespaces, it is further assumed you have added a reference to the Microsoft.Web.Service3.dll assembly.
Real World William Ryan It wasn’t all that long ago that security concerns were largely ignored by the development community. I had worked for a while before returning to graduate school, so when I graduated, most of my friends who worked in the industry had substantially more real-world experience than I did. One day over lunch, I men tioned that the product they were developing sounded like it had a major flaw; it almost totally ignored security. When I mentioned the specifics, most of the people laughed at me, explaining that points such as the one I was making were made by people who spent too much time in school and not enough time in the field. Security was not something clients or venture capitalists could see, so focusing on it was something that was viewed by many as non-value added. It was almost exactly three years after we had this discussion that I was eating lunch with three of the five people at the original meeting. They were quite dejected because they had just been through a humiliating experience and lost a potential customer that they were sure they would win. They had moved a large part of their infrastructure to Web services and focused almost exclusively on performance and functionality. Just about everything that could be done inter nally could now be done by trading partners. They were convinced that security
398
Chapter 10
WSE Security
was pretty much an afterthought and didn’t plan on addressing it until after the application was live. During the demo, they showed their customer how easy it was to access the system externally. They showed the customer how much could be done remotely without having to develop a large amount of new code. Unfor tunately, one of the people performing the demo entered some values that cor responded to a different customer. He had intended to show the customer how easy it was to access all the customer’s financial data, but before he even realized what happened, he showed the customer a different company’s data. Although a few of the people at the demo were focusing on how great the new functionality was, the financial executive there was overwhelmed by the fact that he saw the bank accounts, names, addresses, and much more information of the other company’s customers. When the person doing the demo realized what happened, he tried to smooth over the mistake by saying “Well, this was just a careless mistake on my part; I used your company’s user name and password but specified a different company as the target.” The gentleman giving the demon stration thought this explanation would comfort the people watching. Instead, he just proved unequivocally how easy it would be for someone to accidentally view all of the client’s confidential data. Far from comforting the people watch ing the demo, this instead served to persuade them how dangerous having our company store their data would be. Not only did they not buy the expanded services, within a week they canceled the account, citing the debacle at the demo as their reason. The demo showed some impressive functionality with Web services, but because security wasn’t really implemented, a simple data entry error could expose very sensitive data. Using even simple security features, such as those provided in WSE 3.0, would have stopped another company’s data from being shown and might well have saved the account. Security should never be an afterthought when data is exposed via the Web. Securing this information is even more critical over the Web than over a traditional network. At best it’s professionally irresponsible not to take security seriously, and at worst it could be something that ruins your career or ends your company.
Lesson 1: Web Service Policy
399
Lesson 1: Web Service Policy WSE 3.0 enables Web services to be secured imperatively in code or declaratively using a security policy. WSE policies implement the WS-Policy specification. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwebsrv/html/ understwspol.asp for more information. In general, you should use a policy for imple menting your Web service security requirements, but see http://msdn.microsoft.com/ library/default.asp?url=/library/en-us/wse3.0/html/0610f54f-f8c4-4ded-9617 08384e5ed635.asp for information on securing a Web service without using a policy file. You should use a policy for implementing your Web service security requirements because a policy helps separate the business logic from the security requirements logic. The policy framework can also be extended so that any custom requirements can be added as extensions to the policy framework; think reuse instead of duplicate code. A policy helps your Web services validate that request messages conform to a defined security policy and automatically secures Web service responses. In addition, an administrator can manage a policy file once your Web service has been deployed to a production environment. The WSE 3.0 policy framework describes the constraints and requirements for com municating with Web services. A policy is compiled before any message exchange between a sender and a recipient takes place. So, a policy effectively becomes a run time component in the form of a SOAP message filter (see Lesson 3, “Message Filters,” for more information), and the policy requirements are applied at the sender or enforced at the recipient. Although policies can be used to apply various types of requirements, such as mes sage addressing, in this lesson you’ll see how WSE 3.0 policies are used to apply secu rity requirements. After this lesson, you will be able to: ■
Create a policy file manually.
■
Create a policy file using the WseConfigEditor3 tool.
■
Declare the set of policies in a policy file.
■
Map policies to SOAP endpoints.
■
Configure a policy file in a configuration file.
Estimated lesson time: 45 minutes
400
Chapter 10
WSE Security
Creating a Policy WSE 3.0 makes creating policy assertions files fairly straightforward. A policy assertion is a combination of the capabilities and requirements of your Web service. This means that an assertion is part of the SOAP processing pipeline. You can think of an assertion as a “factory” class that can be used for injecting input filters, output filters, or both into the processing pipeline. You’ll learn more about filters in Lessons 2 and 3. Follow these steps to create and implement a policy: 1. Create a stub to hold the policy elements. This task is accomplished by creating a .config file, known as a policy file or a policy cache file. 2. Create a set of policy assertions. There exists a fairly involved set of assertions that can be used. If these assertions aren’t sufficient for your application’s needs, you can develop custom assertions by simply creating a class that inherits from the SecurityPolicyAssertion or the PolicyAssertion classes. 3. Reference the policy file from the application configuration file. The following example shows the structure of a WSE policy file:
The structure is fairly intuitive, but a brief description is in order. The ele ment is the root element and you should specify the xmlns attribute as shown to avoid build warnings. The element, which is optional, is a container for one or more elements. The element is used to specify a policy exten sion, which is named standard or custom policy assertion. One example of a standard security policy assertion (extension) is usernameOverTransportSecurity:
The element is used to uniquely identify a policy in a policy file by way of the name attribute. It holds one or more child elements, each of which can be one of the standard policy assertions, such as the usernameOverTransportSecurity turnkey secu rity assertion, or a custom policy assertion. See http://msdn.microsoft.com/library/ default.asp?url=/library/en-us/wse/html/88b311eb-03f2-4fec-b8f3-33755413a0ca.asp
Lesson 1: Web Service Policy
401
for more information about the policy file schema.
Creating a Policy File Manually The simplest way to get started with your Web service policy is to create a policy file manually. Basically, you create a blank XML file, which can have any valid filename, but to make the file easier to recognize, give it the standard .config extension. Then add the following structure to the XML file:
To this structure you can manually add the extensions using the and elements, and policy assertions using the and related child ele ments. However, it is much easier to use the WSE Settings 3.0 tool, also known as WseConfigEditor3, as described in the next section, “Creating, Configuring, and Enabling a Policy File Using WseConfigEditor3.”
Creating, Configuring, and Enabling a Policy File Using WseConfigEditor3 Many of the features of WSE 3.0 can be managed using the WSE Settings 3.0 tool, also known as WseConfigEditor3. WseConfigEditor3 is a tool with a graphical user inter face that relieves the workload of configuring the configuration files manually. Once WSE 3.0 has been installed on a computer, the WseConfigEditor3 is available on the Start menu as well as from Solution Explorer in the Microsoft Visual Studio 2005 Inte grated Development Environment. Using the configuration tool is much more convenient than it was in previous ver sions of WSE. Prior to the advent of WSE 3.0, developers could only access the con figuration tool from within Visual Studio 2005. What’s worse, it could only be accessed from inside an existing project. To create a new policy file using WseConfigEditor3, or attach an existing policy file, perform the following actions: 1. In Solution Explorer, right-click the project for which you want to create the pol icy; the Web Service project or the Web Service consumer project, such as a Con sole application or Windows application, and click WSE 3.0 Settings. 2. In the WseConfigEditor3 dialog box, click the Policy tab, as shown in Figure 10-1.
402
Chapter 10
WSE Security
Figure 10-1 The Policy tab of the WseConfigEditor3 tool
3. Select the Enable Policy check box. 4. Click Browse, and in the Open dialog box, navigate to the .config file that con tains the existing policy, or browse to the folder where you want to create a new policy file, type in the name of the file in the File Name box, and click Open. Unless you’re attaching an existing policy file that already contains policies (unlike the blank policy file you might have created manually following the instructions in the “Creating a Policy File Manually” section), you need to add new policy assertions (see the next section, “Adding Policy Assertions,” for more information). Once poli cies have been added to the policy file, you can click OK to enable the policy for your project.
Adding Policy Assertions A policy (file) without policy assertions is hardly useful, not to say it’s useless. In fact, if you click OK in the WseConfigEditor3 dialog box, after policy has been enabled, but no policy assertions have been added to the policy, you’re prompted that policy will be disabled. Unfortunately, the message box that prompts you doesn’t give you the option of canceling the action and returning to the WseConfigEditor3 dialog box. Instead, the policy is disabled for your project and the WseConfigEditor3 dialog box is closed.
Lesson 1: Web Service Policy
403
To add policy assertions to your policy using the WseConfigEditor3 dialog box, the following should be done: 1. Ensure that a policy file has been added to your project. See the previous section, “Creating, Configuring, and Enabling a Policy File Using WseConfigEditor3,” for more information. 2. In the WseConfigEditor3 dialog box, click the Policy tab, and in the Edit Appli cation Policy group, click Add as shown in Figure 10-2.
Figure 10-2 The Add button in the Edit Application Policy group
3. In the Add Or Modify Policy Friendly Name dialog box, shown in Figure 10-3, type the friendly name for the policy assertion in the text box and click OK. The WSE Security Settings Wizard will then walk you through setting an authentica tion method.
Figure 10-3 Add Or Modify Policy Friendly Name dialog box
404
Chapter 10
WSE Security
Once you specify a friendly name for the policy assertion and click OK, the WSE Secu rity Settings Wizard starts. Click Next on the welcome page. On the Authentication Settings page, which is shown in Figure 10-4, you have two options:
Figure 10-4 Authentication Settings page of WSE Security Settings Wizard
This one is fairly obvious: You sim ply select the Secure A Service Application option, if you’re configuring a Web service project, and the Secure A Client Application option if you’re configuring a Web service consumer or client application.
■ Do You Want To Secure A Service Or A Client?
The Choose Client Aut hentication Method group presents options for authentication settings. There are four choices, described here:
■ Choose Client Authentication Method
The client does not provide any credentials in the request. The service ensures that the client has secured the request with the server’s public certificate. The response message is secured with a symmetric key that was supplied by the client. Although this option is the easiest to use, it is also considered the weakest.
❑ Anonymous
The client provides a user name and password as credentials in the request, which the service authenticates. The service ensures that the client has secured the request with the server’s public certificate. The response message is secured with a symmetric key that was supplied by the client.
❑ Username
Lesson 1: Web Service Policy
405
The client provides a certificate as a credential in the request, which the service authenticates. The service ensures that the client has secured the request with the server’s public certificate. The response mes sage is secured with a symmetric key that was supplied by the client.
❑ Certificate
The client provides a Kerberos ticket as a credential in the request, which the service authenticates. The service ensures that the client has secured the request with a Kerberos ticket for the service. The response message is secured with the client’s Kerberos ticket.
❑ Windows
If you select the Username, Certificate, or Windows option and click Next, you have the option of specifying if you want to perform authorization on the User And Roles page. On the following pages you need to specify the protection requirements for the mes sages, which means if you want to enable WS-Security Extensions 1.1, the protection order, and if you want to establish a secure session. In addition, you need to specify the server certificate to be used for the secure message exchange. Finally, review your settings on the Create Security Settings page and click Finish to save the settings to the policy file. Here’s a sample policy file, with a policy named demoPolicy, that uses the usernameForCertificateSecurity security assertion:
406
Chapter 10
WSE Security
For more information about the WSE Security Settings Wizard and the WSE Settings 3.0 tool in general, see http://msdn.microsoft.com/library/default.asp?url=/library/enus /wse3.0/html/5a8f03b1-16ac-4c5c-9d9e-132a9c0b628a.asp.
Using a Policy File After a policy file has been created, it needs to be referenced from the Web.config or App.config file of your application so that the policy can be used for your applications message exchange, which also means that you’re mapping your policies to the SOAP endpoint of your application (this is really WSE 2.0 terminology):
Lab 1: Configuring Security In this lab, you use the WseConfigEditor3 tool to manage the policy your application is using. You create a Web service and use the WseConfigEditor3 to manage it. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005 and create a blank solution named WSEConfigEditorLab. 2. Add a new C# or Visual Basic Web service named WSEConfigEditorLab. 3. Right-click the project and click WSE Settings 3.0. 4. In the WseConfigEditor3 dialog box, on the General tab, select the Enable This Project For Web Services Enhancements and Enable Web Services Enhancement Soap Protocol Factory check boxes.
Lesson 1: Web Service Policy
407
5. Click the Policy tab. 6. Select the Enable Policy check box. 7. In the Edit Application Policy group, click Add. 8. In the Add Or Modify Policy Name dialog box, type demoPolicy in the text box, and click OK. 9. In the WSE Security Settings Wizard, on the Welcome page, click Next. 10. On the Authentication Settings page, in the Do You Want To Secure A Service Or A Client group, click the Secure A Service Application option. 11. In the Choose Client Authentication Method group, click the Anonymous option, and then click Next. 12. On the Message Protection page, in the Protection Order group, click the SignOnly option, and then click Next. 13. On the Server Certificate page, select the Specify The X.509 Certificate In Code check box, and then click Next. 14. On the Create Security Settings page, review the summary of the options you’ve chosen. If you made any mistakes or you want to change any of the options, you can navigate backward and change them. 15. Click Finish to close the wizard, and then click OK to close the WseConfig Editor3 dialog box. 16. Examine the newly created wse3policyCache.config file. It should look similar to the following:
408
Chapter 10
WSE Security
You have just successfully configured your Web service application using the WseConfigEditor3 tool.
Lesson Summary ■
The WseConfigEditor3 tool can be used to manage almost any element of WSE configuration.
■
In previous versions of WSE, the WseConfigEditor3 was only available through individual projects. Starting with WSE 3.0, the tool can be used within Visual Studio 2005 or as a stand-alone application.
■
The WseConfigEditor3 tool can be used to manage general settings, security set tings, policy settings, routing, token issuing, diagnostics, and messaging.
■
If a custom policy is implemented for an application, the WseConfigEditor3 tool’s Policy tab can be used to manage it. This feature provides access to a Security Set tings Wizard and has the abilty to provide very intricate policy configuration.
■
There are four authentication modes available with custom policy: anonymous, Windows, certificate, and username.
■
Anonymous authentication is the simplest mode to use but is considered by many to be the least secure of the available modes and as such should only be used with transport-level security.
■
Windows authentication uses Kerberos and provides both a high level of secu rity and reduced administration complexity.
■
By default, two types of applications can be configured: client applications and services.
■
The policy fileName attribute of the element of a Web.config file can be used to point the application to a custom policy expression file.
Lesson 1: Web Service Policy
409
■
Multiple policies can be added to an application by specifying additional elements.
■
If multiple policies are configured, the WseConfigEditor3 can be used to edit the configuration file manually.
■
If a policy is added manually, great care must be taken to ensure all necessary ele ments are entered and spelled correctly.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Web Service Policy.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which are valid client authentication methods? (Select all that apply.) A. Anonymous B. Username C. Certificate D. Windows 2. How can a policy be specified in a Web.config or App.config file? (Choose the best answer.) A. Add a element and specify the policy information there. B. Add a element and add the policy information there. C. Add a element, which allows for automatic discovery. D. Add a element within the element and specify the policy name using a fileName attribute.
410
Chapter 10
WSE Security
Lesson 2: Custom Policies In the previous lesson you learned about policy (cache) files, policy assertions, policy extensions, and how to configure all of these using the WseConfigEditor3 tool. In this lesson you’ll learn how to create a custom policy assertion that encrypts the messages exchanged. You’ll see how a custom policy assertion can be built using the UsernameToken for a custom security solution. First we’ll cover encryption basics. Security was one of the primary areas of concentration when WSE 3.0 was developed. This shouldn’t be surprising because, as time progresses and Web services become more and more prevalent, the need to provide security that can cover more and more situ ations becomes critical. There are many aspects to security, but without a doubt, encryption and decryption are cornerstones of any secure solution. After this lesson, you will be able to: ■
Create and enforce a custom policy.
■
Set a policy in a client application and in a client computer.
■
Encrypt a SOAP message.
■
Decrypt a SOAP message.
Estimated lesson time: 55 minutes
Overview The most basic purpose of encryption is simply to prevent unwanted parties from see ing information (or at least to make it really difficult for them). Decryption entails the flip side of this: making sure that authorized parties can, in fact, read messages that have been encrypted. Encryption and decryption are used in almost every nontrivial application, and it’s hard to imagine any substantial enterprise application that doesn’t use either of them to at least some degree. In its simplest form, an encryption algorithm might turn the word “Microsoft” into the word “Nuxeiaidr.” The algorithm used in this case was simple substitution algorithm, substituting every letter in the word “Microsoft” with the letter that appears directly to the left of it on a standard key board. Without knowing the algorithm, you could encrypt a message and, thereby, make it difficult for unwanted parties to read. In this case, the algorithm is very sim ple, and any sophisticated attacker would definitely have it in his or her arsenal. Hashing is another component of security (although hashing is used outside of secu rity contexts, as well). Hashing uses mathematics to compute a value for the words
Lesson 2: Custom Policies
411
being obscured. If any portion of the hashed value is changed or tampered with, then the original value won’t be computed correctly when unhashed. Hence, by checking the unhashed value against the value you are expecting, one can determine with a high degree of confidence whether a message has been tampered with. These two concepts are used together to provide digital signatures. In Chapter 9, “Web Services Enhancements 3.0 in Client and Server Applications,” the concept of a digital signature was introduced. The primary objective of a digital signature is to pro vide nonrepudiation. NOTE
Definition of Nonrepudiation
The concept of nonrepudiation essentially holds that if a message is nonrepudiable, the sender cannot deny that the message was in fact sent from him or her and the recipient cannot deny that the message was received. Not only must the identity of both sender and receiver be verified, but a mechanism must be put in place to avoid someone saying something like, “Yes, I did in fact send a message; however, I didn’t send that message.”
Basic Encryption Although nonrepudiation is an important security concept, it might not be the pri mary objective of a given security scenario. Imagine a case where trade secrets are being transferred. Regardless of whether there’s a need to verify the sender and receiver, you’d like to ensure that if the message is lost or stolen, unauthorized third parties will not be privy to the information in the message. It’s worth mentioning that no encryption algorithm is 100 percent secure, meaning that there’s no guarantee that unauthorized parties will be unable to view the message. However, using strong commercial algorithms, it’s possible to make it so costly, time-consuming, or inconve nient that the chances of an unauthorized party accessing the information are minis cule. NOTE
Definition of Privacy
Although nonrepudiation might be important in many transactions (particularly in cases such as financial or health care scenarios), privacy is equally important in many other instances. If you receive a contract from a customer, you often want to verify that the contract was actually signed by the customer and was not tampered with after it was signed. There might be cases where, in addition to or irrespective of nonrepudiation, you might not want anyone other than the intended recipient to see the contents of a message. Essentially, you want to make sure that no one sees the contents of the message other than people you authorize to see it.
412
Chapter 10
WSE Security
To achieve the goal of privacy, two varieties of encryption can be used: The term private key encryption is often used as a synonym for symmetric algorithms. Symmetric algorithms use a key that must be known to both the sender and the recipient. Symmetric algorithms are generally consid ered less secure than their asymmetric counterparts because both the sender and the recipient must share the same key. The integrity of the algorithm is dependent on the key being kept secret; the risk of compromise increases with each additional party that has access to the key.
■ Symmetric algorithms
The term public key encryption is often used as a syn onym for asymmetric algorithms. To use these algorithms, the sender encrypts a message with the recipient’s public key. The recipient’s private key must be used to decrypt the message. This encryption method is generally considered more secure because only one party needs to have access to the private key. As long as the private key is kept private, the probability of the message being com promised is very small.
■ Asymmetric algorithms
MORE INFO
Additional resources on .NET Framework cryptography
Although this discussion focuses on encryption and decryption of SOAP messages using WSE 3.0, there are many different applications of cryptography. Microsoft’s Patterns and Practices group has built an application block for cryptography that has widespread applicability for many applications. Not only is the application block fairly easy to use, it also provides extensive documentation on the .NET Framework’s cryptographic capabilities, and examining it might be a very useful learning tool. As of the time of this writing, this application block can be accessed at http://msdn.microsoft.com/ library/default.asp?url=/library/en-us/dnpag2/html/EntLibJan2006_CryptoAppBlock.asp?frame=true.
WSE 3.0 provides a mechanism to use either type of encryption algorithm. To use asymmetric encryption, the Web service consumer needs to have access to the recip ient’s X.509 certificate that contains the public key matching the recipient’s private key. To use a symmetric algorithm with WSE 3.0, the private key must be distributed to both parties, so any Web service consumer, as well as the Web service itself, needs access to this private key. One common misconception regarding the encryption of SOAP messages is that the entire message is encrypted. This is not the case! Only the body part of the SOAP mes sage is encrypted (and accordingly, decrypted on the other side of the exchange). Therefore, if sensitive information is contained in other elements of the message such as the header, the information needs to be encrypted and decrypted separately.
Lesson 2: Custom Policies
CAUTION
413
Be careful with sensitive information outside of the body part
Any information not contained in the body part of the message is not encrypted and is visible to prying eyes. As such, it’s critical to examine your SOAP messages and know exactly what informa tion they contain.
Real World William Ryan I was doing a presentation on Web Services Enhancements 2.0 at a .NET user’s group a while ago. At the end of the presentation, many developers were gath ered in the room and talking shop. One person told me of a consulting firm his company had hired to build a messaging subsystem for them. This company had a very high billing rate and claimed to have extensive expertise in the area of security. The project they built was deployed for more than six months before a mandatory yearly audit was performed. One of the first things the auditors examined was the content of the SOAP messages being transmitted. What they discovered was very disheartening. By looking at the messages, they discovered that although everything in the body part of the message was properly secured, a substantial amount of very sensitive data was being transmitted in a custom SOAP header and the consultants failed to address this information. So although a substantial amount of time and money was spent to keep information in the body part private, most of the same information was contained in the header and readily visible in plain text. This situation was analogous to locking one of your car doors while leaving the other doors wide open. Now that you know about encryption basics, we need to combine this knowledge with a custom policy so that we can build a custom policy assertion that is used by both the Web service and the client, making sure all messages exchanged are encrypted.
Creating a Custom Policy Assertion A custom policy assertion should be created when one of the turnkey security asser tions doesn’t meet the needs of your application. The custom policy assertion is used to enforce security requirements or for modifying SOAP messages. As mentioned in Lesson 1, a custom policy assertion must be derived from either the PolicyAssertion or
414
Chapter 10
WSE Security
SecurityPolicyAssertion class. Because you’ll be creating a security assertion, you’ll derive yours from the SecurityPolicyAssertion class. Follow these steps to create a custom policy assertion that secures a SOAP message exchange: 1. Create a new Class Library project, rename the default class appropriately, and derive it from the SecurityPolicyAssertion class. Add two private variables, username and password, and the corresponding read-only properties for retrieving the values of the private variables. Then add two constructors, one default and parameterless, and one that accepts a username and a password. In the nonde fault constructor, save the passed username and password values to the private variables: 'VB Public Class CustomSecurityAssertion
Inherits SecurityPolicyAssertion
Private usn As String = Nothing
Private pwd As String = Nothing
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal userName As String, ByVal password As String) MyBase.New() Me.usn = userName
Me.pwd = password
End Sub
Public ReadOnly Property UserName() As String Get Return Me.usn End Get End Property public readonly property Password() as string Get Return Me.pwd
End Get
End Property
End Class
//C# public class CustomSecurityAssertion : SecurityPolicyAssertion {
Lesson 2: Custom Policies
415
private string usn = null;
private string pwd = null;
public CustomSecurityAssertion() : base()
{
}
public CustomSecurityAssertion(string userName, string password)
: base()
{
this.usn = userName;
this.pwd = password;
} public string UserName {
get
{
return this.usn;
}
}
public string Password {
get
{
return this.pwd;
}
}
}
2. Override the abstract CreateServiceInputFilter method of the SecurityPolicyAsser tion class: 'VB Public Overrides Function CreateServiceInputFilter(ByVal context As _
Microsoft.Web.Services3.Design.FilterCreationContext) As _
Microsoft.Web.Services3.SoapFilter
Throw New Exception("The method or operation is not implemented.")
End Function
//C# public override SoapFilter CreateServiceInputFilter(FilterCreationContext context)
{
throw new Exception("The method or operation is not implemented.");
}
3. Override the abstract CreateServiceOutputFilter method of the SecurityPolicyAsser tion class:
416
Chapter 10
WSE Security
'VB Public Overrides Function CreateServiceOutputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Throw New Exception("The method or operation is not implemented.") End Function //C# public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context) { throw new Exception("The method or operation is not implemented."); }
4. Override the abstract CreateClientInputFilter method of the SecurityPolicyAsser tion class: 'VB Public Overrides Function CreateClientInputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Throw New Exception("The method or operation is not implemented.") End Function //C# public override SoapFilter CreateClientInputFilter(FilterCreationContext context) { throw new Exception("The method or operation is not implemented."); }
5. Override the abstract CreateClientOutputFilter method of the SecurityPolicyAsser tion class: 'VB Public Overrides Function CreateClientOutputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Throw New Exception("The method or operation is not implemented.") End Function //C# public override SoapFilter CreateClientOutputFilter(FilterCreationContext context) { throw new Exception("The method or operation is not implemented."); }
Lesson 2: Custom Policies
417
6. Override the ReadXml method of the SecurityPolicyAssertion class. Although the ReadXml method isn’t abstract and as such doesn’t have to be overridden like other methods described previously, overriding ReadXml is necessary when con figuration is done through a configuration file. If you don’t, a System.Net.WebEx ception is thrown because the operation times out, waiting for the start element to be read from the configuration file. So, in the ReadXml method, add code for parsing the custom XML elements and attributes, if any, that can be placed in the policy file for the security policy assertion. Security policy assertions (turnkey and custom) can provide an XML element that is used for specifying the options in the policy file. An XmlReader object is passed to the ReadXml method, and the reader is positioned on the XML element for the security policy assertion. The name of the XML element is specified when the security policy assertion is reg istered in the policy file with the extension element. Therefore, the XmlReader can be used to retrieve the options that are specified in the policy file: 'VB Public Overrides Sub ReadXml(ByVal reader As XmlReader, _
ByVal extensions As IDictionary(Of String, Type))
' Was an XmlReader object passed?
If reader Is Nothing Then
Throw New ArgumentNullException( _
"XmlReader parameter cannot be null")
End If
' Was an IDictionary object passed?
If extensions Is Nothing Then
Throw New ArgumentNullException( _
"IDictionary parameter cannot be null")
End If
Dim elementName As String = Nothing ' Loop through extensions For Each extensionName As String In extensions.Keys
' Our extension?
If extensions(extensionName) Is _
GetType(CustomSecurityAssertion) Then ' Save the extension name
elementName = extensionName
Exit For
End If
Next
' Read the start element
418
Chapter 10
WSE Security
reader.ReadStartElement(elementName)
End Sub
//C# public override void ReadXml(XmlReader reader,
IDictionary extensions)
{
// Was an XmlReader object passed?
if (reader == null)
throw new ArgumentNullException( "XmlReader parameter cannot be null"); // Was an IDictionary object passed? if (extensions == null) throw new ArgumentNullException( "IDictionary parameter cannot be null"); string elementName = null; // Loop through extensions foreach (string extensionName in extensions.Keys) { // Our extension?
if (extensions[extensionName] == typeof(CustomSecurityAssertion))
{
// Save the extension name elementName = extensionName; break;
}
}
// Read the start element
reader.ReadStartElement(elementName);
}
7. Create your Web service’s custom input filter by adding a new class to the class file created in step 1 that derives from Microsoft.Web.Services3.Security.ReceiveSecurityFilter. This is the base class for filtering incoming SOAP messages. You need to create a custom constructor, because the base class doesn’t have a parameterless constructor. The call to the overloaded base constructor takes two parameters; a SOAP actor and a Boolean value indicating whether the filter is to be used with a Web service client. You also need to override the abstract ReceiveSecurityFilter.ValidateMessageSecurity: 'VB Public Class ServiceFilterIn
Inherits ReceiveSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, False)
Lesson 2: Custom Policies
419
End Sub Public Overrides Sub ValidateMessageSecurity(ByVal envelope As _
Microsoft.Web.Services3.SoapEnvelope, _
ByVal security As Microsoft.Web.Services3.Security.Security)
End Sub
End Class
//C# public class ServiceFilterIn : ReceiveSecurityFilter
{
public ServiceFilterIn(CustomSecurityAssertion parentAssertion):
base(parentAssertion.ServiceActor, false)
{
}
public override void ValidateMessageSecurity(
Microsoft.Web.Services3.SoapEnvelope envelope,
Microsoft.Web.Services3.Security.Security security)
{
}
}
8. Create your Web service’s custom output filter by adding a new class to the class file created in step 1 that derives from Microsoft.Web.Services3.Security.SendSecu rityFilter. This is the base class for filtering outgoing SOAP messages. You need to create a custom constructor, because the base class doesn’t have a parameterless constructor. The call to the overloaded base constructor takes two parameters; a SOAP actor and a Boolean value indicating whether the filter is to be used with a Web service client. You also need to override the abstract SendSecurityFilter.SecureMessage: 'VB Public Class ServiceFilterOut
Inherits SendSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, False)
End Sub
Public Overrides Sub SecureMessage(ByVal envelope As _
Microsoft.Web.Services3.SoapEnvelope, _
ByVal security As Microsoft.Web.Services3.Security.Security)
End Sub
End Class
//C# public class ServiceFilterOut : SendSecurityFilter
420
Chapter 10
WSE Security
{ public ServiceFilterOut(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, false) { } public override void SecureMessage( Microsoft.Web.Services3.SoapEnvelope envelope, Microsoft.Web.Services3.Security.Security security) {
}
}
9. Create your Web service client’s custom input filter by adding a new class to the class file created in step 1 that derives from Microsoft.Web.Services3.Secu rity.ReceiveSecurityFilter: 'VB Public Class ClientFilterIn
Inherits ReceiveSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, True) End Sub Public Overrides Sub ValidateMessageSecurity(ByVal envelope As _ Microsoft.Web.Services3.SoapEnvelope, _ ByVal security As Microsoft.Web.Services3.Security.Security) End Sub
End Class
//C# public class ClientFilterIn : ReceiveSecurityFilter { public ClientFilterIn(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, true) { } public override void ValidateMessageSecurity( Microsoft.Web.Services3.SoapEnvelope envelope, Microsoft.Web.Services3.Security.Security security) {
}
}
10. Create your Web service client’s custom output filter by adding a new class to the class file created in step 1 that derives from Microsoft.Web.Services3.Security.SendSecurityFilter. Create a private variable for saving the parent security assertion, which is passed to the constructor, and save it in the constructor:
Lesson 2: Custom Policies
421
'VB Public Class ClientFilterOut
Inherits SendSecurityFilter
Private parentAssertion As CustomSecurityAssertion = Nothing Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, True) Me.parentAssertion = parentAssertion
End Sub
Public Overrides Sub SecureMessage(ByVal envelope As _ Microsoft.Web.Services3.SoapEnvelope, _ ByVal security As Microsoft.Web.Services3.Security.Security) End Sub
End Class
//C# public class ClientFilterOut : SendSecurityFilter { private CustomSecurityAssertion parentAssertion = null; public ClientFilterOut(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, true) { this.parentAssertion = parentAssertion; } public override void SecureMessage( Microsoft.Web.Services3.SoapEnvelope envelope, Microsoft.Web.Services3.Security.Security security) {
}
}
In the steps outlined, you create a single security policy assertion class or assembly, but depending on your preferences, you could just as easily split the class into two security policy assertion classes or assemblies; one for the Web service SOAP pipeline and one for the Web service client SOAP pipeline. The custom security assertion will s i g n a n d v e r i f y a n d e n c r y p t a n d d e c r y p t S OA P m e s s a ge s u s i n g t h e Microsoft.Web.Services3.Security.Tokens.UsernameToken as described in the next sec tion, “Encryption with a Security Token.”
Encryption with a Security Token Security tokens can be used to sign and encrypt SOAP messages and the WSE 3.0 class library provides a number of tokens in the Microsoft.Web.Services3.Security.Tokens
422
Chapter 10
WSE Security
namespace. There are many different types of tokens, each of which has its own respec tive strengths and weaknesses. Each token implementation in WSE 3.0 derives from the SecurityToken base class. The WSE 3.0 classes that inherit from SecurityToken are shown in the following list: ■
Microsoft.Web.Services3.Security.Tokens.BinarySecurityToken
■
Microsoft.Web.Services3.Security.Tokens.DerivedKeyToken
■
Microsoft.Web.Services3.Security.Tokens.EncryptedKeyToken
■
Microsoft.Web.Services3.Security.Tokens.IssuedToken
■
Microsoft.Web.Services3.Security.Tokens.UsernameToken
■
Microsoft.Web.Services3.Security.Tokens.X509SecurityToken
While an in-depth discussion about the strengths and weaknesses of each type of token is beyond the scope of this discussion, the WSE 3.0 documentation file pro vides a good bit of background about each token’s usage and benefits or weaknesses. To be used with the custom security policy assertion that was introduced in the pre vious section, “Creating a Custom Policy Assertion,” you’ll use the UsernameToken. A UsernameToken object contains a user name and/or a password. When a Web service receives a request, the user name and password values can be retrieved and compared against a store, such as a database or Windows Active Directory (or whatever other mechanism one chooses to implement), to determine whether the request is valid. The major benefit of using UsernameToken is its simplicity. To sign and encrypt a mes sage with a SecurityToken, the mechanism is fairly simple. In the context of WSE 3.0, we’re adding code to the Web service client’s custom output filter, the overridden SecureMessage method of the ClientFilterOut class: 1. Create a token type, such as UsernameToken. 2. Add credentials to the token. 3. Decide which PasswordOption value is appropriate. 4. Add the UsernameToken to the SOAP security header. 5. Sign the SOAP message using an XML signature object. 6. Create a new EncryptedData object, passing in the UsernameToken. 7. Add the EncryptedData object to the collection of signatures and encryption keys in the security context, as shown in the following code: 'VB ' Create token for signing and encryption
Lesson 2: Custom Policies
423
Dim userToken As New UsernameToken(parentAssertion.UserName, _
parentAssertion.Password, PasswordOption.SendPlainText)
' Add token to SOAP security header
security.Tokens.Add(userToken)
' Sign SOAP message using an XML signature object
Dim mesSignature As New MessageSignature(userToken)
security.Elements.Add(mesSignature)
' Encrypt message body
Dim encData As New EncryptedData(userToken)
' Add encrypted data to collection of signatures and
' encryption keys
security.Elements.Add(encData)
//C# // Create token for signing and encryption
UsernameToken userToken = new UsernameToken(parentAssertion.UserName,
parentAssertion.Password, PasswordOption.SendPlainText);
// Add token to SOAP security header
security.Tokens.Add(userToken);
// Sign SOAP message using an XML signature object
MessageSignature mesSignature = new MessageSignature(userToken);
security.Elements.Add(mesSignature);
// Encrypt message body
EncryptedData encData = new EncryptedData(userToken);
// Add encrypted data to collection of signatures and
// encryption keys
security.Elements.Add(encData);
Although the code doesn’t specify which type of authentication to use (that is, Win dows or custom), both types can be used with the UsernameToken. However, if you want custom authentication, that requires creating a class deriving from the User nameTokenManager and overriding the AuthenticateToken method to authenticate against a custom data store such as a database. The derived class must then be regis tered in the Web.config file for the Web service using the Type attribute of the element. Otherwise, the code is straightforward, and the only tricky part of the process is choosing the correct PasswordOption value to use. A brief discus
424
Chapter 10
WSE Security
sion of each PasswordOption value is provided in Table 10-1. Table 10-1 Table 10-1 The PasswordOption Enumeration
Value
Description
SendHashed
The password is included and the SHA-1 algorithm is used to hash it. To use this value, you must provide a class that inher its from the UsernameTokenManager class, which automati cally calls an overridden AuthenticateToken method to handle authentication.
SendNone
The password is not included in the transmission of the mes sage; however, it is used to sign the message and must be pro vided to allow the message to be decrypted.
SendPlainText
The password is sent in plain text. This option can be useful, but because it is transmitted in plain text, it has limited appli cability. It is only suitable for scenarios where a certificate is used to encrypt the UsernameToken value, or if the transport channel has been secured using Secure Sockets Layer (SSL).
Decryption Depending on the level of security the application requires, additional encryption or decryption might be desirable; however, the built-in functionality is quite powerful and more than suitable for most commercial applications. The way you’ve signed and encrypted the messages, assuming you have used valid Windows account credentials, means that the message is automatically authenticated and decrypted, because WSE 3.0 has a built-in UsernameTokenManager. If you don’t pass Windows account credentials, you must implement a custom Microsoft .Web.Services3.UsernameTokenManager class. The UsernameTokenManager class repre sents a security token manager for security tokens of type UsernameToken. There’s a token manager class for each of the security token classes described at the beginning of the previous section, “Encryption with a Security Token.”
Using a Security Token Issuing Service If instead of creating your own security tokens, you want to have the tokens created for you automatically when required, WSE 3.0 provides this capability. The SOAP message sender obtains a security token from the security token service and then uses
Lesson 2: Custom Policies
425
the token to digitally sign a message exchange. To request a token from the token ser vice, which must be trusted by the recipient of the message exchange, the SOAP mes sage sender sends the first SOAP message, also known as a Request Security Token (RST) message. The RST must be signed for the security token service to verify that the SOAP message sender is authorized to request the security token. Once the signa ture has been verified, authenticated, and authorized, a SOAP message, known as a Request Security Token Response (RSTR) message, which contains the security token, is returned to the requester. The issued security token can then be used for message exchanges until the token expires. WSE 3.0 provides a very elegant mechanism for issuing tokens, the SecurityContextTokenService class. For this class to handle token requests, the SOAP header needs to meet the following conditions: ■
The header must contain an element.
■
The value of the element must be set to http://schemas.xmlsoap.org/ws/ 2004/04/security/trust/RST/SCT.
CAUTION
SecurityTokenService base class for non-SecurityContextToken security tokens
If the application employs the use of any tokens that are not SecurityContextToken security tokens, the SecurityTokenService class must be used as a base class from which your custom token class inherits.
Although the SecurityContextTokenService class has many members, the primary method used in the context of issuing tokens is the IssueSecurityContextTokenRequest. This method has two overloads that accept a different object as a parameter, either RequestSecurityToken or RequestSecurityTokenResponse. The distinction regarding when to use which parameter is provided in Table 10-2. Table 10-2 Table 10-2 IssueSecurityContextTokenRequest Overloads
Parameter
Explanation
RequestSecurityToken
This object should be used whenever a security token request is processed within a ele ment. Provided the request is valid, a security token is returned.
426
Chapter 10
WSE Security
Table 10-2 Table 10-2 IssueSecurityContextTokenRequest Overloads
Parameter
Explanation
RequestSecurityTokenResponse
This object should be used whenever a security token request is received within a element.
The following code shows a sample invocation using a SecurityContextTokenService object as the parameter to the IssueSecurityContextTokenRequest method: 'VB Public Sub RequestSecurityTokenDemo() Dim ServiceInstance As New SecurityContextTokenService() Dim BaseToken As New RequestSecurityToken("TokenTypeHere") ServiceInstance.IssueSecurityContextTokenRequest(BaseToken) End Sub //C# public void RequestSecurityTokenDemo() { SecurityContextTokenService ServiceInstance = new SecurityContextTokenService(); RequestSecurityToken BaseToken = new RequestSecurityToken("TokenTypeHere"); ServiceInstance.IssueSecurityContextTokenRequest(BaseToken); }
The second overloaded IssueSecurityContextTokenRequest method accepts a RequestSecurityTokenResponse object and is ultimately invoked in the same manner: 'VB Public Sub RequestSecurityTokenResponseDemo() Dim ServiceInstance As New SecurityContextTokenService() Dim BaseTokenResponse As New RequestSecurityTokenResponse() ServiceInstance.IssueSecurityContextTokenRequest(BaseTokenResponse) End Sub //C# public void RequestSecurityTokenResponseDemo(){ SecurityContextTokenService ServiceInstance = new SecurityContextTokenService(); RequestSecurityTokenResponse BaseTokenResponse = new RequestSecurityTokenResponse(); ServiceInstance.IssueSecurityContextTokenRequest(BaseTokenResponse); }
In both cases, you create a RequestSecurityToken or a RequestSecurityTokenResponse object and use it as the parameter for the IssueSecurityContextTokenResponse method
Lesson 2: Custom Policies
427
call. This call in turn handles the token request and issues a token based on the object.
Lab 2: Signing and Encrypting a Message Exchange Using Custom Policy In this lab, you have an existing Web service, but you need to create a custom policy, and a Web service consumer. The latter signs and encrypts a message using the cus tom policy and sends it to the Web service, which uses the same policy to verify and decrypt the message. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Copy the solution named CustomPolicyLab, including all the files and projects from the Code folder on the companion CD. This solution, which exists in both Visual Basic and C#, contains a sample Web service named CustomPolicyWS with the infamous HelloWorld Web method. WSE 3.0 has been enabled on the Web service and a policy file with no policies defined has been created and ref erenced from the Web.config file. 2. Add a new Class Library project named CustomPolicyAssertion to the solution, and rename Class1.vb or Class1.cs to CustomSecurityAssertion.vb or CustomSecurityAssertion.cs. 3. To the CustomPolicyAssertion project, add a reference to the Microsoft.Web .Services3.dll and System.Web.Services.dll assemblies. 4. Replace the code in the CustomSecurityAssertion.vb or CustomSecurityAsser tion.cs file with the following code, to create your custom security policy assertion: 'VB Imports Imports Imports Imports Imports Imports
System.Xml
System.Collections.Generic
Microsoft.Web.Services3
Microsoft.Web.Services3.Design
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
Public Class CustomSecurityAssertion
Inherits SecurityPolicyAssertion
Private usn As String = Nothing
Private pwd As String = Nothing
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal userName As String, ByVal password As String)
428
Chapter 10
WSE Security
MyBase.New() Me.usn = userName
Me.pwd = password
End Sub Public ReadOnly Property UserName() As String Get Return Me.usn End Get End Property Public ReadOnly Property Password() As String Get Return Me.pwd End Get End Property Public Overrides Function CreateClientInputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Return New ClientFilterIn(Me) End Function Public Overrides Function CreateClientOutputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Return New ClientFilterOut(Me) End Function Public Overrides Function CreateServiceInputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Return New ServiceFilterIn(Me) End Function Public Overrides Function CreateServiceOutputFilter(ByVal context As _ Microsoft.Web.Services3.Design.FilterCreationContext) As _ Microsoft.Web.Services3.SoapFilter Return Nothing
End Function
Public Overrides Sub ReadXml(ByVal reader As XmlReader, _ ByVal extensions As IDictionary(Of String, Type)) ' Was an XmlReader object passed? If reader Is Nothing Then Throw New ArgumentNullException( _ "XmlReader parameter cannot be null")
Lesson 2: Custom Policies
End If ' Was an IDictionary object passed? If extensions Is Nothing Then Throw New ArgumentNullException( _ "IDictionary parameter cannot be null") End If Dim elementName As String = Nothing ' Loop through extensions For Each extensionName As String In extensions.Keys ' Our extension? If extensions(extensionName) Is _ GetType(CustomSecurityAssertion) Then ' Save the extension name elementName = extensionName Exit For
End If
Next
' Read the start element
reader.ReadStartElement(elementName)
' Do all other processing here, including retrieving ' custom elements and attributes if needed End Sub End Class Public Class ServiceFilterIn Inherits ReceiveSecurityFilter Private parentAssertion As CustomSecurityAssertion = Nothing Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, False) Me.parentAssertion = parentAssertion
End Sub
Public Overrides Sub ValidateMessageSecurity(ByVal envelope As _ Microsoft.Web.Services3.SoapEnvelope, _ ByVal security As Microsoft.Web.Services3.Security.Security) Dim signed As Boolean = False
Dim encrypted As Boolean = False
If Not security Is Nothing Then ' Loop through collection of signatures and encryption keys For Each element As ISecurityElement In security.Elements ' Is this an XML signature?
429
430
Chapter 10
WSE Security
If TypeOf element Is MessageSignature Then ' Cast to XML Signature element Dim signature As MessageSignature = _ CType(element, MessageSignature) ' Is body signed? If ((SignatureOptions.IncludeSoapBody And _ signature.SignatureOptions) = _ SignatureOptions.IncludeSoapBody) Then ' Is message signed with UsernameToken? If (TypeOf signature.SigningToken _ Is UsernameToken) Then signed = True End If End If End If ' Is this encrypted data? If TypeOf element Is EncryptedData Then Dim encData As EncryptedData = _ CType(element, EncryptedData) encrypted = True End If Next End If If Not signed OrElse Not encrypted Then Throw New SecurityFault("Message does not contain " & _ “UsernameToken and/or message isn't encrypted") End If End Sub End Class Public Class ServiceFilterOut
Inherits SendSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion) MyBase.New(parentAssertion.ServiceActor, False) End Sub Public Overrides Sub SecureMessage(ByVal envelope As _ Microsoft.Web.Services3.SoapEnvelope, _ ByVal security As Microsoft.Web.Services3.Security.Security) End Sub
End Class
Public Class ClientFilterIn
Inherits ReceiveSecurityFilter
Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
Lesson 2: Custom Policies
MyBase.New(parentAssertion.ServiceActor, True)
End Sub
Public Overrides Sub ValidateMessageSecurity(ByVal envelope As _
Microsoft.Web.Services3.SoapEnvelope, _
ByVal security As Microsoft.Web.Services3.Security.Security)
End Sub End Class Public Class ClientFilterOut Inherits SendSecurityFilter Private parentAssertion As CustomSecurityAssertion = Nothing Public Sub New(ByVal parentAssertion As CustomSecurityAssertion)
MyBase.New(parentAssertion.ServiceActor, True)
Me.parentAssertion = parentAssertion
End Sub
Public Overrides Sub SecureMessage(ByVal envelope As _
Microsoft.Web.Services3.SoapEnvelope, _
ByVal security As Microsoft.Web.Services3.Security.Security)
' Create token for signing and encryption
Dim userToken As New UsernameToken(parentAssertion.UserName, _
parentAssertion.Password, PasswordOption.SendPlainText)
' Add token to SOAP security header
security.Tokens.Add(userToken)
' Sign SOAP message using an XML signature object
Dim mesSignature As New MessageSignature(userToken)
security.Elements.Add(mesSignature)
' Encrypt message body
Dim encData As New EncryptedData(userToken)
' Add encrypted data to collection of signatures and
' encryption keys
security.Elements.Add(encData)
End Sub End Class //C# using using using using using using using
System;
System.Data;
System.Configuration;
System.Collections.Generic;
System.Web;
System.Xml;
Microsoft.Web.Services3;
431
432
Chapter 10
WSE Security
using Microsoft.Web.Services3.Design; using Microsoft.Web.Services3.Security; using Microsoft.Web.Services3.Security.Tokens; namespace MSLearning.TK70_529.Chapter10.Lesson2 { /// /// Summary description for CustomSecurityAssertion /// public class CustomSecurityAssertion : SecurityPolicyAssertion { private string usn = null; private string pwd = null; public CustomSecurityAssertion() : base()
{
}
public CustomSecurityAssertion(string userName, string password) : base() { this.usn = userName; this.pwd = password; } public string UserName {
get
{
return this.usn; } } public string Password {
get
{
return this.pwd; } } public override SoapFilter CreateClientInputFilter(FilterCreationContext context) { return new ClientFilterIn(this); } public override SoapFilter CreateClientOutputFilter(FilterCreationContext context) { return new ClientFilterOut(this);
Lesson 2: Custom Policies
} public override SoapFilter CreateServiceInputFilter(FilterCreationContext context) { return new ServiceFilterIn(this); } public override SoapFilter CreateServiceOutputFilter(FilterCreationContext context) { return null; } public override void ReadXml(XmlReader reader,
IDictionary extensions)
{
// Was an XmlReader object passed?
if (reader == null)
throw new ArgumentNullException( "XmlReader parameter cannot be null"); // Was an IDictionary object passed? if (extensions == null) throw new ArgumentNullException( "IDictionary parameter cannot be null"); string elementName = null; // Loop through extensions foreach (string extensionName in extensions.Keys) { // Our extension? if (extensions[extensionName] == typeof(CustomSecurityAssertion)) { // Save the extension name elementName = extensionName; break;
}
}
// Read the start element
reader.ReadStartElement(elementName);
// Do all other processing here, including retrieving // custom elements and attributes if needed } } public class ServiceFilterIn : ReceiveSecurityFilter { CustomSecurityAssertion parentAssertion = null;
433
434
Chapter 10
WSE Security
public ServiceFilterIn(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, false) { this.parentAssertion = parentAssertion; } public override void ValidateMessageSecurity( Microsoft.Web.Services3.SoapEnvelope envelope, Microsoft.Web.Services3.Security.Security security) { bool signed = false; bool encrypted = false; if (security != null) { // Loop through collection of signatures // and encryption keys foreach (ISecurityElement element in security.Elements) { // Is this an XML signature? if (element is MessageSignature) { // Cast to XML Signature element MessageSignature signature = (MessageSignature) element; // Is body signed? if ((SignatureOptions.IncludeSoapBody & signature.SignatureOptions) == SignatureOptions.IncludeSoapBody) { // Is message signed with UsernameToken? if (signature.SigningToken is UsernameToken) { signed = true; } } } // Is this encrypted data? if (element is EncryptedData) { EncryptedData encData = (EncryptedData) element; encrypted = true; } } } if (!signed || !encrypted) throw new SecurityFault("Message does not contain " + "UsernameToken and/or message isn't encrypted");
Lesson 2: Custom Policies
} } public class ServiceFilterOut : SendSecurityFilter { public ServiceFilterOut(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, false)
{
}
public override void SecureMessage(
Microsoft.Web.Services3.SoapEnvelope envelope,
Microsoft.Web.Services3.Security.Security security)
{ } } public class ClientFilterIn : ReceiveSecurityFilter { public ClientFilterIn(CustomSecurityAssertion parentAssertion) : base(parentAssertion.ServiceActor, true)
{
}
public override void ValidateMessageSecurity(
Microsoft.Web.Services3.SoapEnvelope envelope,
Microsoft.Web.Services3.Security.Security security)
{ } } public class ClientFilterOut : SendSecurityFilter { private CustomSecurityAssertion parentAssertion = null; public ClientFilterOut(CustomSecurityAssertion parentAssertion)
: base(parentAssertion.ServiceActor, true)
{
this.parentAssertion = parentAssertion;
}
public override void SecureMessage(
Microsoft.Web.Services3.SoapEnvelope envelope,
Microsoft.Web.Services3.Security.Security security)
{
// Create token for signing and encryption
UsernameToken userToken = new
UsernameToken(parentAssertion.UserName, parentAssertion.Password, PasswordOption.SendPlainText); // Add token to SOAP security header
security.Tokens.Add(userToken);
435
436
Chapter 10
WSE Security
// Sign SOAP message using an XML signature object MessageSignature mesSignature = new MessageSignature(userToken); security.Elements.Add(mesSignature); // Encrypt message body
EncryptedData encData = new EncryptedData(userToken);
// Add encrypted data to collection of signatures and
// encryption keys
security.Elements.Add(encData);
}
}
}
5. Set the Root namespace (Visual Basic) or Default namespace (C#) for the Cus tomPolicyAssertion project to MSLearning.TK70_529.Chapter10.Lesson2. 6. To the CustomPolicyWS project, add a reference to the CustomPolicyAssertion project. 7. Add a new Visual Basic or C# Console Application project named CustomPolicyClient to the solution. 8. Set the CustomPolicyClient project as the startup project, and WSE 3.0 enable the project. 9. Set the Root namespace (Visual Basic) or Default namespace (C#) for the Cus tomPolicyClient project to MSLearning.TK70_529.Chapter10.Lesson2. 10. To the CustomPolicyClient project add a reference to the CustomPolicyAssertion project. 11. Using the Add Web Reference dialog box, add a reference to the CustomPolicyWS Web service and name it CustomPolicyWS. 12. In the CustomPolicyClient project, replace the code in Module1.vb or Pro gram.cs with the following code (make sure you replace the user name and pass word for the UsernameToken with values that are valid on your system): 'VB Imports Imports Imports Imports
Microsoft.Web.Services3
Microsoft.Web.Services3.Design
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
Module Module1 Sub Main() Dim custPolicyWS As New CustomPolicyWS.ServiceWse() ' Create custom assertion Dim assertion As New _ CustomSecurityAssertion("WindowsUserName", _
Lesson 2: Custom Policies
437
"password") ' Create policy and add custom assertion
Dim pol As New Policy()
pol.Assertions.Add(assertion)
' Apply policy to Web service proxy
custPolicyWS.SetPolicy(pol)
' Call Web service method and display result
Console.WriteLine(custPolicyWS.HelloWorld())
End Sub
End Module
//C# using using using using using using using
System;
System.Collections.Generic;
System.Text;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Design;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
namespace MSLearning.TK70_529.Chapter10.Lesson2 {
class Program
{
static void Main(string[] args)
{
CustomPolicyWS.ServiceWse custPolicyWS = new CustomPolicyWS.ServiceWse();
// Create custom assertion CustomSecurityAssertion assertion = new CustomSecurityAssertion("WindowsUserName", "password"); // Create policy and add custom assertion Policy pol = new Policy(); pol.Assertions.Add(assertion); // Apply policy to Web service proxy
custPolicyWS.SetPolicy(pol);
// Call Web service method and display result
Console.WriteLine(custPolicyWS.HelloWorld());
}
}
}
13. In the CustomPolicyWS project, replace the code in WSE with the following code, which creates a new policy named servicePolicy, which uses the CustomSe
438
Chapter 10
WSE Security
curityAssertion class you just created:
14. In the CustomPolicyWS project, apply the Policy attribute to the Service class: 'VB _ _ _ _ Public Class Service
Inherits System.Web.Services.WebService
//C# [WebService(Namespace = "http://contoso.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[Policy("servicePolicy")]
public class Service : System.Web.Services.WebService
{
15. Run the solution and watch the output “Hello World” in the console window. Press Enter to exit the console window. 16. To watch the signed and encrypted messages going from the client to the Web service, in Solution Explorer, right-click the CustomPolicyWS project, and click WSE Settings 3.0. Ignore the warning about not being able to load the CustomPolicyAssertion assembly. 17. In the WseConfigEditor3 tool, click the Diagnostics tab, select Enable Message Trace, and then click OK. 18. Rerun the solution and again watch the output “Hello World” in the console window. Press Enter to exit the console window. 19. In Solution Explorer, right-click the CustomPolicyWS project, and click Refresh Folder. Notice how two new files, InputTrace.webinfo and OutputTrace.webinfo, have been created by the WSE 3.0 infrastructure. Open the InputTrace.webinfo file and see the contents of the incoming messages.
Lesson 2: Custom Policies
439
Lesson Summary ■
The identity of a recipient or sender as well as verification that a transmission has not been tampered with can be accomplished through digital signatures.
■
The process of obscuring a message so that unauthorized parties cannot view it is known as encryption. Digital signatures and encrypted messages can be used separately, but used together they provide a very powerful framework for secur ing data.
■
The process of taking an encrypted message and making it readable is known as decryption.
■
To prevent unauthorized parties from viewing the contents of a message, that message must be encrypted.
■
By default, WSE 3.0 encryption only encrypts the body part of the message. If sensitive data is contained in the message outside of the body, the data will be accessible to unauthorized third parties unless it too is encrypted.
■
Symmetric encryption algorithms, also known as private key algorithms, neces sitate both the sender and the recipient having access to the same private key. Because this key must be distributed to at least two parties to be useful, symmet ric algorithms are generally considered less secure than their asymmetric coun terparts.
■
Asymmetric algorithms, also known as public key algorithms, only require the sender to have access to a public key. The sender uses this public key to encrypt messages that can only be decrypted by someone with access to the correspond ing private key.
■
The IssueSecurityContextTokenRequest method of the SecurityContextTokenService class can be used to address both the and the elements of a request.
■
A custom policy assertion should be created when one of the turnkey security assertions doesn’t meet the needs of your application.
■
A custom policy assertion must be derived from either the PolicyAssertion or Secu rityPolicyAssertion class.
440
Chapter 10
WSE Security
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Custom Policies.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What is the primary difference between symmetric and asymmetric algorithms? (Choose the best answer.) A. Symmetric algorithms are considered more secure than their asymmetric counterparts. B. Asymmetric algorithms are considered more secure than their symmetric counterparts. C. Symmetric algorithms are the primary mechanism involved in creating dig ital signatures and have little value in terms of data hiding. D. Asymmetric algorithms are the primary mechanism involved in creating digital signatures and have little value in terms of data hiding. 2. By default, which element of a request is protected when a message is encrypted? (Choose the best answer.) A. The body part B. The header part of the request C. The element, if and only if it’s present D. The element, if and only if it’s present 3. Which of the following statements are true with respect to encrypting and decrypting SOAP requests? (Select all that apply.) A. The header or the body parts can be encrypted. B. A UsernameToken can be used. C. Certificates can be used to handle the key exchange. D. Both asymmetric and symmetric algorithms can be used.
Lesson 3: Message Filters
441
Lesson 3: Message Filters In Lesson 2 you were introduced to filters in the SOAP messaging processing pipeline. In this lesson we’ll take a slightly different approach to message filters. However, for the WSE 3.0 message filters, you can refer back to Lesson 2, and Lab 2 in particular. Message filters warrant a section of their own precisely because they are one of the major “breaking changes” between WSE 2.0 and WSE 3.0. In short, filters allow an application to define precisely how outgoing messages should be handled (secured, for instance) as well as specifying how incoming messages should be handled. After this lesson, you will be able to: ■
Migrate a WSE 2.0 InputFilter or OutputFilter to WSE 3.0.
■
Create a new filter.
■
Create a policy assertion to handle the filter.
Estimated lesson time: 35 minutes
The way filters are implemented has changed drastically, as evidenced by the follow ing text from the “How to: Migrate Custom Filters to Custom Policy Assertions” article in the MSDN documentation (http://msdn.microsoft.com/library/default.asp?url=/ library/en-us/wse3.0/html/4ffe5169-ec97-47ae-9df8-0bca49421777.asp): “Custom fil ters that were written for previous versions of the Web Services Enhancements for Microsoft .NET (WSE) must be migrated to custom policy assertions for WSE 3.0. Pol icy assertions are different from WSE 2.0 custom filters in that custom filters filter only a portion of the SOAP messages exchanged between a client and a Web ser vice….” By simply examining WseConfigEditor tool for both WSE 2.0 and WSE 3.0 (shown in Figure 10-5), the differences should be apparent (in case they aren’t, notice that the tabs are different).
442
Chapter 10
WSE Security
Figure 10-5 WseConfigEditor tabs in WSE 2.0 and WSE 3.0
Message Filters Overview Message filters help to enhance security in Web services by controlling what is trans mitted in the message and what is allowed to be received. They serve, as their name implies, to filter data. The process of how they work is fairly straightforward and is illustrated in Figure 10-6. Output Filters
Input Filters WSE Enabled Web Service
Soap Message Sender Input Filters
Output Filters
Figure 10-6 Message filter flow
Because you can create your own filters, there is no reasonable limit on how much granularity you can employ with security. Essentially, if you want it to happen, it can. The more complex the rules, the more complex the code, but this correlation is cer tainly not uncommon and no more burdensome than anything else.
Lesson 3: Message Filters
443
Implementation and Migration If an application is being migrated from WSE 2.0 to WSE 3.0, a few steps must be fol lowed. If an application is starting from scratch, then the same steps need to be fol lowed with one exception: In the latter case, new classes are actually created, whereas in the former case, existing definitions need to be changed. In both cases, the process consists of the following: 1. If this is a new application, create a class that derives from SoapFilter, ReceiveSe curityFilter, or SendSecurityFilter. If the application is being ported, change the existing filter’s base class to one of the same three classes. Table 10-3 describes what purpose each of these base classes serves. Table 10-3 The SoapFilter, ReceiveSecurityFilter, and SendSecurityFilter Classes
Class Name
Usage
SoapFilter
Base class from which all WSE 3.0 filters must derive; replaces input and output filters in WSE 2.0; used pri marily for filters that do not secure SOAP messages.
ReceiveSecurityFilter
Base class from which all filters that handle receiving and securing SOAP messages should derive.
SendSecurityFilter
Base class from which all filters that handle the trans mission and securing of SOAP messages should derive.
2. In new applications, specify a particular method to handle processing. For migrations, change the return type of the ProcessMessage method, depending on what tasks the filter is to perform. Table 10-4 illustrates when each should be used. Table 10-4 Add Methods or Specify Return Types for ProcessMessage Method
Action
Usage
Filters that do not secure SOAP messages
Use SoapFilterResult as the return type. Use SoapFilterResult.Continue to ensure backward compatibility.
Output filters that secure SOAP messages
Add a SecureMessage method.
444
Chapter 10
WSE Security
Table 10-4 Add Methods or Specify Return Types for ProcessMessage Method
Action
Usage
Input filters that secure SOAP messages
Add a ValidateMessageSecurity method.
3. Create a custom security assertion. 4. In the assertion created in step 3, return a new instance of the custom filter in the corresponding method (CreateClientInputFilter, CreateClientOutputFilter, CreateServiceInputFilter, or CreateServiceOutputFilter).
Using the SoapFilter Class At the risk of being repetitive, please note that classes derived from SoapFilter are not to be used if securing a SOAP message is necessary (see Lesson 2 for more on filtering with a custom security policy assertion). Hence, the primary usage of such classes will be to take advantage of exisiting functionality—for instance, tracing. With that said, all that’s necessary to implement a class that derives from SoapFilter is the inheritance definition and the overriding of the ProcessMessage method. (The key areas mentioned in the preceding steps are shown in bold.) 'VB Imports Imports Imports Imports
Microsoft.Web.Services3 Microsoft.Web.Services3.Design Microsoft.Web.Services3.Security Microsoft.Web.Services3.Security.Tokens
Public Class DemoSoapFilter Inherits SoapFilter Public Overrides Function ProcessMessage( _
ByVal envelope As SoapEnvelope) As SoapFilterResult
Me.Trace("Message you want to trace") Return SoapFilterResult.Continue End Function End Class //C# using using using using
Microsoft.Web.Services3; Microsoft.Web.Services3.Design; Microsoft.Web.Services3.Security; Microsoft.Web.Services3.Security.Tokens;
public class DemoSoapFilter : SoapFilter { public DemoSoapFilter() {}
Lesson 3: Message Filters
445
public override SoapFilterResult ProcessMessage(
SoapEnvelope envelope)
{
this.Trace("Message I want to trace");
return SoapFilterResult.Continue;
} }
Using the ReceiveSecurityFilter Class For classes that will handle the reception of messages that are secured, the ReceiveSe curityFilter class must be used. The class that you derive from must provide additional constructor logic to match the base class’s definition. (The key areas mentioned in the preceding steps are shown in bold.) 'VB Imports Imports Imports Imports
Microsoft.Web.Services3 Microsoft.Web.Services3.Design Microsoft.Web.Services3.Security Microsoft.Web.Services3.Security.Tokens
Public Class DemoReceiveSecurityFilter Inherits ReceiveSecurityFilter Public Overrides Sub ValidateMessageSecurity( _
ByVal envelope As SoapEnvelope, ByVal security As Security)
'Implement validation here End Sub Public Sub New(ByVal serviceActor As String, ByVal isClient As Boolean)
MyBase.New(serviceActor, isClient)
End Sub
End Class //C# using System;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
public class DemoReceiveSecurityFilter : ReceiveSecurityFilter
{
public DemoReceiveSecurityFilter(String serviceActor, Boolean isClient) : base(serviceActor, isClient)
{
}
public override void ValidateMessageSecurity(SoapEnvelope envelope,
Security security)
{
//Implement validation here } }
446
Chapter 10
WSE Security
Using the SendSecurityFilter Class For classes that will handle transmission of messages that are secured, the SendSecu rityFilter class must be used. The class that you derive from must provide additional constructor logic to match the base class’s definition. (The key areas mentioned in the preceding steps are shown in bold.) 'VB Imports Imports Imports Imports
Microsoft.Web.Services3
Microsoft.Web.Services3.Design
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
Public Class DemoSendSecurityFilter Inherits SendSecurityFilter Public Overrides Sub SecureMessage(ByVal envelope As SoapEnvelope, _ ByVal security As Security) 'Process message here End Sub Public Sub New(ByVal serviceActor As String, ByVal isClient As Boolean) MyBase.New(serviceActor, isClient) End Sub End Class //C# using using using using using
System;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Design;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
public class DemoSendSecurityFilter : SendSecurityFilter
{
public DemoSendSecurityFilter(String serviceActor, Boolean isClient) : base(serviceActor, isClient)
{
}
public override void SecureMessage(SoapEnvelope envelope, { //Implement validation here }
Security security)
}
Lab 3: Creating a Custom Filter In this lab, you create a custom message filter. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder.
Lesson 3: Message Filters
1. Open Visual Studio 2005 and create a blank solution named DemoFilter. 2. Add a new Visual Basic or C# Web service project named DemoFilter. 3. Add a reference to the Microsoft.Web.Services3.dll assembly. 4. Add a class named DemoSoapFilter to the project in the App_Code folder. 5. Modify the class so that it looks like the following: 'VB Imports Imports Imports Imports Imports Imports Imports Imports Imports Imports
Microsoft.VisualBasic
System
System.Collections.Generic
System.Text
System.Xml
System.Security.Cryptography.X509Certificates
Microsoft.Web.Services3
Microsoft.Web.Services3.Design
Microsoft.Web.Services3.Security
Microsoft.Web.Services3.Security.Tokens
Public Class DemoSoapFilter
Inherits SoapFilter
Public Overrides Function ProcessMessage( _
ByVal envelope As SoapEnvelope) _
As Microsoft.Web.Services3.SoapFilterResult
Me.Trace("Message you want to trace")
Return SoapFilterResult.Continue
End Function
End Class
//C# using using using using using using using using using using
System.Web;
System.Web.Services;
System.Web.Services.Protocols;
System.Collections.Generic;
System.Text;
System.Security.Cryptography.X509Certificates;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Design;
Microsoft.Web.Services3.Security;
Microsoft.Web.Services3.Security.Tokens;
public class DemoSoapFilter : SoapFilter { public DemoSoapFilter() {} public override SoapFilterResult ProcessMessage(SoapEnvelope envelope) { this.Trace("Message I want to trace");
447
448
Chapter 10
WSE Security
return SoapFilterResult.Continue;
}
}
6. Compile the application and verify that it completes. At this point, you now should have a working filter that can be consumed in a Web service.
Lesson Summary ■
Message filters represent a major area of security functionality in WSE but intro duce breaking changes between versions 2.0 and 3.0.
■
Classes that are to be used as filters in WSE 3.0 must inherit from the SoapFilter, ReceiveSecurityFilter, or SendSecurityFilter classes.
■
The SoapFilter class should be used to process tasks that do not involve securing SOAP messages.
■
Classes derived from SoapFilter must implement the ProcessMessage method and return SoapFilterResult.Continue to ensure that pre-existing client code can still call it.
■
Classes derived from the SendSecurityFilter class should implement the SecureMessage method.
■
Classes derived from the ReceiveSecurityFilter class should implement the Vali dateMessageSecurity method.
■
Because filters are no longer just added, in order to work in WSE 3.0, a custom policy assertion must be created to handle their implementation.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “Message Filters.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which of the following are valid base classes from which custom filters can be derived? (Select all that apply.) A. SoapFilter
Lesson 3: Message Filters
449
B. ReceiveSecurityFilter C. SendSecurityFilter D. ProcessMessage 2. Classes that derive from the SendSecurityFilter class should implement which of the following methods? (Choose the best answer.) A. ProcessMessage B. ValidateMessageSecurity C. SecureMessage D. CreateClientOutputFilter
450
Chapter 10 Review
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
The identity of a recipient or sender as well as verification that a transmission has not been tampered with can be accomplished through digital signatures.
■
The process of obscuring a message so that unauthorized parties cannot view it is known as encryption. Digital signatures and encrypted messages can be used separately, but used together they provide a very powerful framework for secur ing data.
■
The process of taking an encrypted message and making it readable is known as decryption.
■
To prevent unauthorized parties from viewing the contents of a message, a mes sage must be encrypted.
■
By default, WSE 3.0 encryption only encrypts the body part of the message. If sensitive data is contained in the message outside of the body, it will be accessi ble to unauthorized third parties unless it too is encrypted.
■
Symmetric encryption algorithms, also known as private key algorithms, neces sitate both the sender and the recipient having access to the same private key. Because this key must be distributed to at least two parties to be useful, symmet ric algorithms are generally considered less secure than their asymmetric coun terparts.
■
Asymmetric algorithms, also known as public key algorithms, only require the sender to have access to a public key. The sender uses this public key to encrypt messages that can only be decrypted by someone with access to its matching pri vate key.
Chapter 10 Review
451
■
The IssueSecurityContextTokenRequest method of the SecurityContextTokenService class can be used to address both the and the elements of a request.
■
Configuration files can be used to control and manipulate virtually every aspect of custom policies.
■
The element can be used to specify endpoints of the application.
■
At a minimum, a policy expression file must contain a element, an element, and a element (which must contain , , and elements). In addition, each custom policy must be added.
■
The fileName attribute of the element of a Web.config file can be used to point the application to a custom policy expression file.
■
Three components can be configured under the element: the , the , and the .
■
Multiple policies can be added to an application by specifying additional elements.
■
If multiple policies are configured, the WseConfigEditor3 can be used to edit the configuration file manually.
■
If a policy is added manually, great care must be taken to ensure that element names are spelled correctly.
■
If multiple policies are configured, each must contain a unique name.
■
Assertions must be added to policy files to be of any use.
■
The WseConfigEditor3 can be used to manage most elements of WSE configu ration.
■
In previous versions of WSE, the WseConfigEditor was only available through individual projects. Starting with WSE 3.0, the tool can be used within Visual Studio 2005 or as a stand-alone application.
■
The WseConfigEditor3 can be used to manage general settings, security settings, policy settings, routing, token issuing, diagnostics, and messaging.
■
If a custom policy was implemented for an application, the Policy tab can be used to manage it. This feature provides access to a Security Settings Wizard and has the abilty to provide very intricate policy configuration.
■
There are four authentication modes available with custom policy: Anonymous, Windows, Certificate, and Username.
452
Chapter 10 Review
■
Anonymous authentication is the simplest mode to use but is considered by many to be the least secure of the available modes.
■
Windows authentication uses Kerberos (a proprietary Microsoft format) and provides both a high level of security and reduced administration complexity.
■
By default, two types of applications can be configured: client application and services.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
asymmetric algorithm
■
digital signature
■
integrity
■
policy assertion
■
policy expression
■
policy framework
■
symmetric algorithm
■
timestamp
Case Scenario In the following case scenario you apply what you’ve learned about how to use secu rity features provided by WSE 3.0. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: How Secure Is Secure Enough? Having strong and flexibile security policies in place is often critical in Web services. After all, the Web service is an entry point into your corporation and, in most instances, one that needs to be secure. In the following scenario, making these deter minations is addressed.
Chapter 10 Review
453
Interviews Following is a list of company personnel interviewed and their statements: “What we’ve accomplished with respect to adding func tionality for users has been nothing short of amazing. Business has been great and not only is it increasing quickly, but our support calls are down and our cus tomers have never been happier. The main two risks we face, from my perspec tive, are service disruptions and a security breach. I want to do whatever is necessary to ensure neither happens. My main objective right now is to deter mine how good we’re doing in terms of security and start providing documenta tion for our customers about our security story.”
■ IT Department Head
“We’ve gotten through most of our technical challenges and our customers are delighted. Because we’re ahead of the curve, we really need to focus on product documentation so we can show our customers our infrastructure and hopefully use what we’re doing right to our advantage. I want to start developing a series of white papers with an emphasis on our security configuration. Is WSE 3.0 something that is recognized in the industry? Are the algorithms held in high regard in the academic and professional communities? What specifics can we highlight?”
■ Lead Business Analyst
“Financially, things couldn’t be better and we really need to take advantage of that. Sales are up, costs are down, and our existing customers are very pleased. Like my IT Department Head mentioned, the two things we have nightmares about are service interruptions and security breaches. I’ve directed a large share of resources toward documenting our service infrastructure. We need to do the same with respect to security.”
■ CIO
Questions Answer the following questions for your manager: 1. Are the security features provided by WSE held in high regard in the software community? 2. Within the parameters of what we do, how does WSE contribute to our security story? 3. Can white papers be developed about the security story that highlight the fea tures of WSE and our specific implementation?
454
Chapter 10 Review
Suggested Practices To successfully master the objectives covered in this chapter, complete the following tasks: For this task, you should complete at least Practices 1 and 2. You can do Practice 3 for a more in-depth understanding of WSE 3.0. ■ Practice 1
Create a Web service that uses WSE 3.0 that can decrypt encrypted
messages.
Create a new Web service consumer that uses WSE 3.0. Design this application
so that it can encrypt a message body using either an asymmetric or symmetric
algorithm.
Write down three or more desired objectives that you might have for a custom security policy. After analyzing these objectives, create a custom policy that implements these features. After the policy is created, build a Web service consumer and a Web service client that can use the policy you just built. To ensure that you understand how this task is accomplished, create the policy manually, and then use the WseConfigEditor3 tool to re-create the policy.
■ Practice 2
Create a custom policy and add it to a Web Service. From there, spec ify a filter or filters for the service to use via the policy file.
■ Practice 3
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just one exam objective, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely simulates the expe rience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the “How to Use the Practice Tests” sec tion in this book’s Introduction.
Chapter 11
Messaging and Routing
This chapter focuses on the ways you can expand what you do with Web Services Enhancements (WSE) through messaging and routing. WSE Messaging allows you to add capabilities to traditional Web services such as one-way or two-way (bidirec tional) messaging and attachments. You can also use WSE messaging to specify that the Web service use an alternative communication protocol and increase the effi ciency of message transfers. A WSE router can be implemented for the purpose of directing requests to the appro priate servers, Web services, or both, including different versions of these. Once the router application is created, it can be configured to route requests for one or more Web services. Instead of accessing the Web services directly, outside clients make requests to the WSE router. Lesson 3 focuses on how to add and verify security credentials. In Chapter 9, “Web Services Enhancements 3.0 in Client and Server Applications,” you were introduced to using digital signatures to ensure message integrity. When using an intermediary such as a WSE router, you need to add credentials using WSE instead of assigning them to the proxy as you did in Chapter 9. In this chapter you learn how to add the security credentials and then verify those credentials.
Exam objectives in this chapter: ■
■
Implement WSE SOAP messaging. ❑
Select a protocol.
❑
Implement one-way SOAP messaging.
❑
Implement bidirectional SOAP messaging.
❑
Send the attachments from a Web service application.
❑
Receive attachments in a client application.
Route SOAP messages by using a WSE router. ❑
Create a WSE router application.
❑
Configure a WSE router application.
❑
Configure a referral cache for routing. 455
456
Chapter 11
■
Messaging and Routing
Add and verify security credentials. ❑
Add security credentials to a SOAP message.
❑
Verify security credentials.
Lessons in this chapter: ■
Lesson 1: How to Configure WSE Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . 457
■
Lesson 2: How to Create a WSE Router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
■
Lesson 3: How to Add and Verify Security Credentials . . . . . . . . . . . . . . . . . . 494
Before You Begin To complete the lessons in this chapter, you must have ■
A computer that meets or exceeds the minimum hardware requirements listed in the Introduction of the book.
■
Microsoft Visual Studio 2005 and the .NET Framework 2.0.
■
Knowledge of programming in Microsoft Visual Basic or C# and XML.
■
Downloaded and installed the Web Services Enhancements (WSE) 3.0 Service Pack 2 for Microsoft .NET.
■
Read and completed the labs from Chapter 1, “Creating an XML Web Service,” regarding creating an Extensible Markup Language (XML) Web service.
■
Read and completed the labs from Chapter 9 regarding WSE in client and server applications.
Lesson 1: How to Configure WSE Messaging
457
Lesson 1: How to Configure WSE Messaging This lesson explores how to use WSE Messaging to extend the functionality of your Web services. Specifically, this lesson will first cover how you can specify a communi cation protocol. It will also cover how you can implement both one-way and two-way (bidirectional) messaging. Finally, it will cover how to use Message Transmission Optimization Mechanism (MTOM) to send and receive attachments. After this lesson, you will be able to: ■
Select the protocol.
■
Implement one-way SOAP messaging.
■
Implement two-way SOAP messaging.
■
Send attachments from the XML Web service application.
■
Receive attachments in the client application.
Estimated lesson time: 45 minutes
WSE Soap Messaging One of the cornerstones of Service Oriented Architecture (SOA) is the notion of mes sages. Messaging has become increasingly popular with developers recently and is a critical component of Microsoft’s future direction with respect to how applications and services communicate with each other. Messaging in WSE 3.0 has some major enhancements over previous versions in that it can be accomplished exclusively through the Transmission Control Protocol (TCP) negating the need for an HTTP server. In addition, data being transmitted does not have to be sent as XML and can instead be sent in a binary format. Because XML greatly increases the data size and because TCP is considered a more efficient protocol, by combining the two, a tremen dous amount of efficiency can be achieved. MORE INFO
WSE Hands On Lab for messaging
MSDN offers a Hands On Lab that directly concerns WSE Messaging. It covers both basic and advanced scenarios and would be an excellent aid in preparation for the exam. The Hands On Lab is available for download at http://www.microsoft.com/downloads/details.aspx?familyid=0e5491c1 8bde-4fff-88c4-8e3dc102fad6&displaylang=en.
458
Chapter 11
Messaging and Routing
Selecting a Communication Protocol WSE 3.0–enabled Web services can make use of both the traditional HTTP protocol as well as the faster TCP protocol. Which one you select is really a matter of where and how the Web service should be accessed. HTTP traffic travels through most firewalls, whereas TCP traffic generally requires one or more specific ports to be open. As a gen eral rule of thumb, you should consider HTTP in Internet scenarios, whereas closed intranet scenarios could make use of TCP, especially if performance is important. If you intend to use TCP as the communication protocol, you should make sure you evaluate and mitigate potential security risks. Whichever protocol you choose, you need to register a SOAP receiver. To register a receiver with HTTP, you will need to add an element in the sec tion of the web.config for your Web service. First, though, make sure your Web service project is WSE 3.0 enabled. The following code is an example of what this entry would look like, if you register a class derived from the SoapReceiver class, named DemoReceiver in the SoapReceivers namespace located in the assembly DemoRe ceiver.dll:
NOTE
What is an .ashx file?
A file with an .ashx extension is called an ASP.NET Web handler file, and it is used to handle raw HTTP requests received by ASP.NET.
If you prefer to utilize TCP as the communication protocol, then you will need to cre ate an endpoint for the receiver and use the soap:tcp prefix in the Uniform Resource Indicator (URI) that is specified. You will then register the endpoint with the instance of the custom receiver class. The code for this will go inside the application that is receiving the request, and we will see another example of this code later in this lesson. For now you just need to know that an instance of a class derived from SoapReceiver will need to be created and then added to the SoapReceivers collection. The following is an example of what this code would look like: 'VB Dim receiver As New DemoReceiver()
Dim destination As New Uri("soap.tcp://" & _
System.Net.Dns.GetHostName() & "/DemoReceiver")
Lesson 1: How to Configure WSE Messaging
459
Dim demoEndPoint As New EndpointReference(destination)
SoapReceivers.Add(demoEndPoint, receiver)
//C# DemoReceiver receiver = new DemoReceiver();
Uri destination = new Uri(
"soap.tcp://" + System.Net.Dns.GetHostName() + "/DemoReceiver" ); EndpointReference demoEndPoint = new EndpointReference(destination); SoapReceivers.Add(demoEndPoint, receiver);
The first parameter of the Uri class has been set to soap.tcp.//, because you’re using TCP in this case. Replace with http:// if you want to use HTTP as the communication protocol.
Implementing One-Way Messaging This section will cover how to implement one-way messaging, in which a message is sent from one machine to another, but communication can only occur in one direc tion. A similar concept was covered in Chapter 2, “Extending XML Services with SOAP Formatting, Custom Headers, and Extensions,” but in this case we are imple menting one-way messaging using WSE. In WSE 3.0, this is facilitated through the SoapSender (see Table 11-1) and SoapReceiver (see Table 11-2) classes. Table 11-1 Properties of the SoapSender Class
Name
Description
Channel
Retrieves the output channel for the sender.
Destination
Specifies the SOAP message receiver endpoint, which is where you indicate the communication protocol and specify the URI to be accessed.
Pipeline
Retrieves or sets the object that allows custom filtering of messages.
RequireMtom
Retrieves or sets a Boolean value that indicates whether the message must be encoded with MTOM. This is used when adding an attachment.
SessionState
Retrieves or sets an object that represents state information for a SOAP message.
460
Chapter 11
Messaging and Routing
Specifying a Sender To implement an application that can send a message, you will need to create a new SoapSender object. To do this, you will first import the required namespaces, such as in the following code: 'VB Imports Imports Imports Imports //C# using using using using using using using
System.Xml
Microsoft.Web.Services3
Microsoft.Web.Services3.Addressing
Microsoft.Web.Services3.Messaging
System;
System.Collections.Generic;
System.Text;
System.Xml;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Addressing;
Microsoft.Web.Services3.Messaging;
You will then need to specify a destination URI, which represents where the message will be sent. You will also need to specify an endpoint that corresponds to the desti nation URI, such as in the following code: 'VB Dim destinationUri As New Uri( _
"soap.tcp://" & _
System.Net.Dns.GetHostName() & "/DemoReceiver")
Dim destination As New EndpointReference(destinationUri) //C# Uri destinationUri = new Uri("soap.tcp://" +
System.Net.Dns.GetHostName() & "/DemoReceiver");
EndpointReference destination = new EndpointReference(destinationUri);
Finally, you will need to create new SoapSender and SoapEnvelope objects that are used to send the message. The following code demonstrates what this should look like: 'VB Dim sender As New SoapSender(destination)
Dim demoEnvelope As New SoapEnvelope()
demoEnvelope.Context.Addressing.Action = _
New Action("soap.tcp://" & _ System.Net.Dns.GetHostName() & "/DemoReceiver")
demoEnvelope.SetBodyObject("This is a test")
sender.Send(demoEnvelope)
//C# SoapSender sender = new SoapSender(destination);
Lesson 1: How to Configure WSE Messaging
461
SoapEnvelope demoEnvelope = new SoapEnvelope(); demoEnvelope.Context.Addressing.Action = new Action("soap.tcp://" + System.Net.Dns.GetHostName() & "/DemoReceiver"); demoEnvelope.SetBodyObject("This is a test"); sender.Send(demoEnvelope);
Specifying a Receiver Both the TCP and HTTP protocols can be used to receive messages. In both cases, a class needs to be created to handle the received message, and, in the latter case, a con figuration file entry must be made to process HTTP requests. Table 11-2 Properties of the SoapReceiver Class
Name
Description
Actor
Retrieves the actor name for the SoapReceiver, which is returned as a URI.
DispatchModel
Retrieves the dispatch model for the SoapReceiver.
Pipeline
Retrieves or sets the object that allows custom filtering of messages.
To create a class that can handle receiving the messages, use the following steps: 1. Create a new handler class that inherits from SoapReceiver (keep in mind that the System.Web, System.Web.Services, and Microsoft.Web.Services3 namespaces need to be referenced). 2. Override the Receive method, and process the message parameter according to your requirements.
Depending on the exact approach you are using to create a given remote object,
the invocation might look something like the following:
'VB Imports Imports Imports Imports
System.Xml
Microsoft.Web.Services3
Microsoft.Web.Services3.Addressing
Microsoft.Web.Services3.Messaging
Namespace DemoSoapReceivers
Public Class DemoReceiver
Inherits SoapReceiver
Protected Overloads Overrides Sub Receive( _
462
Chapter 11
Messaging and Routing
ByVal message As SoapEnvelope) Console.WriteLine("Message Received")
End Sub
End Class
End Namespace
//C# using using using using
System.Xml;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Addressing;
Microsoft.Web.Services3.Messaging;
namespace DemoSoapReceivers {
class DemoReceiver : SoapReceiver
{
protected override void Receive(SoapEnvelope message) { Console.WriteLine("Message Received"); } }
}
This additional statement must be added to the configuration file for the Web service to process HTTP requests:
With the SoapReceiver object in place, one last piece of legwork needs to be performed for an application to consume the class: An instance of the class needs to be declared and added to the Receivers collection of the application. 'VB Dim destination As Uri = New Uri("soap.tcp://" & _ System.Net.Dns.GetHostName() & "/DemoReceiver")
Dim demoEndPoint As New EndpointReference(destination)
SoapReceivers.Add(demoEndPoint, GetType(DemoSoapReceivers.DemoReceiver))
//C# Uri destination = new Uri( "soap.tcp://" + System.Net.Dns.GetHostName() + "/DemoReceiver");
EndpointReference demoEndPoint = new EndpointReference(destination);
SoapReceivers.Add(demoEndPoint, typeof(DemoSoapReceivers.DemoReceiver));
Lesson 1: How to Configure WSE Messaging
463
Implementing Two-Way (Bidirectional) Messaging As was the case with one-way messaging, two-way messaging is very straightforward. However, in this case, you will use the SoapClient (see Table 11-3) and SoapService (see Table 11-4) classes to derive from in the same way the SoapSender and SoapReceiver were used. Keep in mind that these two classes can also be used for one-way messag ing as well as two-way messaging, which is covered. Table 11-3 Properties of the SoapClient Class
Name
Description
Channel
Retrieves the output channel for the sender.
DefaultTimeout
Specifies a time in milliseconds to wait for a response from a SendRequestResponse operation for all clients. The default value is 120000, or 2 minutes.
Destination
Specifies the SOAP message receiver endpoint, which is where you indicate the communication protocol and spec ify the URI to be accessed.
Pipeline
Retrieves or sets the object that allows custom filtering of messages.
RequireMtom
Retrieves or sets a Boolean value that indicates whether the message must be encoded with MTOM. This is used when adding an attachment.
SessionState
Retrieves or sets an object that represents state informa tion for a SOAP message.
SoapVersion
Specifies a time in milliseconds to wait for a response from a SendRequestResponse operation for this specific client request. The default value is 120000, or 2 minutes.
Specifying a Sender The process for creating a sender in a two-way scenario is very similar to the one-way scenario. The following steps are all that’s necessary: 1. Create a class that inherits from SoapClient.
464
Chapter 11
Messaging and Routing
2. Add a method that accepts a SoapEnvelope as a parameter and calls the base class’s SendRequestResponse method passing in that envelope. 3. Add a constructor that accepts an EndpointReference as a parameter and pass this parameter to the base class’s constructor. 'VB Namespace Sender
Public Class TwoWaySender
Inherits SoapClient
_ Public Function RequestResponseMethod( _ ByVal envelope As SoapEnvelope) As SoapEnvelope Return MyBase.SendRequestResponse("RequestResponseMethod", _ envelope) End Function Public Sub New(ByVal destination As EndpointReference) MyBase.New(destination) End Sub End Class End Namespace //C# namespace Sender {
class TwoWaySender : SoapClient
{
[SoapMethod("RequestResponseMethod")]
public SoapEnvelope RequestResponseMethod(SoapEnvelope envelope)
{
return base.SendRequestResponse("RequestResponseMethod", envelope); } public TwoWaySender(EndpointReference destination) : base(destination) { } }
}
Specifying a Receiver To create a receiver class, a virtually identical approach to the one used in the SoapRe ceiver example in the one-way section will be used. The following steps are all that’s necessary:
Lesson 1: How to Configure WSE Messaging
465
1. Create a class that inherits from the SoapService class (see Table 11-4). Table 11-4 Properties of the SoapService Class
Name
Description
Actor
Retrieves the actor name for the inherited instance of SoapReceiver, which is returned as a URI.
DispatchModel
Retrieves the dispatch model for the inherited instance of SoapReceiver.
Pipeline
Retrieves or sets the object that allows custom filter ing of messages.
2. Add a RequestResponseMethod to handle incoming responses. 3. Decorate this method with the SoapMethod attribute. 'VB Imports Imports Imports Imports
System.Xml
Microsoft.Web.Services3
Microsoft.Web.Services3.Addressing
Microsoft.Web.Services3.Messaging
Namespace DemoReceiver
Public Class DemoService
Inherits SoapService
_ Public Function RequestResponseMethod( _ ByVal envelope As SoapEnvelope) As SoapEnvelope Dim response As SoapEnvelope = New SoapEnvelope response.SetBodyObject("Response") Return response
End Function
End Class
End Namespace
//C# using using using using
System.Xml;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Addressing;
Microsoft.Web.Services3.Messaging;
namespace DemoReceiver {
class DemoService : SoapService
{
466
Chapter 11
Messaging and Routing
[SoapMethod("RequestResponseMethod")]
public SoapEnvelope RequestResponseMethod(SoapEnvelope envelope)
{
SoapEnvelope response = new SoapEnvelope(); response.SetBodyObject("Response"); return response;
}
}
}
The approach with respect to TCP and HTTP follows the same procedures that are used in one-way calls.
Sending Attachments One of the other major changes in WSE 3.0 is the way attachments are handled. In previous versions, Dynamic Internet Message Encapsulation (DIME) was the primary vehicle used for handling attachments. In 3.0, MTOM is the primary vehicle for send ing binary data. Before selling the benefits, it’s worth taking a step back to address attachments in gen eral. Consider a situation where you wanted to send the string literal “WSE 3.0”. If you used XML as a wrapper to send this message, at a minimum you’d have the overhead associated with “WSE 3.0” and you’d have the tag that encapsulated this. Depending on the name used, the opening and closing tags could easily consume more resources than the message itself. Considering that one of the major benefits of using XML is the human-readable form it can take, it should be obvious that most descriptive names will also be resource-intensive. Now picture the same situation where something non trivial were being sent, say, a directory of Excel files. Obviously, the size of the extra data due to XML serialization could easily get quite large. So instead of encoding the request, attachments that have a smaller footprint can be used, which is the primary benefit of MTOM. However, performance isn’t the only benefit. The binary data that is being sent as an attachment can be digitally signed, which enables message verification to take place. If attachments weren’t signable, then their usefulness would be limited. After all, how much value would you assign to an attachment you couldn’t verify? In some cases, you might have no problem with this risk, but in others, it may be a deal-breaker. For those situations, digital signatures can be used. To enable a Web service to use MTOM, perform the following steps: 1. Right-click on the project, and choose the WSE Settings 3.0 menu item.
Lesson 1: How to Configure WSE Messaging
467
2. When the WSE 3.0 dialog box (see Figure 11-1) appears, on the General tab, select the Enable This Project for Web Services Enhancements and Enable Microsoft Web Services Enhancement Soap Protocol Factory check boxes. 3. Select the Messaging tab and set the Server Mode to Optional, Always, or Never.
Figure 11-1 The General tab from the WSE Settings 3.0 context menu
This will add a element to the configuration file and will include an element inside of it. Assuming you selected Always as the Server Mode, the web.config file should look like the following (the important sections are shown in bold): q21
468
Chapter 11
Messaging and Routing
The differences between the three modes are shown in the following table: Mode Name
Behavior
Optional
WSE Messages will be processed whether or not they are MTOM encoded. If any SOAP faults are encountered, they are MTOM encoded.
Always
All incoming and outgoing messages are MTOM encoded. If an incoming message is received that is not MTOM encoded, a SOAP fault will be returned.
Never
All incoming and outgoing messages are not MTOM encoded and if one comes in, a SOAP fault will be returned.
Once this is in place, the only thing that needs to be done to return binary data is to create a method with a return type of byte array. The following code demonstrates how this can be accomplished: 'VB _ Public Function GetFile(ByVal filename As String) As Byte() ' Return file here End Function //C# [WebMethod]
public byte[] GetFile(string fileName)
{
// Return file here }
Now, to build a consumer for this service, all of the work has already been performed. All that needs to be done to consume this service is to create a client application that references the Web service and calls the method that is returning the MTOM object. 'VB Sub Main()
Lesson 1: How to Configure WSE Messaging
469
Dim DemoService As New Service()
Dim ArrayValue As Byte() = DemoService.GetFile("FileName.extension")
End Sub
//C# static void Main(string[] args) {
Service DemoService = new Service();
Byte[] DemoArray = DemoService.GetFile("Filename.extension");
}
Lab 1: Data Transfer with MTOM In this lab, you’ll enable a Web service to use MTOM to send a binary file. Addition ally, you’ll create a MTOM-enabled client to receive the binary file. For the sake of sim plicity, a small image file will be transferred, but to fully test the benefits of MTOM, you can substitute the image file provided on the accompanying CD with a larger file of your choice. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. �
Exercise 1: Creating an MTOM enabled Web service
In this exercise, you’ll create a Web service by enabling MTOM; the service will return a JPEG image as an attachment. 1. Open Visual Studio 2005. 2. Select File, New, Web Site. 3. In the New Web Site dialog box, select ASP.NET Web Service as the template, and name the project file MTOMDemoService. 4. In Solution Explorer, right-click the MTOMDemoService project and choose Add Reference. On the .NET tab, add references to the System.Web.Services.dll assembly and click OK. 5. In Solution Explorer, right-click the MTOMDemoService project, and click WSE Settings 3.0. 6. In the WSE Settings dialog box, on the General tab, select the Enable This Project For Web Services Enhancements and Enable Microsoft Web Services Enhancement SOAP Protocol Factory check boxes. 7. On the Messaging tab (see Figure 11-2), click Optional in the Server Mode dropdown list box. Click OK to finish the configuration process.
470
Chapter 11
Messaging and Routing
Figure 11-2 Messaging tab, which is visible when enabling the project for Web service enhancement
8. Open the application’s web.config file and verify that the and elements have been added. Further ver ify that the Messaging element was added and that it contains an element with the serverMode attribute set to Optional. If the settings are configured cor rectly, the web.config file should resemble the following (the critical fragments are shown in bold, and the default comment sections have been removed for the sake of readability): 'VB
Lesson 1: How to Configure WSE Messaging
//C#
NOTE
Setting the Server Mode option
The default value for Server Mode is optional. Unless this setting is changed to a value other than the default, it will not appear in the web.config file. In order for the tag to appear, you must first set the value to something other than optional.
9. Open the App_Code folder and open the Service.vb or Service.cs file. 10. Import the System.IO namespace. 11. Delete the HelloWorld method, which is created by default when you create a Web service. 12. Create a method named GetVistaImage with a return type of byte array as shown here: 'VB _ Public Function GetVistaImage() As Byte()
Dim ResponseImage As Byte()
Dim ImagePath As String = AppDomain.CurrentDomain.BaseDirectory & _
"App_Data\VistaImage.jpg"
ResponseImage = File.ReadAllBytes(ImagePath)
Return ResponseImage
End Function
//C# [WebMethod(Description = "Get Demo Image")]
public Byte[] GetVistaImage()
Lesson 1: How to Configure WSE Messaging
473
{
Byte[] ResponseImage;
String ImagePath = AppDomain.CurrentDomain.BaseDirectory +
@"App_Data\VistaImage.jpg";
ResponseImage = File.ReadAllBytes(ImagePath);
return ResponseImage;
}
13. In Solution Explorer, right-click the project’s App_Data folder, and click Add Existing Item. 14. Navigate to the Images subdirectory of the Chapter 11 folder on the accompany ing CD, select the VistaImage.jpg file, and click OK to add the image to the project. 15. Rename the Web service to MtomDemoService. Change the Web service’s namespace to http://contoso.com and add the namespaces shown below. The full file definition should look like the following (again, the critical portions are shown in bold): 'VB Imports Imports Imports Imports Imports Imports Imports
System.IO
System.Web
System.Web.Services
System.Web.Services.Protocols
Microsoft.Web.Services3
Microsoft.Web.Services3.Addressing
Microsoft.Web.Services3.Messaging
_
_
_
Public Class MtomDemoService
Inherits System.Web.Services.WebService
_ Public Function GetVistaImage() As Byte() Dim responseImage As Byte() Dim imagePath As String = AppDomain.CurrentDomain.BaseDirectory & _ "App_Data\VistaImage.jpg"
responseImage = File.ReadAllBytes(imagePath)
Return responseImage
End Function
End Class //C#
using using using using
System;
System.IO;
System.Web;
System.Web.Services;
474
Chapter 11
using using using using
Messaging and Routing
System.Web.Services.Protocols;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Addressing;
Microsoft.Web.Services3.Messaging;
[WebService(Namespace = "http://contoso.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class MtomDemoService : System.Web.Services.WebService { public MtomDemoService ()
{
}
[WebMethod(Description = "Get Demo Image")] public Byte[ ] GetVistaImage(){ Byte[ ] responseImage; String imagePath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\VistaImage.jpg"; responseImage = File.ReadAllBytes(imagePath); return responseImage;
} }
16. Compile the application, run it, and select the GetVistaImage hyperlink. You’ll be directed to the GetVistaImage demo page. Click Invoke and verify that the namespace is http://contoso.com and that the return value is enclosed in a element. If done correctly, the screen should resemble Figure 11-3.
Figure 11-3 Debug Confirmation of call to the GetVistaImage method
Lesson 1: How to Configure WSE Messaging
�
475
Exercise 2: Create a Winforms client to consume the MTOM attachment
In this exercise, you’ll create a Web service client that displays a JPEG image returned as an MTOM attachment. 1. Add a new C# or Visual Basic 2005 Windows Application project to the MTOMDemoService solution, and name it MTOMDemoClient. 2. In Solution Explorer, right-click the MTOMDemoClient project and click Add Reference. On the .NET tab, add a reference to the System.Web.Services.dll assem bly and click OK. 3. In Solution Explorer, right-click the MTOMDemoClient project and click Add Web Reference. 4. Click Web Services In This Solution. 5. Select the MTOMDemoService Web service. 6. Name the reference MtomDemoService, and click Add Reference to close the dialog box. 7. In Solution Explorer, right-click the MTOMDemoClient project and click WSE Settings 3.0. 8. On the General tab, select the Enable This Project for Web Services Enhance ments check box. 9. On the Messaging tab, click Always in the Server Mode drop-down list box, click On in the Client Mode drop-down list box, and then click OK to close the dialog box. 10. Open the app.config file that was created by the WseConfigEditor tool and ver ify that each of the elements mentioned in steps 3 and 4 have been added. If con figured correctly, the app.config file should look like the following: 'VB
http://localhost:2520/MTOMDemoService/MtomDemoService.asmx
//C#
Lesson 1: How to Configure WSE Messaging
477
http://localhost:2517/MTOMDemoService/MtomDemoService.asmx
11. Select Form1 in Design view and drag a PictureBox control onto the designer. Name the PictureBox vistaImagePictureBox. Set the size to 150 x 113. 12. Drag a button onto the designer. Name the button getImageButton and set its Text property to Get Image. 13. Double-click getImageButton and insert the following code (the full class defini tion is shown): 'VB Imports Imports Imports Imports Imports Imports Imports
System.IO
System.Web
System.Web.Services
System.Web.Services.Protocols
Microsoft.Web.Services3
Microsoft.Web.Services3.Addressing
Microsoft.Web.Services3.Messaging
Public Class Form1 Private Sub getImageButton_Click(ByVal sender As System.Object, _
478
Chapter 11
Messaging and Routing
ByVal e As EventArgs) Handles getImageButton.Click Dim mtomProxy As New MtomDemoService
Dim imageStream As Byte()
imageStream = mtomProxy.GetVistaImage
Dim memStream As New MemoryStream(imageStream)
vistaImagePictureBox.Image = _
System.Drawing.Image.FromStream(memStream)
End Sub
End Class //C# using using using using using using using using using using using using using using
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Text;
System.IO;
System.Windows.Forms;
System.Web;
System.Web.Services;
System.Web.Services.Protocols;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Addressing;
Microsoft.Web.Services3.Messaging;
namespace MTOMDemoClient {
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void getImageButton_Click(object sender, EventArgs e)
{
MtomDemoService.MtomDemoService mtomProxy =
new MtomDemoService.MtomDemoService();
Byte[] imageStream = mtomProxy.GetVistaImage();
MemoryStream
memStream = new MemoryStream(imageStream);
vistaImagePictureBox.Image =
System.Drawing.Image.FromStream(memStream);
} }
}
14. In Solution Explorer, right-click the MTOMDemoClient project, and click Set as Startup Project. 15. Compile and run the application. When the form appears, click Get Image to invoke the Web service and retrieve the attachment.
Lesson 1: How to Configure WSE Messaging
479
16. If the request is processed correctly, the form should display VistaImage.jpg in the vistaImagePicture control. The form should now look like Figure 11-4.
Figure 11-4 Form appearance after call to the GetVistaImage Web method
Lesson Summary ■
WSE Messaging, available with WSE 3.0, can be used to extend the functionality available with traditional Web services.
■
WSE 3.0 allows you to specify the communication protocol. You can specify that your Web service use TCP as opposed to HTTP.
■
WSE Messaging can be used to implement one-way messaging, in which the communication occurs in both directions and uses the SoapSender and SoapReceiver classes.
■
Two-way messaging, in which the communication is allowed in both directions, uses the SoapClient and SoapService classes. These classes are similar to the SoapSender and SoapReceiver classes used for one-way messaging.
■
Attachments can be sent with SOAP messages through the use of the MTOM, which is the primary vehicle for sending binary data.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “How to Configure WSE Messaging.” The questions are also available on the companion CD if you prefer to review them in electronic form.
480
Chapter 11
Messaging and Routing
NOTE Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What two classes are needed to facilitate one-way messaging? A. SoapClient and SoapReceiver B. SoapClient and SoapService C. SoapSender and SoapReceiver D. SoapSender and SoapService 2. What steps are needed to implement a sender for a two-way messaging scenario? (Select all that apply.) A. Create a class that inherits from SoapClient. B. Create a class that inherits from SoapReceiver. C. Add a constructor that accepts a URI as a parameter. D. Add a constructor that accepts an EndpointReference object as a parameter. 3. Identify the XML that would appear in the configuration file of a project in which the Server Mode was set to Always. A.
B.
C.
D.
Lesson 2: How to Create a WSE Router
481
Lesson 2: How to Create a WSE Router This lesson explores how to create and configure a WSE router application. You first learn what a WSE router is and then step through how to create an application using Visual Studio 2005. You then configure the WSE router application by creating a con figuration file and adding handlers for each Web service that needs to be routed. Finally, you create a referral cache, which is an XML document that contains the Uni form Resource Locators (URLs) used by the WSE router application. After this lesson, you will be able to: ■
Create a WSE router application.
■
Configure the WSE router application.
■
Configure a referral cache for routing.
Estimated lesson time: 45 minutes
What Is a WSE Router? The WSE router serves as an intermediary between the outside world and your Web services. It is used to direct requests to the appropriate server and confirm that the requester is valid. Imagine a security guard who protects a building. The security guard stands at the door and checks the credentials of any people trying to enter the building. Once it is determined that the person is allowed to enter, the security guard might also act as a guide and direct the person to the right office within that building. A WSE router acts as a security guard for your Web services. It represents a gate between your Web services and the outside world. Your Web services can reside on a private network and be inaccessible to external clients. Any clients that want to use your Web services access the WSE router, which is also a Web service. Once validated, the clients are directed to the destination Web service on the private network. One of the benefits to using a WSE router is the ability to hide the details about your Web service. You can assign a virtual name to the router and the clients use this name instead of the server name on which the actual Web service resides. The client is unaware of your network’s topology. The biggest benefit to using a WSE router, how ever, is the ability to perform maintenance on servers hosting Web services without experiencing any downtime. When maintenance needs to be performed, a change is made to the configuration that routes all requests to an alternative server until the original becomes available again.
482
Chapter 11
Messaging and Routing
Real World Sara Morgan A fellow developer recently shared an experience he had working with a WSE router. He was doing consulting work for a large financial firm that hosted sev eral Web services. External clients used the Web services to access financial ser vices through handheld devices. The company decided to implement a WSE router so that they could routinely take servers down for maintenance while still providing 24/7 access to the Web services. The company made many considerations regarding security, but they failed to consider performance. The extra layer of the WSE router immediately caused a performance reduction and angered many of their customers. At periods of high demand, the servers were so overwhelmed that most customers just gave up try ing to get what they needed. Eventually, the company was able to recover, but this is just one example of how important it is to consider performance before implementing a WSE router.
Creating a WSE Router Application A WSE router application is actually just a Web service. The sole job of this Web service is to route requests for other Web services. To create a WSE router, you need to create a project using the Web service template in Visual Studio 2005. Figure 11-5 shows the New Web Site dialog box that is displayed when selecting this type of project.
Figure 11-5 Use the New Web Site dialog box to create a new ASP.NET Web service project, which is the basis for your WSE router
Lesson 2: How to Create a WSE Router
NOTE
483
Which version of WSE?
The latest version of WSE available is version 3.0. Refer to the Introduction for instructions on how to download and install this service pack add-on.
After the new project has been created, you need to add references to the following two .NET Framework components: This namespace contains the base classes needed to access WSE 3.0, which is needed to create a WSE router application.
■ Microsoft.Web.Services3
This namespace contains the base classes needed to create XML Web services. This namespace includes the WebService and WebMethodAttribute classes, which are needed when creating methods exposed within your Web service application.
■ System.Web.Services
You also need to add a new class file to your project that contains the code for the router handler. In addition to the namespaces added by default, the class file should contain Imports or using directives for the following namespaces: 'VB Imports Microsoft.Web.Services3 Imports Microsoft.Web.Services3.Messaging Imports System.Xml //C# using Microsoft.Web.Services3; using Microsoft.Web.Services3.Messaging; using System.Xml;
The class file that serves as your router handler needs to derive from the Microsoft.Web.Services3.Messaging.SoapHttpRouter class. This is accomplished by add ing the following code to the newly created class file: 'VB Public Class RouterHandler Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter //C# public class RouterHandler: Microsoft.Web.Services3.Messaging.SoapHttpRouter
Now you need to add logic to the router handler class that tells it how to route mes sages. This is a process known as content-based routing because you are routing mes sages based on their content. To accomplish this you need to create a method that overrides the ProcessRequestMessage method. The overloaded method declaration accepts the incoming Simple Object Access Protocol (SOAP) message as an input
484
Chapter 11
Messaging and Routing
parameter and return a Universal Resource Indicator (URI). The method would appear as follows: 'VB Protected Overrides Function ProcessRequestMessage(ByVal message As SoapEnvelope) As Uri ' Add some logic here to process the SOAP Message Return base.ProcessRequestMessage(message) End Function //C# protected override Uri ProcessRequestMessage(SoapEnvelope message) {
//Add some logic to process the SOAP message
return base.ProcessRequestMessage(message);
}
The logic you add inside the ProcessRequestMessage method depends on what your router needs to accomplish. If you just want to direct requests to the appropriate Web service, then some simple if..then logic is all that is needed. However, if you would like to add additional functionality in which you inspect the SOAP message and then route the message based on some complex criteria, the logic could get quite complicated. Because the WSE router is essentially a door to the outside world, make sure that door is secure, accessible, and functional. NOTE
Avoid adding too much functionality to your WSE router
If too much logic is added to the router handler, clients accessing the router could experience delays during peak usage times. To avoid this, minimize the amount of logic you add to the router handler and perform stress testing with tools such as the Microsoft Web Application Stress Tool (available as a free download from MSDN through the following URL: http://www.microsoft.com/ downloads/details.aspx?familyid=E2C0585A-062A-439E-A67D-75A89AA36495&displaylang=en).
Typically, a WSE router inspects the SOAP header to look for something that indicates how the request should be handled. It then returns a URI as a string that indicates where the request should be directed.
Configuring the WSE Router Application To configure the WSE router, you need to add one or more elements for (refer to Table 11-5). This is added to the Web.config file for your WSE router Web service. This element is used to specify that the Web service is using WSE. By adding this element you allow the WebServicesExtension class to intercept any SOAP messages sent to the Web service and process the SOAP headers within those
Lesson 2: How to Create a WSE Router
485
messages. To add the element, open your Web.config file in Solution Explorer by dou ble-clicking the file. You can then add a handler such as the following to handle all requests with an .asmx extension:
CAUTION
Warning about copying code
When following the examples in this section, make sure you remove the line breaks for the element. The line breaks were included here for readability, but if you leave them in the actual application, an error is generated.
Table 11-5 Attributes of the Element
Name
Description
Verb
Specifies the Hypertext Transfer Protocol (HTTP) operation to per form in the form of a comma-separated list or an asterisk to indi cate a wildcard value. The HTTP verbs can be values such as GET, PUT, and POST.
Path
Specifies either a path to a specific file or a wildcard reference (using an asterisk). You can use a single asterisk to represent all files, or you can use an asterisk with an extension to indicate all files with a certain extension.
Type
Specifies the class and assembly for the WSE router. The class and assembly names are comma-separated values, and you can also append additional information such as the assembly version.
In cases where you want the WSE router to handle more than one Web service, you need to add multiple elements. The following example is the configuration for a router that routes messages for two Web services named WebServiceA.asmx and WebServiceB.asmx:
Configuring a Referral Cache for Routing A referral cache is an XML-based file that contains information about where the SOAP requests need to be routed. This is a required file and you must ensure that the user account under which WSE runs has access to this file. The account that WSE uses is specified in the Machine.config file for your Web server. Look for the username attribute in the element of this file. Ensure that this account has access to the file, but restrict access to all others except the administrator. You do not want anyone else to have the ability to update this file. Name the file ReferralCache.config and place it in the root folder for your WSE router application. NOTE
Referral cache should always have a .config extension
Microsoft Internet Information Services (IIS) ensures that files with a .config extension cannot be opened in an Internet browser. Make sure that your referral cache uses the .config extension to pre vent outside sources from reading this file and learning the actual locations of your Web services.
Each time a request comes in to the WSE router, it refers to the referral cache file for routing instructions. The file itself contains URL references that point to where requests are routed. Table 11-6 shows the elements included in this file. Table 11-6 Elements Contained in the Referral Cache File
Name
Description
This is the root element for the referral cache.
This is the top element used to specify the location where a request will eventually be routed. You can have more than one of these elements or none at all.
There is one of these elements for each element. It contains an or element to specify the loca tion of the destination Web service.
Lesson 2: How to Create a WSE Router
487
Table 11-6 Elements Contained in the Referral Cache File
Name
Description
This is used when you need the URL to match exactly and the entire path for the Web service is included. This is a caseinsensitive match.
This is used when specifying only a portion of the Web ser vice name.
This is used to specify conditions for how to route requests.
This is used to specify a routing instruction that is no longer valid when the instruction being referenced is valid.
This is used in conjunction with the element and it specifies the routing instruction that will be invali dated.
This is used to specify where the request will be rerouted.
This is used in conjunction with the element and spec ifies a URI to which the request will be routed. There can be multiple elements.
This is used to specify a unique identifier that represents the routing instruction. Typically this is a globally unique identi fier (GUID).
More than likely, your referral cache file contains two URLs, which specify the loca tion exposed to the outside world and the location known only by your company. The following is a sample referral cache file that directs requests made to a Web service of Company A to the destination service located on the Company B server: http://www.companya.com/MyWebService/MyWebService.asmx
http://www.companyb.com/MyWebService/MyWebService.asmx
488
Chapter 11
Messaging and Routing
uuid:fa469956-0057-4e77-962a-81c5e292f2ae
Once the ReferralCache.config file has been created, you need to add a configuration section to the Web.config file for your WSE router. The configuration section indi cates that the router will be using WSE 3.0, and a element is used to specify the name of the referral cache file. The following is an example of what this addition to the Web.config file would look like:
Real World Sara Morgan The lab for this lesson includes code that writes a message to the Application Event Log. Typically you would not want to go through the trouble of creating a WSE router if its only function was to log the request to the Event Log. Generally a WSE router is used only if there is a specific reason you need to route messages based on something contained in the SOAP message. Otherwise the WSE router creates a lot of unnecessary overhead. Always consider alternatives before making a decision to implement a WSE router. For instance, if you want a way to log requests to your Web services, you can use a SOAP extension instead (such as what was covered in Chapter 2). Just keep in mind that by using a WSE router, you are adding one extra layer through which requests have to go, which could reduce the performance of your Web services.
Lesson 2: How to Create a WSE Router
489
Lab 2: Creating a WSE Router This lab steps you through how to create a WSE router using Visual Studio. You begin by creating a new Web service project that represents the WSE router. The lab also demonstrates how to configure the WSE router by adding an entry to the Web.config file and then creating a referral cache file that contains the locations of where requests will be routed from and to. You also add a class to the router project that overrides the ProcessRequestMessage method, intercepts the SOAP message coming from the client, and writes an entry to the Application Event Log. If you encounter a problem com pleting this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005. 2. Click File, New, Web Site. 3. In the New Web Site dialog box (see Figure 11-5), select ASP.NET Web Service as the template and name the project file MyWSERouter. By default, Visual Studio saves the project in the My Documents\Visual Studio 2005\WebSites\ directory. 4. Set the language in the Language drop-down list box by selecting Visual Basic or Visual C#. By default, Visual Studio selects the language specified when you con figured the development environment. 5. A new solution named MyWSERouter is created. By default, the solution file cor responding to the project is stored in your My Documents\Visual Studio 2005\WebSites directory. The Web service project files themselves are stored in the directory specified in step 3. 6. In Solution Explorer, right-click the MyWSERouter project and click Add Refer ence. On the .NET tab, add references to the Microsoft.Web.Services3 and System .Web.Services namespaces. 7. In Solution Explorer, right-click the project and click Add New Item. Add a new Web configuration file named ReferralCache.config and click Add to add the new file to the project root. 8. Replace the code that appears in the code window with the following: http://localhost/MyWSERouter/Service.asmx
490
Chapter 11
Messaging and Routing
http://localhost/MyWSERouterWS/Service.asmx
uuid:fa469956-0057-4e77-962a-81c5e292f2ae
9. Delete the eb.config file and then right-click the project in Solution Explorer and click Add New Item. Add a new Web configuration file, and this time leave the name as the default name, Web.config. Click Add to add the new file to the project. 10. Replace the code in the code window with the following:
11. Right-click the App_Code folder and click Add New Item. Select Class as the template and name the file RouterHandler.cs or RouterHandler.vb, and then click Add. 12. In the code window, replace the entire contents of the file with the following: 'VB Imports System.Web.Services
Imports Microsoft.Web.Services3
Imports Microsoft.Web.Services3.Messaging
Lesson 2: How to Create a WSE Router
491
Imports System.Diagnostics Imports System.Xml Public Class RouterHandler Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter Protected Overrides Function ProcessRequestMessage(ByVal message As SoapEnvelope) As Uri Dim EventLog1 As EventLog = New EventLog If EventLog.SourceExists("WSERouter") Nothing Then
EventLog.CreateEventSource("WSERouter", "Application")
End If
EventLog1.Source = "WSERouter"
EventLog1.WriteEntry("Routing a request for MyWSERouterWS web service")
'Add code here that will read the SOAP message and make ' necessary changes
Return MyBase.ProcessRequestMessage(message) End Function End Class //C# using using using using using using using using using using using
System; System.Data; System.Configuration; System.Web; System.Web.Security; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.WebControls.WebParts; System.Web.UI.HtmlControls; Microsoft.Web.Services3; Microsoft.Web.Services3.Messaging;
/// /// Summary description for RouterHandler /// public class RouterHandler : Microsoft.Web.Services3.Messaging.SoapHttpRouter { public RouterHandler()
{
} protected override Uri ProcessRequestMessage( SoapEnvelope message) { System.Diagnostics.EventLog EventLog1 = new System.Diagnostics.EventLog(); if (!System.Diagnostics.EventLog.SourceExists("WSERouter"))
492
Chapter 11
Messaging and Routing
{ System.Diagnostics.EventLog.CreateEventSource("WSERouter", "Application"); } EventLog1.Source = "WSERouter";
EventLog1.WriteEntry ("Routing a request for MyWSERouterWS web service");
//Add code here that will read the SOAP message and make // necessary changes
return base.ProcessRequestMessage (message);
} }
13. In Solution Explorer, right-click the solution and click Build Solution. Ensure that the message Build Succeeded appears in the bottom left-hand task bar.
Lesson Summary A WSE router serves as an intermediary between your Web services and the outside world. A router is just a Web service that receives requests and routes them to the appropriate destination Web service. A router handler class is added to this project, which contains an overridden method named ProcessRequestMessage. This method reads the incoming SOAP message, determines where it should be routed, and returns the URI. ■
The router is configured by adding a configuration file named ReferralCache .config that includes the URLs for the router and the target Web services.
■
You also add an element to the element in the Web.config file. This element is used to instruct the router which requests to handle.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “How to Create a WSE Router.” The questions are also available on the com panion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
Lesson 2: How to Create a WSE Router
493
1. What namespaces should be included with your WSE router project? (Select all that apply.) A. System.Web.Services B. System.Web.Services2 C. System.Web.Services3 D. Microsoft.Web.Services3 2. Identify the correct code to configure a WSE router to accept requests for all Web service files. (Choose the best answer.) A.
B.
C.
D.
3. Which element in the referral cache file is used to specify the exact location to which a request will eventually be routed? (Choose the best answer.) A. B. C. D.
494
Chapter 11
Messaging and Routing
Lesson 3: How to Add and Verify Security Credentials This lesson explores how to add security credentials to a SOAP message. Rather than adding the security credentials using the proxy’s credentials property, you use WSE to add credentials so that the request can still pass through an intermediary. You also learn how to verify the digital signatures of the SOAP message sent by the client. After this lesson, you will be able to: ■
Add security credentials to a SOAP message.
■
Verify the security credentials sent by the client.
Estimated lesson time: 30 minutes
Why Add Security Credentials? You might be wondering why security tokens are covered here when they were dis cussed in Chapter 9. The reason is that this chapter discusses WSE routers, which serve as an intermediary. Whenever you go through an intermediary, you cannot just set the credentials of the proxy class as you saw in Chapter 9. The credentials are not passed through the intermediary and the client is not authenticated. Instead, you must use WSE to add the security credentials, which allows them to be passed through the WSE router.
Adding Security Credentials Using an X.509 Certificate To add security using WSE, you need to add a class to your WSE router that defines at least one policy. You can create two policies that allow for security between the cli ent and the router and also between the router and the Web service. In this lesson, we examine a class that uses a single policy assertion. It is concerned only about security between the client and the router. It then passes the message on to the Web service with no security. MORE INFO
Passing security through to the Web service
If you want to learn how to secure the message between the router and the Web service, refer to the sample named SecureRoutingToUltimateReceiver that is included in the sample folders for WSE 3.0. By default, this project is located at \Program Files\Microsoft WSE\v3.0\Samples\\QuickStart\Routing\SecureRoutingToUltimateReceiver.
Lesson 3: How to Add and Verify Security Credentials
495
The policy creates a custom policy assertion that uses an X.509 security token. In this case, security is applied using a set of packaged operations known as security assertions. The X.509 security token is applied using the X509SecurityToken class (refer to Table 11-7), which is used to represent an X.509 version 3 certificate. The certificate is the digital document that is used to verify that the person sending the request is legitimate. Table 11-7 Public Methods of the X509SecurityToken Class
Name
Description
Equals
Retrieves a value that indicates whether two objects are equal.
GetHashcode
Retrieves the hash code for the X.509 certificate.
GetSignedTokenXML
Retrieves XML that represents a signed token.
GetSTRTransformXML
Included only for use by WSE and is not used in your code.
GetXML
Retrieves an XML document that represents the secu rity token.
LoadXML
Used to load XML for the current security token.
Verify
Used to check the signatures of all signed parties and make sure the certificate is current.
VerifySignedTokenXML
Used to verify the signature of a token in its XML form.
The first thing you need to do is add a new class file that contains your router policies. If you add the class to the same project that was created in Lesson 2, you should already have references set to the System.Web.Services and Microsoft.Web.Services3 dynamic link libraries (DLLs), but you need to add directives for the following namespaces to this class: 'VB Imports Imports Imports Imports
Microsoft.Web.Services3 Microsoft.Web.Services3.Messaging Microsoft.Web.Services3.Design System.Security.Cryptography.X509Certificates
496
Chapter 11
//C# using using using using
Messaging and Routing
Microsoft.Web.Services3;
Microsoft.Web.Services3.Messaging;
Microsoft.Web.Services3.Design;
System.Security.Cryptography.X509Certificates;
Just like the RouterHandling class that was created in Lesson 2, the RouterPolicy class needs to derive from the HttpSoapRouter class. The following code shows what this would look like: 'VB Public Class RouterPolicy
Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter
//C# public class RouterPolicy : Microsoft.Web.Services3.Messaging.SoapHttpRouter
The next step is to add another class to the same class file you just created. This class contains the actual policy assertion, and the class inherits from Microsoft.Web .Services3.Design.Policy as in the following code: 'VB Public Class PolicyAssertion
Inherits Microsoft.Web.Services3.Design.Policy
//C# public class PolicyAssertion : Microsoft.Web.Services3.Design.Policy
You now add the code used to define the policy for messages passed between the cli ent and the WSE router. The following code creates a new assertion that is used to set what the client and service actor will be. You might recall from Chapter 2 that the actor/role attribute is included in the header element of your SOAP message. For requests exchanged between the router (service) and the client, the actor attribute must be set with a value other than an empty string. The following code also creates a token for both the router (service) and client and resides in the constructor for the PolicyAssertion class: 'VB Public Sub New()
Dim assertion As New MutualCertificate11Assertion()
assertion.ClientActor = "http://microsoft.web.services3.samples.securerouting/client" assertion.ServiceActor = "http://schemas.xmlsoap.org/soap/actor/next" assertion.ClientX509TokenProvider = New X509TokenProvider(StoreLocation.CurrentUser, StoreName.My, "CN=WSClient") assertion.ServiceX509TokenProvider = New X509TokenProvider(StoreLocation.LocalMachine,
Lesson 3: How to Add and Verify Security Credentials
497
StoreName.My, "CN=WSERouter") Me.Assertions.Add(assertion)
End Sub
//C# public PolicyAssertion() : base() { MutualCertificate11Assertion assertion = new MutualCertificate11Assertion(); assertion.ClientActor =
"http://microsoft.web.services3.samples.securerouting/client";
assertion.ServiceActor =
"http://schemas.xmlsoap.org/soap/actor/next";
assertion.ClientX509TokenProvider = new
X509TokenProvider(StoreLocation.CurrentUser,
StoreName.My, "CN=WSClient");
assertion.ServiceX509TokenProvider = new
X509TokenProvider(StoreLocation.LocalMachine,
StoreName.My, "CN=WSERouter");
this.Assertions.Add(assertion); }
In the previous code example, we defined both the serviceActor and clientActor. The serviceActor is used when messages are passed between the client and the router. The clientActor is required when additionally securing messages between the router and the Web service. NOTE
Creating a policy file
This lesson features an example in which the policy was defined in code, but you could have defined the policy in an XML-based policy file instead. You would have then returned that policy in the GetRequestPolicy method instead of returning the overridden PolicyAssertion class. The obvious benefit to using a policy file is that if the values used in your policy are likely to change, a policy file is preferred because changes will not require a code recompile.
Now you override the GetRequestPolicy method, which is used to get the policy asso ciated with the SOAP request. This code is placed in the RouterPolicy class. The method you create returns the policy assertion defined in the previous code example and looks like the following: 'VB Protected Overrides Function GetRequestPolicy() As Policy Return New PolicyAssertion() End Function
498
Chapter 11
Messaging and Routing
//C# protected override Policy GetRequestPolicy()
{
return new PolicyAssertion();
}
Other Security Tokens The previous section demonstrated how you can secure the router using an X.509 security token. This is just one security token supported by WSE 3.0. This type of security is known as message layer security because the security credentials are passed with the SOAP message. You can also use one of the following security tokens: Uses a username and password combination that is typically stored in an external database. You can also authenticate against Microsoft Active Directory directory service. Usually the password is stored as a hash of the actual password to provide extra security. It is important that the password be protected and not sent as clear text to prevent it from being compromised. To create a Username token, you use the UsernameToken class, which is part of the Microsoft.Web.Services3.Security.Tokens namespace to sign or encrypt the SOAP message. This is also message layer security.
■ UsernameToken
MORE INFO
Implementing message layer security
For more information about how to implement this type of security, refer to the Patterns and Practices document in MSDN titled “Implementing Direct Authentication with UsernameToken in WSE 3.0” and available through the following URL: http://msdn.microsoft.com/library/ default.asp?url=/library/en-us/dnpag2/html/WSS_Ch3_ImpDirectAuth_WSE30.asp
Uses a user login and password to perform authentica tion, but the security is handled by Secure Sockets Layer (SSL) instead of a signed certificate. For many people, using SSL is a preferred method of handling security. It is known as transport layer security, and in this case the authentication credentials are passed on by the transport layer, which is SSL. You need to be aware that when you go through a WSE router using SSL, you need to create a new SSL connection between each access point. There is one SSL connection from the client to the router and another one between the router and the Web service. You also need to consider that the overhead associated with this method might cause your Web services not to scale well.
■ UsernameOverTransport
Lesson 3: How to Add and Verify Security Credentials
499
Also known as AnonymousForCertificate, this method allows any user with the server’s public key to authenticate, but the security is still handled by the server’s X.509 certificate. The client is unknown because it authenticates anonymously, so you would only want to apply this security level to noncritical services or those where the public key is only provided to a limited number of outside parties (such as company vendors or partner companies).
■ AnonymousOverX509
Verifying the Security Credential You might recall from Lesson 2 that the ReferralCache.config file was referenced by including a element in the Web.config file for the WSE router. This is just one of the elements used to configure WSE 3.0. You can also include a ele ment that includes the security settings for your WSE application. This lesson showed you how to implement a WSE router that handled security with an X.509 certificate. To verify these types of certificates, you need to include an element (refer to Table 11-8) in your WSE router’s Web.config file. Table 11-8 Attributes of the Element
Name
Description
allowTestRoot
Boolean value that indicates whether WSE allows the X.509 certificate signed by a test root to pass verification. This is used in conjunction with the verifyTrust attribute and is valid only when the attribute is set to true.
revocationMode
This attribute was included to allow for applications upgraded from WSE 2.0. It is equivalent to the AllowRevocationUrlRe trival attribute used with that version and is used to specify the algorithm used to compute the subject key for the X.509 certif icate. This attribute can be set with a value of NoCheck, Offline, or Online.
skiMode
Used to specify the algorithm that WSE 3.0 uses to compute the value of the subject key. It can be set with a value of RIC3280, IssueSerial, or ThumbprinSHA1 (default).
storeLocation
Used to specify the location where WSE stores the X.509 cer tificate. It also specifies the certificate store used during the verification process. It can be set with a value of CurrentUser or LocalMachine.
500
Chapter 11 Messaging and Routing
Table 11-8 Attributes of the Element
Name
Description
verificationMode
Indicates whether WSE looks in the Trusted People certificate store during verification. Set with a value of ChainOnly, TrustedPeopleOnly, or TrustedPeopleOrChain.
verifyTrust
Boolean value that indicates whether WSE verifies that the cer tificate was issued by a valid authority.
A typical entry in the Web.config file of a WSE router that uses an X.509 certificate would appear as follows:
Lab 3: Adding Security to Your WSE Router This lab steps you through how to add security to the WSE router created in Lab 2. You add a class to this project that is used to configure a policy file using an X.509 cer tificate. If you encounter a problem completing this lab, the completed projects are available on the companion CD in the Code folder. 1. Open Visual Studio 2005 and load the MyWSERouter project that was created in Lab 2 of this chapter. 2. Right-click the App_Code folder and click Add New Item. Select Class as the template, name the file RouterPolicy.cs or RouterPolicy.vb and then click Add. 3. Replace all the code in this class with the following: 'VB Imports Imports Imports Imports Imports
Microsoft.VisualBasic
Microsoft.Web.Services3
Microsoft.Web.Services3.Messaging
Microsoft.Web.Services3.Design
System.Security.Cryptography.X509Certificates
Public Class RouterPolicy Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter Protected Overrides Function GetRequestPolicy() As Policy Return New PolicyAssertion() End Function
Lesson 3: How to Add and Verify Security Credentials
501
End Class Public Class PolicyAssertion Inherits Microsoft.Web.Services3.Design.Policy Public Sub New() Dim assertion As New MutualCertificate11Assertion() assertion.ClientActor = "http://microsoft.web.services3.samples.securerouting/ client" assertion.ServiceActor = "http://schemas.xmlsoap.org/soap/actor/next" assertion.ClientX509TokenProvider = New X509TokenProvider(StoreLocation.CurrentUser, StoreName.My, "CN=WSE2QuickStartClient") assertion.ServiceX509TokenProvider = New X509TokenProvider(StoreLocation.LocalMachine, StoreName.My, "CN=WSE2QuickStartServer") Me.Assertions.Add(assertion) End Sub End Class //C# using using using using using
System.Web.UI.HtmlControls;
Microsoft.Web.Services3;
Microsoft.Web.Services3.Messaging;
Microsoft.Web.Services3.Design;
System.Security.Cryptography.X509Certificates;
///
/// Summary description for RouterPolicy
///
public class RouterPolicy : Microsoft.Web.Services3.Messaging.SoapHttpRouter
{ protected override Policy GetRequestPolicy() { return new PolicyAssertion();
}
} public class PolicyAssertion : Microsoft.Web.Services3.Design.Policy { public PolicyAssertion() : base() {
502
Chapter 11
Messaging and Routing
MutualCertificate11Assertion assertion = new MutualCertificate11Assertion(); assertion.ClientActor = "http://microsoft.web.services3.samples.securerouting/client"; assertion.ServiceActor = "http://schemas.xmlsoap.org/soap/actor/next"; assertion.ClientX509TokenProvider = new X509TokenProvider(StoreLocation.CurrentUser, StoreName.My, "CN=WSClient"); assertion.ServiceX509TokenProvider = new X509TokenProvider(StoreLocation.LocalMachine, StoreName.My, "CN=WSERouter"); this.Assertions.Add(assertion);
}
}
4. Right-click the Web.config file and click Open. In the code window, add the fol lowing code right below the element:
5. In Solution Explorer, right-click the solution and click Build Solution. Ensure that the message Build Succeeded appears in the bottom left-hand task bar.
Lesson Summary ■
Security credentials are handled differently for requests that pass through a WSE router. To allow for this, you need to use WSE to add the credentials. You can ver ify the security between the client and the router and then optionally between the router and the Web service.
■
If you add security using an X.509 certificate, you need to create a custom policy assertion using either code in a class file or an XML-based policy file.
■
For messages passed between the client and the router, the serviceActor attribute must be set with a value other than an empty string. Messages passed between the router and the Web service must also set the clientActor to a value other than the empty string.
■
In addition to the X.509 certificate, you can implement security using either UsernameToken, UsernameOverTransport, or AnonymousOverX509.
■
Verifying the security credentials for an X.509 certificate is done by including an element in your router’s Web.config file.
Lesson 3: How to Add and Verify Security Credentials
503
Lesson Review You can use the following questions to test your knowledge of the information in Les son 3, “How to Add and Verify Security Credentials.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. What are the two alternatives for creating a custom policy assertion? (Select two answers.) A. Add code to the constructor for the WSE router that verifies the signer’s credentials. B. Create an XML-based policy file and return it in the overridden GetRequestPolicy method. C. Add code to the GetRequestPolicy method to verify the signer’s credentials. D. Add code to a class file that adds an assertion that is returned by the over ridden GetRequestPolicy method. 2. Which security method utilizes a username and password that is stored in an external source such as Microsoft SQL Server or Active Directory? (Choose the best answer.) A. X.509 B. UsernameToken C. UsernameOverTransport D. AnonymousOverX509
504
Chapter 11
Messaging and Routing
3. Identify the code used to configure the router to allow certificates signed by a test root to pass verification. (Choose the best answer.) A.
B.
C.
D.
Chapter 11 Review
505
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
A WSE router serves as an intermediary between your Web services and the out side world. It is actually just another Web service that is configured to route requests to the appropriate Web services.
■
You configure the WSE router by adding an element for to the router Web.config file. You also create a ReferralCache.config file that contains the locations of your router and the Web services that will be the final destination.
■
When using a WSE router, you have to use WSE to add security credentials rather than adding them to the proxy. This is necessary for them to pass through the router.
■
When configuring security for a WSE router, you must consider two steps: secu rity between the client and the router, and security between the router and the Web service.
■
You can create a custom policy assertion using an XML-based policy file or code added to a class file. Either way, the policy is returned from the overridden GetRequestPolicy method.
■
Security is configured for verification by adding an element to the ele ment in the WSE router’s Web.config file.
506
Chapter 11 Review
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
assertion
■
certificate
■
message layer security
■
transport layer security
Case Scenarios In the following case scenarios, you apply what you’ve learned about how to imple ment and secure a WSE router. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Performing a Server Upgrade You work for a medical services company that hosts several Web services on a large network. The network administrator has informed your department that all of the servers running these services need to be taken offline for several hours to perform a server upgrade. Fortunately, all of the Web services are routed through a WSE router and you know that all you need to do is devise a strategy for using the router to tem porarily reroute the requests. 1. What strategy do you suggest?
Case Scenario 2: Selecting a Security Method for Your WSE Router You have implemented a WSE router for the medical services company mentioned in Case Scenario 1. The Web services provided are only accessed by ancillary branches of your company. Although the branches do not reside on your public network and access the Web services through the public Internet, they are trusted members of your organization. You have been asked to implement security for the WSE router such that performance of the Web services is a primary consideration. 1. What security method might you recommend?
Chapter 11 Review
507
Suggested Practices To help you successfully master the exam objectives presented in this chapter, com plete the following tasks.
Implement WSE SOAP Messaging You only need to complete practice 1 to understand the WSE SOAP Messaging objective. For further understanding, download and install the MSDN Hands On Lab concerning WSE Messaging available through the following URL: http:// www.microsoft.com/downloads/details.aspx?familyid=0e5491c1-8bde-4fff-88c4 8e3dc102fad6&displaylang=en. This will allow you to complete practice 2. Create a Web service project and leave the HelloWorld Web method created by default. Enable WSE for the project and use WSE Messaging to change the Web method to use TCP as the communication protocol. You will then add a Windows application project to the solution and set a Web reference to the Web service in this solution. Add a label to the default form for this project and add code to the Page_load method that calls the HelloWorld Web method and displays the string result in text of the label control.
■ Practice 1
After downloading and installing the MSDN Hands On Lab, browse to the WSE Messaging folder that was created during the installation. Drill down to the folder for the language you prefer (VB or C#) and open the Basic folder. Open the Manual.doc file and review the instructions for completing the Hands On Lab. Walk through part 1 and part 2 of the basic lab and review the code sup plied with the lab.
■ Practice 2:
Route SOAP Messages by using a WSE Router To help master this objective, you should complete practice 1. Practice 2 is optional since it deals with more advanced concepts such as passing in a SOAP header so that message can be routed based on their content. Create a Web service project that will act as a WSE router. Configure the WSE Router to accept requests for all .asmx files and create a referralCache.config file that routes messages no matter what the content is. You can route messages for the Web service project you created in practice 1 for WSE SOAP Messaging. You will then add a Web application project that acts as a cli ent and makes a request to the Web service.
■ Practice 1
508
Chapter 11 Review
Modify the WSE Router project created in practice 1 to create a method that overrides the ProcessRequestMessage method and thus routes a mes sage based on a value passed in the SOAP header. You will then have to modify the client project to pass in the SOAP header.
■ Practice 2
Add and Verify Security Credentials To complete the practices in this section, you need to first complete practice 1 in the Route SOAP Messages section. Add a class to the WSE Router project created in practice 1 of the pre vious section. This class will be used to pass the username token through to the Web service. In this case, you will be using a username and password that can be retrieved from a database. However, you can just have the username and pass word passed in as static text. Refer to the MSDN document, http:// msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/ WSS_Ch3_ImpDirectAuth_WSE30.asp, for more information about implement ing a username token.
■ Practice 1
Verify the security credentials added in practice 1 by adding a element to the web.config file for the WSE Router project.
■ Practice 2
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 12
Creating Serviced Components
Enterprise Services are part of the toolbox that any developer needs to use when developing complex transactional systems. Distributed transactions, high-volume systems, object pooling, and just-in-time (JIT) activation are but a few of the services that you need, but implementing code at the infrastructure level is not very produc tive. Enterprise Services and the underlying COM+ framework offer these services. Serviced components are the heart of the solution when it comes to accessing these services from a managed environment.
Exam objectives in this chapter: ■
Create, configure, and access a serviced component. ❑
Create a serviced component.
❑
Add attributes to a serviced component.
❑
Register a serviced component.
❑
Implement security.
❑
Add a reference to a serviced component in an application.
❑
Create an instance of a serviced component.
❑
Call the methods of a serviced component.
Lessons in this chapter: ■
Lesson 1: Serviced Component Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
■
Lesson 2: Consuming the Serviced Component . . . . . . . . . . . . . . . . . . . . . . . . 555
Before You Begin To complete the lessons in this chapter, you should be familiar with Microsoft Visual Basic or C# and be comfortable with the following tasks: ■
Creating a library and console application in Microsoft Visual Studio using Visual Basic or C#.
■
Adding references to system class libraries to a project. 509
510
Chapter 12
Creating Serviced Components
■
Adding references to projects within a solution.
■
A basic understanding of remoting methodologies (XML Web services, DCOM, .NET Remoting, CORBA, and so on).
■
A basic understanding of COM+.
■
A basic understanding of queuing technologies such as Microsoft Message Queue Server (MSMQ).
■
A basic understanding of distributed transactions.
■
A basic understanding of ADO.NET.
Real World Mark Blomsma Serviced components are indispensable in the enterprise environment. I’ve worked on projects where transactional integrity across multiple data sources was an absolute must. We inserted data in two and sometimes more databases and pushed multiple messages on a queue, all in a high-transaction environ ment. Using serviced components to interact with the Microsoft Distributed Transaction Coordinator (DTC) was the only way to get the job done reliably.
Lesson 1: Serviced Component Overview
511
Lesson 1: Serviced Component Overview In this lesson we look at how COM, COM+, MTS, Enterprise Services, and serviced components are all related. You gain an understanding of what a serviced component is, how to make one, and how to use the Enterprise Services such as transaction man agement, object pooling, and JIT activation.
Interconnected Technologies There are a couple of technologies that are interconnected when it comes to ser viced components: COM, COM+, Microsoft Transaction Server, and Enterprise Services. The Common Language Runtime (CLR) is the replacement for COM but not for COM+. COM+ is a run-time environment that provides a set of ser vices intended to make building scalable distributed systems easier. COM+ is the name given to Microsoft Transaction Server 2.0 (MTS 2.0). Both COM+ and MTS had poorly chosen names, which do not cover the underlying technology. This has been corrected. The .NET Framework introduces Enterprise Services, the next generation of COM+. Enterprise Services is a run-time environment that revolves around serviced components. To use the services offered by the Enterprise Services run-time environment, you need to create a serviced component. The serviced component provides access to Enterprise Services, and Enterprise Services give you access to services such as JIT activation, queuing, role-based security, object pooling, synchronization, and transactions. Using the classes in the System.EnterpriseServices namespace, Visual Studio enables you to easily create serviced components, and essentially create a class that you’ll use to extend the ServicedComponent class. Let your class inherit from ServicedComponent and mark the class and its methods with attributes, providing metadata about how the component should be registered in the COM+ catalog. We’ll see how all this works in Lesson 1. An assembly for a serviced component must be strongly named. A serviced com ponent can be consumed from a .NET assembly in the same way as you would consume a regular component: simply add an assembly reference to the dynamic link library (DLL) defining the serviced component.
512
Chapter 12
Creating Serviced Components
Serviced components can also be made available as Web services by using the COM+ Simple Object Access Protocol (SOAP) service. Achieving this is merely a matter of applying the right attributes to your class. To be precise, use the SoapVRoot property of the serviced component’s ApplicationActivation attribute. One of the most frequently used COM+ services is the Microsoft DTC. By enlist ing the .NET transaction in the DTC you can create transactions that run across multiple data sources and can even use a compensating resource manager (CRM) for resources that are not transactional by nature. You can for example, create a transaction that updates a record in the database, inserts a message in a message queue, and writes an entry to a file, all within the scope of one transac tion. The database and the message queue are both transactional, but the file sys tem is not. In this example a CRM would need to be created to reverse the changes made to the file in case the transaction needs to be rolled back. COM+ gives developers more control over their applications by allowing config urable transaction isolation levels. Versions of COM+ prior to COM+ 1.5 always used the highest level of isolation for transactions. Although this level guaran tees that data integrity is always preserved, it can lead to performance issues, such as timeouts, when many transactions need to be performed on a large data base. With configurable isolation levels, experienced developers can increase concurrency to improve performance and scalability. Serviced components are most powerful in a server-side environment and can be used to enhance both the functionality and performance of your .NET application.
After this lesson, you will be able to: ■
Describe the background and uses of COM+ Services.
■
Create a serviced component.
■
Register a serviced component.
■
Add attributes to a serviced component.
■
Implement security on a serviced component.
Estimated lesson time: 45 minutes
Lesson 1: Serviced Component Overview
513
COM+ Services COM+ builds on and extends applications that have been written using COM, MTS, and other COM-based technologies. COM+ handles many of the resource manage ment tasks that developers previously had to program, such as thread allocation and security. Some COM+ services can be used within the .NET Framework to enhance functionality and performance. The .NET Framework attributes cause COM+ config uration to be stored in the COM+ catalog when the assembly is registered. The following COM+ functionality can be added to your managed application by implementing a serviced component: ■
Transaction support ❑
Automatic transaction processing
❑
Bring your own transaction (BYOT)
❑
CRMs
■
Object pooling
■
Just-in-time activation
■
Loosely coupled events
■
Object construction
■
Private components
■
Queued components
■
Role-based security
■
SOAP service
■
Synchronization
Transaction Support A transaction is a set of operations that are considered to be one unit. Either all oper ations succeed, or all fail. When a failure occurs, no operations are committed. The .NET Framework does have other kinds of transaction support within ADO.NET, but the COM+ transaction model supports a declarative coding style and the ability to perform distributed transactions.
514
Chapter 12
Creating Serviced Components
Automatic Transaction Processing Using the AutoCompleteAttribute you can have a transactional method rollback auto matically if an unhandled exception terminates the regular flow of the application. When not using the AutoCompleteAttribute the ContextUtil class can be used to inter act with the COM+ application and inform it of success or failure using the methods SetComplete() and SetAbort().
Bring Your Own Transaction (BYOT) In a distributed transaction scenario it might be necessary to manually manage the enlistment of code into a running transaction. The solution of connecting to the DTC to enlist in a running transaction is known as BYOT.
CRMs CRMs are used for resources that are not transactional by nature. You might, for exam ple, create a transaction that updates a record in the database, inserts a message in a message queue, and writes an entry to a file, all within the scope of one transaction. The database and the message queue are both transactional, but the file system is not. In this example a CRM would be needed to to reverse the changes made to the file in case the transaction needs to be rolled back.
Object Pooling Object pooling means that a limited supply of objects are made available for client use. When clients request a new object instance, they either receive a new object instance or an instance that already exists in the pool. After clients have finished using objects, they are returned to the pool rather than destroyed, so subsequent clients can reuse these pooled instances.
Just-in-Time Activation JIT activation is a process whereby COM+ components are only created when they are required and are destroyed as soon as they are no longer required. This activation and deactivation occurs when methods are called (although context information is saved between calls). When clients create instances of COM+ components, they receive a proxy class. However, the COM+ component that is accessed by the proxy class does not actually exist until the client uses component methods to perform operations.
Lesson 1: Serviced Component Overview
515
Loosely Coupled Events Loosely coupled events, or the LCE system as it often referred to, allows events to be sent across the network. See Chapter 8, “Method Invocations and Event Management with .NET Remoting,” for more information on how .NET Remoting is used to lever age this functionality.
Object Construction COM+ offers a mechanism for string-based object construction where, after creating the object using the default constructor, the Construct method is called, passing a string containing information about the state of the object. This feature needs to be enabled on the Activation tab of the component’s Properties dialog box or by decorat ing your class with a ConstructionEnabled attribute. This automatically sets the option the moment the component is imported in a COM+ application.
Private Components COM+ 1.0 marks all components in an application as public. A public component can be activated from any other application. An application typically has a number of com ponents that are internal to the application. COM+ 1.5, as implemented by Microsoft Windows Server 2003, allows you to mark these components as private. This means that the components are only visible and accessible by other components in the same application. The ability for developers to mark components as private gives developers more con trol over what functionality to expose. It is also possible to mark a component as pri vate but still take advantage of all the features of Enterprise Services.
Queued Components Very often, asynchronous messaging is accomplished using MSMQ. When using MSMQ, rather than updating data synchronously, we send a message to MSMQ with information about the task at hand (typically, but not always, in Extensible Markup Language [XML] format). Later on, we retrieve that message from MSMQ and perform the actual task. MSMQ works very well for this kind of operation. However, using MSMQ directly requires a significant amount of custom source code. The application needs to be specifically designed to post information to the queue, and the compo nents need to manually read information from the queue. For more information on message queuing, see Chapter 13, “Serviced Component Management.”
516
Chapter 12
Creating Serviced Components
Queued components are different. They make use of MSMQ but hide all of the com plexity. Setting up queued components is a purely administrative task. This makes it easy to convert a regular synchronous operation to an asynchronous operation.
Role-Based Security .NET has basic role-based security, but the .NET definition of a role is a Windows user group. This is a severe limitation because often you do not have control over your cus tomer’s information technology (IT) department. If you deploy your application in an environment where the user groups in your domain don’t match the roles expected by your application, nobody will have access to your application. There are two solu tions to this problem: (a) define a custom principle that redefines how a role needs to be verified, or (b) use Enterprise Services role-based security. Enterprise Services role-based security is unrelated to Windows user groups, allowing you to define roles directly from the application’s business domain, even if no corre sponding user groups exist.
SOAP Service The .NET Framework allows any COM+ component to be accessible through a SOAP service. Using the Component Services Microsoft Management Console (MMC) snapin you can configure the COM+ component in such a way that the interface will be available as a SOAP service. Microsoft Internet Information Services (IIS) will be used to host the service. Notice the use of the term SOAP service. The service uses SOAP over Hypertext Transfer Protocol (HTTP), but the SOAP spoken here is that of .NET Remoting. You’ll need the soapsuds command-line utility to create a .NET remoting proxy for this service.
Synchronization The last service offered through Enterprise Services is synchronization. When you use synchronization, COM+ creates a proxy for you that runs all instances of your object in its context. COM+ marshals all calls across this proxy where a performance penalty occurs. The service guarantees that only one thread is available to run each object at a time. COM+ synchronization provides another easy way to provide synchronization, but be careful when using it. Many calls to a COM+ synchronized object degrade your application greatly because of all the marshaling across the proxy. Be sure to test responsiveness when using it.
Lesson 1: Serviced Component Overview
517
Creating a Serviced Component The following steps need to be completed to create a serviced component: 1. Inherit from ServicedComponent. 2. Add a default constructor. 3. Make your class ComVisible. 4. Choose the COM+ activation type. 5. Assign a strong name.
Inheriting from ServicedComponent You create a serviced component by implementing a .NET Framework class that inherits, directly or indirectly, from the System.EnterpriseServices.ServicedComponent class. Serviced component classes are hosted in a COM+ application and can use COM+ services by using the System.EnterpriseServices namespace. To access the System.Enter priseServices namespace you have to add an assembly reference to System.EnterpriseServices.dll, which is part of the .NET Framework Class Library. 'VB
Imports System.EnterpriseServices
Public Class OrderService Inherits ServicedComponent End Class //C#
using System.EnterpriseServices;
namespace MSLearning.Chapter12.Services
{
public class OrderService : ServicedComponent
{
}
}
Adding a Default Constructor For COM+ to be able to manage your component, it needs to be able to create an instance of your class. COM+ will not be able to provide any default parameters when creating your class, so you need to implement a default public constructor. 'VB Imports System.EnterpriseServices Public Class OrderService
518
Chapter 12
Creating Serviced Components
Inherits ServicedComponent '''
''' Default constructor is required for COM+ registration.
'''
'''
Public Sub OrderService() End Sub End Class //C# using System.EnterpriseServices;
namespace MSLearning.Chapter12.Services
{
public class OrderService : ServicedComponent { /// /// Default constructor is required for COM+ registration. /// public OrderService() {
}
}
}
Making Your Class ComVisible Types in your managed code assembly are by default not visible to COM+. This is because your assembly info file contains the following entry: 'VB Imports System.Runtime.InteropServices
' Setting ComVisible to false makes the types in this assembly not visible
' to COM components. If you need to access a type in this assembly from
' COM, set the ComVisible attribute to true on that type.
//C# using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
You need to select Show All Files in Solution Explorer to be able to see the assemblyinfo in Visual Basic.
Lesson 1: Serviced Component Overview
519
It is considered poor design to make all your types visible to the COM+ environment. To make your custom type visible to COM+ you need to add the ComVisibleAttribute to your class. The ComVisibleAttribute can be found in the System.Runtime.InteropServices namespace. 'VB Imports System.EnterpriseServices Imports System.Runtime.InteropServices Public Class OrderService Inherits ServicedComponent '''
''' Default constructor is required for COM+ registration.
'''
'''
_
Public Sub OrderService()
End Sub
End Class //C# using System.EnterpriseServices; using System.Runtime.InteropServices; namespace MSLearning.Chapter12.Services { [ComVisible(true)] public class OrderService : ServicedComponent { /// /// Default constructor is required for COM+ registration. /// public OrderService() { } } }
Choosing a COM+ Activation Type In COM+ you can choose between the following two types of application activation: A library application runs in the process of the client that creates it and can be called only by clients located on the same computer. This is the default setting.
■ Library
■ Server
Server applications run in their own dedicated server process.
520
Chapter 12
Creating Serviced Components
It is possible to specify whether components in the assembly run in the creator’s pro cess or in a system process using the ApplicationActivationAttribute in the Assemblyinfo.cs file: 'VB Imports System.EnterpriseServices //C# using System.EnterpriseServices; [assembly: ApplicationActivation(ActivationOption.Library)]
Assigning a Strong Name A serviced component needs a strong name to be registered. A strong name consists of information about the assembly’s identity: the string that makes up the name of the assembly, a version number, culture information (if provided), a public key, and a dig ital signature. The information is generated from an assembly file that uses the corre sponding private key. The assembly file contains the assembly manifest, which contains the names and hashes of all the files that make up the assembly. This signa ture provides name uniqueness for the assembly and prevents people from taking over the name of your assembly (called name spoofing). Note that all assemblies that reference an assembly with strong names must also have strong names themselves. You can create a strong name using the Sn.exe command-line utility or by using the property pages of your project in Visual Studio 2005. When using the Sn.exe com mand-line utility, first create the keyfile. Sn.exe –k mykey.snk
Now use the property pages of your project to refer to the file you have just created. In the property pages you’ll find a tab named Signing. Select the Sign The Assembly check box and navigate to the Mykey.snk file. In .NET Framework 1.1 the reference to the keyfile was stored in the Assemblyinfo.cs file, but .NET Framework 2.0 stores the reference in the project file. true mykey.snk
Although not necessarily required by the runtime, providing your assembly with a name is a good practice. Using the ApplicationNameAttribute in the System.Enterprise
Lesson 1: Serviced Component Overview
521
Services namespace allows you to set a default application name at assembly level: 'VB Imports System.EnterpriseServices //C# using System.EnterpriseServices; [assembly: ApplicationName("AdventureWorks")]
Register a Serviced Component After completing the steps in the preceding section, you are ready to register your ser viced component in the COM+ catalog. There are four ways to register your serviced component: ■
MMC
■
Service Installation Tool
■
Dynamic registration
■
Windows Installer (MSI) package
Microsoft Management Console Component Services is a snap-in for the MMC. Use this snap-in to create a COM+ application, add components to the application, and set the attributes for the applica tion and the components. Start the Component Services management console by clicking Start, Run. Type c:\windows\system32\com\comexp.msc, and then click OK. Alternatively, click Start, Control Panel, Administrative Tools, Component Services. Then click Com ponent Services, Computers, My Computer, COM+ Applications. Your screen should now look similar to Figure 12-1.
522
Chapter 12
Creating Serviced Components
Figure 12-1 Default view of Component Services management console
Right-click COM+ Application and click New, Application. This starts the COM+ Application Install Wizard. Now follow these steps: 1. On the Welcome page, click Next. 2. On the Install Or Create A New Application page, click Create An Emtpy Application. 3. On the Create An Empty Application page, enter AdventureWorks as the name for the application. Click Library Application, and then click Next. 4. On the Thank You page, click Finish. You’ve now added the initial COM+ application. Of course it is still empty because we have not yet added our application. This can be done using drag-and-drop. In Com ponent Services Explorer, in the AdventureWorks folder, select the Components folder. As you can see, it is empty. Next, using Windows Explorer, locate your assem bly (DLL). Drag the assembly onto the Components folder. Your screen should now look like Figure 12-2.
Lesson 1: Serviced Component Overview
523
Figure 12-2 You have successfully installed your COM+ application
Congratulations! You’ve just successfully installed your COM+ application. To uninstall the COM+ application, just right-click AdventureWorks and click Delete.
Services Installation Tool The .NET Framework Software Development Kit provides the .NET Framework Ser vices Installation Tool (Regsvcs.exe), which can load and register an assembly, install a type library into a specified COM+ application, and configure COM+ services. Start the Visual Studio 2005 command prompt by clicking Start, All Programs, Microsoft Visual Studio 2005, Visual Studio Tools, Visual Studio 2005 Command Prompt. Change your current directory to the directory where your assembly is located and use Regsvcs.exe to register your COM+ application: regsvcs chapter12.dll AdventureWorks
Notice that because we’re using the Visual Studio 2005 command prompt there is automatically a path setting to the folder C:\Windows\Microsoft.NET\Frame work\v2.0.50727 where Regsvcs.exe is located. Another thing to take note of is that Regsvcs.exe does not use the application name from Assemblyinfo.cs. Instead it needs to be provided as one of the command-line arguments.
524
Chapter 12
Creating Serviced Components
Use the –u switch to unregister the COM+ application: regsvcs –u chapter12.dll AdventureWorks
Dynamic Registration Dynamic registration copies an assembly containing the serviced components to the folder that contains the client application. These are not placed in the global assembly cache (GAC). When a client tries to create an instance of the serviced component, the CLR registers the assembly and configures the COM+ catalog. This occurs only once for each version of an assembly. The technique only works if the calling code is man aged code, and the process that performs dynamic registration must have local administrator rights. We use dynamic registration when we consume our serviced component in Lesson 2 of this chapter.
Windows Installer (MSI) Package After a serviced component application has been installed on one system, it can be exported from the Component Services MMC snap-in in the form of a Microsoft Win dows Installer (MSI) package. Start the Component Services management console and browse to your COM+ appli cation (see the section “Microsoft Management Console” earlier in this lesson). Rightclick your application and click Export. You’ve now entered the COM+ Application Export Wizard. Next, follow these steps: 1. On the Welcome page, click Next. 2. On the Application Export Information page (see Figure 12-3), enter a folder and name for your MSI file, then click Next. 3. On the last page, click Finish.
Lesson 1: Serviced Component Overview
525
Figure 12-3 Export your COM+ application
Two files are created when exporting your COM+ Application, an .msi file and a .cab file. Copy both files to your target machine and double-click the .msi file to install your COM+ application on this machine. After installation your files are located in the following folder: C:\Program Files\ComPlus Applications\{GUID of your application}
You can uninstall your application in Control Panel using Add/Remove Programs.
Adding Attributes to a Serviced Component So far we know what serviced components can do, how to make one, and how to reg ister one. In this section we get into how to leverage the functionality offered by Enter prise Services. Most of the serviced component features are applied by using .NET Framework attributes. When a service is called, the associated attribute is set to inform the run time about the required COM+ service. The .NET Framework attributes cause COM+ configuration to be stored in the COM+ catalog when the assembly is regis tered. These attributes inform the COM+ hosting environment how to interact with
526
Chapter 12
Creating Serviced Components
the serviced components through the services. When we added a default applica tion name to our assembly in the previous section we were actually using an attribute, the ApplicationNameAttribute. Note that these attributed configuration set tings can be changed in the Component Services snap-in of the MMC after the com ponent has been installed. We’ll look at how to use attributes to utilize the following: ■
Transactions
■
Object pooling
■
JIT activation
■
Object construction
■
Private components
■
Queued components
Transactions Let’s take another look at our OrderService. We have two methods: SubmitOrder and GetOrders. Let’s assume that in our application when we place an order we want to store the order in our AdventureWorks database, but we also want to inform a separate application, our Billing Engine, of this order. We have direct access to our own data base, but we need to send a message via a message queue to our Billing Engine (see Chapter 13 for more information on message queues). For our database access we’re following the Data Access Layer pattern (see the Patterns & Practices Web site at http:/ /msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpatterns/html/ArcThreeLayeredSvcsApp.asp for more information) and have implemented a class named Adven tureWorksDB. To encapsulate the complexities of MSMQ we’ve also added a class named BillingEngineQueue. The code would look like this: 'VB Imports System.EnterpriseServices Imports System.Runtime.InteropServices Namespace MSLearning.Chapter12.Services Public Class OrderService
Inherits ServicedComponent
''' ''' ''' '''
Default constructor is required for COM+ registration.
Lesson 1: Serviced Component Overview
_
Public Sub OrderService()
End Sub
Public Sub SubmitOrder(ByVal customerId As Integer, ByVal articleId As Integer,
ByVal quantity As Integer)
Dim db As New AdventureWorksDB()
Dim orderId As Integer
orderId = db.InsertOrder(customerId, articleId, quantity)
Dim q As New BillingEngineQueue()
q.InformOfNewOrder(customerId, orderId)
End Sub
Public Function GetOrders(ByVal customerId As Integer) As DataSet
Dim db As New AdventureWorksDB()
Return db.GetOrders(customerId)
End Function End Class End Namespace //C# using System;
using System.Data;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
namespace MSLearning.Chapter12.Services
{
[ComVisible(true)]
public class OrderService : ServicedComponent
{
///
/// Default constructor is required for COM+ registration.
///
public OrderService()
{
}
public void SubmitOrder(int customerId, int articleId,
int quantity)
{
AdventureWorksDB db = new AdventureWorksDB();
int orderId = db.InsertOrder(customerId, articleId, quantity);
BillingEngineQueue q = new BillingEngineQueue();
q.InformOfNewOrder(customerId, orderId);
}
public DataSet GetOrders(int customerId)
{
527
528
Chapter 12
Creating Serviced Components
AdventureWorksDB db = new AdventureWorksDB();
return db.GetOrders(customerId);
}
}
}
If implemented as shown here, the SubmitOrder method would work. So all is well, you say. However, it is not. An exception is thrown if, for some reason, the InformOfNewOrder method fails. The InsertOrder, however, will have already committed its changes to the database, leaving the application in an inconsistent state. We need to add transaction support, and, because we’re running our transaction over more than just a database, we need the DTC. The easiest way to do this is to add two attributes to the class: one at the class level and one at the method level. 'VB _
Public Class OrderService
Inherits ServicedComponent
'... _ Public Sub SubmitOrder(ByVal customerId As Integer, ByVal articleId As Integer, ByVal quantity As Integer) Dim db As New AdventureWorksDB()
Dim orderId As Integer
orderId = db.InsertOrder(customerId, articleId, quantity)
Dim q As New BillingEngineQueue()
q.InformOfNewOrder(customerId, orderId)
End Sub
'... End Class //C# [ComVisible(true)] [Transaction(TransactionOption.Required,
Isolation=IsolationLevel.Serializable, Timeout=30)]
public class OrderService : ServicedComponent
{
///...
Lesson 1: Serviced Component Overview
529
[AutoComplete] public void SubmitOrder(int customerId, int articleId,
int quantity)
{
AdventureWorksDB db = new AdventureWorksDB();
int orderId = db.InsertOrder(customerId, articleId, quantity);
BillingEngineQueue q = new BillingEngineQueue();
q.InformOfNewOrder(customerId, orderId);
}
///...
}
At class level we have used the TransactionAttribute to specify that for this class a trans action is Required, the transaction isolation level is set to Serializable, and the timeout for the transaction is set at 30 seconds. Note that a timeout value of 30 seconds is very short when you’re debugging, so you might consider setting this value higher while debugging. The following options are allowed when specifying how this class will use the COM+ transaction: ■ Disabled
Ignores any transaction in the current context.
■ NotSupported ■ Required
Creates the component in a context with no governing transaction.
Shares a transaction, if one exists, and creates a new transaction if
necessary. Creates the component with a new transaction, regardless of the state of the current context.
■ RequiresNew
■ Supported
Shares a transaction, if one exists.
The isolation level can be set to the following values: The pending changes from more highly isolated transactions cannot be overwritten.
■ Chaos
Shared locks are held while the data is being read to avoid dirty reads, but the data can be changed before the end of the transaction, resulting in nonrepeatable reads or phantom data.
■ ReadCommitted
A dirty read is possible, meaning that no shared locks are issued and no exclusive locks are honored.
■ ReadUncommitted
530
Chapter 12
Creating Serviced Components
Locks are placed on all data that is used in a query, preventing other users from updating the data. This prevents nonrepeatable reads but phantom rows are still possible.
■ RepeatableRead
A range lock is placed on the dataset, preventing other users from updating or inserting rows in the dataset until the transaction is complete.
■ Serializable
Reduces blocking by storing a version of data that one application can read while another is modifying the same data. It indicates that from one trans action you cannot see changes made in other transactions, even if you re-query.
■ Snapshot
A different isolation level than the one specified is being used, but the level cannot be determined. When using OdbcTransaction, if you do not set IsolationLevel or you set IsolationLevel to Unspecified, the transaction executes according to the default isolation level of the underlying Open Database Con nectivity (ODBC) driver.
■ Unspecified
What is great about .NET 2.0 is that when using transactions this way the DTC doesn’t actually become involved until it becomes absolutely necessary. This is good, because managing a transaction across multiple data sources creates a fair amount of overhead. Delaying the involvement of the DTC dramatically improves performance. What happens in SubmitOrder? A great way to find out is to set a debugging break point at the first line in SubmitOrder and add a watch to System.Transactions.Transac tion.Current. To do this you need to add a project reference to System.Transactions. Also open the Component Services management console and select the Distributed Trans action Coordinator node and click Transaction Statistics. Now start debugging the application. You see that there is no transaction until the connection to the AdventureWorks database is opened. At this point you see that System.Transactions.Transac tion.Current holds a reference to a transaction object and that this transaction only has a LocalIdentifier (see Figure 12-4).
Lesson 1: Serviced Component Overview
531
Figure 12-4 Watch System.Transactions.Transaction.Current
The DistributedIdentifier has not yet been initialized because at this point in time the transaction has not yet been handed over to the DTC. We confirm this by looking at the Transaction Statistics pane (see Figure 12-5).
Figure 12-5 No currently active transactions
The statistics show that there are currently no active transactions. Now we continue stepping through our code. Enter the InformOfNewOrder method. At the very moment that you send the message, you see a change in the Watch window. The DistributedIdentifier gets initialized (see Figure 12-6) and when you check the transaction statistics you see that there is one currently active distributed transaction (see Figure 12-7).
532
Chapter 12
Creating Serviced Components
Figure 12-6 The Watch dialog box now shows a distributed identifier
Figure 12-7 Transaction statistics show an active distributed transaction
The System.Transactions namespace that is used to monitor what happens during the course of SubmitOrder is new to the .NET Framework 2.0. The System.EnterpriseSer vices namespace in the .NET Framework 2.0 has been partially rewritten to make use of this new namespace. System.EnterpriseServices makes use of the Lightweight Transac tion Manager (LTM). The LTM has been created as part of the .NET Framework 2.0 to improve performance of the transaction mechanism. LTM is part of the System.Trans actions namespace, which is discussed later. Note that you can only create applica tions using this namespace in the Microsoft Windows 2000, Windows XP, and Windows 2003 platforms. Creating a transaction in the Microsoft Windows 98 and Windows ME platforms throws a PlatformNotSupportedException.
Lesson 1: Serviced Component Overview
533
Object Pooling Object pooling means that a limited number of objects are made available for client use, and when clients have finished using objects, they are returned to the pool rather than destroyed, so subsequent clients can reuse these pooled instances. Use the ObjectPoolAttribute to specify the minimum (MinPoolSize) and maximum (MaxPoolSize) number of instances and the CreationTimeout. 'VB Namespace MSLearning.Chapter12.Services _
Public Class OrderService
Inherits ServicedComponent
'... End Class End Namespace //C# namespace MSLearning.Chapter12.Services { [ObjectPooling(MinPoolSize = 1, MaxPoolSize = 10,
CreationTimeout = 1000)]
public class OrderService : ServicedComponent { ///... } }
■ MinPoolSize
The minimum number of objects in the pool.
■ MaxPoolSize
The maximum number of objects in the pool.
The timeout value in milliseconds. Specifies how long a client will wait, in milliseconds, for an object to be returned from the pool. An excep tion is thrown if an object does not become available within the specified time.
■ CreationTimeout
JIT Activation JIT activation is a process whereby COM+ components are only created when they are required and are destroyed as soon as they are no longer required. JIT is often used in conjunction with object pooling. As the name says, the JustInTimeActivationAttribute is used to specify that a component needs to be activated JIT.
534
Chapter 12
Creating Serviced Components
'VB Namespace MSLearning.Chapter12.Services _ Public Class OrderService
Inherits ServicedComponent
'... End Class
End Namespace
//C# namespace MSLearning.Chapter12.Services
{
[JustInTimeActivation] public class OrderService : ServicedComponent
{
///...
}
}
Object Construction As mentioned earlier, COM+ offers a mechanism for string-based object construction where, after creating the object using the default constructor, the Construct method is called, passing a string containing information about the state of the object. Use the ConstructionEnabledAttribute to enable this behavior on registration of your COM+ application. 'VB Imports System.EnterpriseServices
Imports System.Runtime.InteropServices
Namespace MSLearning.Chapter12.Services _ Public Class OrderService
Inherits ServicedComponent
'... End Class
End Namespace
//C# namespace MSLearning.Chapter12.Services
{
[ConstructionEnabled(true, Default="place your default string here")] public class OrderService : ServicedComponent
Lesson 1: Serviced Component Overview
535
{
///
/// Default constructor is required for COM+ registration.
///
public OrderService()
{
}
///
/// Override the Construct method to get access
/// to the construction string.
///
/// Construction String
protected override void Construct(string s)
{
base.Construct(s); } } }
Note that the string placed in the constructor of the ConstructionEnabledAttribute is placed in the COM+ configuration at registration time. If the setting is changed, on the Activation tab, the default in your code becomes obsolete.
Private Components An application typically has a number of components that are internal to the applica tion. This means that the components are only visible and accessible by other compo nents in the same application. The PrivateComponentAttribute allows you to mark a component as internal. The fol lowing code sample shows how this is done: 'VB Imports System.EnterpriseServices Namespace MSLearning.Chapter12.Services _ Public Class AdventureWorksDB
Inherits ServicedComponent
Public Sub AdventureWorksDB()
End Sub
'... End Class End Namespace
536
Chapter 12
Creating Serviced Components
//C# using System.EnterpriseServices; namespace MSLearning.Chapter12.Services
{
[PrivateComponent] public class AdventureWorksDB {
public AdventureWorksDB()
{
}
///...
}
}
Queued Components Queued components make use of MSMQ but hide all of the complexity. Setting up queued components is a purely administrative task. This makes it easy to convert a regular synchronous operation to an asynchronous operation. Queued components are sometimes referred to as queued invocation or even asynchronous component invocation. Use both InterfaceQueuingAttribute at class level and the ApplicationQueuingAttribute at assembly level to configure this feature. A component needs to implement a public interface to be set up as a queued component. This can be implicit by decorating a class with the InterfaceQueuingAttribute, but the recommended method is to define an interface. In the following code sample, the Visual Studio 2005 refactoring Extract Interface is used to create the required interface definition: 'VB Namespace MSLearning.Chapter12.Services Public Class OrderService
Inherits ServicedComponent
Implements IOrderServiceQueued
'...
End Class
_ Public Interface IOrderServiceQueued '...
End Interface
End Namespace
Lesson 1: Serviced Component Overview
537
//C# namespace MSLearning.Chapter12.Services {
public class OrderService : ServicedComponent, IOrderServiceQueued
{
///...
}
[InterfaceQueuing(true)] public interface IOrderServiceQueued
{
///...
}
}
The Assemblyinfo.cs file needs to be changed to include the following: 'VB ' Mark the COM+ application as queued at compile time by using the ' ApplicationQueuing attribute. Enable the COM+ listener by ' setting the QueueListenerEnabled to true //C# // Mark the COM+ application as queued at compile time by using the // ApplicationQueuing attribute. Enable the COM+ listener by // setting the QueueListenerEnabled to true [assembly: ApplicationQueuing(Enabled = true, QueueListenerEnabled = true)]
Note that the initial SubmitOrder returns an integer containing the order ID. For obvi ous reasons, this return value is not available when calling the interface through a queued component. This is why IOrderServiceQueued implements an overloaded method that returns no value. In Lesson 2 of this chapter, we look at how to consume a serviced component. The underlying technology for queued components is message queuing. We look at con suming a queued component in Chapter 13.
Implementing Security on a Serviced Component The Enterprise Services role-based security is unrelated to Windows user groups, allowing you to define roles directly from the application’s business domain, even if no corresponding user groups exist. Management of which domain users belong to a specific group in your application can be done using the Component Services man agement console, but first you need to set up your component to make use of the secu rity features of Enterprise Services.
538
Chapter 12
Creating Serviced Components
You start at the assembly level. In the AssemblyInfo file, add the ApplicationAccessCon trolAttribute, which specifies access controls to an assembly containing ServicedCom ponent classes. 'VB Imports System.EnterpriseServices //C# using System.EnterpriseServices; [assembly: ApplicationAccessControl(true)]
At class level, specify that the class should be enabled for security checking and which roles you’re using in the class. The ComponentAccessControlAttribute enables security checking on calls to a component. The SecurityRoleAttribute configures a role for an application or component. The SecurityRoleAttribute allows for an extra Boolean parameter specifying whether domain group Everyone should be linked to the role. This is especially useful when allowing for a Guest account. 'VB Imports System.EnterpriseServices Namespace MSLearning.Chapter12.Services _ _
_
_
Public Class OrderService
Inherits ServicedComponent
Implements IOrderServiceQueued
'... End Class End Namespace //C# using System.EnterpriseServices; namespace MSLearning.Chapter12.Services { [ComVisible(true)] [ComponentAccessControl(true)]
[SecurityRole("Manager")]
[SecurityRole("Guest",true)]
public class OrderService : ServicedComponent, IOrderServiceQueued
{
Lesson 1: Serviced Component Overview
539
///... } }
Now all that remains is to perform the actual security check. Using COM+ security, use the ContextUtil or SecurityCallContext classes to retrieve information about the user. In this example, we want to change the SubmitOrder method in such a way that only managers are allowed to submit orders. To do this, add a private Boolean prop erty CurrentUserIsManager. To make the exception thrown more informative, include the account name of the user in the exception. 'VB Imports System.EnterpriseServices; Namespace MSLearning.Chapter12.Services _
_
_
_
Public Class OrderService
Inherits ServicedComponent
Implements IOrderServiceQueued
'... _ Public Sub SubmitOrder(ByVal customerId As Integer, ByVal articleId As Integer,
ByVal quantity As Integer)
If CurrentUserIsManager Then Dim db As New AdventureWorksDB()
Dim orderId As Integer
orderId = db.InsertOrder(customerId, articleId, quantity)
Dim q As New BillingEngineQueue()
q.InformOfNewOrder(customerId, orderId)
Else
Dim msg As String
msg = "Only Managers can submit orders. " _
& GetAccountName() _
& " is not a Manager."
Throw New Exception(msg)
End If
End Sub Private ReadOnly Property CurrentUserIsManager() As Boolean
540
Chapter 12
Creating Serviced Components
Get If (ContextUtil.IsSecurityEnabled) Then Return ContextUtil.IsCallerInRole("Manager") Else Return (False) End If End Get End Property Private Function GetAccountName() As String If (ContextUtil.IsSecurityEnabled) Then Return (SecurityCallContext.CurrentCall.OriginalCaller.AccountName) Else
Return String.Empty
End If
End Function
End Class
End Namespace
//C# using System.EnterpriseServices; namespace MSLearning.Chapter12.Services { [ComVisible(true)] [ComponentAccessControl(true)] [SecurityRole("Manager")] [SecurityRole("Guest",true)] public class OrderService : ServicedComponent, IOrderService { ///... [AutoComplete] public void SubmitOrder(int customerId, int articleId, int quantity) {
if (CurrentUserIsManager)
{
AdventureWorksDB db = new AdventureWorksDB(); int orderId = db.InsertOrder(customerId, articleId, quantity); BillingEngineQueue q = new BillingEngineQueue(); q.InformOfNewOrder(customerId, orderId); } else { string msg = "Only Managers can submit orders. " + GetAccountName() + " is not a Manager."; throw new Exception(msg); }
Lesson 1: Serviced Component Overview
541
} public DataSet GetOrders(int customerId) {
AdventureWorksDB db = new AdventureWorksDB();
return db.GetOrders(customerId);
}
///
/// Use ContextUtil to determine if current user is a Manager.
///
///
private bool CurrentUserIsManager
{
get {
if (ContextUtil.IsSecurityEnabled)
{
return ContextUtil.IsCallerInRole("Manager"); } else { return (false);
}
}
}
///
/// Use SecurityCallContext to determine account name of the
caller. /// /// public string GetAccountName() { if (ContextUtil.IsSecurityEnabled) return (SecurityCallContext.CurrentCall.OriginalCaller.AccountName); else return String.Empty; ; } } }
The roles for the component look as shown in Figure 12-8 after registering the com ponent in the COM+ catalog.
542
Chapter 12
Creating Serviced Components
Figure 12-8 The registered component is visible in Component Services
Services Without Components In the previous sections we looked at how to create and register a serviced compo nent. Doing this creates a situation where the serviced component can be configured through the Component Services management console. COM+ 1.5 offers an alterna tive way of gaining access to a subset of Enterprise Services, using the ServiceConfig class. This class has been available since the release of the CLR version 1.1. COM+ 1.5 is available on the Windows XP, Windows 2000, and Windows 2003 platforms. 'VB Public Sub DeleteCustomer(ByVal customerId As Integer) Try ' Create ServiceConfig and set properties to define the behavior ' of the services. Dim svc As New ServiceConfig() svc.Transaction = TransactionOption.RequiresNew svc.TransactionTimeout = 30 svc.TransactionDescription = "Service without Component" svc.TrackingAppName = "AdventureWorks advanced" svc.TrackingComponentName = "Chapter12" svc.TrackingEnabled = True ServiceDomain.Enter(svc) ' Use data access layer for database interaction
Dim db As New AdventureWorksDB()
'db.DeleteCustomer(id)
Lesson 1: Serviced Component Overview
' Use queue proxy for informing remote system
Dim q As New BillingEngineQueue()
'q.InformOfDeletedCustomer(id)
' Commit transaction
ContextUtil.SetComplete()
Catch ex As Exception
' Log error and abort transaction
Trace.WriteLine("ERROR: " & ex.Message)
ContextUtil.SetAbort()
Finally
' Always leave the service domain.
ServiceDomain.Leave()
End Try End Sub //C# public void DeleteCustomer(int id) { try { // Create ServiceConfig and set properties to define the behavior
// of the services.
ServiceConfig svc = new ServiceConfig();
svc.Transaction = TransactionOption.RequiresNew;
svc.TransactionTimeout = 30;
svc.TransactionDescription = "Service without Component";
svc.TrackingAppName = "AdventureWorks advanced";
svc.TrackingComponentName = "Chapter12";
svc.TrackingEnabled = true;
ServiceDomain.Enter(svc);
// Use data access layer for database interaction
AdventureWorksDB db = new AdventureWorksDB();
db.DeleteCustomer(id);
// Use queue proxy for informing remote system
BillingEngineQueue q = new BillingEngineQueue();
q.InformOfDeletedCustomer(id);
// Commit transaction ContextUtil.SetComplete();
}
catch (Exception ex)
{
// Log error and abort transaction
Trace.WriteLine("ERROR: " + ex.Message);
ContextUtil.SetAbort();
}
finally
{
543
544
Chapter 12
Creating Serviced Components
// Always leave the service domain.
ServiceDomain.Leave();
}
}
Not all Enterprise Services are available when using ServiceConfig. Some very useful services such as object pooling, JIT activation, queued components, and loosely cou pled events are not available. Also note that this only works on platforms that run COM+ 1.5 (currently Windows XP, Windows 2000, and Windows 2003).
System.Transactions System.Transactions builds on top of services without components. The most impor tant features offered by System.Transactions are the following: ■
An easy-to-use programming model.
■
Support for transactional code blocks using the TransactionScope class.
■
A fast LTM for appdomain transactions that involve at most a single durable resource manager.
■
Automatic promotion from “lightweight” to distributed transactions on an asneeded basis (as shown earlier in this chapter).
■
Protection against early commits in an asynchronous environment using IDepen dentTransaction.
System.Transactions is built using ServiceConfig. This results in not having to register the serviced component in the COM+ catalog, but the use of COM+ 1.5 has as a con sequence that the namespace is only supported on Windows XP, Windows 2000, and Windows 2003. The following code shows the easiest way to use the classes in the System.Transactions namespace to manage a transaction: 'VB Imports System.Transactions
Imports System.Data.SqlClient
Public Class CustomerService ''' ''' ''' ''' '''
This method demonstrates how to use
System.Transactions.TransactionScope
to manage a transaction.
Lesson 1: Serviced Component Overview
'''
'''
Public Sub AddCustomer(ByVal name As String)
Using ts As New TransactionScope() Dim conn As New SqlConnection("your connection string") conn.Open() Dim cmd As New SqlCommand("insert into Customer ...", conn) cmd.ExecuteNonQuery() conn.Close() ts.Complete() End Using End Sub End Class //C# using using using using using
System; System.EnterpriseServices; System.Diagnostics; System.Transactions; System.Data.SqlClient;
namespace MSLearning.Chapter12.Services { public class CustomerService { ///
/// This method demonstrates how to use
/// System.Transactions.TransactionScope
/// to manage a transaction.
///
///
public void AddCustomer(string name)
{
using (TransactionScope ts = new TransactionScope()) { SqlConnection conn = new SqlConnection("your connection string"); conn.Open(); SqlCommand cmd = new SqlCommand("insert into Customer ...", conn); cmd.ExecuteNonQuery(); conn.Close(); ts.Complete(); } } } }
545
546
Chapter 12
Creating Serviced Components
Lab 1: Building a Simple Serviced Component In this lab, you create a simple serviced component and register it in the COM+ cata log. �
Exercise 1: Creating a Serviced Component
In this exercise, you create a class library named SalesService that offers methods for reading and inserting Sales Reasons values in the AdventureWorks database. 1. Open Visual Studio 2005 and create a blank solution named MSLearning.Exercises. 2. Add a new C# or Visual Basic Class Library project. 3. Name the project AdventureWorksServices. 4. In Solution Explorer, right-click the project and click Properties. In the Default Namespace text box, type MSLearning.Chapter12.Services. 5. In the project’s Properties window, click the Signing tab. Select the Sign The Assembly check box. Create a new key using the drop-down list box. 6. Delete the Class1 file. 7. Select Project, Add New Item, and click Class. Name the class SalesService and define it as illustrated in the following code example: 'VB Namespace MSLearning.Chapter12.Services {
Public Class SalesService
{
}
} //C# using System; namespace MSLearning.Chapter12.Services {
public class SalesService
{
}
}
8. Click Project, Add Reference, click System.EnterpriseServices on the .NET tab, and click OK. 9. Click Project, Add New Item, and click Class. Name the class AdventureWorksDB and define it as illustrated in the following code example, adjusting
Lesson 1: Serviced Component Overview
547
the connection string to point to the right location for the AdventureWorks data base: 'VB Imports System.Data.SqlClient Imports System.EnterpriseServices Namespace MSLearning.Chapter12.Services
_
Friend Class AdventureWorksDB
' Change string to match where your AdventureWorks database is
' located
Private Const cConnectionString As String = _
"DataSource=.\SQLEXPRESS;" & _
"AttachDbFilename='C:\Program Files\Microsoft SQL" & _
"Server\MSSQL.1\MSSQL\Data\AdventureWorks_Data.mdf';" & _
"IntegratedSecurity=True;Connect Timeout=30;User Instance=True"
Friend Sub AdventureWorksDB()
End Sub
Friend Function InsertSalesReason(ByVal name As String, _
ByVal reason As String) As Integer Dim sql As String sql = "INSERT INTO Sales.SalesReason (Name, ReasonType," & _ "ModifiedDate) VALUES ('" & name & "', '" & reason & _ "', GETDATE()); select COPE_IDENTITY()"
Dim conn As SqlConnection
conn = New SqlConnection(cConnectionString)
Dim cmd As New SqlCommand(sql, conn)
conn.Open()
Dim id As Object
id = cmd.ExecuteScalar()
conn.Close()
Return Convert.ToInt32(id)
End Function End Class End Namespace //C# using System; using System.Data.SqlClient; using System.EnterpriseServices; namespace MSLearning.Chapter12.Services {
548
Chapter 12
Creating Serviced Components
[PrivateComponent]
internal class AdventureWorksDB
{
internal AdventureWorksDB()
{
}
private const string cConnectionString = @"DataSource=.\SQLEXPRESS;" + @"AttachDbFilename='C:\Program Files\Microsoft SQL" + @"Server\MSSQL.1\MSSQL\Data\AdventureWorks_Data.mdf';" + @"IntegratedSecurity=True;Connect Timeout=30;" + @"User Instance=True";
internal int InsertSalesReason(string name, string reason) { string sql = "INSERT INTO Sales.SalesReason (Name, ReasonType," + "ModifiedDate) VALUES ('" + name + "', '" + reason + "', " + "GETDATE()); selectSCOPE_IDENTITY()"; SqlConnection conn = new SqlConnection(cConnectionString);
SqlCommand cmd = new SqlCommand(sql, conn);
conn.Open();
object id = cmd.ExecuteScalar();
conn.Close();
return Convert.ToInt32(id);
}
}
}
10. Open the SalesService file and add a public constructor, add System.EnterpriseServices and System.Runtime.InteropServices to the using statements, add an attribute to make the class ComVisible, inherit from ServicedComponent, add attributes to manage transactions, and define the security roles Manager and Guest. Only managers can add a SalesReason. Your code should now look like the following: 'VB Imports System
Imports System.EnterpriseServices
Imports System.Runtime.InteropServices
Namespace MSLearning.Chapter12.Services
_
_
_
_
_
Public Class SalesService
Inherits ServicedComponent
Lesson 1: Serviced Component Overview
Public Sub SalesService()
End Sub
_
Public Sub InsertSalesReason(ByVal name As String, _
ByVal reason As String)
If (ContextUtil.IsSecurityEnabled AndAlso _
ContextUtil.IsCallerInRole("Manager")) Then
Dim db As New AdventureWorksDB()
db.InsertSalesReason(name, reason)
End If
End Sub
End Class End Namespace //C# using System; using System.EnterpriseServices; using System.Runtime.InteropServices; namespace MSLearning.Chapter12.Services { [ComVisible(true)] [Transaction(TransactionOption.Required)] [ComponentAccessControl(true)] [SecurityRole("Manager")] [SecurityRole("Guest", true)] public class SalesService : ServicedComponent { public SalesService()
{
}
[AutoComplete]
public void InsertSalesReason(string name, string reason)
{
if (ContextUtil.IsSecurityEnabled &&
ContextUtil.IsCallerInRole("Manager"))
{
AdventureWorksDB db = new AdventureWorksDB();
db.InsertSalesReason(name, reason);
} } } }
549
550
Chapter 12
Creating Serviced Components
11. Open the AssemblyInfo file. In C# it is visible under the Properties node in Solu tion Explorer. In Visual Basic you have to click Show All Files in Solution Explorer before it becomes visible. 12. Set the COM+ application name to AdventureWorks, enable security checking, and mark the COM+ application as a library component. Your code should look like the following: 'VB Imports System.EnterpriseServices
//C# using System.EnterpriseServices; [assembly: ApplicationName("AdventureWorks")]
[assembly: ApplicationActivation(ActivationOption.Library)]
[assembly: ApplicationAccessControl(true)]
13. On the Visual Studio Project menu, click Rebuild Solution. �
Exercise 2: Registering a Serviced Component
1. Start the Component Services management console by clicking Start, Control Panel, Administrative Tools, Component Services. 2. Browse the Component Services node. On a clean machine your system will look like Figure 12-9. Depending on what applications are installed you might see additional COM+ applications. Close the Component Services management console.
Lesson 1: Serviced Component Overview
551
Figure 12-9 A clean view of the COM+ applications on your system
3. Open the Visual Studio 2005 command prompt by clicking Start, All Programs, Microsoft Visual Studio 2005, Visual Studio Tools, Visual Studio 2005 Com mand Prompt. 4. Change your current directory to the location where you’ve just built the project in Lesson 1. By default, it will be a subfolder in My Documents\Visual Studio 2005\Projects. 5. Type the following: regsvcs AdventureWorksServices.dll AdventureWorks
6. On the Start menu, start the Component Services management console by click ing Start, Control Panel, Administrative Tools, Component Services.
552
Chapter 12
Creating Serviced Components
7. Browse the Component Services node. Your system should look like Figure 12-10 (which is the same as we saw earlier in this chapter).
8. The registered component is visible in Component Services
Lesson Summary ■
Serviced components are part of Enterprise Services, the next generation of COM+.
■
A serviced component is created by inheriting from System.EnterpriseServices.Ser vicedComponent.
■
Interaction from managed code to Enterprise Services is done using a variety of attributes, the ContextUtil class, and the SecurityCallContext class.
■
There are four ways of registering your serviced component in the COM+ cata log: MMC, Service Installation Tool (Regsvcs.exe), dynamic registration, and Windows Installer (MSI) package.
■
Transactions in Enterprise Services use System.Transactions if possible but is backward-compatible with older platforms.
■
The Transaction attribute can be used to declare a class part of a transaction.
Lesson 1: Serviced Component Overview
553
■
The AutoComplete attribute can be used to let a method automatically notify the transaction of success or failure, leading to a vote to commit or abort.
■
The .NET Framework 2.0 offers the LTM, a component that promotes a transac tion only to the DTC if necessary.
■
Services without Component allow for the use of a subset of Enterprise Services with the benefit of not having to preregister the component in the COM+ catalog.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Serviced Component Overview.” The questions are also available on the com panion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which of the following statements are true? (Choose all that apply.) A. A serviced component needs to implement the IServicedComponent inter face. B. The ServicedComponent base class is located in the System.EnterpriseServices namespace. C. The ServicedComponent base class is located in the System.EnterpriseCompo nents namespace. D. A serviced component needs to inherit from the ServicedComponent class. 2. Which attributes are relevant when implementing transactions using Enterprise Services? (Choose all that apply.) A. System.EnterpriseServices.AutoCompleteAttribute B. System.Runtime.InteropServices.ComVisibleAttribute C. System.EnterpriseServices.TransactionAttribute D. System.EnterpriseServices.JustInTimeActivationAttribute
554
Chapter 12
Creating Serviced Components
3. Which options are valid ways to register a serviced component? (Choose all that apply.) A. Command line: sn.exe –k myassembly.dll
B. Command line: regsvcs.exe myassembly.dll AppName
C. Create an application folder in C:\Program Files\ComPlus and drag MyAs sembly.dll into this folder. D. Create an application node in the Component Services management con sole and drag MyAssembly.dll onto this node.
Lesson 2: Consuming the Serviced Component
555
Lesson 2: Consuming the Serviced Component In this lesson you learn how to consume a serviced component by creating an appli cation that references an assembly that contains a serviced component and accessing methods and properties on the serviced component. You continue where Lesson 1 finished. After this lesson, you will be able to: ■
Create an application that consumes a serviced component.
■
Access methods, properties, and events on a serviced component.
Estimated lesson time: 25 minutes
Referencing the Assembly that Contains the Component In Lesson 1 you learned how to create and register a serviced component. Moving for ward, we now want to create an application that consumes the services on the ser viced component. The first step in this process in creating a reference to the serviced component. This is actually a pretty straightforward process. You create the reference as you would any other reference to an external assembly. Let’s assume you’ve just added a console application named MSLearning.Chapter12.Con soleClient to our existing solution and from this application we want to consume the AdventureWorks OrderService created in Lesson 1. Click Project, Add Reference, and then click MSLearning.Chapter12.Services.dll from the Projects tab. Alternatively, if you created a new solution, you would browse for MSLearning.Chapter12.Services.dll. Now because MSLearning.Chapter12.Services.dll references System.EnterpriseServices.dll, and this is not a default reference, we also need to add a reference to System.EnterpriseServices.dll from our console application. A serviced component reference is created just as you would create any other reference. Now it is important to note that because MSLearning.Chapter12.Services.dll is a strongnamed assembly, the reference you create to this assembly is also very specific. Chang ing the version number of the assembly and redeploying MSLearning.Chapter12.Ser vices.dll means that you break the reference. This broken reference can be solved by
556
Chapter 12
Creating Serviced Components
recompiling the console application against the new version of MSLearn ing.Chapter12.Services.dll or by using a policy that redirects the binding. The imple mentation of policies is outside the scope of this chapter, but you should be aware that it is an option.
Queued Components Referencing queued components works a little differently. The underlying technology of message queues is not covered until Chapter 13, when we return to how to con sume a queued component.
Declaring and Instantiating the Component Having created a reference to the assembly, you are now ready to declare and instan tiate the serviced component. Again, as the following code shows, there is little magic involved. Create an instance of the serviced component as if it were any other class, call SubmitOrder, telling it customer 10 wants to order 5 articles with the article ID 255. If successful, your display shows the orderId; if an exception occurs, you display the exception. 'VB Imports System Imports MSLearning.Chapter12.Services Namespace MSLearning.Chapter12.ConsoleClient
Public Class Program
Sub Main() Dim os As OrderService = New OrderService() Console.WriteLine("Serviced Component is created.") Console.ReadKey() End Sub
End Class
End Namespace
//C# using System; using MSLearning.Chapter12.Services; namespace MSLearning.Chapter12.ConsoleClient {
class Program
{
static void Main(string[] args) {
OrderService os = new OrderService();
Lesson 2: Consuming the Serviced Component
557
Console.WriteLine(“Serviced Component is created.”);
Console.ReadKey();
}
}
}
Access Properties, Methods, and Events of the Component After creating an instance of the OrderService, you want to add code to call SubmitOrder, telling it customer 10 wants to order 5 articles with the article ID 255. If suc cessful, your display shows the orderId; if an exception occurs, you display the exception. 'VB Imports System Imports MSLearning.Chapter12.Services Namespace MSLearning.Chapter12.ConsoleClient
Public Class Program
Sub Main()
Try Dim os As OrderService = New OrderService() Console.WriteLine("Serviced Component is created.") Console.ReadKey() Catch ex As Exception
Console.WriteLine("An error occured: " + ex.Message)
End Try
End Sub
End Class
End Namespace
//C# using System; using MSLearning.Chapter12.Services; namespace MSLearning.Chapter12.ConsoleClient {
class Program
{
static void Main(string[] args) {
try
{
OrderService os = new OrderService(); int orderid = os.SubmitOrder(10, 255, 5); Console.WriteLine("Order " + orderid.ToString() + " has been submitted."); } catch (Exception ex)
558
Chapter 12
Creating Serviced Components
{ Console.WriteLine("An error occured: " + ex.Message); } Console.ReadKey(); }
}
}
Lab 2: Using the Serviced Component in a Separate Application In this exercise, you create a console application named ConsoleClient that creates and consumes the service for inserting SalesReasons that you created in Lesson 1. If you chose to skip Lesson 1, look on the CD for the results of Lesson 1 and continue from there. 1. Open Visual Studio 2005 and open the solution created in Lesson 1, named MSLearning.Exercises. 2. Add a new C# or Visual Basic 2005 Console Application project. 3. Name the project ConsoleClient. 4. In Solution Explorer, right-click the project and click Properties. In the Default Namespace text box, type MSLearning.Chapter12.ConsoleClient. 5. Right-click the project in Solution Explorer and add a project reference to the AdventureWorksServices project. 6. Open the file Program.cs. 7. Modify the code to include an MSLearning.Chapter12.Lesson1 statement, make the Main method create an instance of the SalesService, and call the InsertSalesReason method. You can make up your own name and reason, write to the console that the sales reason has been added, and wait for a keystroke before terminating the application. Your code should look like this: 'VB Imports MSLearning.Chapter12.Services Module Module1 Sub Main() Using service As New SalesService() service.InsertSalesReason("MCP discount", _ "Certified Professionals are our friends.") Console.WriteLine("Sales reason has been added.") Console.ReadLine() End Using
Lesson 2: Consuming the Serviced Component
559
End Sub End Module //C# using System;
using MSLearning.Chapter12.Services;
namespace MSLearning.Chapter12.ConsoleClient {
class Program
{
static void Main(string[] args) { using (SalesService service = new SalesService()) { service.InsertSalesReason("MCP discount", "Certified Professionals are our friends."); Console.WriteLine("Sales reason has been added."); Console.ReadLine(); }
}
}
}
Lesson Summary ■
Referencing a serviced component is no harder than referencing any other man aged code assembly.
■
Calling a method or accessing a property on a serviced component from man aged code is like calling a regular method or property.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Consuming the Serviced Component.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
560
Chapter 12
Creating Serviced Components
1. Which are true of types that inherit from ServicedComponent? (Choose all that apply.) A. You can use Add Web Reference to consume the service. B. The accessibility of the class needs to be public. C. They have to explicitly implement an interface. D. You can use Add Reference to consume the service. 2. Which methods can you use to create an instance of a serviced component? (Choose all that apply.) A. Use Activator.CreateInstanceFrom(...). B. Add a reference to the assembly and use the new keyword. C. Add a reference to the object registered in the COM+ catalog and use the new keyword. 3. Which of the following statements are true? (Choose all that apply.) A. A serviced component needs to have an application name. B. A serviced component needs to have a strong name. C. A serviced component can only call other serviced components. D. A serviced component can only call components with a strong name.
Chapter 12 Review
561
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Serviced components are created by inheriting from System.EnterpriseServices.Ser vicedComponent.
■
Interaction with Enterprise Services is managed by adorning classes and meth ods with attributes that contain metadata.
■
Distributed transaction management is the most frequently used service offered by Enterprise Services.
■
System.Transactions offers a separate programming model for managing transac tions. The LTM escalates the transaction to a distributed transaction if and when required.
■
Consuming a serviced component is no different than calling a method, prop erty, or event on a regular external type.
■
Security through Enterprise Services can be managed externally, separate from the domain roles, using the Component Services management console.
Key Terms ■
Component Services management console
■
Lightweight Transaction Manager
■
Microsoft Distributed Transaction Coordinator
■
transaction isolation levels
562
Chapter 12 Review
Case Scenario In the following case scenarios you apply what you’ve learned about how to use ser viced components. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Reliability Through Transactions Interviews Following is a list of company personnel interviewed and their statements. We have recently seen a big increase in the load on our application server and suddenly we find that orders seem to go missing. Our sales system shows that the order was accepted from the Web site, but the order to ship never entered the shipping system. Current code that seemed to work fine under low server load appears to be less reliable as load increases. I think we don’t manage our transactions right, the original code was completed under severe time constraints, and I don’t believe we’re using distributed transactions. We need to evaluate our code and fix our transaction problem.”
■ IT Department Head
We need to be able to rely on data integrity across the var ious systems we have in play. Right now we are sending invoices for orders in our sales system, but we never ship. We’re losing customers. This is unacceptable!”
■ Lead Business Analyst
“Every customer lost is loss of face, and, on the Internet, the bad experi ences of customers spread like wildfire. What might look like only two or three unhappy customers can turn into the downfall of our online store at the drop of a hat. Fix it!”
■ CIO
Questions Answer the following questions for your manager: 1. Do our data stores support transactions? 2. Do we have the application logic for the online store running on a separate machine from the actual Web pages? 3. How can changes be made to the application logic that will make it more reliable?
Chapter 12 Review
563
Case Scenario 2: Optimizing Performance Interviews Following is a list of company personnel interviewed and their statements. “Our application runs great in the test environment, with a limited amount of users. The server loads seem a little high, but we never wor ried about it too much. In a production environment with many more users, the application grinds to a halt.”
■ IT Department Head
■ Lead Business Analyst
“We need to support more users.”
“We spend all this money on developing this system. Surely it can’t be that hard to improve the performance.”
■ CIO
Questions Answer the following questions for your manager: 1. Are you using object pooling? 2. Is the component designed to be stateless? If so, are you using JIT activation?
Suggested Practices To successfully master the objectives covered in this chapter, complete the following tasks.
Create, Configure, and Access a Serviced Component The following two practices let you implement a serviced component without the aid of a step-by-step tutorial. Try it to test yourself on how well you’ve understood the material. Create a class that inherits from ServicedComponent. Make use of object pooling service in Enterprise Services. Create a console client that tries to create more objects than are configured in your pool. Use the Component Ser vices management console to monitor the result.
■ Practice 1
564
Chapter 12 Review
Create a class that inherits from ServicedComponent. Set the class to require a transaction using the Transaction attribute. Implement a method that inserts data in two separate databases. Use the AutoComplete attribute on the method. Create a console application to run the code. Now adjust the code to make the method throw an exception after inserting data. Look at the transac tion statistics in the Component Services management console.
■ Practice 2
Implement Security in a Serviced Component The following is a little more advanced than the previous test and tests your overview on security. Create a class that inherits from ServicedComponent. Create a method that adds orders to a database. Create a check to see that only users that are in the manager role can add orders for more than $2,000. Add yourself to the man ager role using the Component Services management console.
■ Practice 1
Using Automatic Transactions This practice tests your understanding of automatic transactions and requires a little more time to implement because multiple databases are involved. Create a class library with a serviced component that implements a TransferFunds method. You need to create two databases, each with an account table. An account should have a number of fields, one of which is balance. Your method should accept an amount of money as a parameter and subtract the amount from an account in Database 1 and add it to an account in Database 2. Throw an exception if there are insufficient funds.
■ Practice 1
Hint: Use the AutoComplete attribute on the TransferFunds method. Building on Practice 1, create a Winform application that allows you to select two accounts, one for source and one for destination, and the amount of money that needs to be transfered. Add a reference to the library created ear lier and call the TransferFunds method.
■ Practice 2
Chapter 12 Review
565
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Prac tice Tests” in this book’s Introduction.
Chapter 13
Serviced Component Management
Having learned how to create and deploy a serviced component in Chapter 12, “Cre ating Serviced Components,” it is now time for you to take matters a step further. In this chapter we take a look at message queuing and securing messages. Microsoft Mes sage Queuing (MSMQ) enables applications running at different times to communicate across networks and systems that might be temporarily offline. MSMQ provides guar anteed message delivery, efficient routing, security, and priority-based messaging. Message queuing can be used to implement scenarios in which messages are sent asynchronously, but synchronous scenarios are also within the realm of possibility. This chapter assumes the use of the latest version of MSMQ, which is MSMQ 3.0. MSMQ 3.0 is available for Microsoft Windows Server 2003 and Windows XP. If you are running older versions of Windows, note that MSMQ 1.0 is part of the Microsoft Windows NT 4.0 option pack. This version requires Microsoft SQL Server for storing the names of the queues. MSMQ 2.0 is part of Microsoft Windows 2000 and uses Microsoft Active Directory directory service for storing queue names. If Active Directory is unavailable, you can only use message queuing in workgroup mode.
Exam objectives in this chapter: ■
■
Create, delete, and set permissions on a message queue. ❑
Create a message queue manually.
❑
Create a message queue programmatically.
❑
Delete a message queue.
❑
Set permissions for a message queue programmatically.
Send messages to a message queue and delete messages from a message queue. ❑
Create a message.
❑
Post a message.
❑
Receive a message synchronously.
❑
Decide which formatter to use.
567
568
Chapter 13
■
■
■
Serviced Component Management
❑
Read a message body.
❑
Delete queued messages.
Receive messages. ❑
Peek at messages.
❑
Enumerate messages.
❑
Receive a message asynchronously.
❑
Use BeginReceive/BeginPeek methods.
❑
Respond to a ReceiveCompleted or PeekCompleted event.
Sign and encrypt messages. ❑
Sign a message.
❑
Encrypt a message by using UseEncryption and EncryptionAlgorithm prop erties.
❑
Handle acknowledgments.
Process messages. ❑
Verify a message source by using a certificate.
❑
Decrypt a message.
❑
Extract response queue details from a message.
❑
Compose and send a response to a response queue.
❑
Apply a rule to a message queue.
Lessons in this chapter: ■
Lesson 1: Message Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
■
Lesson 2: Securing Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
Before You Begin To complete the lessons in this chapter, you should be familiar with Microsoft Visual Basic or C# and be comfortable with the following tasks: ■
Creating a library and console application in Microsoft Visual Studio using Visual Basic or C#.
■
Adding references to system class libraries to a project.
Before You Begin
569
■
Adding references to projects within a solution.
■
A basic understanding of remoting methodologies (XML Web services, DCOM, .NET Remoting, CORBA, and so on).
■
A basic understanding of COM+.
■
A basic understanding of queuing technologies like MSMQ.
■
A basic understanding of distributed transactions.
■
A basic understanding of ADO.NET.
■
A basic understanding of serviced components.
■
Must have read and understood Chapter 12 in this book.
Real World Mark Blomsma Message queuing solutions are ideal for building applications that need to be available 24/7. Asynchronous communication is the key to keeping systems online, even when systems in the vicinity of the application go down. I worked on a huge project for a customer where the system we were developing ended up being split into several subsystems. The goal was to be able to keep system A up and running, even when system B was unavailable. The solution was to use mes sage queuing. All data going from A to B was sent using asynchronous messages. System A never did a Web service call or Remote Procedure Call (RPC), it only sent messages. If system B went offline, the messages would collect in a queue, waiting to get processed as soon as system B came back online. Advantages were realized in both availability and performance. Putting a message on the queue is a fire-and-forget action, costing very little in terms of performance. It is impor tant to note that asynchronous processing does impact the way the user inter acts with the system. If processing in system B fails, how do you notify the user? This is part of the design challenge.
570
Chapter 13
Serviced Component Management
Lesson 1: Message Queues In this lesson we look at how to create, use, and monitor message queues using MSMQ technology. You gain an understanding of what a message queue is, how to cre ate one, and how to use Enterprise Services to use distributed transaction manage ment to enlist the usage of a queue in a transaction. You read and write to the queue and use the Microsoft Management Console to monitor the queues. We look at both synchronous and asynchronous use of message queues. After this lesson, you will be able to: ■
Describe the basics of message queuing.
■
Set up a message queue.
■
Send a message to a message queue.
■
Read a message from a message queue.
■
Send and receive a message asynchronously.
■
Enumerate messages.
■
Peek at messages.
■
Correlate messages.
Estimated lesson time: 45 minutes
Message Queuing Basics Before we go into creating and using message queuing, let’s take a step back and have a quick look at the basics of message queuing. Sending messages in a message queuing scenario is much like sending a letter through the mail. With message queuing there is a sending and receiving application, just as with a letter, where there is a sender and recipient. With message queuing you drop your message in a message queue and expect the message to be delivered, much as with a letter that you drop in a mailbox and wait for its delivery. In a message queu ing scenario, if your network is overloaded your message takes a bit longer to get deliv ered, just as if the mailman gets stuck in traffic, your message might arrive a bit later. If the receiving application does not become available within a preset timeout period, the message is rerouted to a dead-letter queue. With the letter, if the recipient is unavailable, perhaps because he or she moved or is on an extended vacation, the let ter remains at the post office; it is returned to the sender after a 30-day period. Perhaps the only difference between message queuing and the mail system is that MSQM guar
Lesson 1: Message Queues
571
antees 100 percent delivery, whereas the postal system has a lower service level. There are two basic kinds of queues: public and private. A public queue is registered in Active Directory and as such can be discovered by browsing the network. A private queue is created on a machine and can only be accessed from another machine if you know the exact name of the machine and queue. Private queues are usually used if operating in Windows workgroup mode or if the queue is meant to connect two appli cations running on the same machine. In workgroup mode, private queues are the only option, but even in domain mode, consider the following advantages of using private queues: ■
Private queues have all the features of public queues except that private queues are not listed in Active Directory and are not discoverable. If you know the queue is available, you can still connect remotely.
■
Private queues are faster to create than public queues because they require no extra time for Active Directory activity.
■
Private queues do not cause Active Directory replication problems.
Aside from queues there are also a number of queues for administrative purposes. Table 13-1 below shows the queue type, description, and syntax of the pathname. Note that you can use “.” if you want to refer to your local machine, for example, “.\Pri vate$\MyQueue”. Table 13-1 Queue Types, Description, and Syntax of the Pathname
Queue Type
Description
Syntax
Public queue
Registered in directory services, can be located by any message queuing applications
MachineName \QueueName
Private queue
Registered on local machine, typically cannot be located by other applications
MachineName\Private$ \QueueName
Journal queue
Contains removed mes sages, queue specific (if enabled)
MachineName \QueueName\Journal$
572
Chapter 13
Serviced Component Management
Table 13-1 Queue Types, Description, and Syntax of the Pathname
Queue Type
Description
Syntax
Machine journal queue
Contains removed mes sages, machine wide (if enabled)
MachineName\Journal$
Machine dead-letter queue
Contains undeliverable messages (if enabled)
MachineName \Deadletter$
Machine transactional dead-letter queue
Contains undeliverable transactional messages (if enabled)
MachineName \XactDeadletter$
Queues can be transactional. When a queue is transactional, the retrieval of a message from the queue triggers the Distributed Transaction Coordinator (DTC) into manag ing a distributed transaction. This process is particularly useful when you want to guarantee that any message removed from the queue has actually been successfully processed. Consider the following scenario: Our online store has accepted an order and sends a message to the shipping system. The shipping system receives the mes sage on the queue, reads it, and wants to insert a shipping order in the database. The insert fails with a message indicating that the transaction log is full. Now what? The message has been retrieved from the queue but has not been processed, and writing a status to the database is impossible because database access is impossible at this time. If the queue has been marked as transactional, by having a distributed transac tion we ensure that when the database insert fails, the removal of the message from the queue is actually rolled back, to be processed when the database becomes avail able again. A proper design choice would be to automatically alert a system adminis trator of the technical difficulties with the system.
Setting Up a Message Queue A queue can be set up manually, using the Microsoft Management Console (MMC), or through code.
Manually Setting Up a Message Queue The following steps show how to set up a message queue manually: 1. Click Start, Control Panel, Administrative Tools, Computer Management, or click Start, Run, and type compmgmt.msc to start the Computer Management console.
Lesson 1: Message Queues
573
2. Expand the Services And Applications node. 3. Expand the Message Queuing node. If you do not see the Message Queuing node, you most likely have not installed MSMQ. Use Add/Remove Windows Compo nents (part of Add/Remove Programs in Control Panel) to install this feature of Windows XP or Windows Server 2003. Your window should resemble Figure 13-1.
Figure 13-1 Default view of Message Queuing in the Computer Management console
4. Next, create a private queue. Right-click Private Queues, click New, click Private Queue, type MyQueue as a name for your queue, and click the Transactional check box (see Figure 13-2).
Figure 13-2 Create a private, transactional, message queue
574
Chapter 13
Serviced Component Management
5. Click OK. The queue has been created, and your screen should resemble Figure 13-3.
Figure 13-3 MyQueue has been created
Setting Up a Message Queue Programmatically The Framework Class Library contains a namespace named System.Messaging that contains classes that encapsulate the queue functionality. To be able to use this namespace, you need to add a reference to System.Messaging.dll. The two most signif icant classes are MessageQueue and Message. Use the static methods on the MessageQueue class to check whether your queue already exists. If it doesn’t, create the queue and set the label to match the name of the queue. The following code shows a console application named QueueSender implementing the check and creation of a queue named ShippingInbox (bold is used to emphasize the relevant portions). Notice how the private$ in the name of the queue is used to indicate that the queue should be pri vate. Special priviliges are required to register a queue in Active Directory so a try/ catch is warranted when creating a queue. On Windows XP, any member of the Users group can create a private queue. 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
Lesson 1: Message Queues
Dim queue As MessageQueue ' Check to see if queue exists using static method. If MessageQueue.Exists(cQueueName) Then
Console.WriteLine("Queue '{0}' already exists.", cQueueName)
queue = New MessageQueue(cQueueName)
Else
Console.WriteLine("Queue '{0}' does not exist.", cQueueName)
Try
' Create the queue and set the label. queue = MessageQueue.Create(cQueueName, True) queue.Label = cQueueName
Console.WriteLine("Queue created.")
Catch exception As Exception
Console.WriteLine("Queue not created. Error message: {0}", _
exception.Message)
End Try
End If
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub
End Module //C#
using System; using System.Messaging;
namespace QueueSender { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args) {
MessageQueue queue;
// Check to see if queue exists using static method.
if (MessageQueue.Exists(cQueueName))
{
Console.WriteLine("Queue '{0}' already exists.", cQueueName); queue = new MessageQueue(cQueueName); }
else
{
Console.WriteLine("Queue '{0}' does not exist.", cQueueName); try { // Create the queue and set the label. queue = MessageQueue.Create(cQueueName, true); queue.Label = cQueueName; Console.WriteLine("Queue created.");
}
catch (Exception exception)
575
576
Chapter 13
Serviced Component Management
{ Console.WriteLine("Queue not created. Error message: {0}", exception.Message); }
}
Console.WriteLine("Hit enter...");
Console.ReadLine();
} } }
After running the application, use the Computer Management console to check and see that the queue has been created. The Computer Management console should resem ble Figure 13-4.
Figure 13-4 ShippingInbox has been created
Deleting a Message Queue There are two ways to delete a message queue. The first method uses the Computer Management console. Simply right-click the appropriate queue and click Delete. Beware: Any messages in the queue are permanently deleted. The second method uses Delete on the MessageQueue class. The following code shows how this is done (bold is used to emphasize the relevant portions): 'VB Imports System.Messaging
Lesson 1: Message Queues
577
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
If MessageQueue.Exists(cQueueName) Then
MessageQueue.Delete(cQueueName) Console.WriteLine("Queue '{0}' has been deleted.", cQueueName) Else Console.WriteLine("Queue '{0}' does not exist.", cQueueName) End If Console.WriteLine("Hit enter...") Console.ReadLine() End Sub End Module //C# using System;
using System.Messaging;
namespace QueueDelete {
class Program
{
private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args) {
if (MessageQueue.Exists(cQueueName))
{
MessageQueue.Delete(cQueueName); Console.WriteLine("Queue '{0}' has been deleted.", cQueueName); } else { Console.WriteLine("Queue '{0}' does not exist.", cQueueName); } Console.WriteLine("Hit enter..."); Console.ReadLine(); }
}
}
Sending a Message to a Message Queue After creating the message queue, it is now time to send a message. Sending a message is as easy as creating an instance of a Message object and sending it using the Send method on the message queue. There are two types of message delivery: express mes saging and recoverable messaging. Note that the choice for the type of delivery is
578
Chapter 13
Serviced Component Management
made at the message level and not at the queue level. Use the Recoverable option on the message to specify that a message needs to be recoverable.
Express Messaging Using express messaging means that messages are stored in random access memory (RAM) during routing and delivery, providing extremely fast performance but no recoverability if any computer through which the message passes should fail. Notably, express messages are lost whenever the Message Queuing service is stopped. Too many express messages accumulating in RAM can cause paging out to disk, lead ing to performance degradation. Thus, you should not store more express messages than physical memory can hold. Express messages can, however, survive a network failure. For example, if a message queuing application sends express messages through a Message Queuing server and the network link between the Message Queuing server and the destination computer fails, the Message Queuing server continues to store the messages in memory. How ever, if the Message Queuing server fails before the network link is restored, the express messages are lost.
Recoverable Messaging Using recoverable messaging means that messages are written to disk during routing and delivery, making delivery somewhat slower than the use of express messaging, but ideal when failures cannot be tolerated or when computers shut down while mes sages remain in queues (as for mobile clients on laptop computers). If a computer fails or is shut down while sending a message, the message is stored on disk. When the computer is restarted and the Message Queuing service restarts, the sending process is automatically resumed. All recoverable messages are stored on disks in memory-mapped files. Performance gains can be realized by employing several physical disks to store recoverable messages.
Message Aging When sending a message, you need to consider that processing of the message does not occur synchronously. There will be a delay, meaning that the message has a life span of seconds, minutes, hours, or maybe even days, if you let them live that long. As a matter of design you need to consider how long a message should remain valid. For
Lesson 1: Message Queues
579
example, our online shop has an option for next-day delivery. To be able to meet the delivery deadlines, an order needs to be entered into the shipping system before 4:00 p.m. If an express order is entered at 3:30 p.m., this leaves the order valid for 30 min utes. After that the order is not delivered in time. Your system should probably pick up on this and take corrective action; for instance, an e-mail could be sent declaring that due to technical difficulties, the order is to be shipped tomorrow; does the client accept this change, yes or no? Technically this means that the shipping order needs to be redirected from the shipping system back to the online shop. The message offers three properties that help you control how to deal with messages that outlive their usefulness: TimeToReachQueue, TimeToBeReceived, and UseDeadLetterQueue. This property gets or sets the maximum amount of time for the message to reach the queue. If the interval specified by TimeToReachQueue expires before the message reaches its destination, the message is discarded in one of two ways. If UseDeadLetterQueue is set to true, the message is sent to the dead-letter queue. If UseDeadLetterQueue is false, the message is ignored. TimeToReachQueue
Note that you can set the message’s AcknowledgeType property to request that a nega tive acknowledgment message is returned to the sending application if the message does not arrive before the timer expires. If TimeToReachQueue is set to 0 seconds, MessageQueue.Send tries once to send the message to its destination—if the queue is waiting for the message. If the queue is local, the message always reaches it. TimeToBeReceived This property gets or sets the maximum amount of time for the message to be received from the destination queue. If the interval specified by TimeToBeReceived expires before the message is removed from the queue, the message is discarded.
This property gets or sets a value that indicates whether a copy of the message that could not be delivered should be sent to a dead-letter queue. If UseDeadLetterQueue is true, delivery failure (of a nontransactional message) causes the message to be sent to the nontransactional dead-letter queue on the computer that could not deliver the message. UseDeadLetterQueue
In the case of delivery failure for a transactional message, the message is sent to the transactional dead-letter queue on the source machine.
580
Chapter 13
Serviced Component Management
Transactions Let’s take a look at an example where you send a simple string to the queue. The code from before has been refactored so that the check and creation of the queue is moved to a method named GetQueue (bold is used to emphasize the relevant portions). The example shows that you take a string from the command line, put it in the body of a newly created Message object, and send the message. Note that because you designed your message queue to be transactional, you need to either supply the Send method with a reference to a MessageQueueTransaction or specify the MessageQueueTransactionType for defining how the transaction should be handled. 'VB Imports System.Messaging
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main() Dim queue As MessageQueue queue = GetQueue() ' Enter a text for the body of the message
Console.Write("Enter body: ")
Dim body As String = Console.ReadLine()
' Create message and set properties Dim msg As Message = New Message() msg.Body = body msg.Label = "Message from webapplication to shipping system." msg.Priority = MessagePriority.Normal msg.Recoverable = True msg.TimeToBeReceived = New TimeSpan(1, 0, 0, 0, 0) ' 1 day msg.UseDeadLetterQueue = True msg.UseJournalQueue = True ' Send the message using a single MSMQ transaction queue.Send(msg, MessageQueueTransactionType.Single) Console.WriteLine("Message is sent to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub Private Function GetQueue() As MessageQueue
'...
Lesson 1: Message Queues
End Function End Module //C# using System; using System.Messaging; namespace QueueSender { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
MessageQueue queue;
queue = GetQueue();
// Enter a text for the body of the message
Console.Write("Enter body: ");
string body = Console.ReadLine();
// Create message and set properties
Message msg = new Message(); msg.Body = body;
msg.Label = "Message from webapplication to shipping system.";
msg.Priority = MessagePriority.Normal;
msg.Recoverable = true;
msg.TimeToBeReceived = new TimeSpan(1, 0, 0, 0, 0); // 1 day
msg.UseDeadLetterQueue = true;
msg.UseJournalQueue = true;
// Send the message using a single MSMQ transaction
queue.Send(msg, MessageQueueTransactionType.Single); Console.WriteLine("Message is sent to queue."); Console.WriteLine("Hit enter..."); Console.ReadLine(); }
///
/// Get queue, create the queue if it does not exist.
///
///
private static MessageQueue GetQueue()
{
//... } } }
581
582
Chapter 13
Serviced Component Management
MessageQueueTransactionType can take one of the following options: A transaction type used for Microsoft Transaction Server (MTS). If there is already an MTS transaction context, it is used when sending or receiving the message. Use this in conjuction with the serviced component transactions you saw in Chapter 12.
■ Automatic
The Send operation is not transactional. In our case this results in a failure to send.
■ None
A transaction type used for single internal transactions. The Send opera tion creates, begins, and commits an internal transaction for sending this single message.
■ Single
Figure 13-5 shows the result when we run the code and enter as the body the text “Ship new camera to Mark Blomsma.”
Figure 13-5 Run the application to send a message
After running the application you can check your results by opening the Computer Management console and checking the ShippingInbox queue to see that the message has been placed in the queue. Double-click the message to inspect its properties. On the Body tab, you can actually inspect the contents of the message, and as you can see in Figure 13-6, the string has been serialized as Extensible Markup Language (XML).
Lesson 1: Message Queues
583
Figure 13-6 The body of the message is serialized as XML
When sending a message, the body of the message is by default serialized as XML. It is also possible to send a binary representation of an object as a message. To do so, you need to utilize the BinaryMessageFormatter, which is part of the System.Messaging namespace. In the following code, notice that instead of putting a string in the body of the message we create an instance of a custom type named ShippingOrder and set the properties of the object (bold is used to emphasize the relevant portions). Set the body of message by using the Write method on the BinaryMessageFormatter. Note that the ShippingOrder class needs to be marked as serializable using the Serial izableAttribute; otherwise, the BinaryMessageFormatter won’t be able serialize the order. 'VB Imports System.Messaging
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main() Dim queue As MessageQueue queue = GetQueue()
584
Chapter 13
Serviced Component Management
' Enter a text for the body of the message
Console.Write("Enter to: ")
Dim shipTo As String = Console.ReadLine()
Dim order As QueueData.ShippingOrder = New QueueData.ShippingOrder() order.Id = 1
order.ArticleId = 555
order.Quantity = 1
order.ShipTo = shipTo
' Create message and set properties Dim msg As Message = New Message() SetMessageProperties(msg) ' Use the binary formatter for filling the body of the message Dim formatter As BinaryMessageFormatter = New BinaryMessageFormatter() formatter.Write(msg, order) ' Send the message using a single MSMQ transaction queue.Send(msg, MessageQueueTransactionType.Single) Console.WriteLine("Message is sent to queue.") Console.WriteLine("Hit enter...") Console.ReadLine() End Sub Private Sub SetMessageProperties(ByVal msg As Message) '... End Sub Private Function GetQueue() As MessageQueue
'...
End Function
End Module
//C# using System;
using System.Messaging;
namespace QueueSender {
class Program
{
private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
MessageQueue queue;
queue = GetQueue();
Lesson 1: Message Queues
585
// Enter a text for the body of the message
Console.Write("Enter to: ");
string to = Console.ReadLine();
ShippingOrder order = new ShippingOrder(); order.Id = 1; order.ArticleId = 555; order.Quantity = 1; order.To = to; // Create message and set properties Message msg = new Message(); SetMessageProperties(msg); // Use the binary formatter for filling the body of the message BinaryMessageFormatter formatter = new BinaryMessageFormatter(); formatter.Write(msg, order); // Send the message using a single MSMQ transaction queue.Send(msg, MessageQueueTransactionType.Single); Console.WriteLine("Message is sent to queue."); Console.WriteLine("Hit enter..."); Console.ReadLine(); }
///
/// Set the message properties.
///
///
private static void SetMessageProperties(Message msg)
{
//...
}
///
/// Get queue, create the queue if it does not exist.
///
///
private static MessageQueue GetQueue()
{
//... } } }
If in the preceding sample you replace BinaryMessageFormatter with XmlMessageFormatter you would actually implement the same serialization as the implicit serial ization implemented by the Send method.
586
Chapter 13
Serviced Component Management
Reading a Message from a Queue Reading a message from a queue is very much the reverse of the earlier code. Create a new console application named QueueReceiver, and instead of using Send, use Receive to read from the queue; rather than using Write on the BinaryMessageFormat ter, use Read to format the body back to the original object. Notice how we now use a MessageQueueTransaction when reading from the queue. If anything fails during the formatting of the object, you don’t want the message to be removed from the queue. Because you’re reverting the serialized object back to its original state, your new project needs to have a reference to the assembly that defines the ShippingOrder type. Because you’re deploying this type to both the sending and receiving application, it makes sense to move the ShippingOrder class to a separate assembly, in this case named QueueData.dll. 'VB Imports System.Messaging
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
Dim queue As MessageQueue = GetQueue()
Dim tran As MessageQueueTransaction = New MessageQueueTransaction() tran.Begin() ' Receive will wait for a message to appear in the queue Dim msg As Message = queue.Receive(tran) Dim formatter As BinaryMessageFormatter = New BinaryMessageFormatter() Dim body As Object = formatter.Read(msg) Console.WriteLine("Type: " + body.GetType().ToString()) tran.Commit() Console.WriteLine("Hit enter...") Console.ReadLine() End Sub Private Function GetQueue() As MessageQueue
'...
End Function
End Module
//C#
Lesson 1: Message Queues
587
using System; using System.Messaging; namespace QueueRecipient { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
MessageQueue queue = GetQueue();
using (MessageQueueTransaction tran =
new MessageQueueTransaction())
{ // Receive will wait for a message to appear in the queue Message msg = queue.Receive(tran); BinaryMessageFormatter formatter = new BinaryMessageFormatter(); object body = formatter.Read(msg); Console.WriteLine("Type: " + body.GetType().ToString()); } Console.WriteLine("Hit enter...");
Console.ReadLine();
}
///
/// Get queue, create the queue if it does not exist.
///
///
private static MessageQueue GetQueue()
{
//... } } }
The preceding code shows that the object in the queue is of type QueueData.ShippingOrder. Start the QueueReceive application. It runs and waits for a message to appear in the queue. Subsequently start the QueueSender application from the previous paragraph. Try to open the console applications next to each other. As soon as the QueueSender application puts the message in the queue you’ll see the QueueRecipi ent application retrieve the message from the queue and print the type.
588
Chapter 13
Serviced Component Management
Deleting a Message It is important to note that it is not possible to delete a message from the queue pro grammatically. There is no Delete on a queue. By receiving a message it is automati cally removed from the queue.
Sending and Receiving a Message Asynchronously Figure 13-7 shows a message being delivered instantaneously. It is important to note that even though delivery of the message took very little time, the actual sending and receiving of the message is an asynchronous act. You can test this by running the QueueSender application without running the QueueRecipient. The application starts and you can send a message. However, because the QueueRecipient application is not running, the message has nowhere to go and sits in the queue until it either gets retrieved from the queue, or the the time span you set for TimeToBeReceived has expired. In the latter case the message is moved to the queue named Dead-letter mes sages, also known as the dead-letter queue.
Figure 13-7 The message is delivered instantaneously
Sending and Receiving a Message Synchronously You’ve seen how we can use queues to send messages in an asynchronous manner. Now in some very unique scenarios it might be interesting to implement a synchro nous scenario using MSMQ. This would in effect create an RPC using the MSMQ pro tocol, and the advantage would be that it is possible to have the RPC return a value. MSQM does support this behavior. Because it is considered a highly unlikely sce
Lesson 1: Message Queues
589
nario, the .NET Framework Class Library classes that are available in the System.Mes saging namespace do not support RPC Message Queuing. If you’re interested in pursuing this scenario, search the MSDN Web site (http://msdn.microsoft.com) for RPC in conjunction with MSQM; you’ll find a number of interesting items under the header of “RPC Message Queuing” (http://msdn.microsoft.com/librar y/ default.asp?url=/library/en-us/rpc/rpc/rpc_message_queuing.asp).
Listening to a Queue Asynchronously The Peek and Receive methods will examine the queue and wait for a message to become available. You can specify how long to listen using a TimeSpan as one of the parameters. The code will either halt until a message arrives or wait for the amount of time specified. If you wish to run code while listening to the queue then one option is to use the methods BeginPeek, BeginReceive, EndPeek, and EndReceive to listen to the queue in an asynchronous manner. Or even use the PeekCompleted or ReceiveCompleted events. If such a scenario fits with your needs, it is recommended that you look further into how this part of the MSQM API works. NOTE
Using BackgroundWorkerProcess
If the scenario you’re considering involves asynchronous listening to a queue where a WinForm application wants to monitor a queue in the background while the user continues using the user interface, then using the BackgroundWorkerProcess would be more appropriate.
Sending Objects Using Messages By using generics, it becomes relatively easy to encapsulate a message queue and cre ate a typed representation of the message queue. There are numerous ways to do this, one of which is through inheritance. In the following code you see a class that inherits from MessageQueue and adds a generic type argument. The type parameter is passed on as a type parameter to the IMessageQueue interface, and used in the Send and Receive methods of the generic MessageQueue type of T. The static GetQueue method from the earlier example has also been moved to this new class and now returns a object of type T as well. 'VB Imports System
Imports System.Messaging
'/
'/ Simple interface for sending and receiving messages on a typed queue.
590
Chapter 13
Serviced Component Management
'/
'/
Public Interface IMessageQueue(Of T)
Sub Send(ByVal obj As T)
Function Receive() As T
End Interface
'/
'/ Generic message queue, using binary formatting for serializing objects.
'/
'/
Public Class MessageQueue(Of T)
Inherits System.Messaging.MessageQueue
Implements IMessageQueue(Of T)
Sub New()
MyBase.New()
End Sub
Sub New(ByVal path As String)
MyBase.New(path)
End Sub
Public Shadows Sub Send(ByVal obj As T) Implements IMessageQueue(Of T).Send Dim msg As Message = New Message() ' Use the binary formatter for filling the body of the message Dim formatter As BinaryMessageFormatter = New BinaryMessageFormatter() formatter.Write(msg, obj) MyBase.Send(msg, MessageQueueTransactionType.Single) End Sub Public Shadows Function Receive() As T _
Implements IMessageQueue(Of T).Receive
Dim obj As T
Dim tran As MessageQueueTransaction
tran = New MessageQueueTransaction()
tran.Begin()
' Receive will wait for a message to appear in the queue
Dim msg As Message = MyBase.Receive(tran)
Dim formatter As BinaryMessageFormatter = New BinaryMessageFormatter()
Dim body As Object = formatter.Read(msg)
obj = CType(body, T)
tran.Commit()
Return obj
End Function
'/
Lesson 1: Message Queues
'/ Get queue, create the queue if it does not exist.
'/
'/
Public Shared Function GetQueue(ByVal path As String) As MessageQueue(Of T)
Dim queue As MessageQueue(Of T) = Nothing
' Check to see if queue exists using static method.
If MessageQueue.Exists(path) Then
queue = New MessageQueue(Of T)(path)
Else
Try
' Create the queue and set the label.
MessageQueue.Create(path, True)
queue = New MessageQueue(Of T)(path)
queue.Label = path
Catch exception As Exception
'Add error logging.
Throw
End Try
End If
Return queue
End Function End Class //C# using System; using System.Messaging; namespace QueueSendAndReceive { ///
/// Simple interface for sending and receiving messages on a typed queue.
///
///
public interface IMessageQueue
{
void Send(T obj);
T Receive();
}
///
/// Generic message queue, using binary formatting for serializing objects.
///
///
public class MessageQueue : System.Messaging.MessageQueue,
IMessageQueue
{
public MessageQueue()
: base()
{
}
public MessageQueue(string path) : base(path)
591
592
Chapter 13
Serviced Component Management
{
}
public void Send(T obj)
{
Message msg = new Message();
// Use the binary formatter for filling the body of the message BinaryMessageFormatter formatter = new BinaryMessageFormatter(); formatter.Write(msg, obj); base.Send(msg, MessageQueueTransactionType.Single); } public new T Receive() { T obj; using (MessageQueueTransaction tran = new MessageQueueTransaction()) { // Receive will wait for a message to appear in the queue Message msg = base.Receive(tran); BinaryMessageFormatter formatter = new BinaryMessageFormatter(); object body = formatter.Read(msg); obj = (T)body; }
return obj;
}
///
/// Get queue, create the queue if it does not exist.
///
///
public static MessageQueue GetQueue(string path)
{
MessageQueue queue = null;
// Check to see if queue exists using static method.
if (MessageQueue.Exists(path))
{
queue = new MessageQueue(path); } else { try { // Create the queue and set the label. MessageQueue.Create(path, true); queue = new MessageQueue(path); queue.Label = path; } catch (Exception exception) {
Lesson 1: Message Queues
593
//Add error logging.
throw;
}
}
return queue;
} } }
Implementing a generic interface allows you to use the queue in a type-safe manner. It also simplifies the typed message queue by reducing the set of relevant operations to just Send and Receive. In a more real-world piece of code you would want to add a number of overloads to these two methods to facilitate transaction management in a more comprehensive manner, as follows: 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main(ByVal args() As String)
Dim queue As IMessageQueue(Of QueueData.ShippingOrder)
queue = MessageQueue(Of QueueData.ShippingOrder).GetQueue(cQueueName) ' Enter text for the body of the message
Console.Write("Enter to: ")
Dim shipTo As String = Console.ReadLine()
Dim order1 As QueueData.ShippingOrder = CreateOrder(shipTo) ' Send the message using typed queue
queue.Send(order1)
Console.WriteLine("Message is sent to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
' Receive an object of type QueueData.ShippingOrder
Dim order2 As QueueData.ShippingOrder = queue.Receive()
Console.WriteLine("Received message to: '{0}'", order2.ShipTo)
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub Private Function CreateOrder(ByVal shipTo As String) _
As QueueData.ShippingOrder
Dim order As QueueData.ShippingOrder = New QueueData.ShippingOrder()
order.Id = 1
order.ArticleId = 555
594
Chapter 13
Serviced Component Management
order.Quantity = 1
order.ShipTo = shipTo
Return order
End Function End Module //C# using System;
using System.Messaging;
namespace QueueSendAndReceive {
class Program
{
private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args) { IMessageQueue queue; queue = MessageQueue.GetQueue(cQueueName);
// Enter a text for the body of the message
Console.Write("Enter to: ");
string to = Console.ReadLine();
QueueData.ShippingOrder order1 = CreateOrder(to);
// Send the message using typed queue
queue.Send(order1);
Console.WriteLine("Message is sent to queue.");
Console.WriteLine("Hit enter...");
Console.ReadLine();
// Receive an object of type QueueData.ShippingOrder
QueueData.ShippingOrder order2 = queue.Receive();
Console.WriteLine("Received message to: '{0}'", order2.To);
Console.WriteLine("Hit enter...");
Console.ReadLine();
} private static QueueData.ShippingOrder CreateOrder(string to) { QueueData.ShippingOrder order = new QueueData.ShippingOrder(); order.Id = 1; order.ArticleId = 555; order.Quantity = 1; order.To = to; return order; }
}
}
Lesson 1: Message Queues
595
Sending a Message Using Queued Components In Chapter 12 we saw that it is possible to call a method on a serviced component using MSMQ. This is referred to as queued components. Instead of putting a message on a queue in a rather explicit manner, as we have seen in the previous sections, we can use a queued component to encapsulate the particulars of the message. When using queued components, it is recommended that the service you want to make available is specified using an interface. The following code shows what needs to be done. The application needs to be registered in the COM+ catalog with ApplicationActivation set to Server. ApplicationQueueing needs to be enabled using the correspond ing application attribute. The interface you want to expose needs to be marked with InterfaceQueuing and, of course, both the class and the interface need to be ComVisible. The client application doesn’t actually need access to the implementation of IShippingSystem, but it does need to reference the assembly defining the interface. Now instead of using the new statement, use the Marshal class, which can be found in the System.Runtime.InteropServices namespace to create a moniker that references the queue that the ShippingSystem will be listening to. The moniker can be cast to the ISh ippingSystem interface, so in your code and Visual Studio you have full benefit of type checking and intellisense. If you call SendOrder, instead of actually directly calling the method, the moniker creates a message and puts it on the queue. The COM+ compo nent runs in the background, picks up the message from the queue and, in the case of this example, writes an entry in the event log. After you are done with your moni ker, release the COM+ resources by calling Marshal.ReleaseComObject. 'VB Imports Imports Imports Imports
System
System.Reflection
System.EnterpriseServices
System.Runtime.InteropServices
Namespace QueuedComponent
_
_
Public Interface IShippingSystem
Sub SendOrder(ByVal shipTo As String)
End Interface
596
Chapter 13
Serviced Component Management
_ Public Class ShippingSystem
Inherits ServicedComponent
Implements IShippingSystem
Public Sub New()
End Sub
Public Sub SendOrder(ByVal shipTo As String) _ Implements IShippingSystem.SendOrder System.Diagnostics.EventLog.WriteEntry("ShippingOrder", _ "Ship order to: " + shipTo) End Sub End Class Class Program Shared Sub Main(ByVal args() As String) 'ShippingSystem s = new ShippingSystem(); Dim iss As IShippingSystem = Nothing Try iss = CType(Marshal.BindToMoniker( _ "queue:/new:QueuedComponent.ShippingSystem"), IShippingSystem) Catch exception As Exception Console.WriteLine("Error: {0}", exception.Message) End Try iss.SendOrder("MSLearning") Marshal.ReleaseComObject(iss) Console.WriteLine("Order send.") Console.WriteLine("Hit enter...") Console.ReadLine() End Sub
End Class
End Namespace
//C# using using using using
System;
System.Reflection;
System.EnterpriseServices;
System.Runtime.InteropServices;
[assembly: ApplicationName("ShippingSystem")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationQueuing(Enabled = true, QueueListenerEnabled = true)]
namespace QueuedComponent
{
[ComVisible(true)]
[InterfaceQueuing]
public interface IShippingSystem
{
Lesson 1: Message Queues
597
void SendOrder(string to);
}
[ComVisible(true)] public class ShippingSystem : ServicedComponent, IShippingSystem { public ShippingSystem()
{
}
public void SendOrder(string to) { System.Diagnostics.EventLog.WriteEntry("ShippingOrder", "Ship order to: " + to); } } class Program {
static void Main(string[] args)
{
//ShippingSystem s = new ShippingSystem(); IShippingSystem iss = null;
try
{
iss = (IShippingSystem) Marshal.BindToMoniker( "queue:/new:QueuedComponent.ShippingSystem"); }
catch( Exception exception)
{
Console.WriteLine("Error: {0}", exception.Message); } iss.SendOrder("MSLearning"); Marshal.ReleaseComObject(iss); Console.WriteLine("Order send."); Console.WriteLine("Hit enter..."); Console.ReadLine(); }
}
}
As shown by the example, queued components almost completely hide the queuing that is behind the queued components solution. Except for the BindToMoniker state ment, queues remain invisible.
Setting Permissions on a Message Queue So far we’ve looked at and used queues using the default security settings for message queues, and the default is that Everyone has full access. Although this is the most use
598
Chapter 13
Serviced Component Management
ful default for a developer, you will most likely want to change the settings once you are deploying your application. Like most of the features we’ve looked at so far, setting permissions can be done manually or through code. Manually setting the permissions is done using the Computer Management console. Start the Computer Management console, right-click the queue, and click Properties. In the Properties dialog box, click the Security tab. Figure 13-8 shows the default set tings.
Figure 13-8 Default security settings for a message queue
The rights to a queue can be any combination of the following: ■
Full Control
■
Delete Message
■
Receive Message
■
Peek Message
■
Receive Journal Message
■
Get Queue Properties
■
Set Queue Properties
■
Get Permissions
Lesson 1: Message Queues
■
Set Permissions
■
Take Queue Ownership
■
Write Message
599
We look at what these permissions entail in more detail when looking at how to set permissions using code. Setting the permissions on a queue is done using the MessageQueue class SetPermissions method. It is very easy to make a mistake that makes the queue inaccessible from the Computer Management console. To correct any mistakes, you can revert to the default settings using ResetPermissions on the MessageQueue class. The following code demonstrates how to set the permissions on your queue to allow only the user Mark to have full control (bold is used to emphasize the relevant por tions): 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
If MessageQueue.Exists(cQueueName) Then
Dim queue As MessageQueue = New MessageQueue(cQueueName)
queue.SetPermissions("Mark", MessageQueueAccessRights.FullControl) End If
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System; using System.Messaging; namespace QueuePermissions { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args) {
if (MessageQueue.Exists(cQueueName))
{
600
Chapter 13
Serviced Component Management
MessageQueue queue = new MessageQueue(cQueueName); queue.SetPermissions("Mark", MessageQueueAccessRights.FullControl); }
Console.WriteLine("Hit enter...");
Console.ReadLine();
} } }
MessageQueueAccessRights matches the options you have when setting the permissions
manually but extends the granularity of permissions to include messages in the jour
nal queue. Possible values are the following:
ChangeQueuePermissions The right to modify queue permissions.
DeleteJournalMessage The right to delete messages from the journal queue.
The right to delete messages from the queue.
DeleteMessage
DeleteQueue The right to delete the queue.
FullControl
Full rights to the queue. A union of all other rights in the enumeration.
A combination of GetQueueProperties, GetQueuePermissions, ReceiveMes
sage, and ReceiveJournalMessage.
GenericRead
GenericWrite
A combination of GetQueueProperties, GetQueuePermissions, and Write-
Message. The right to read queue permissions.
GetQueuePermissions GetQueueProperties PeekMessage
The right to read properties of the queue.
The right to peek messages from the queue.
The right to receive messages from the journal queue. This includes the rights to delete and peek messages from the journal queue.
ReceiveJournalMessage
The right to receive messages from the queue. This includes the rights to delete and peek messages.
ReceiveMessage
SetQueueProperties TakeQueueOwnership WriteMessage
The right to modify properties of the queue. The right to take ownership of the queue.
The right to send messages to the queue.
The SetPermissions method has a number of overloads, which can be useful when set ting up more complex security scenarios. The following code shows how an AccessControlList is created, two trustees are added, permissions are set, and the list is used to set the permissions on the queue.
Lesson 1: Message Queues
'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main() If MessageQueue.Exists(cQueueName) Then Dim queue As MessageQueue = New MessageQueue(cQueueName) Dim acl As AccessControlList = New AccessControlList()
Dim mark As Trustee = New Trustee("Mark")
Dim enTryMark As AccessControlEnTry = _
New AccessControlEnTry(mark, GenericAccessRights.All, _ StandardAccessRights.All, AccessControlEnTryType.Allow) acl.Add(enTryMark) Dim ken As Trustee = New Trustee("Ken") Dim enTryKen As AccessControlEnTry = _ New AccessControlEnTry(ken, GenericAccessRights.All, _ StandardAccessRights.All, AccessControlEnTryType.Allow) acl.Add(enTryKen) queue.SetPermissions(acl) End If
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System; using System.Messaging; namespace QueuePermissions { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args) {
if (MessageQueue.Exists(cQueueName))
{
MessageQueue queue = new MessageQueue(cQueueName);
AccessControlList acl = new AccessControlList();
Trustee mark = new Trustee("Mark");
AccessControlEntry entryMark = new AccessControlEntry(mark,
GenericAccessRights.All, StandardAccessRights.All, AccessControlEntryType.Allow); acl.Add(entryMark);
601
602
Chapter 13
Serviced Component Management
Trustee ken = new Trustee("Ken"); AccessControlEntry entryKen = new AccessControlEntry(ken, GenericAccessRights.All, StandardAccessRights.All, AccessControlEntryType.Allow); acl.Add(entryKen); queue.SetPermissions(acl);
}
Console.WriteLine("Hit enter...");
Console.ReadLine();
} } }
After running the code, the Computer Management console shows the security set tings for the queue as shown in Figure 13-9.
Figure 13-9 Adjusted security settings for a message queue
Peeking and Enumerating Messages The previous samples have involved receiving just one message at a time. More often than not you’ll be receiving multiple messages. To have a look at all the messages in a queue, you can use the GetAllMessages method on the MessageQueue. Now the GetAllMessages introduces the concept of peeking at a message. Peeking is the process of cre ating a copy of a message in the queue without removing the message from the queue. GetAllMessages loops through all the messages in the queue and creates copies of each one. Use the appropriately named Peek method if you want to just create a copy of the
Lesson 1: Message Queues
603
first message on the queue. The option to peek at messages is often used when there are multiple messages in the queue that are part of a single transaction. This is best illustrated by an example. The following code shows five messages sent to a queue, but rather than using a sep arate transaction for each message, you make all messages part of the same transac tion. Now when you read the messages from the queue, you of course want to process all messages that entered the queue in a write transaction as part of a new, read trans action. If any message fails to process, then all messages need to remain on the queue. Note that the use of GetAllMessages most likely creates unnecessary overhead, but for this demonstration it serves a purpose. 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
' Create access to queue
Dim queue As MessageQueue = New MessageQueue(cQueueName)
queue.MessageReadPropertyFilter.TransactionId = True
Dim writeTransaction As MessageQueueTransaction = _
New MessageQueueTransaction()
writeTransaction.Begin()
Dim i As Integer For i = 0 To 5 - 1 Step i + 1
' Create message and set properties
Dim msg As Message = New Message()
msg.Formatter = New BinaryMessageFormatter()
msg.Body = "Test " + i.ToString()
msg.Label = "Test " + i.ToString()
' Send the message using MSMQ transaction
queue.Send(msg, writeTransaction)
Next
writeTransaction.Commit()
Console.WriteLine("Messages have been sent to queue.") Dim messages() As Message = queue.GetAllMessages()
Console.WriteLine("{0} messages in queue.", messages.Length)
Dim transactiondId As String = messages(0).TransactionId
Console.WriteLine("Retrieving messages part of transaction: {0}", _
transactiondId)
604
Chapter 13
Serviced Component Management
Dim readTransaction As MessageQueueTransaction = _ New MessageQueueTransaction() readTransaction.Begin()
Dim m As Message
For Each m In messages
If m.TransactionId = transactiondId Then ' message is part of read transaction ' retrieve and remove from queue Dim msg As Message = _ queue.ReceiveByLookupId( _ MessageLookupAction.Current, m.LookupId, readTransaction) msg.Formatter = New BinaryMessageFormatter()
Console.WriteLine("Message received: {0}", msg.Body.ToString())
' Use the lines below to see behavior when transaction fails.
' if (msg.Body.ToString().Equals("Test 3"))
' throw new Exception("Testing");
End If
Next
readTransaction.Commit()
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System;
using System.Messaging;
namespace QueueEnumeration {
class Program
{
private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
// Create access to queue
MessageQueue queue = new MessageQueue(cQueueName);
queue.MessageReadPropertyFilter.TransactionId = true;
using (MessageQueueTransaction writeTransaction = new MessageQueueTransaction()) { writeTransaction.Begin(); for (int i = 0; i < 5; i++) { // Create message and set properties
Lesson 1: Message Queues
Message msg = new Message();
msg.Formatter = new BinaryMessageFormatter();
msg.Body = "Test " + i.ToString();
msg.Label = "Test " + i.ToString();
// Send the message using MSMQ transaction
queue.Send(msg, writeTransaction);
}
writeTransaction.Commit();
}
Console.WriteLine("Messages have been sent to queue."); Message[] messages = queue.GetAllMessages(); Console.WriteLine("{0} messages in queue.", messages.Length); string transactiondId = messages[0].TransactionId; Console.WriteLine("Retrieving messages part of transaction: {0}", transactiondId); using (MessageQueueTransaction readTransaction =
new MessageQueueTransaction())
{
readTransaction.Begin();
foreach (Message m in messages)
{
if (m.TransactionId == transactiondId) { // message is part of read transaction // retrieve and remove from queue Message msg = queue.ReceiveByLookupId( MessageLookupAction.Current, m.LookupId, readTransaction); msg.Formatter = new BinaryMessageFormatter(); Console.WriteLine("Message received: {0}", msg.Body.ToString()); // Use the lines below to see behavior when // transaction fails. // if (msg.Body.ToString().Equals("Test 3")) // throw new Exception("Testing"); }
}
readTransaction.Commit();
} Console.WriteLine("Hit enter..."); Console.ReadLine(); } } }
605
606
Chapter 13
Serviced Component Management
Note that to be able to retrieve the TransactionId you need to adjust the MessageReadPropertyFilter. MSMQ keeps track of a number of properties. To optimize queue per formance as much as possible, MSQM does not copy all of those properties to every message; instead you need to specify which properties you want to be made available. The preceding sample specified that you want to make the TransactionId available by setting MessageReadPropertyFilter.TransactionId to true.
Correlating Messages A common scenario is for an application to send a message and then wait for a reply, the most common reply being an acknowledgment that the message has been received and processed by the recipient. In message queuing, when the reply is received it needs to be matched to the original message. This process is called corre lating messages. To be able to correlate messages, you need an identifier that can be used by acknowledgment, report, and response messages to reference the original message. The identifier used for correlation of acknowledgments is actually the mes sage ID of the first message. The next code example shows that you use two queues, one for sending your message and a second for receiving acknowledgments. The queues are configured to provide information about acknowledgments, correlation identifiers, and the time a message was sent. When you post your original message to the queue, you add information to the message. The Acknowledgment property is used to specify which acknowledg ments you want to receive; in this case you want notification of the message arriving in the queue and also of being received, or being taken off the queue. The Acknowledg mentQueue property is used to tell the recipient in which queue you want the acknowl edgment. The next step in the code shows how you retrieve the message from the queue. As you can see, no extra code is needed to send the acknowledgments. This is all handled by the MSMQ. Note that at this point you’re still looking at the original message, so you can expect the CorrelationId to be empty. The last step in the code is to look at the acknowledgment queue and see if the mes sage has arrived and whether the recipient has acknowledged receiving the message. You can now use the ID of the original message to look for acknowledgment. Because you’ve requested two acknowledgments, there is a while loop to look for all the expected acknowledgments. 'VB Imports System.Messaging
Lesson 1: Message Queues
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox"
Private Const cAdminQueueName As String = ".\private$\AdminQueue"
Sub Main() Dim queue As MessageQueue = New MessageQueue(cQueueName) Dim adminQueue As MessageQueue = New MessageQueue(cAdminQueueName) queue.MessageReadPropertyFilter.CorrelationId = True queue.MessageReadPropertyFilter.SentTime = True adminQueue.MessageReadPropertyFilter.CorrelationId = True adminQueue.MessageReadPropertyFilter.Acknowledgment = True adminQueue.MessageReadPropertyFilter.SentTime = True Dim sendMessage As Message = New Message()
sendMessage.Formatter = New BinaryMessageFormatter()
sendMessage.Label = "Test"
sendMessage.Body = "Test"
sendMessage.AcknowledgeType = AcknowledgeTypes.PositiveArrival Or _
AcknowledgeTypes.PositiveReceive sendMessage.AdministrationQueue = adminQueue queue.Send(sendMessage, MessageQueueTransactionType.Single) Dim messageId As String = sendMessage.Id Console.WriteLine("Send Message Information:") Console.WriteLine("Id: '{0}'", sendMessage.Id) Console.WriteLine("Sent at: {0}", System.DateTime.Now.Ticks) Console.WriteLine() Console.WriteLine("Hit enter...") Console.ReadLine() Dim receiveMessage As Message = _ queue.Receive(MessageQueueTransactionType.Single) receiveMessage.Formatter = New BinaryMessageFormatter() Console.WriteLine("Received Message Information:") Console.WriteLine("Id: '{0}'", receiveMessage.Id) Console.WriteLine("CorrelationId: '{0}'", receiveMessage.CorrelationId) Console.WriteLine("Body: '{0}'", receiveMessage.Body) Console.WriteLine("Sent at: {0}", receiveMessage.SentTime.Ticks) Console.WriteLine()
Dim ackReceived As Boolean = False Try While (Not (adminQueue.PeekByCorrelationId(messageId) Is Nothing)) Dim acknowledgmentMessage As Message = _ adminQueue.ReceiveByCorrelationId(messageId) ackReceived = True ' Output acknowledgment message information. The correlation Id ' is identical to the id of the original message. Console.WriteLine("Acknowledgment Message Information:") Console.WriteLine("Id: " + acknowledgmentMessage.Id.ToString())
607
608
Chapter 13
Serviced Component Management
Console.WriteLine("Correlation Id: {0}", _ acknowledgmentMessage.CorrelationId) Console.WriteLine("Acknowledgment Type: {0}", _ acknowledgmentMessage.Acknowledgment) Console.WriteLine("Sent at: {0}", _ acknowledgmentMessage.SentTime.Ticks) Console.WriteLine() End While Catch exception As Exception If Not ackReceived Then Console.WriteLine("Acknowledgement not received. (error: {0})", _ exception.Message) End If End Try Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub
End Module //C# using System; using System.Messaging; namespace QueueCorrelation { class Program { private const string cQueueName = @".\private$\ShippingInbox"; private const string cAdminQueueName = @".\private$\AdminQueue"; static void Main(string[] args) { MessageQueue queue = new MessageQueue(cQueueName); MessageQueue adminQueue = new MessageQueue(cAdminQueueName); queue.MessageReadPropertyFilter.CorrelationId = true; queue.MessageReadPropertyFilter.SentTime = true; adminQueue.MessageReadPropertyFilter.CorrelationId = true; adminQueue.MessageReadPropertyFilter.Acknowledgment = true; adminQueue.MessageReadPropertyFilter.SentTime = true; Message sendMessage = new Message();
sendMessage.Formatter = new BinaryMessageFormatter();
sendMessage.Label = "Test";
sendMessage.Body = "Test";
sendMessage.AcknowledgeType = AcknowledgeTypes.PositiveArrival | AcknowledgeTypes.PositiveReceive; sendMessage.AdministrationQueue = adminQueue; queue.Send(sendMessage, MessageQueueTransactionType.Single);
string messageId = sendMessage.Id;
Console.WriteLine("Send Message Information:");
Lesson 1: Message Queues
Console.WriteLine("Id: '{0}'", sendMessage.Id); Console.WriteLine("Sent at: {0}", System.DateTime.Now.Ticks); Console.WriteLine(); Console.WriteLine("Hit enter..."); Console.ReadLine(); Message receiveMessage = queue.Receive(MessageQueueTransactionType.Single); receiveMessage.Formatter = new BinaryMessageFormatter(); Console.WriteLine("Received Message Information:"); Console.WriteLine("Id: '{0}'", receiveMessage.Id); Console.WriteLine("CorrelationId: '{0}'", receiveMessage.CorrelationId); Console.WriteLine("Body: '{0}'", receiveMessage.Body); Console.WriteLine("Sent at: {0}", receiveMessage.SentTime.Ticks); Console.WriteLine();
bool ackReceived = false; try { while ((adminQueue.PeekByCorrelationId(messageId) != null))
{
Message acknowledgmentMessage =
adminQueue.ReceiveByCorrelationId(messageId); ackReceived = true; // Output acknowledgment message information. The // correlation Id is identical // to the id of the original message. Console.WriteLine("Acknowledgment Message Information:"); Console.WriteLine("Id: " + acknowledgmentMessage.Id.ToString());
Console.WriteLine("Correlation Id: {0}" +
acknowledgmentMessage.CorrelationId);
Console.WriteLine("Acknowledgment Type: {0}",
acknowledgmentMessage.Acknowledgment);
Console.WriteLine("Sent at: {0}",
acknowledgmentMessage.SentTime.Ticks);
Console.WriteLine();
} } catch (Exception exception) { if (!ackReceived)
{
Console.WriteLine(
"Acknowledgement not received. (error: {0})",
exception.Message);
} } Console.WriteLine("Hit enter..."); Console.ReadLine();
609
610
Chapter 13
Serviced Component Management
} }
}
The result of the preceding code is shown in Figure 13-10. Notice that the sent time is only accurate to the second and is therefore not too useful.
Figure 13-10 Two acknowledgments have been received
Rules and Triggers The .NET Framework 2.0 does not offer any support for creating rules or triggers on a queue. It is, however, possible to set up one or more rules using the Computer Man agement console. A trigger will allow you to associate a COM component or an exe cutable to an incoming message, passing properties of the message as parameters. If you wish to make your .NET application callable from a trigger, you will need to create a COM Callable Wrapper for your assembly or create a console application that accepts parameters as command line arguments.
Lab 1: Creating a Message and Sending It to a Queue In this lab, you create a queue, create a message, and send that message to the queue. If you encounter a problem completing an exercise, the completed projects are avail able on the companion CD in the Code folder. �
Exercise 1: Creating a Queue
In this exercise, you create an application that creates a transactional queue named InvoicingQueue.
Lesson 1: Message Queues
611
1. From the Start menu, launch the Computer Management console by clicking Start, Control Panel, Administrative Tools, Computer Management. 2. Check the private queue to see that there is no queue named InvoicingQueue (see Figure 13-11). Depending on what you have installed on your machine you might see more queues than shown in Figure 13-11.
Figure 13-11 Check that there is no InvoicingQueue
3. If there is an InvoicingQueue, right-click that queue and click Delete. 4. Open Visual Studio 2005 and create a blank solution named MSLearning .Exercises. 5. Add a new C# or Visual Basic 2005 Console Application project named OnlineStore. 6. Right-click the project’s folder and click Properties. In the Default Namespace text box, type MSLearning.Chapter13.Sender. 7. Click Project, Add Reference. Click the .NET tab, click System.Messaging, and click OK. 8. Open the Program.cs or Module1.vb file. 9. Add a private constant string named cQueueName and assign a value reflecting that you want to create a private queue with the name InvoicingQueue. Add a using/imports statement to indicate that you want to use classes from System .Messaging, and add a new method named GetQueue. Add code to the method to check and see whether the InvoicingQueue exists; if it does not exist, create a
612
Chapter 13
Serviced Component Management
nontransactional queue, set the label, return the InvoicingQueue, adjust Main to call GetQueue, and wait for the user to press Enter. 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\InvoicingQueue" Sub Main() Dim queue As MessageQueue = GetQueue(cQueueName) Console.WriteLine("Using queue: {0}", cQueueName) Console.WriteLine("Hit enter...") Console.ReadLine() End Sub Function GetQueue(ByVal path As String) As MessageQueue Dim queue As MessageQueue If MessageQueue.Exists(path) Then queue = New MessageQueue(path) Else queue = MessageQueue.Create(path) End If queue.Label = path Return queue End Function
End Module
//C# using System;
using System.Messaging;
namespace MSLearning.Chapter13.Queues {
class Program
{
private const string cQueueName = @".\private$\InvoicingQueue"; static void Main(string[] args) { MessageQueue queue = GetQueue(cQueueName); Console.WriteLine("Using queue: {0}", cQueueName); Console.WriteLine("Hit enter..."); Console.ReadLine(); } static private MessageQueue GetQueue(string path) { MessageQueue queue; if (MessageQueue.Exists(path)) {
Lesson 1: Message Queues
613
queue = new MessageQueue(path);
}
else
{
queue = MessageQueue.Create(path, false); } queue.Label = path; return queue; }
}
}
10. Start the console application. 11. Use the Computer Management console to check that the queue has been cre ated, as shown in Figure 13-12.
Figure 13-12 InvoicingQueue has been created �
Exercise 2: Creating and Sending a Message
In this exercise, you use the application created in Exercise 1 to create and send a mes sage containing some simple order information. 1. Add a new method named CreateMessage. Implement code that sets the body of the message to “CustomerId=888;OrderId=501;ArticleId=9900232;Quan tity=10,” use XML as formatter, and set the label of the message to read “Request to invoice customer 888 for order 501.” Make the message recoverable, and give the message a life span of 1 hour. 'VB Private Function CreateMessage() As Message
Dim body As String =
"CustomerId=888;OrderId=501;ArticleId=9900232;Quantity=10"
Dim message As Message = New Message(body)
614
Chapter 13
Serviced Component Management
message.Formatter = New XmlMessageFormatter(New Type() {Type.GetType("System.String")})
message.Label = "Request to invoice customer 888 for order 501."
message.Recoverable = True
message.TimeToBeReceived = New TimeSpan(1, 0, 0)
Return message
End Function //C# static private Message CreateMessage() { string body = "CustomerId=888;OrderId=501;ArticleId=9900232;Quantity=10"; Message message = new Message(body); message.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); message.Label = "Request to invoice customer 888 for order 501."; message.Recoverable = true; message.TimeToBeReceived = new TimeSpan(1, 0, 0); return message; }
2. Now add code to Main to call CreateMessage and use the queue object to send the newly created message: 'VB Sub Main()
Dim queue As MessageQueue = GetQueue(cQueueName)
Console.WriteLine("Using queue: {0}", cQueueName)
Dim message As Message = CreateMessage()
queue.Send(message)
Console.WriteLine("Send message to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub
//C# static void Main(string[] args) {
MessageQueue queue = GetQueue(cQueueName);
Console.WriteLine("Using queue: {0}", cQueueName);
Message message = CreateMessage();
queue.Send(message);
Console.WriteLine("Send message to queue.");
Console.WriteLine("Hit enter...");
Console.ReadLine();
}
3. Start the console application.
Lesson 1: Message Queues
615
4. Use the Computer Management console to check that a message is now visible in the queue. You might have to refresh the display for the message to become visible (see Figure 13-13).
Figure 13-13 One message in the queue
5. Inspect the body of the message in the message’s Properties dialog box on the Body tab. Notice how the string is wrapped in XML (see Figure 13-14).
Figure 13-14 Body of the message is wrapped in XML
616
Chapter 13
�
Serviced Component Management
Exercise 3: Receiving a Message
In this exercise, you use the application created in Exercises 1 and 2 to receive the information that was put into the queue. Note that in a real-world scenario you would not use the same application to both send and receive a message in this manner, but for educational purposes this is a good way to get started. 1. Add code to Main to wait for an incoming message. On receiving a message, write the label and body to the console, and do not forget to set the correct formatter on the message: 'VB Sub Main()
Dim queue As MessageQueue = GetQueue(cQueueName)
Console.WriteLine("Using queue: {0}", cQueueName)
Dim message As Message = CreateMessage()
queue.Send(message)
Console.WriteLine("Send message to queue.")
Dim incoming As Message = queue.Receive() incoming.Formatter = New XmlMessageFormatter(New Type() _ {Type.GetType("System.String")}) Console.WriteLine("Incoming message.label : {0}", incoming.Label) Console.WriteLine("Incoming message.body : {0}", incoming.Body) Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub //C# static void Main(string[] args) {
MessageQueue queue = GetQueue(cQueueName);
Console.WriteLine("Using queue: {0}", cQueueName);
Message message = CreateMessage(); queue.Send(message); Console.WriteLine("Send message to queue."); Message incoming = queue.Receive(); incoming.Formatter = new XmlMessageFormatter( new Type[] { typeof(string) }); Console.WriteLine("Incoming message.label : {0}", incoming.Label); Console.WriteLine("Incoming message.body : {0}", incoming.Body); Console.WriteLine("Hit enter...");
Console.ReadLine();
}
2. Purge the InvoicingQueue using the Computer Management console. Rightclick the Queue Messages node and click All Tasks, Purge (see Figure 13-15).
Lesson 1: Message Queues
617
Figure 13-15 Purge the InvoicingQueue
3. Start the console application. 4. The result should be the following: Using queue: .\private$\InvoicingQueue
Send message to queue.
Incoming message.label : Request to invoice customer 888 for order 501.
Incoming message.body : CustomerId=888;OrderId=501;ArticleId=9900232;
Quantity=10
Hit enter...
Lesson Summary ■
MSMQ enables applications running at different times to communicate across heterogeneous networks and systems that might be temporarily offline.
■
MSMQ provides guaranteed message delivery.
■
MSMQ can be used to implement solutions for both asynchronous and synchro nous messaging scenarios.
■
MSMQ is wrapped by the classes in System.Messaging, the two dominant classes being MessageQueue and Message.
■
A message queue can participate in a distributed transaction, and alternatively System.Messaging offers a MessageQueueTransaction.
■
There are two types of message delivery: express and recoverable.
618
Chapter 13
Serviced Component Management
■
The Computer Management console can be used to monitor activity and status of queues.
■
Permissions can be set using the MessageQueue class or using the Computer Management console.
■
When peeking at a message, a clone of the message is created. Receiving a mes sage, in contrast, removes the message from the queue.
■
Enumerating messages using GetAllMessages allows for peeking at all messages in the queue and iterates over them.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 1, “Message Queues.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Which of the following statements are true? (Select all that apply.) A. A message queue is always registered in Active Directory. B. The prefix public$\ needs to be used to mark a queue as public. C. Private queues can operate in workgroup mode. D. MessageQueue.Create(“.\\InvoicingQueue”) creates a public queue named InvoicingQueue. 2. Which of the following statements are true? (Select all that apply.) A. A queue with messages cannot be deleted. B. MessageQueue.Remove(“.\\private$\\MyQueue”) deletes a queue by the name of MyQueue. C. MessageQueue.Delete(“.\\private$\\MyQueue”) deletes a queue by the name of MyQueue. D. The Computer Management console can be used to delete a queue. 3. Which of the following statements are true? (Choose the best answer.) A. Only simple types can be used when using queued components.
Lesson 1: Message Queues
619
B. A message can only be sent using System.Messaging.Message. C. The body of a message is always transmitted as binary data. D. When creating a message you do not need to specify whether it is to be part of a transaction. 4. Which of the following statements are true? (Select all that apply.) A. Using the Journal option on a queue allows you to view a message even after it has been removed from the queue. B. If a computer crashes, all messages are lost because MSMQ keeps all the messages in memory. C. After receiving a message from the queue using MessageQueue.Receive(...) you need to call Message.Delete()to remove it from the queue. D. You can retrieve a message from the queue without deleting it using Mes sageQueue.Peek(...).
620
Chapter 13
Serviced Component Management
Lesson 2: Securing Messaging There are two parts to securing a message: signing a message and encrypting a mes sage. In this lesson we look at signing and encypting messages, and, of course, at receiving these messages. After this lesson, you will be able to: ■
Sign a message.
■
Encrypt a message.
■
Validate a message.
Estimated lesson time: 25 minutes
Signing a Message MSMQ authenticates messages using internal or external security certificates. A cer tificate is used to generate a digital signature that uniquely identifies a user who sends an authenticated message. Both the user’s certificate and digital signature are attached to a message when it is sent. The digital signature is encrypted by the MSMQ service on the sending computer and decrypted by the MSMQ service on the destina tion computer. Internal certificates, provided by MSMQ, authenticate the Windows security identi fier (SID) of the sender. When an internal certificate is used, MSMQ guarantees only that the SID attached to the message is valid. Internal certificates are created by MSMQ the first time a user runs MSMQ in Control Panel. Users must register their internal certificates in the Message Queue Information Service (MQIS) before sending authenticated messages. External certificates use information about a user, supplied by a certificate authority (CA) rather than the sender’s SID, to verify the sender’s identity. The information in the external certificate is guaranteed by the CA that created the certificate. External certificates are required for sending authenticated messages to operating environ ments other than Windows machines. If external certificates are used for sending authenticated messages to other computers running versions of Windows Worksta tion or Windows Server, users must register their certificates only if they also want their SIDs to be used in authenticating the message. Doing so provides an additional— although optional—measure of authentication.
Lesson 2: Securing Messaging
621
Authentication is the process of verifying that the message sender is authentic (that is, that the sender has not been impersonated by another user). MSMQ uses digital sig natures to provide message authentication. MSMQ authentication also guarantees message integrity (that the message has not been tampered with) and nonrepudiation (because no user can sign a message with another user’s identity, no user can refute that he or she sent a message if it contains his or her signature). You can configure a queue to accept messages from authenticated users only. When configured to accept only messages from authenticated users, MSMQ checks the user credentials to see if a user certificate is available. If so, MSMQ includes the user certif icate and the SenderId in the message. By default, authentication is only available when the machine that you’re sending your message from is in an Active Directory domain. This is because any user that has been authenticated against Active Directory gets an internal user certificate, thus satisfying MSMQ’s need for a certificate. This is reflected in the security settings of MSMQ. When running in workgroup mode, the Security tab is unavailable. As shown in Figure 13-16, when connected to a domain three tabs are available: User Certificate, Service Security, and Security.
Figure 13-16 Machine-level security settings for MSMQ
Actually, the default setting for any queue is to include SenderId, but when running in workgroup mode no SenderId is available. You can adjust the default behavior by set ting AttachSenderId to false.
622
Chapter 13
Serviced Component Management
The following code shows some additional message properties set, namely AttachSenderId, to indicate that you want MSMQ to retrieve your identity from the current thread when sending the message. Use the Authenticated property in conjunction with the SenderId property to verify the sender’s access rights. The UseAuthentication prop erty specifies whether the message needs to be authenticated. If the sending applica tion requests authentication, Message Queuing creates a digital signature and uses it to sign the message when it is sent and authenticate the message when it is received. Use the UseAuthentication property to indicate that authentication is required. If UseAuthentication is false and a message is sent to a queue that accepts only authenticated messages, the message is rejected when it reaches the queue. 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
' Create queue
Dim queue As MessageQueue
queue = MessageQueue.Create(cQueueName, True)
queue.Label = cQueueName
queue.Authenticate = True
' Create message and set properties
Dim msg As Message = New Message()
msg.UseAuthentication = True
msg.AttachSenderId = True
' Use the binary formatter for filling the body of the message
msg.Formatter = New XmlMessageFormatter()
msg.Body = "Test"
' Send the message using a single MSMQ transaction
queue.Send(msg, MessageQueueTransactionType.Single)
Console.WriteLine("Message is sent to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System; using System.Messaging;
Lesson 2: Securing Messaging
623
namespace QueueSenderSecure { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
// Create queue
MessageQueue queue;
queue = MessageQueue.Create(cQueueName, true);
queue.Label = cQueueName;
queue.Authenticate = true;
// Create message and set properties
Message msg = new Message();
msg.UseAuthentication = true;
msg.AttachSenderId = true;
// Use the binary formatter for filling the body of the message
msg.Formatter = new XmlMessageFormatter();
msg.Body = "Test";
// Send the message using a single MSMQ transaction
queue.Send(msg, MessageQueueTransactionType.Single);
Console.WriteLine("Message is sent to queue.");
Console.WriteLine("Hit enter...");
Console.ReadLine();
} } }
After running that code, you’ll be able to inspect the message using the Computer Management console. The Sender tab of the message should resemble Figure 13-17, although the User property should be the name that you use to log on to the system, and the SenderId will also be different.
624
Chapter 13
Serviced Component Management
Figure 13-17 The message is authenticated and the SenderId is included
It is also possible to not include the SenderId but still require authentication. Just change the code to msg.AttachSenderId = false. Your message will then show that it has been authenticated when posted to the message queue, but the identity of the sender is hidden from the recipient, as shown in Figure 13-18.
Figure 13-18 The message is authenticated, but the sender is anonymous
Lesson 2: Securing Messaging
625
If you want to use authentication in workgroup mode, you’ll have to create your own certificate and use the SenderCertificate property on the message to set the certificate. The drawback here is that any certificate is actually acceptable. The recipient of the message needs to inspect the certificate contained in the message and determine whether it wants to accept this certificate. To authenticate without Active Directory, you need to obtain an X.509 certificate. Included with Visual Studio 2005 and also with the .NET Framework 2.0 Software Development Kit is a command-line utility named makecert. Use this tool to create a personal certificate and store in your per sonal certificates: makecert –n "CN=MSMQCertificate" –ss My
The certificate should become visible in your personal certificate store. You can inspect your certificate store by starting Internet Explorer, and clicking Tools, Internet Options, Content, Certificates, Personal. You should see the certificate that you’ve just created, as shown in Figure 13-19.
Figure 13-19 Your personal certificate
The next step is to load the certificate from the personal store and attach it to the mes sage. This is shown in the following code: 'VB Imports System.Messaging Imports System.Security.Cryptography.X509Certificates Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox"
Private Const cCertificateName As String = "MSMQCertificate"
626
Chapter 13
Serviced Component Management
Sub Main() Dim store As X509Store = New X509Store(StoreName.My) store.Open(OpenFlags.ReadOnly) Dim collection As X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, _ cCertificateName, False) Dim certificate As X509Certificate2 = Collection(0) Console.WriteLine("Using '{0}' certificate issued by '{1}'", _ certificate.Subject, certificate.Issuer) Dim queue As MessageQueue = New MessageQueue(cQueueName)
Dim message As Message = New Message()
message.Body = "Authenticated message test - body"
message.Label = "Authenticated message test - label"
message.UseDeadLetterQueue = True
' Request authentication and supply the external certificate
message.UseAuthentication = True
message.SenderCertificate = certificate.GetRawCertData()
' Make sure the SenderID isn't sent. In workgroup mode MSMQ cannot
' associate a public key with the SID. Authenticated messages that
' include a SID will fail the authentication check and be sent to
' the dead-letter queue.
message.AttachSenderId = False
queue.Send(message, MessageQueueTransactionType.Single)
Console.WriteLine("Message is sent to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System;
using System.Messaging;
using System.Security.Cryptography.X509Certificates;
namespace QueueSenderWorkgroup {
class SendProgram
{
private const string cQueueName = @".\private$\ShippingInbox"; private const string certificateName = "MSMQCertificate";
Lesson 2: Securing Messaging
627
static void Main(string[] args)
{
X509Store store = new X509Store(StoreName.My); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, false); X509Certificate2 certificate = collection[0]; Console.WriteLine("Using '{0}' certificate issued by '{1}'", certificate.Subject, certificate.Issuer); MessageQueue queue = new MessageQueue(cQueueName);
Message message = new Message();
message.Body = "Authenticated message test - body";
message.Label = "Authenticated message test - label";
message.UseDeadLetterQueue = true;
// Request authentication and supply the external certificate
message.UseAuthentication = true;
message.SenderCertificate = certificate.GetRawCertData();
// Make sure the SenderID isn't sent. In workgroup mode MSMQ
// cannot associate a public key with the SID. Authenticated
// messages that include a SID will fail the authentication check // and be sent to the dead-letter queue.
message.AttachSenderId = false;
queue.Send(message, MessageQueueTransactionType.Single);
Console.WriteLine("Message is sent to queue.");
Console.WriteLine("Hit enter...");
Console.ReadLine();
}
}
}
Validating a Message In domain mode, there is hardly any need to check the origin of the message. If the Authenticated property on the message is true, then the message was checked as it was inserted into the queue. In workgroup mode, the recipient won’t know the certificate of the sender, so rather than rely on the SenderId it has to inspect the properties of the certificate to see if it was published by a trusted CA. The following code shows how to access the properties of the certificate:
628
Chapter 13
Serviced Component Management
'VB Imports System.Messaging
Imports System.Security.Cryptography.X509Certificates
Imports CChars = Microsoft.VisualBasic.ControlChars
Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Private Const cCertificateName As String = "MSMQCertificate" Sub Main() Dim queue As MessageQueue = New MessageQueue(cQueueName) ' Request the Authenticated property and the sender's certificate queue.MessageReadPropertyFilter.Authenticated = True queue.MessageReadPropertyFilter.SenderCertificate = True ' Retrieve the message
Dim message As Message
message = queue.Receive()
If Not message.Authenticated Then Console.WriteLine("Message with label '{0}' was not authenticated", _ message.Label) Return End If Console.WriteLine("Authenticated message received with label '{0}'", _ message.Label) Dim certificate As X509Certificate2 = _ New X509Certificate2(message.SenderCertificate) Console.WriteLine("\tSender was '{0}'", certificate.Subject) Console.WriteLine("\tCertificate Issuer was '{0}'", certificate.Issuer) Console.WriteLine("\tCertificate effective {0}", certificate.NotBefore) Console.WriteLine("\tCertificate expires {0}", certificate.NotAfter) Console.WriteLine("\tCertificate Verify: {0}", certificate.Verify()) Console.WriteLine() If certificate.NotBefore > DateTime.Now Then Console.WriteLine("The certificate used to authenticate the " + _ "message will not be valid until {0}", _ certificate.NotBefore) Return
End If
If certificate.NotAfter < DateTime.Now Then Console.WriteLine("The certificate used to authenticate the " + _ "message expired on {0}", _ certificate.NotAfter) Return
Lesson 2: Securing Messaging
End If If Not certificate.Verify() Then Console.WriteLine("The certificate used to authenticate the " + _ "message could not be validated using " + _ "the basic validation policy. Perhaps it is a test " + _ "certificate or not issued by a trusted " + _ "authority." + CChars.NewLine + CChars.NewLine + _ "Use the X509Chain class to perform a more detailed analysis.") End If Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C# using System;
using System.Messaging;
using System.Security.Cryptography.X509Certificates;
namespace QueueRecipientWorkgroup
{ class Program { private const string cQueueName = @".\private$\ShippingInbox"; private const string certificateName = "MSMQCertificate"; static void Main(string[] args)
{
MessageQueue queue = new MessageQueue(cQueueName);
// Request the Authenticated property and the sender's certificate queue.MessageReadPropertyFilter.Authenticated = true; queue.MessageReadPropertyFilter.SenderCertificate = true; // Retrieve the message
Message message;
message = queue.Receive();
if (!message.Authenticated) { Console.WriteLine("Message with label '{0}' was not " + "authenticated", message.Label); return; } Console.WriteLine("Authenticated message received with label " + "'{0}'", message.Label);
629
630
Chapter 13
Serviced Component Management
X509Certificate2 certificate = new X509Certificate2(message.SenderCertificate); Console.WriteLine("\tSender was '{0}'", certificate.Subject); Console.WriteLine("\tCertificate Issuer was '{0}'", certificate.Issuer); Console.WriteLine("\tCertificate effective {0}", certificate.NotBefore); Console.WriteLine("\tCertificate expires {0}", certificate.NotAfter); Console.WriteLine("\tCertificate Verify: {0}", certificate.Verify()); Console.WriteLine(); if (certificate.NotBefore > DateTime.Now) { Console.WriteLine("The certificate used to authenticate " + _ "the message will not be valid until {0}", certificate.NotBefore); return;
}
if (certificate.NotAfter < DateTime.Now) { Console.WriteLine("The certificate used to authenticate " + _ "the message expired on {0}", certificate.NotAfter); return;
}
if (!certificate.Verify())
{
Console.WriteLine("The certificate used to authenticate " + "the message could not be validated using " + "the basic validation policy. Perhaps it is a test " + "certificate or not issued by a trusted " + "authority. \n\nUse the X509Chain class to perform " + "a more detailed analysis."); } Console.WriteLine("Hit enter...");
Console.ReadLine();
}
}
}
When retrieving the message you sent earlier, you’ll see the output as shown in Figure 13-20.
Lesson 2: Securing Messaging
631
Figure 13-20 The authenticated message has the personal certificate embedded
Encrypting a Message The second way to secure your messages is encryption. Encryption is the process of encrypting and decrypting messages, ensuring they cannot be read or used by anyone not authorized to do so. MSMQ supports encryption through the use of public and pri vate keys. The MSMQ public key implementation is based on the Microsoft CryptoAPI and uses the Microsoft Base Cryptographic Provider version 1.0. As with authentication, encryption of MSMQ messages requires the use of a crypto graphic service provider (CSP). Although you can install a variety of CSPs for authen tication, the Microsoft Base Cryptographic Provider version 1.0 must be installed on any MSMQ server, independent client, or dependent client computer that sends or receives encrypted messages. (When you install the Microsoft Base Cryptographic Provider version 1.0, non-MSMQ applications can continue to use other CSPs for encryption.) You can specify whether a queue accepts encrypted messages, unencrypted messages, or both. If the queue privacy level is None, the queue accepts only unencrypted mes sages. If the queue privacy level is Optional, the queue accepts both unencrypted and encrypted messages. If the queue privacy level is Body, the queue accepts only encrypted messages. Messages are encrypted at the source computer and decrypted at the destination com puter; they appear in the destination queue as clear text. If the queue privacy level is Optional, users can verify whether a message sent to the queue was encrypted or unencrypted by checking the message properties in MSMQ Explorer. When you use encryption, MSMQ message throughput is significantly reduced, although typically not as much as by authentication. When you send multiple messages to the same destination, only the first message sent takes significantly longer to send.
632
Chapter 13
Serviced Component Management
Securing your message through encryption is a service offered at the queue level. The first step is to configure your queue to accept only encrypted messages. The next is to actually encrypt the message. Configuring the queue’s encryption setting can be done through the Computer Management console or using code to set the EncryptionRequired property. There are three possible settings for EncryptionRequired: ■ Body
Accepts only private (encrypted) messages.
■ None
Accepts only nonprivate (nonencrypted) messages.
Does not force privacy. Accepts private (encrypted) messages and nonprivate (nonencrypted) messages.
■ Optional
At the message level, specify that the message needs to be encrypted by setting UseEncryption to true. The following code shows a sample of how to set a queue to accept only encrypted messages and subsequently sends a message with UseEncryption set to true. 'VB Imports System.Messaging Module Module1 Private Const cQueueName As String = ".\private$\ShippingInbox" Sub Main()
' Create queue
Dim queue As MessageQueue = New MessageQueue(cQueueName)
queue.Label = cQueueName
queue.EncryptionRequired = EncryptionRequired.Body
' Create message and set properties
Dim msg As Message = New Message()
' This will only work together with Active Directory
msg.UseEncryption = True
msg.Body = "Test"
msg.Label = "Test"
' Send the message using a single MSMQ transaction
queue.Send(msg, MessageQueueTransactionType.Single)
Console.WriteLine("Message is sent to queue.")
Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub End Module //C#
Lesson 2: Securing Messaging
633
using System; using System.Messaging; namespace QueueSenderEncrypt { class Program { private const string cQueueName = @".\private$\ShippingInbox"; static void Main(string[] args)
{
// Create queue
MessageQueue queue = new MessageQueue(cQueueName);
queue.Label = cQueueName;
queue.EncryptionRequired = EncryptionRequired.Body;
// Create message Message msg = new // This will only msg.UseEncryption
and set properties
Message();
work together with Active Directory
= true;
msg.Body = "Test";
msg.Label = "Test";
// Send the message using a single MSMQ transaction
queue.Send(msg, MessageQueueTransactionType.Single);
Console.WriteLine("Message is sent to queue.");
Console.WriteLine("Hit enter...");
Console.ReadLine();
} } }
When looking at the properties of the message using the Computer Management con sole, it becomes clear that encryption has been applied. The receiving application retrieves a private message in the same way it would retrieve any clear text message. It can, however, look at the privacy level property of the mes sage to determine whether the message was sent encrypted and look at the encryp tion algorithm property to see how the message was encrypted. In workgroup mode, there is no support for this automatic level of encryption or even enforcement ensuring that only encrypted messages are sent. If you do want to encrypt the body of the message, you can do this by first serializing the body of your message and then encrypting the result using the cryptography classes, like the Rijndael class, available in the Framework Class Library.
634
Chapter 13
Serviced Component Management
Lab 2: Encrypting a Message and Verifying Its Authenticity After Transmission In this lab we elaborate on what you learned in the previous lab and create a certifi cate, then use it to sign and encrypt a message to later inspect the certificate and verify its authenticity. If you encounter a problem completing an exercise, the completed projects are avail able on the companion CD in the Code folder. �
Exercise 1: Encrypting and Verifying
In this exercise, you use the application created in Lesson 1 of this chapter to encrypt the information in the message and verify the message when receiving it. You can con tinue with your personal results or choose to copy the results from the CD and take it from there. 1. Start by creating a personal certificate. Open the Visual Studio 2005 command prompt. Type the following: makecert –n "CN=MSMQExercises" –ss My
2. Open Visual Studio 2005 and open the solution named MSLearning.Exercises. 3. Open Program.cs. 4. Add a method named GetCertificate, which loads the certificate from the per sonal certificate store: 'VB Function GetCertificate() As X509Certificate2 Dim store As X509Store = New X509Store(StoreName.My) store.Open(OpenFlags.ReadOnly) Dim collection As X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, _ "MSMQExercises", False) Dim certificate As X509Certificate2 = collection(0) Return certificate End Function //C# static X509Certificate2 GetCertificate() {
X509Store store = new X509Store(StoreName.My);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection collection = _ store.Certificates.Find(X509FindType.FindBySubjectName,
Lesson 2: Securing Messaging
635
“MSMQExercises”, false); X509Certificate2 certificate = collection[0];
return certificate;
}
5. Add code to CreateMessage to encrypt the message (relevant portions shown in bold): 'VB Private Function CreateMessage() As Message
Dim body As String = _
"CustomerId=888;OrderId=501;ArticleId=9900232;Quantity=10"
Dim message As Message = New Message(body)
message.Formatter = New XmlMessageFormatter(New Type() _
{Type.GetType("System.String")})
message.Label = "Request to invoice customer 888 for order 501."
message.Recoverable = True
message.TimeToBeReceived = New TimeSpan(1, 0, 0)
message.SenderCertificate = GetCertificate().GetRawCertData()
message.UseEncryption = True
Return message
End Function
//C# static private Message CreateMessage() {
string body = "CustomerId=888;OrderId=501;ArticleId=9900232;Quantity=10";
Message message = new Message();
message.Formatter = new XmlMessageFormatter(new Type[]{typeof(string)});
message.Body = body;
message.Label = "Request to invoice customer 888 for order 501.";
message.Recoverable = true;
message.TimeToBeReceived = new TimeSpan(1, 0, 0);
message.SenderCertificate = GetCertificate().GetRawCertData();
message.UseEncryption = true;
return message;
}
6. Add code to GetQueue to make the queue require encryption (relevant portions shown in bold): 'VB Function GetQueue(ByVal path As String) As MessageQueue
Dim queue As MessageQueue
If MessageQueue.Exists(path) Then
queue = New MessageQueue(path)
Else
queue = MessageQueue.Create(path)
End If
queue.Label = path
queue.EncryptionRequired = EncryptionRequired.Body
queue.MessageReadPropertyFilter.SenderCertificate = True
636
Chapter 13
Serviced Component Management
Return queue
End Function
//C# static private MessageQueue GetQueue(string path) {
MessageQueue queue;
if (MessageQueue.Exists(path))
{
queue = new MessageQueue(path);
}
else
{
queue = MessageQueue.Create(path, false); } queue.Label = path; queue.EncryptionRequired = EncryptionRequired.Body; queue.MessageReadPropertyFilter.SenderCertificate = true; return queue;
}
7. Add code to Main to retrieve and display information from the certificate used to encypt the message (relevant portions shown in bold): 'VB Sub Main()
Dim queue As MessageQueue = GetQueue(cQueueName)
Console.WriteLine("Using queue: {0}", cQueueName)
Dim message As Message = CreateMessage()
queue.Send(message)
Console.WriteLine("Send message to queue.")
Dim incoming As Message = queue.Receive() incoming.Formatter = New XmlMessageFormatter(New Type() _ {Type.GetType("System.String")}) Console.WriteLine("Incoming message.label : {0}", incoming.Label) Console.WriteLine("Incoming message.body : {0}", incoming.Body) Dim certificate As X509Certificate2 = _ New X509Certificate2(incoming.SenderCertificate) Console.WriteLine("\tSender was '{0}'", certificate.Subject) Console.WriteLine("\tCertificate Issuer was '{0}'", certificate.Issuer) Console.WriteLine("\tCertificate effective {0}", certificate.NotBefore) Console.WriteLine("\tCertificate expires {0}", certificate.NotAfter) Console.WriteLine("\tCertificate Verify: {0}", certificate.Verify()) Console.WriteLine("Hit enter...")
Console.ReadLine()
End Sub //C# static void Main(string[] args)
Lesson 2: Securing Messaging
637
{
MessageQueue queue = GetQueue(cQueueName);
Console.WriteLine("Using queue: {0}", cQueueName);
Message message = CreateMessage();
queue.Send(message);
Console.WriteLine("Send message to queue.");
Message incoming = queue.Receive();
incoming.Formatter = new XmlMessageFormatter(new Type[]{typeof(string)});
Console.WriteLine("Incoming message.label : {0}", incoming.Label);
Console.WriteLine("Incoming message.body : {0}", incoming.Body);
X509Certificate2 certificate = new X509Certificate2(incoming.SenderCertificate); Console.WriteLine("\tSender was '{0}'", certificate.Subject); Console.WriteLine("\tCertificate Issuer was '{0}'", certificate.Issuer); Console.WriteLine("\tCertificate effective {0}", certificate.NotBefore); Console.WriteLine("\tCertificate expires {0}", certificate.NotAfter); Console.WriteLine("\tCertificate Verify: {0}", certificate.Verify()); Console.WriteLine("Hit enter...");
Console.ReadLine();
}
8. Start the console application. 9. The result you see should look like this, although the dates on the certificate will be different: Using queue: .\private$\InvoicingQueue
Send message to queue.
Incoming message.label : Request to invoice customer 888 for order 501.
Incoming message.body :
CustomerId=888;OrderId=501;ArticleId=9900232;Quantity=10
Sender was 'CN=MSMQExercises' Certificate Issuer was 'CN=Root Agency' Certificate effective 17-7-2006 22:08:25 Certificate expires 1-1-2040 0:59:59 Certificate Verify: False Hit enter...
Lesson Summary ■
Authentication of the sender can be enforced by MSMQ by checking against Active Directory or against a certificate issued by a CA.
■
Signing a message is done by turning on authentication. This adds a digital sig nature to the message, which is invalidated if the message is corrupted before being received by the recipient.
638
Chapter 13
Serviced Component Management
■
Validation against a certificate requires custom code by the recipient of the message.
■
MSMQ encryption of messages is only supported in a domain. Encryption of a message is performed by the sender of a message; decryption is done by MSMQ and is thus transparent to the recipient.
■
In workgroup mode, custom encryption is required using the .NET Framework Class Library.
■
The recipient of a message can verify the sender by inspecting the SenderCertificate.
Lesson Review You can use the following questions to test your knowledge of the information in Les son 2, “Securing Messaging.” The questions are also available on the companion CD if you prefer to review them in electronic form. NOTE
Answers
Answers to these questions and explanations of why each answer choice is right or wrong are located in the “Answers” section at the end of the book.
1. Consider the following code being run on a machine in workgroup mode: 'VB Dim queue As MessageQueue = MessageQueue.Create(".\\private$\\myqueue") queue.Authenticate = True
Dim message As Message = New Message()
queue.Send(message)
//C# MessageQueue queue = MessageQueue.Create(".\\private$\\myqueue");
queue.Authenticate = true;
Message message = new Message();
queue.Send(message);
Which of the following statements is true? (Choose the best answer.) A. This code will run just fine. B. This code won’t work in workgroup mode because in workgroup mode you need to specify a SenderCertificate. C. This code won’t work because the message needs to specify UseAuthentication as true. D. This code won’t work because of both B and C.
Lesson 2: Securing Messaging
639
2. Which of the following statements is correct? (Choose the best answer.) A. MessageQueue.GetAllMessages() reads and deletes all messages from a queue. B. MessageQueue.Peek() clones the first message on the queue and does not delete it. C. MessageQueue.Receive() clones the first message on the queue and does not delete it. D. MessageQueue.Delete() deletes the first message on the queue.
640
Chapter 13 Review
Chapter Review To further practice and reinforce the skills you learned in this chapter, you can per form the following tasks: ■
Review the chapter summary.
■
Review the list of key terms introduced in this chapter.
■
Complete the case scenarios. These scenarios set up real-world situations involv ing the topics of this chapter and ask you to create a solution.
■
Complete the suggested practices.
■
Take a practice test.
Chapter Summary ■
Message queuing is an optional part of Windows that needs to be installed explicitly.
■
Queues are created, accessed, deleted, and managed using the System.Messaging .MessageQueue class.
■
Messages can be any object, but it’s good practice to put your object in the body of a System.Messaging.Message object.
■
The message body can be serialized using either a binary formatter or an XML formatter.
■
Queues can participate in transactions.
■
Authentication of a message can be configured as a requirement for being allowed to even send a message into a queue.
■
Messages can be secured using encryption.
■
The Computer Management console can be used to monitor and maintain mes sage queues.
Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book. ■
Computer Management console
■
digital signature
Chapter 13 Review
■
encryption
■
message queue
■
Microsoft Message Queuing (MSMQ)
641
Case Scenarios In the following case scenarios you apply what you’ve learned about how to use mes sage queues and secure messaging. You can find answers to these questions in the “Answers” section at the end of this book.
Case Scenario 1: Online Shop Interviews Following is a list of company personnel interviewed and their statements. “We have an online shop, our shipping system, and our financial system all connected using Web services. It works quite well, but to back up our financial system we need to bring it down for two hours. Because the system is down, the Web services are unavailable and our online shop stops functioning.”
■ IT Department Head
“It’s not that things don’t work right now, but sometimes our users get a slow response due to the monthly invoicing run in the financial system. We try and do all our financial updates the second the user clicks Pur chase, but the response is too slow.”
■ Lead Business Analyst
“Slow? Systems unavailable? What is this, the Dark Ages? Think of some thing smart! I want high performance, high availability and by that I mean 24/7/ 365!”
■ CIO
Questions Answer the following questions for your manager: 1. Does the online store have to perform all of its processing functions the moment the customer clicks Purchase? 2. What kind of security do we currently have when communicating between our online store and the shipping system and financial system?
642
Chapter 13 Review
Case Scenario 2: Batches Interviews Following is a list of company personnel interviewed and their statements. “We have a monthly invoice batch that runs 48 hours and we have no way to easily scale this across more machines.”
■ IT Department Head
“We want to have the system available every day of the week. Our batch window needs to be reduced to 6 hours, and 4 hours if possible.”
■ Lead Business Analyst
“The board has made it clear: We need to be open for business every day of the week, including weekends. Our systems can no longer afford to claim the whole weekend for batch jobs.”
■ CIO
Questions Answer the following questions for your manager: 1. How does the batch currently work? 2. Is there a particular order in which items need to be processed during this batch? If so, what is the smallest chunk of work that can be identified? 3. How many machines do we have available? How many processes per machine can we start at once?
Suggested Practices To successfully master the objectives covered in this chapter, complete the following tasks.
Create, Delete, and Set Permissions on a Message Queue For this task, you should complete both practices.
Practice 1 ■
Create a console application that checks for the existence of a queue named MyInboxQueue. If it exists, delete it; if it doesn’t exist, create it.
Chapter 13 Review
643
Practice 2 ■
Create a console application that checks for the existence of a queue named MyInboxQueue. If it does not exist, create it.
■
Modify the rights on the queue such that only you can write to the queue, but everyone can read from the queue.
■
Write two messages to the queue, with the text I can read from the queue. as the body.
■
Start the console application.
■
Create a second console application that reads a message from and displays the body.
■
Start the second console application. You should now see the text “I can read from the queue.”
■
Log off, and log on as a different user.
■
Start the first console application. You should get a security exception.
■
Start the second console application. You should now see the text “I can read from the queue.”
Send and Receive Messages For this task, you should complete both practices.
Practice 1 ■
Create a console application that creates a queue and sends a message to that queue.
■
Check the message body using the Computer Management console.
■
Change the message formatter to XML and repeat the preceding steps.
■
Change the message formatter to Binary and repeat the preceding steps.
Practice 2 ■
Create a class library project with a SubmitOrder method on an OrderService. Use an interface named IOrderService. Make the service into a queued component and register it as a service application in the COM+ catalog. A number of queues are created automatically. Use the Computer Management console to enable journaling on these queues.
644
Chapter 13 Review
■
Create a console application that uses a moniker to access the queued compo nent, casting the moniker to the IOrderService interface. Call SubmitOrder. Exam ine the journal queues to view the message that was sent.
■
If you feel ambitious, you might want to pass an Order object that implements IPersistStream as a parameter.
Sign and Encrypt Messages There is only one practice for this task.
Practice 1 ■
Create a console application that creates a transactional queue requiring authen tication and encryption of messages. Make it expect an acknowledgment on receipt of a message. Put an order object in the queue using a binary formatter. Make it listen to the administrative queue and display any messages that come in.
■
Create a second console application that receives the order object and, within a transaction, writes an entry to the database.
■
Play around with this setup and create intentional errors in the second applica tion. See what happens to the messages, dead-letter queue, and acknowledgments.
Take a Practice Test The practice tests on this book’s companion CD offer many options. For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70-529 certification exam content. You can set up the test so that it closely sim ulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question. MORE INFO
Practice tests
For details about all the practice test options available, see the section titled “How to Use the Practice Tests” in this book’s Introduction.
Answers Chapter 1: Lesson Review Answers Lesson 1 1. Correct Answers: A, C, and D A. Correct: This namespace is included by default for a new Web service project created with the template. B. Incorrect: There is no namespace named System.WebServices. C. Correct: This namespace is included by default for a new Web service project created with the template. D. Correct: This namespace is included by default for a new Web service project created with the template. 2. Correct Answer: D A. Incorrect: This code is valid and is used to specify that the Web service will refer to another assembly. B. Incorrect: This code is valid and is used to specify that the Web service will reference a single assembly. C. Incorrect: This code is correct, even though the name in the class is differ ent from the name specified in the CodeBehind attribute. As long as there is an actual file named ANewService.vb and the class is internally named Ser vice, this code is valid. D. Correct: This code references a second assembly but uses a colon and not a comma to separate the class from the second assembly name. 3. Correct Answer: A A. Correct: The namespace uniquely distinguishes your Web service from other Web services. B. Incorrect: This property is not used to reference any standards organization. C. Incorrect: The namespace can refer to a valid URL, but its primary purpose is to uniquely identify the Web service and not to reference documentation.
645
646
Answers
D. Incorrect: The namespace can refer to a valid URL, but its primary purpose is to uniquely identify the Web service and not to reference a company Web site.
Lesson 2 1. Correct Answers: A, B, and D A. Correct: A method must be public before it can be exposed through a Web service. B. Correct: The WebService processing directive tells the .asmx handler where to locate the class files that implement the Web service. C. Incorrect: There is no such thing as a WebService configuration section in the web.config file. D. Correct: The WebMethod attribute must be attached to all public methods that will be exposed through the Web service. 2. Correct Answer: C A. Incorrect: Transaction processing is available for Web services with the .NET Framework 2.0. It is set by using the TransactionOption property for the WebMethod attribute. B. Incorrect: The correct property name is TransactionOption, not Transaction. C. Correct: The TransactionOption property accepts the following values: Dis abled, NotSupported, Supported, Required, or RequiredNew. D. Incorrect: There is no Transaction property for the WebService attribute. 3. Correct Answer: B A. Incorrect: The OneWay property is not set through the WebMethod attribute. B. Correct: Either the SoapDocumentMethod or the SoapRpcMethod can be used to set the OneWay attribute to true. C. Incorrect: Although the System.Web.Services.Protocols namespace does con tain the SoapDocumentMethod and SoapRpcMethod methods, there is no such method as SoapProtocol. D. Incorrect: Even though B is correct, A is not.
Answers
647
Lesson 3 1. Correct Answer: B A. Incorrect: The Service method help page is what is used to invoke a partic ular Web method and does not display a link to all consumable Web meth ods. B. Correct: The Service help page is accessible by browsing to the .asmx file for a Web service. This page displays a link to all consumable Web methods in your Web service. C. Incorrect: There is no such thing as a Web method help page. D. Incorrect: Only choice B is correct. 2. Correct Answers: A, C, and D A. Correct: You can browse to a Web service using the .asmx file in a Web browser. B. Incorrect: There is no such thing as a Web service Object Browser. C. Correct: You can use a debugging session within the Web service project to step through the code of your Web method. D. Correct: You can create an ASP.NET client application to consume your Web methods. 3. Correct Answers: A, C, and D A. Correct: You will need to create a Web reference in your test application that points to the .asmx file before you are able to access any of the public Web methods. B. Incorrect: You do not need to create a routine to publish your Web service. Creating a Web reference that points to the .asmx file should be all that is necessary to establish a connection to the Web service. C. Correct: You will need to instantiate a new variable that will be used to access the Web methods exposed in your Web service. D. Correct: You will need to call the Web method directly from the code using the variable instantiated in the previous step.
648
Answers
Chapter 1: Case Scenario Answers Case Scenario 1: Deciding to Use Web Services ■
You suggest to your boss that instead of allowing the partner company access to the database through an SQL Server port, you design a Web service application that exposes only the key data needed. You explain that granting the company access to the entire database presents several security obstacles that might require the company to compromise its network architecture design. By utilizing Web services, you can control exactly what data are exposed to the partner com pany. They will only be able to query for data that are exposed through the pub lic methods you provide.
Case Scenario 2: Testing your Web Service ■
You should firmly explain to your boss that even though you are sure that your database queries return valid data, it may or may not be what the client expects or needs. You would like to expand the testing to include the creation of a test application that consumes all the publicly exposed Web methods. The test application would simulate each company partner and retrieve the necessary data for that partner. The application would then display the data. You further explain that even though your company is not directly responsible for creating the applications that consume these Web services, it would be fool ish not to see if what they provided was useful and easy to manipulate for the consumer application. Your boss readily agrees and congratulates you for think ing proactively.
Chapter 2: Lesson Review Answers Lesson 1 1. Correct Answer: D A. Incorrect: There is no Action element for the 1.1 specification. B. Incorrect: There is no Action element for either the 1.1 or 1.2 specification. C. Incorrect: Although the elements are correct here, the keyword must indi cates that all elements are required but the Header element is optional.
Answers
649
D. Correct: SOAP messages formatted with either the 1.1 or 1.2 specification might contain an Envelope, Header, and Body element. The Header element is optional. 2. Correct Answer: A A. Correct: The encoding value is used to indicate a specific formatting schema. B. Incorrect: The encoding value has nothing to do with encryption of Web methods. That is handled by Web Services Enhancements (WSE). C. Incorrect: Encoding is not the default value used for parameter encoding; the Literal value is. D. Incorrect: Encoding is not the default value used for parameter encapsula tion. This value is instead used for specifying the parameter encoding. 3. Correct Answer: B A. Incorrect: The property used to indicate conformance is not named Con formance; it is ConformsTo. B. Correct: This is the correct syntax. C. Incorrect: The property used to indicate conformance is not named Con formance; it is ConformsTo. Also, the value used to indicate the WS-I con formance is not correct. D. Incorrect: There is no such property as BindingName. 4. Correct Answer: C A. Incorrect: There is no method named ToSerial. B. Incorrect: Deserialize is a valid method, but it is the second step in the seri alization process and involves the mapping of the XML to a .NET object. C. Correct: The Serialize method is the first step in the serialization process and is used to create an XML document. D. Incorrect: There is no method named XmlSerialize.
Lesson 2 1. Correct Answers: A, C, and D A. Correct: Typically information concerning how the client should handle authentication and transactions is included in the SOAP header.
650
Answers
B. Incorrect: The SOAP specification version is not included in the SOAP header. C. Correct: Information concerning how the SOAP request should be pro cessed by the client is typically included in the SOAP header. D. Correct: The encodingStyle attribute is included in a header block. 2. Correct Answer: B A. Incorrect: You would want to create a class that inherits from the Sys tem.Web.Services.Protocols.SoapHeader namespace. This is your custom SOAP header class. B. Correct: You do want to create a variable in your Web service class that ref erences the new SOAP header class, but the variable should be public and not private. C. Incorrect: You do want to add a SoapHeader attribute to your public Web method and also ensure that the member name matches the variable name defined in your Web service class. D. Incorrect: You do want to add code that references the variable name cre ated in your Web service class. However, to do so, that variable must be declared as public. 3. Correct Answer: C A. Incorrect: In and Out are valid values for the Direction property, but they are not the only ones. B. Incorrect: In, Out, and InOut are valid values for the Direction property, but they are not the only ones. They were, however, the three valid options for the .NET Framework, version 1.1. C. Correct: These are the four valid values for the Direction property in the .NET Framework 2.0. D. Incorrect: The NoFault value is not a valid option for the Direction property.
Lesson 3 1. Correct Answer: A A. Correct: This is what occurs during the BeforeSerialize stage. B. Incorrect: This is what occurs during the BeforeDeserialize stage. C. Incorrect: This is what occurs during the AfterSerialize stage.
Answers
651
D. Incorrect: This is what occurs during the AfterDeserialize stage. 2. Correct Answer: D A. Incorrect: The ChainStream method allows you to access the memory buffer where the SOAP message resides, but not actually determine the stage in which processing is occurring. B. Incorrect: This method is where data that is used by the extension is ini tialized. C. Incorrect: There is no method named ProcessStage. D. Correct: This method is where the SoapMessageStage enumeration is checked to determine which stage is occurring. 3. Correct Answer: C A. Incorrect: There is no such thing as a configuration element named . B. Incorrect: There is no such thing as a configuration element named . C. Correct: You do need to add a class that inherits from the System.Web.Ser vices.Protocols.SoapExtensionAttriubute class, which then allows you to attach the newly created SoapExtensionAttribute to a particular Web method. D. Incorrect: You need to inherit specifically from the System.Web.Services.Pro tocols.SoapExtensionAttribute class and not the System.Web.Services.Protocols class.
Chapter 2: Case Scenario Answers Case Scenario 1: Creating a Custom SOAP Header ■
You propose that a custom SOAP header should be created and used to pass in a parameter indicating which partner is requesting the data. This would allow you to use a single Web method to handle all partners. The SOAP header would accept several optional parameters, and each partner would be given instruc tions on how to pass in the parameters. You point out that this allows you to reduce the number of Web methods exposed by your Web service and also to reduce any redundant code.
652
Answers
Case Scenario 2: Creating a SOAP Extension ■
You suggest that XML serialization can be used along with the SOAP header to handle authenticating the requestor. The SOAP header would accept a parame ter that contained an encrypted password specific to each partner. The encrypted password would be processed in the ProcessMethod method and would handle data received during the BeforeDeserialize stage. The encrypted password passed in through the incoming stream would be checked against the database and, if it was valid, the request would continue. Otherwise, the unau thorized request would be logged, and an alert would be sent to the server administrator.
Chapter 3: Lesson Review Answers Lesson 1 1. Correct Answers: C and D A. Incorrect: There is no EnableApplication property. Also, it is not necessary to disable application state to utilize session state. Theoretically, both can be used within the same Web service. B. Incorrect: Even though there is a SessionState section in the Web.config file, there is no such thing as an Enabled property. C. Correct: You need to set the EnableSession property using the WebMethod attribute for each Web method that needs to use session state. D. Correct: You can add a session variable using the Add method for the Ses sion object. 2. Correct Answer: A A. Correct: A small integer-based data value such as an employee ID would most likely be stored in a session variable. B. Incorrect: The text of a document would be too large for a session or appli cation variable. It would be better to cache this value or just retrieve it from the Web server on each request. C. Incorrect: An array containing customer purchase history would be too large for a session or application variable. It would be better to retrieve this data from the database on each request.
Answers
653
D. D. Incorrect: Datasets of any size are not good candidates for storage in an application or session variable. 3. Correct Answer: B A. Incorrect: There is no such thing as a SessionCookie property for the proxy class. B. Correct: You need to create an instance of the CookieContainer property and then reference the CookieContainer property of the proxy class. C. Incorrect: You do need to store the value of the CookieContainer property to session state on the client, but this is not the first thing that must occur. D. Incorrect: You do not need to store the CookieContainer value in a clientside cookie. Instead you would use session state to do this after the instance is created and then set with the value of the CookieContainer prop erty of the proxy class.
Lesson 2 1. Correct Answers: A, C, and D A. Correct: Although not installed by default, HTTP POST is one of the mes saging protocols available. B. Incorrect: A secure HTTP session is not available as one of the messaging protocols. C. Correct: Although not installed by default, HTTP GET is one of the mes saging protocols available. D. Correct: HTTP SOAP is a messaging protocol that is installed by default. 2. Correct Answer: D A. Incorrect: There is no disableDocument attribute for the protocol element. B. Incorrect: The remove element can be used to disable documentation, but answer D is correct because it includes answer C, which is also correct. C. Incorrect: The wsdlHelpGenerator element can be used to point to a blank HTML page, but answer D is correct because it includes answer B, which is also correct. D. Correct: Both answers B and C are correct.
654
Answers
3. Correct Answer: C A. Incorrect: Turning session state off will result in no data retrieval. B. Incorrect: Storing session state to SQL Server is typically not the fastest mode for data retrieval. C. Correct: InProc, the default mode, is typically considered the fastest for data retrieval. D. Incorrect: As with SQLServer mode, StateServer is typically not the fastest mode for data retrieval.
Lesson 3 1. Correct Answers: A, B, C, and D A. Correct: A discovery file is automatically generated when you add a Web reference to a Web service through an ASP.NET application. B. Correct: A discovery document is automatically generated by browsing to the .asmx file with a ?DISCO suffix. C. Correct: You can enable dynamic discovery for all Web services by adding an add element to the httpHandlers section of your Web server’s Machine.config file. D. Correct: You can generate a static discovery file that references all the sup porting documents for your Web service. 2. Correct: D A. Incorrect: There is no wsdlRef element. B. Incorrect: The discoveryRef element is used to add one or more references to other discovery files with a .disco extension. C. Incorrect: The schemaRef element is used to reference one or more schemas with an .xsd extension. D. Correct: The contractRef element is used to reference the WSDL file associ ated with your Web service. 3. Correct Answers: A, B, and C A. Correct: .disco files are the discovery files used by consumers to locate the files associated with your Web service. B. Correct: .asmx files represent the actual Web service files that will be acces sible through a Web browser by consumers of your Web service.
Answers
655
C. Correct: .dll files are the compiled results that should be copied to the /bin folder of your virtual directory. D. Incorrect: .vb and .cs files are source files that do not need to be copied to the destination server because the code will be compiled into the .dll file.
Chapter 3: Case Scenario Answers Case Scenario 1: Creating a Session Variable to Store the Selected Vendor ID ■
The simplest way to address the vendor’s request is to alter your Web service code to utilize a session variable. The variable will store the vendor’s ID for each user session. You can set the value of the session variable at the time a vendor is first selected. You can then have all other Web methods reference the session variable as opposed to the vendor ID parameter.
Case Scenario 2: Creating a Custom Service Help Page for All Your Web Services ■
The easiest way to “brand” your Web services and associate all Web services with your company’s image is to modify the template page used to render the Service help pages for all Web services. By default, this page is named DefaultWsdlHelpGenerator.aspx and it is located in the same directory as your Machine.config file. You can open this file with a text editor and insert HTML after the body element. The HTML inserted here is then rendered along with the Service help page for every Web service accessed on that machine.
Case Scenario 3: Creating Setup Projects to Deploy Your Web Services ■
You recommend that the software teams start creating Web setup projects to handle the deployment of all Web applications, which includes Web services. Instead of relying on team leads to manually select deployment files, the Web setup project bundles all these files into one installation file that can be executed by a network administrator. This solution should help to ensure that certain department standards are followed and that each deployment includes all the necessary files for a successful execution.
656
Answers
Chapter 4: Lesson Review Answers Lesson 1 1. Correct Answer: A A. Correct: Singleton objects are server-activated objects that can be used to service multiple clients and maintain state between method calls. B. Incorrect: Single call objects are server-activated objects that are used for a single request and then the object is destroyed, so state is not maintained. C. Incorrect: Client-activated objects are maintained and initiated by the cli ent. They can store state, but it would only be specific for that client and so in this case, singleton is the best method for maintaining state. D. Incorrect: A server-activated object is correct, but in this case, you needed to be more specific and pick a singleton object. 2. Correct Answers: A, B, and C A. Correct: Session and application state combined with caching are some of the built-in benefits available when using ASP.NET as the hosting applica tion. B. Correct: By using an ASP.NET application you can use Secure Sockets Layer (SSL) for a secure line. C. Correct: Manual startup is not needed because IIS starts automatically and does not require a user to be logged on to the machine. D. Incorrect: The SOAP formatter is not considered the faster option when compared to the binary formatter, especially when data is transmitted over an HTTP channel and not a TCP channel. 3. Correct Answers: B and D A. Incorrect: There is no such thing as a Remote Objects .NET component. B. Correct: You do need to set a reference to the DLL for your remote object that should have the same name as the project and a DLL filename extension. C. Incorrect: There is no such thing as the System.Remoting namespace. D. Correct: You do need to reference the System.Runtime.Remoting namespace, which gives you access to the RemotingConfiguration and RemotingServices classes.
Answers
657
Lesson 2 1. Correct Answer: B A. Incorrect: This is valid code for registering a single call server-activated object but not a singleton object. B. Correct: This is the correct code for registering a singleton server-activated object. C. Incorrect: This is invalid code because RegisterActivatedServiceType is used to register a client-activated object, and also because the method does not accept a parameter for the object mode. D. Incorrect: This is valid code for registering a client-activated object and not a singleton object. 2. Correct Answer: A A. Correct: You can specify a version when registering the object, but if one is not specified and a conflict exists, then remoting automatically uses the lat est version available. B. Incorrect: You do not have to specify a version because remoting automat ically uses the latest version, but it would be a good idea to specify the ver sion number when multiple versions are known to exist. C. Incorrect: You can have two strongly named assemblies with the same name located on the same machine, but you need to specify the version to ensure that the correct one is located. D. Incorrect: There is no such method as RegisterVersion. 3. Correct Answer: D A. Incorrect: This statement is valid—a channel can only be registered once with the same port number. B. Incorrect: This statement is valid—you do use RegisterChannel to register a channel. C. Incorrect: This statement is valid—you do use UnregisterChannel to unreg ister a channel. D. Correct: This is an invalid statement because you can register a channel without specifying a port number.
658
Answers
Lesson 3 1. Correct Answer: C A. Incorrect: This XML is invalid because there is no version attribute for the element. B. Incorrect: This XML is invalid because the assembly name is not included in the type attribute. C. Correct: This statement is valid because the version is included with the type attribute D. Incorrect: This XML is invalid because the assembly name is not included in the type attribute. The version does not have to be there, but the assem bly name does. 2. Correct Answer: A A. Correct: The portName is used when registering an IPC channel to uniquely identify the port. B. Incorrect: The port is a valid attribute, but only the portName is required when registering an IPC channel. C. Incorrect: There is no portNumber attribute. D. Incorrect: The useIPAddress attribute is valid, but is not required when reg istering an IPC channel.
Chapter 4: Case Scenario Answers Case Scenario 1: Suggesting a Distributed Technology ■
Because all of the data will be collected and processed on the institute’s private network, you know that you are assured that client and server applications will be hosted on the .NET Framework. Since the data collected and analyzed will be processor intensive, you realize that efficiency is important for the success of the proposed solution. You therefore suggest that .NET remoteable types are used to implement a distributed solution. You further suggest that the remoteable types use a TCP communication channel and a binary formatter to ensure that the data is handled as quickly as possible.
Answers
659
Case Scenario 2: Using a Configuration File to Configure Your Remoting Application ■
You suggest that a configuration file be used to configure the remoting solution. This allows you to make changes to the values in these configuration files with out the need for a code recompile. This provides you with the most flexible solu tion, considering the need for reoccurring configuration changes.
Chapter 5: Lesson Review Answers Lesson 1 1. Correct Answer: A A. Correct: The IPC channel is used for interprocess communication on a sin gle machine. IPC is able to utilize proprietary Windows protocols that per form better than the HTTP and TCP protocols that must communicate beyond the local machine. B. Incorrect: The HTTP channel does not perform as well as IPC on the same machine. C. Incorrect: The TCP channel does not perform as well as IPC on the same machine. D. Incorrect: FTP is not a valid channel name. 2. Correct Answers: A, B, and D A. Correct: Remote objects can be activated on the server as Singleton objects. B. Correct: Remote objects can be activated on the client. C. Incorrect: Remote objects cannot be activated on the server on-demand. D. Correct: Remote objects can be activated on the server as SingleCall objects. 3. Correct Answers: A, C, and D A. Correct: Marshal-by-value objects maintain state between client calls. B. Incorrect: A proxy is not created for a marshal-by-value remote object because the object is copied to the client and activated as a locally defined object. C. Correct: Marshal-by-reference objects can directly access server resources such as databases.
660
Answers
D. Correct: A proxy object is created for marshal-by-reference objects. The objects reside on the server, and calls to the object are relayed through the proxy created. E. Incorrect: Marshal-by-value objects cannot directly access resources hosted on the server because the objects reside on the client.
Lesson 2 1. Correct Answer: C A. Incorrect. The WellKnownClientTypeEntry class is used to programmati cally load a server-activated object. B. Incorrect. The ChannelServices class is used to register a channel. C. Correct. The RemotingConfiguration class is used to load a configuration file. D. Incorrect. The RemotingServices class is used to connect to a remote object. 2. Correct Answer: C A. Incorrect. The element is not a valid element. B. Incorrect. The element is the root element for the entire .NET configuration file. C. Correct. The element is the root element for .NET remoting configuration. D. Incorrect. The element is used to register a service on a server.
Lesson 3 1. Correct Answer: B A. Incorrect. The new operator in C# requires more lines of code to be writ ten. B. Correct. The Activator.GetObject method requires the fewest lines of code to be written. C. Incorrect. The New operator in Visual Basic requires more lines of code to be written. D. Incorrect. The Activator.Create method is not a valid method.
Answers
661
2. Correct Answers: A and C A. Correct. The new operator in C# requires configuration prior to creating an instance of a remote object. B. Incorrect. The Activator.GetObject method does not require configuration prior to creating an instance of a remote object. C. Correct. The New operator in Visual Basic requires configuration prior to creating an instance of a remote object. D. Incorrect. The Activator.Create method is not a valid method.
Chapter 5: Case Scenario Answers Case Scenario 1: Creating a Secure Globally Distributed Application 1. The available communication channels are HTTP, TCP, and IPIPC is out of the question because it is used only for communication on a single machine. In the presented scenario, either HTTP or TCP could be used over the Web. However, TCP is typically used for intranet communication and with a binary formatter. TCP could be used with a SOAP formatter and could provide some security ben efits by utilizing an uncommon port. Due to the remote object being hosted using IIS, HTTP is the default channel and is perfectly suited to the scenario. 2. The remote object could be activated on the server or on the client. To improve performance somewhat, the remote object should be activated on the server, as this arrangement will minimize data being sent over the Web. If the object is acti vated on the client, the entire object will need to be passed to the client. Further more, if the object is activated on the client, the object typically will not have access to the database on the server. With the object activated on the server, a Singleton object would be best suited to the Web environment, as it can maintain state between client calls.
Case Scenario 2: Improving the Remoting Client Using Interfaces ■
You can modify the design of your application to improve security by creating interfaces that define the structure of your remote objects. Your remote objects should implement the interfaces you create to guarantee compliance with the interface. When you deploy your application to a client, a copy of the remote object is not necessary. The interface can be deployed to the client. The client can reference the interface instead of a copy of the remote object and the client will
662
Answers
successfully compile. By deploying an interface instead of a copy of the remote object, no source code will be deployed to the client. Hence, this is an even better option than deploying a copy of the remote object that contains encrypted source code.
Chapter 6: Lesson Review Answers Lesson 1 1. Correct Answers: A and C A. Correct: A Windows service application can be used to host .NET remote objects. B. Incorrect: A class library cannot execute on its own but is used by other applications, hence it cannot be used to host .NET remote objects. C. Correct: An ASP.NET Web application can be used to host .NET remote objects using IIS. D. Incorrect: A smart device application cannot be used to host .NET remote objects because the .NET Compact Framework does not support .NET remoting (as of .NET Compact Framework version 2.0). 2. Correct Answer: B A. Incorrect: Deploying the entire remote object assembly exposes the remote object source code on the client. B. Correct: Deploying an interface implemented by the remote object assem bly protects the remote object assembly source code and works with a con sole application hosted object. C. Incorrect: Extracting and re-creating the entire remote object assembly exposes the remote object source code on the client. Furthermore, SoapSuds cannot be used with console application hosted objects. D. Incorrect: SoapSuds cannot be used with console application hosted objects. 3. Correct Answer: A A. Correct: When you build a Web setup project, a Microsoft Installer file and a setup executable are generated.
Answers
663
B. Incorrect: When you build a Web setup project, a .NET managed assembly is not generated. C. Incorrect: When you build a Web setup project, a .NET managed assembly is not generated. D. Incorrect: When you build a Web setup project, a .NET configuration file is not generated.
Lesson 2 1. Correct Answer: D A. Incorrect: Debugging is not initiated in the server application. B. Incorrect: Debugging is not initiated in a remote object. C. Incorrect: Debugging is not initiated in a proxy object. D. Correct: Debugging is initiated in a client application. 2. Correct Answers: A, C, and D A. Correct: The Total Remote Calls counter is used to track .NET remoting application performance. B. Incorrect: The Proxies Instantiated counter is not a valid counter. C. Correct: The Context Proxies counter is used to track .NET remoting appli cation performance. D. Correct: The Channels counter is used to track .NET remoting application performance. 3. Correct Answers: A, B, and D A. Correct: Registered objects are notified when a remote object is marshaled. B. Correct: Registered objects are notified when a remote object is discon nected. C. Incorrect: Registered objects are not notified when a remote object is con nected to. D. Correct: Registered objects are notified when a remote object is unmarshaled.
Lesson 3 1. Correct Answer: B A. Incorrect: InitializeLease is not a valid function.
664
Answers
B. Correct: The InitializeLifetimeService function must be overridden to initial ize a lease. C. Incorrect: InitializeLeaseService is not a valid function. D. Incorrect: InitializeLifetime is not a valid function. 2. Correct Answer: A A. Correct: 5 minutes is the default. B. Incorrect: 0 minutes signifies an infinite lease duration. C. Incorrect: 15 minutes is not the default value. D. Incorrect: 2 minutes is not the default value. 3. Correct Answer: B A. Incorrect: You cannot instantiate a new lease object on the server from the client. B. Correct: To extend the duration of a lease from the client, register a sponsor. C. Incorrect: You cannot register a lease in the lease manager programmati cally from the client. D. Incorrect: You cannot register a lease in the lease manager by using a con figuration file from the client.
Chapter 6: Case Scenario Answers Case Scenario 1: Tracking and Improving the Performance of a Distributed Application 1. Two of the facilities at your disposal that are discussed in this chapter are a per fect fit here. .NET remoting tracking services can be used to create custom classes that are notified as new instances of remote objects are created and destroyed. You can also take action in the methods of the remote objects them selves to keep track of performance loads. Keeping track of performance and counts is also relatively easy by integrating performance counters. Some perfor mance counters are already designed to track performance of .NET remoting objects. However, if you’d like to track anything that is not being tracked, you can do so by using performance counters programmatically. 2. Microsoft currently supports network load balancing for .NET remoting compo nents but only if they are configured as server-activated, single-call remote
Answers
665
objects. To ensure scalability, Microsoft recommends that you host remote objects using IIS with an HTTP channel and binary formatter. Furthermore, Microsoft recommends setting network load balancing affinity to None.
Case Scenario 2: Simplifying Remote Object Deployment ■
Deploying the remote objects to each museum in the future could require a developer’s attention and could be overlooked. However, you can place the bur den of deploying the remote objects in the hands of the partners as they are ready to access the objects by using the SoapSuds utility. One simple solution could be to direct partners to a secured help page on the Web that includes the Uniform Resource Locator (URL) for the remote object host and instructions on how to use the SoapSuds utility. SoapSuds can be used to extract metadata and create a metadata-only assembly on the client. This serves the same purpose as deploying an interface.
Chapter 7: Lesson Review Answers Lesson 1 1. Correct Answers: A, B, and D A. Correct: A Web reference is the first step to consuming a Web service. B. Correct: An instance of the object must be declared and instantiated before its methods can be called. C. Incorrect: Calling the method directly calls the method synchronously. D. Correct: Calling async is necessary to call the asynchronous methods. 2. Correct Answers: A, B, and C A. Correct: If there is a return type of the synchronous method, then the sig nature will definitely differ. At a minimum, the names will be different. B. Correct: The whole purpose of using asynchronous calls is to allow other processing to occur while the Web method is processing. C. Correct: The Completed event must be trapped to determine that the method has finished. D. Incorrect: In most material respects, the two methods are notably different.
666
Answers
Lesson 2 1. Correct Answer: B A. Incorrect: This approach will not work with a standard invocation. B. Correct: Using an IAsyncResult object and polling for the IsCompleted prop erty to turn true is a valid way of accomplishing this goal. C. Incorrect: IsCompleted isn’t necessary when using a callback because the callback sends back notification when it has completed. D. Incorrect: Using the OneWay attribute allows a method to execute asyn chronously but does not send any notification about completion. 2. Correct Answers: A, B, and C A. Correct: If there is a return type of the synchronous method, then the sig nature will definitely differ. At a minimum, the method names will be dif ferent. B. Correct: The whole purpose of using asynchronous calls is to allow other processing to occur while the Web method is processing. C. Correct: The Completed event must be handled to determine that the method has finished. D. Incorrect: In most material respects, the two methods are notably different. 3. Correct Answers: B and D A. Incorrect: Although it’s technically possible to call a Web service directly, doing so is filled with many potential problems. Moreover, Web service calls are intended to be performed via the proxy class and should only be performed this way. B. Correct: The proxy class allows client code to call Web service methods just like it was any other code. C. Incorrect: Although separate threads can be used to call methods asyn chronously, delegates can be used as well. D. Correct: Threads or delegates can both be used to invoke methods asyn chronously.
Answers
667
Chapter 7: Case Scenario Answers Case Scenario 1: Exposing Functionality Through .NET Web Services 1. CORBA was cool stuff at the time but it wasn’t for the weak of heart and it cer tainly wasn’t the best fit for this scenario. XML Web services appear to me to be the only and best answer and, based on your other questions, I think it fits the bill perfectly. 2. .NET remoting is not especially complex, but it’s not for everyone. Moreover, it’s not the right solution here. If everything was sitting on different internal machines, it would be recommended, but .NET remoting does little in exposing functionality to the outside world. Web services bridge this gap and the best part is that after a Web reference to the service is added to a project, there’s nothing more to using it than there is to using any other object. (That’s a bit of an over simplification, but it’s not too far from the truth.) Even a first-year computer sci ence student should be able to consume an object. 3. All we need to do is write some code to get the data into the SQL Server database or write code that can talk to each of their proprietary systems. From there, we can expose the data via a Web service, and end users and trading partners are free to do what they want with the information. So if customer data is stored in three applications, we can have a Web method that can retrieve all of that infor mation and return the data to customers as though it were one source. The same applies for everything that they want customers and trading partners to have.
Case Scenario 2: Refining the Use of Web Services 1. Asynchronous calls need to be made in many cases. Fortunately, by simply declaring a delegate with a signature that matches a given method, many meth ods can be called asynchronously without much modification to the code base. Care needs to be taken, as just because a method is invoked asynchronously doesn’t mean that the method doesn’t need to return data. Nothing happens magically, so if a synchronous method call takes 30 seconds to complete, an asynchronous method call will also take 30 seconds unless the Web method changes. 2. The OneWay attribute provides “fire and forget” functionality. On methods that don’t have return values or methods that aren’t critical, it’s safe to use the OneWay attribute. Be careful, however, because if something is marked with the OneWay attribute, it can’t return any values. This can be a very big deal.
668
Answers
Chapter 8: Lesson Review Answers Lesson 1 1. Correct Answers: A and B A. Correct: Each method that should continue processing regardless of what happens on the server must be decorated with the OneWay attribute. B. Correct: An interface might not be used, but if one is, a method must have the OneWay attribute defined for any calls that will use one-way functionality. C. Incorrect: Because the method is processed on the server, setting the OneWay attribute on the client does not cause the method to continue process ing regardless of completion. D. Incorrect: Although a delegate can allow for asynchronous processing, it does not ignore exceptions thrown on the server. 2. Correct Answers: A, B, and C A. Correct: If there is a return type of the synchronous method, then the sig nature definitely differs. At a minimum, the names are different. B. Correct: The whole purpose of using asynchronous calls is to allow other processing to occur while the remoting method is processing. C. Correct: The Completed event must be trapped to determine that the method has finished. D. Incorrect: In most material respects, the two methods are notably different.
Lesson 2 1. Correct Answer: B A. Incorrect: This approach does not work with a standard invocation. B. Correct: Using an IAsyncResult object and polling for the IsCompleted prop erty to turn true is a valid way of accomplishing this goal. C. Incorrect: IsCompleted isn’t necessary when using a callback because the callback sends notification when it has completed. D. Incorrect: Using the OneWay attribute allows a method to execute asyn chronously but does not send any notification about completion.
Answers
669
2. Correct Answers: A and B A. Correct: The OneWay attribute is designed specifically to provide fire and forget functionality. B. Correct: Methods marked as one-way can continue processing even if the server throws an exception. C. Incorrect: The OneWay attribute cannot protect client code from client-side exceptions. D. Incorrect: Both the server methods and the interface need to be marked with this attribute if an interface is implemented.
Lesson 3 1. Correct Answers: A, B, C, and D A. Correct: Using the OneWay attribute can definitely result in notifications being sent to clients that no longer exist, because no exception notification would be raised. B. Correct: Any EventArgs classes must be serializable. C. Correct: Because each client must register for events, each additional client adds overhead to the application. This overhead can severely limit scalability. D. Correct: Because of the problems associated with events, they are often best suited to applications running on the same machine because running the client and server on the same machine avoids many of the problems related to events.
Chapter 8: Case Scenario Answers Case Scenario 1: Building Robust, Scalable Enterprise Applications 1. .NET remoting and Web services can handle these problems. Because of the needs of this application, configurability and maximum performance, .NET remoting is the best choice. 2. .NET remoting allows clients to consume new application servers by simply changing a configuration file. No new libraries need to be distributed. Moreover, by using interfaces, hard-coded library references don’t need to be distributed either. This arrangement makes changing servers and logic simple.
670
Answers
3. .NET remoting can minimize downtime because of reasons listed in the answer to question 2. Moreover, remoting increases application performance over Web services because remoting can use Transmission Control Protocol (TCP) and binary serialization. TCP and binary serialization both consume fewer resources and are faster than Extensible Markup Language (XML) over Hypertext Transfer Protocol (HTTP), which is what Web services use.
Chapter 9: Lesson Review Answers Lesson 1 1. Correct Answers: A, B, and C A. Correct: Although this method might not work for Web applications, it definitely works for most other project types. B. Correct: Although this method might not work for Web applications, it definitely works for most other project types. C. Correct: This method works for any project type and is the surest method to use to add a reference to the WSE 3.0 library. D. Incorrect: Other objects are imported via the proxy class, but the proxy is not able to create any project references to WSE 3.0 on its own. 2. Correct Answer: C A. Incorrect: This inheritance isn’t necessary in all cases, although there are some cases where it might be. B. Incorrect: Classes that don’t need WSE 3.0 features don’t need to reference WSE 3.0, let alone inherit from WebServicesClientProtocol. C. Correct: This is the main use case for the WebServicesClientProtocol class. D. Incorrect: The two classes can be used interchangeably in some cases, but properties of WebServicesClientProtocol such as RequestSoapContext and ResponseSoapContext are not available in SoapHttpClientProtocol. 3. Correct Answer: C A. Incorrect: An instance of WebServicesClientProtocol can be cast to SoapHttpClientProtocol without any exceptions. However, SoapHttpClientProtocol objects cannot be cast to WebServicesClientProtocol objects.
Answers
671
B. Incorrect: Only the properties that are present in the WebServicesClientPro tocol class and exist in the SoapHttpClientProtocol class are converted. Prop erties that don’t exist result in null values in C# or Nothing values in Visual Basic .NET. C. Correct: This is the behavior of casts from WebServicesClientProtocol objects to SoapHttpClientProtocol objects. D. Incorrect: The WebServicesClientProtocol class inherits from the SoapHttpClientProtocol. The rules of conversion are the same in this case as the rules when casting between any two objects where one inherits from another.
Lesson 2 1. Correct Answers: A, B, and C A. Correct: soapExtensionTypes can be added through the add tag. B. Correct: soapExtensionTypes can be removed from the application through the remove subtag. C. Correct: The clear subtag can clear all existing tags. D. Incorrect: Not only can configuration be used to manage soapExtensionTypes, it’s the preferred method. 2. Correct Answer: C A. Incorrect: Lower priority values take precedence over higher values, so 1 has higher precedence than 2. B. Incorrect: Lower group values take precedence over higher values, so 0 has higher precedence than 1. C. Correct: A priority value of 1 supersedes a value of 2. D. Incorrect: Numeric values in both subtags are used exclusively for setting precedence. 3. Correct Answers: A, B, and C A. Correct: An entry in the portion of the configuration file must be added for each configSection that will be used. B. Correct: The assembly name, version, and culture can all be specified in the portion of the configuration file. C. Correct: An entry matching the name specified in the addi tion must be included in the configuration file.
672
Answers
D. Incorrect: can be used for custom settings but will not be rec ognized correctly if stored here.
Lesson 3 1. Correct Answers: A, C, and D A. Correct: Digital signatures are used to verify the identity of both the sender and the receiver. B. Incorrect: Authorization is not a specific objective of digital signatures. Other features, authentication in particular, handle this objective. C. Correct: Message integrity is a major goal of digital signatures. D. Correct: Confidentiality is a goal of digital signatures. 2. Correct Answers: A, B, C, and D A. Correct: Kerberos tokens can definitely be used, although they have lim ited applicability depending on the operating system of the machine that’s using them. B. Correct: X.509 is one of the main mechanisms for token implementation. C. Correct: UserNameToken objects are a valid and simple way of implement ing tokens. D. Correct: Custom tokens can be implemented using WSE 3.0.
Chapter 9: Case Scenario Answers Case Scenario 1: Where Does WSE Fit into My Application Development Strategy? 1. The two biggest concerns are security and performance. WSE can help enhance both of these when using Web services. 2. Learning the WS-* standards and writing code to implement them would take a long time. Learning any standard and stumbling through getting it correct is always an error-prone process. Fortunately, Microsoft has already accomplished this task for us and provides all this functionality out of the box without forcing developers to know every nuance of the standard. However, like any technology, you need to understand what you are doing and why you are doing it. WSE greatly simplifies the process, but there will still be learning involved.
Answers
673
3. We should only use proven security protocols. Anyone can write an encryption algorithm, but she or he can’t honestly guarantee the strength of such algo rithms. This limitation, however, doesn’t stop many people from writing their own encryption algorithms. Using proven, peer-reviewed security standards is the only safe way to go. However, there’s a tremendous amount of customization that can be done within the confines of using strong proven algorithms. WSE gives you the best of both worlds.
Case Scenario 2: Refining the Process? 1. There are a lot of things that might help the problems at hand, but the only ones that don’t require new hardware is changing the data transfer methods. WSE 1.0 and 2.0 introduce DIME, which can improve performance, and WSE 3.0 intro duces MTOM. Either should address the issues raised. 2. DIME was available in all versions of WSE prior to 3.0. With 3.0, DIME is no longer supported and is replaced with MTOM. MTOM is more efficient, but the main reason to use it is because of obsolescence. While DIME will work well for a while, it’s already been deprecated, and MTOM will provide a much smoother transition to WCF. 3. In its simplest form, an application can be retrofitted to use either DIME or MTOM in around 20 lines of code (less in some cases but more for most realistic cases). Either way, adding MTOM or DIME support to both the Web service and the client is a trivial endeavor.
Chapter 10: Lesson Review Answers Lesson 1 1. Correct Answers: A, B, C, and D A. Correct: Anonymous is a valid authentication method. See the “Adding Policy Assertions” section for a description of this authentication method. B. Correct: Username is a valid authentication method. See the “Adding Pol icy Assertions” section for a description of this authentication method. C. Correct: Certificate is a valid authentication method. See the “Adding Pol icy Assertions” section for a description of this authentication method.
674
Answers
D. Correct: Windows is a valid authentication method. See the “Adding Policy Assertions” section for a description of this authentication method. 2. Correct Answer: D A. Incorrect: This action does not tell the application where to find the file. B. Incorrect: This action does not tell the application where to find the file. C. Incorrect: This action does not tell the application where to find the file. D. Correct: You can add a element with a fileName attribute to specify an external policy file.
Lesson 2 1. Correct Answer: B A. Incorrect: Because symmetric algorithms necessitate at least two parties holding the private key, they are generally considered less secure than their asymmetric counterparts. B. Correct: Asymmetric algorithms allow a user to keep a private key totally secure while distributing only a public key. The private/public key pair is used to encrypt and decrypt messages and as such has a much lower risk of compromise. C. Incorrect: Hashing is the primary mechanism used to create digital signa tures, and symmetric algorithms still have tremendous value for data con cealment. D. Incorrect: Hashing is the primary mechanism used to create digital signa tures, and asymmetric algorithms still have tremendous value for data con cealment. 2. Correct Answer: A A. Correct: This is the only part that is protected by default when a SOAP mes sage is encrypted. B. Incorrect: The header can be protected if a determination is made that pro tecting information contained inside it is necessary. However, this is not done without specific implementation on the part of the developer. C. Incorrect: Although the can be used to facilitate a more secure solution, it is not encrypted or protected by default.
Answers
675
D. Incorrect: Although the can be used to facilitate a more secure solution, it is not encrypted or protected by default. 3. Correct Answers: A, B, C, and D A. Correct: Both the header and the body part can be encrypted, although only the body part is handled by default. B. Correct: A UsernameToken can be used to encrypt a message. C. Correct: Certificates can be used to handle key transfer between parties that want to securely exchange data. D. Correct: WSE 3.0 provides mechanisms to use both asymmetric and sym metric algorithms.
Lesson 3 1. Correct Answers: A, B, and C A. Correct: The SoapFilter class can serve as a valid base class from which to inherit custom filters. It is appropriate for instances where the SOAP mes sage is not secured. B. Correct: The ReceiveSecurityFilter can serve as a valid base class from which to inherit custom filters. C. Correct: The SendSecurityFilter can serve as a valid base class from which to inherit custom filters. D. Incorrect: ProcessMessage is a method and, while it should be implemented in many instances, it cannot serve as a valid base class. 2. Correct Answer: C A. Incorrect: ProcessMessage should be used in conjunction with the SoapFil ter class, not the SendSecurityFilter class. B. Incorrect: ValidateMessageSecurity should be used in conjunction with the ReceiveSecurityFilter class, not the SendSecurityFilter class. C. Correct: This is the correct method to implement. D. Incorrect: CreateClientOutputFilter is valid only in the context of policy assertions and will not serve the purposes specified.
676
Answers
Chapter 10: Case Scenario Answers Case Scenario 1: How Secure Is Secure Enough? 1. Home-grown security is something that’s generally frowned on. An implementa tion of security by obscurity is no longer tolerated. Even though obscurity pro vides some level of security because the attack surface area is harder to define, the security features implemented by WSE are ubiquitous throughout the indus try. Each feature can be implemented in conjunction with the .NET Framework security libraries that are all based on widely used, peer-reviewed, tested imple mentations. The strength of these features is widely recognized and even though their acclaim makes them easy to target, breaching them is so difficult that, in most cases, they provide as much security as any company would want. 2. WSE implements the WS-* Security standards. These are widely published, dis tributed, and well known. Because this specification is known to the degree it is, it carries with it a tremendous amount of credibility. 3. Absolutely. Because there are already many white papers written on the WS-* Security specification, existing documentation can be referenced. The fact that there is so much documentation in existence only enhances the reputation and credibility of the specification.
Chapter 11: Lesson Review Answers Lesson 1 1. Correct Answer: C A. Incorrect: While the SoapClient and SoapService classes can be used for one-way messaging, they are mostly used for two-way messaging. In this answer, the SoapSender and SoapReceiver classes are correct. B. Incorrect: The SoapClient and SoapService classes are used for two-way messaging. C. Correct: The SoapSender and SoapReceiver classes are used in one-way mes saging. D. Incorrect: The SoapClient and SoapService classes are used for two-way messaging. In this answer, SoapService is incorrect.
Answers
677
2. Correct Answers: A and D A. Correct: You will need to create a class that inherits from the SoapClient class. B. Incorrect: The SoapReceiver class is used when implementing one-way messaging. C. Incorrect: You will add a constructor, but the URI is not passed as a reference. D. Correct: You will need to add a constructor to the newly created class that accepts an EndpointReference object as a parameter. 3. Correct Answer: A A. Correct: In this case, the element is nested within the element. B. Incorrect: In this case, the element is nested within the element, but the entire section is wrapped in a tag for WSE 2.0 and not WSE 3.0. C. Incorrect: There is no such thing as an attachments element here. D. Incorrect: There is no such thing as an attachments element here.
Lesson 2 1. Correct Answers: A and D A. Correct: You need to add a reference to the System.Web.Services namespace. B. Incorrect: There is no namespace named System.Web.Services2. C. Incorrect: There is no namespace named System.Web.Services3. D. Correct: You need to add a reference to the Microsoft.Web.Services3 namespace. 2. Correct Answer: C A. Incorrect: This code would only be correct if you were configuring a router using WSE 2.0 and not version 3.0. B. Incorrect: This code not only references WSE 2.0, but it states that the file to be routed is literally named webservices. C. Correct: This code references the correct version of WSE and uses a wild card to specify all files with an .asmx file extension.
678
Answers
D. Incorrect: This code references the correct version of WSE, but states that the file to be routed is literally named webservices. 3. Correct Answer: A A. Correct: The element contains the exact path to which a request will be routed. B. Incorrect: This element is used to specify the path, but is only the con tainer element for the element, which is the correct answer. C. Incorrect: This element is the top container element used to specify the routed request’s final destination, but the element contains the exact path. D. Incorrect: There is no element named .
Lesson 3 1. Correct Answers: B and D A. Incorrect: You do not add code to the constructor for the WSE router, but instead to a class file added to the App_Code folder and returned in the GetRequestPolicy method. B. Correct: An alternative to adding code to a policy class file is to create an XML-based policy file and return that in the GetRequestPolicy method. C. Incorrect: You do not add code to verify the signer’s credentials and espe cially not directly to the GetRequestPolicy method. D. Correct: You can add code that adds an assertion to a class file that is returned from the GetRequestPolicy method. 2. Correct Answer: B A. Incorrect: The X.509 token uses a public key that is stored in the certificate and included in the message. B. Correct: A UsernameToken uses a username and password combination that can be stored in a database, Active Directory, or some other directory service. C. Incorrect: UsernameOverTransport sends the credentials through SSL.
Answers
679
D. Incorrect: AnonymousOverX509 accepts a server’s public key from an anon ymous or unknown client. 3. Correct Answer: A A. Correct: Wrapped in a element, the verifyTrust attribute must be set to true when the allowTestRoot attribute is set to true. B. Incorrect: The verifyTrust attribute must be set to true when the allowTestRoot is set to true. C. Incorrect: Although the element is correct, it is wrapped in a element, which does not exist. D. Incorrect: The verifyTrust attribute cannot be set to false, and the element is wrapped in a element, which does not exist.
Chapter 11: Case Scenario Answers Case Scenario 1: Performing a Server Upgrade 1. Prior to the server upgrade, you need to help prepare a backup server. This server is used to host the Web services while the original is being upgraded. You also need to prepare a Web.config file that refers to a new referral cache file. The new referral cache file contains a URL that points to the backup server. When the original server is taken offline, the new Web.config and referral cache files are placed on the computer hosting the WSE router.
Case Scenario 2: Selecting a Security Method for Your WSE Router 1. In this scenario, you would likely recommend an AnonymousOverX509 security method. Because performance is a consideration, you might want to reject the idea of using UsernameOverTransport because the overhead associated with using SSL can cause performance problems with your Web services. The AnonymousOverX509 method provides message layer security but still allows the client to authenticate anonymously. This is acceptable in this situation because the only clients accessing your Web services are trusted members to whom you can provide the public key.
680
Answers
Chapter 12: Lesson Review Answers Lesson 1 1. Correct Answers: B and D A. Incorrect: This interface does not exist. A serviced component needs to inherit from the ServicedComponent class. B. Correct: The ServicedComponent base class is located in the System.Enter priseServices namespace. C. Incorrect: This namespace does not exist. The ServicedComponent base class is located in the System.EnterpriseServices namespace. D. Correct: A serviced component needs to inherit from the ServicedCompo nent class. 2. Correct Answers: A, B, and C A. Correct: Use the System.EnterpriseServices.AutoCompleteAttribute to mark a method such that it will vote in the transaction. B. Correct: Use the System.Runtime.InteropServices.ComVisibleAttribute to mark your class as visible to COM+. C. Correct: Use the System.EnterpriseServices.TransactionAttribute to specify whether your class will participate in a running transaction or require a new transaction. D. Incorrect: The System.EnterpriseServices.JustInTimeActivationAttribute is used to turn JIT activation on or off. 3. Correct Answers: B and D A. Incorrect: The Sn.exe tool is used to create a strong name key pair. B. Correct: The Regsvcs.exe tool can be used to register a serviced component. C. Incorrect: The C:\Program Files\ComPlus folder is used when using the MSI deployment option, but dropping an assembly in this folder does not register the assembly in the COM+ catalog. D. Correct: The Component Services management console can be used to reg ister a serviced component using drag-and-drop.
Answers
681
Lesson 2 1. Correct Answers: B and D A. Incorrect: ServicedComponents cannot be referenced using a Web reference. Use the command-line tool SoapSuds.exe if you want to create a reference to a SOAP-enabled COM+ component. B. Correct: The class needs to be public to be visible from outside the assembly. C. Incorrect: A serviced component does not need to explicitly implement an interface. However, for queued components it is recommended that they do. D. Correct: This is how to consume a service. 2. Correct Answers: A and B A. Correct: This will work. B. Correct: This is the preferred method. C. Incorrect: Visual Studio does not allow you to treat a managed assembly as a Component Object Model (COM) component; you need to reference the service as a managed assembly. 3. Correct Answers: B and D A. Incorrect: Although it is recommended practice to assign an application name, it is not a requirement. B. Correct: A serviced component needs to have a strong name to be regis tered in the COM+ catalogue. C. Incorrect: A serviced component can call any component, but because a serviced component is strong-named, it will only be able to call compo nents that are also strong-named. D. Correct: Any component with a strong name will only be able to call other components that also have a strong name.
682
Answers
Chapter 12: Case Scenario Answers Case Scenario 1: Reliability Through Transactions Interviews 1. If the data stores being used do not support transactions and cannot participate in a distributed transaction, then the first step would be to migrate the data stores to a database product that supports transaction, such as Microsoft SQL Server, or optionally implement custom resource managers for the said data store. 2. A Web application is typically deployed to what is commonly referred to as a perimeter network. This a zone in the network, protected from the Internet by a firewall and separated from your backoffice by another firewall (and by any other security measures your company sees fit to use). From a security perspec tive you don’t want the DTC to manage a transaction across network zones. Set up your online store to use .NET remoting or secured Web services from the perimeter network to an application server in your local area network (LAN). The DTC can coordinate transactions from your application server across the LAN. 3. Fix the application logic to use serviced components to enlist transactions in the DTThis way an order is either submitted to both the sales system and the ship ping system or it is not submitted at all, in which case the user will be informed of an error.
Case Scenario 2: Optimizing Performance 1. If object pooling is turned off, then creation and cleanup of resources can be greatly improved by turning it on. Perform some calculations on how many users, at any point in time, will be using a specific component, and determine the optimal size for the object pool. 2. JIT activation allows an application to use resources just as the resources are needed and release them as soon as it is done. This way the minimum amount of resources are claimed at any specific point in time. Because the state of the component is lost between service calls, you need to make sure that your com ponent is stateless by design.
Answers
683
Chapter 13: Lesson Review Answers Lesson 1 1. Correct Answers: C and D A. Incorrect: Only public queues are registered in Active Directory. B. Incorrect: Queues are by default public. A prefix of private$\ is needed to mark a queue as private. C. Correct: Private queues can operate in workgroup mode, whereas public queues cannot. D. Correct: This is the correct syntax for creating a public queue. 2. Correct Answers: C and D A. Incorrect: If there are messages in a queue when deleting a queue, the mes sages are lost. B. Incorrect: There is no method MessageQueue.Remove. The correct method is MessageQueue.Delete. C. Correct: This is the correct way of deleting a queue programmatically. D. Correct: The Computer Management console can be used to delete a queue. 3. Correct Answer: D A. Incorrect: When using queued components, the creation of a message is done in the background. The drawback is that the parameters on the ser vice need to implement IPersistStream, but if they do, they can be used as parameters. B. Incorrect: Any object can be sent using MessageQueue.Send(...). Wrapping your object in the Message.Body is recommended, however. C. Incorrect: The way the body of the message is transmitted is determined by the Formatter property of the message. D. Correct: Whether or not a message is sent as part of a transaction is defined on the queue, not on the message. 4. Correct Answers: A and D A. Correct: When the Journal option is turned on, all processed messages are copied to the Journal.
684
Answers
B. Incorrect: This depends on whether the message was marked as Recoverable. C. Incorrect: MessageQueue.Receive(...)removes the message from the queue, so no deletion is necessary or even possible. D. Correct: MessageQueue.Receive(...)removes a message from the queue when it receives a message, but MessageQueue.Peek(...)creates a clone of the mes sage, leaving the original message on the queue.
Lesson 2 1. Correct Answer: D A. Incorrect: This code will fail because in workgroup mode you need to spec ify a SenderCertificate and because the message must set UseAuthentication to true. B. Incorrect: Although in workgroup mode you need to specify a SenderCer tificate the code will also fail because the message must set UseAuthentica tion to true. C. Incorrect: Although the message must set UseAuthentication to true the code will also fail because in workgroup mode you need to specify a SenderCertificate. D. Correct: Both B and C need to be fixed before this code runs on a machine in workgroup mode. 2. Correct Answer: B A. Incorrect: GetAllMessages() reads all the messages from the queue, but cre ates clones and does not delete them. B. Correct: Peek() clones the first message on the queue and does not delete it. C. Incorrect: Receive() reads the first message on the queue and deletes it. D. Incorrect: Delete() does not exist.
Chapter 13: Case Scenario Answers Case Scenario 1: Online Shop 1. Right now we give instant feedback that the order has been processed when the customer clicks Purchase, but at a cost. All checks and updates are done in a sin gle transaction. Sometimes the user has to wait 20 seconds for the order to com
Answers
685
plete. By introducing message queuing we can do the bare essentials when the user clicks Purchase. The customer just sees that his or her order has been received. This means that our online store has registered the order and that MSMQ messages have been sent to the shipping and financial systems. These get processed, and once they do, those systems send messages back, updating the order status. The online store sends an e-mail informing the customer. Usually this occurs within a couple of seconds, but if the shipping system or the financial system are down, it might take longer. The overall customer experience will be better for it, and more important, we’ll still be making sales. 2. The current solution is Web services using WSE 3.0 security. Because the online store is in the perimeter network we want to be as secure as possible when accessing servers in our internal network. We’ll replace a number of the Web ser vice calls with MSMQ messages. To maintain our high level of security in the perimeter network we set up the queues to accept only encrypted and signed messages.
Case Scenario 2: Batches 1. The invoicing batch currently executes an SQL statement to join the customers with their orders, selecting only those that actually had an order within the bill ing period. This produces a dataset and for each customer in the dataset the orders are retrieved, an order total is calculated per order, and with these totals an invoice is created. 2. The smallest chunk of work is determined by looking at the deliverables. We could identify the calculation of order totals as the smallest chunk of work, but the deliverable is unclear and the order in which the orders get processed is quite relevant because an invoice is not complete until all the orders on the invoice have been calculated, so a completed invoice is the smallest deliverable. We now want to redesign the batch into two separate batches. The first batch will select the customers that need to be invoiced. For each customer that needs to be invoiced, we put a message on a message queue. Next we create a console application that will act as a batch agent. It will look at the queue and when it receives a message from the queue it will create an invoice for the customer iden tified in the message. Once created it will see if there are any more messages to be processed. The great part about this solution is that we can start as many batch agents as we want, on as many machines as we want.
686
Answers
3. The job currently runs on one server, but there are at least three or four other servers that could be assigned to help if needed. Determining at design time how many processes can run on one machine is nearly impossible. Too many factors come into play. With the solution we came up with here, we can start with run ning one batch agent. By looking at how many messages per minute get pro cessed, we can see what happens when we add another batch agent, another, and so on. After a couple of agents, the performance bottleneck on the machine will most likely become disk access or network I/O. At that point, stop adding. You can start batch agents on another machine. Keep doing so until your data base server can take no more clients. At that point you’ll have reached the max imum you can do with your current configuration.
Glossary
Used to explicitly grant or deny access to a file or folder to individuals or groups of individuals.
access control list (ACL)
Used by the CLR to represent a boundary between objects that are part of the same application.
application domain
application URL An application Uniform Resource Locator (URL) is used to identify a
unique location for the application. Represents a condition that you expect to be true at some point. If the con dition is not true, then the assertion fails.
assertion
Also known as public key encryption, this method involves a key pair. Messages that are signed with the public key (which can be distributed to multiple parties) can only be decrypted with the private key.
asymmetric algorithm
An invocation that does not block processing from occurring (an asyn chronous call does not block execution of the program while processing occurs).
asynchronous
Specific class type in the .NET Framework that allows for declarative bind ing of code.
attribute
authentication Process of verifying the identity of both the sender and receiver.
Method of specifying that an XML Web method conforms to a certain specification.
binding
blocking The interruption of a thread until a value is returned.
An object that is sent to a method that will notify the caller when processing has completed.
callback
certificate Digital document that uses public keys to verify that the person sending
the certificate is who he or she says he or she is. channel A communication channel serves as a conduit for communication between a
client application and a server that hosts remote objects. The .NET Framework provides an HTTP channel, a TCP channel, and an IPC channel. Common Language Runtime (CLR)
The core engine that manages code for the .NET
Framework. The tool found on the Administrative Tools menu that can be used to monitor and configure your serviced components.
Component Services management console
687
688
Glossary
Computer Management console The tool found on the Administrative Tools menu
that can be used to monitor and configure various parts of your computer, including Message Queuing. This tool can also be started by clicking Start, Run, and then typing compmgmt.msc. consumer The client that will access Web methods exposed through a Web service. cookies Small text files that are stored on a client machine and are exchanged with a
Web server during Web page requests. deserialization
Process of converting a stream into a specified object.
digital signature A digital signature takes the concept of traditional paper-based sign
ing and turns it into an electronic fingerprint. This fingerprint, or coded mes sage, is unique to both the message or document and the signer. A digital signature ensures that the signatory is indeed the originator of the message. Any changes made to the document after it was signed invalidate the signature, thereby protecting against forgery. Digital signatures help organizations sustain signer authenticity, accountability, data integrity, and nonrepudiation of docu ments and transactions. A lightweight, binary message format that can be used to encapsulate one or more application-defined payloads of arbitrary type and size into a single message construct. In WSE 3.0, MTOM replaces DIME.
Direct Internet Message Encapsulation (DIME)
Involves the ability to hide the internal members of an object and expose only what is needed by the client.
encapsulation
Process of attaching certain attributes to an XML element to identify it in a certain context.
encoding
The process of obscuring information to make it unreadable to those who not have the key to decipher or decrypt the information.
encryption
enumeration (also known as enum) A list of named constants that are grouped
together. Initiating a call to a method and not retrieving any results back from it, even if the method throws an exception.
fire and forget
Process of verifying that a message has not been tampered with during transmission.
integrity
Kerberos
Proprietary Microsoft standard that provides authentication functionality.
lease A lease is used to maintain a reference to a remote object on a server for a client
application. A lease is used to prevent the Common Language Runtime (CLR)
Glossary
689
garbage collector (GC) from collecting a remote object due to the absence of any local references to the remote object. Implemented as part of System.Transactions, this fea ture promotes a (lightweight) transaction to a fully distributed transaction on an as-needed basis.
Lightweight Transaction Manager
A marshal-by-reference object is a remote object that is referenced by a proxy object residing on the client machine. Marshal-by-refer ence objects reside on the server.
marshal-by-reference (MBR)
A marshal-by-value object is a remote object that is copied to the client machine; no proxy object is necessary.
marshal-by-value (MBV)
The public key, which is used to authenticate the client, is included with the message.
message layer security
message queue A component used for interprocess communication. It utilizes a
queue for messaging, or the passing of control, content, or objects. Message Transmission Optimization Mechanism (MTOM) MTOM has effectively replaced
DIME in WSE 3.0. messaging protocols The method for communication between two parties. This
method can involve specific rules about what types of objects are created and what they can contain. metadata
Data that describes other data.
A distributed transaction facility for Microsoft Windows platforms that uses proven transaction processing technol ogy. It is robust despite system failures, process failures, and communication fail ures; it exploits loosely coupled systems to provide scalable performance; and it is easy to install, configure, and manage.
Microsoft Distributed Transaction Coordinator
A Microsoft Installer (.msi) file is a deployment package supported by Microsoft Windows. Microsoft Installer is an application used to install appli cations. Due to the bulk of the installation logic already residing on the destina tion system, a Microsoft Installer deployment package is typically much smaller than standard setup programs.
Microsoft Installer
MSMQ technology enables applications run ning at different times to communicate across heterogeneous networks and systems that might be temporarily offline. MSMQ provides guaranteed mes sage delivery, efficient routing, security, and priority-based messaging. It can
Microsoft Message Queuing (MSMQ)
690
Glossary
be used to implement solutions for both asynchronous and synchronous mes saging scenarios. Mechanism that allows client-side processing to continue irrespective of anything that happens on the server.
one-way
A performance counter is used by the Windows Performance Monitor to track the performance of an aspect of an application. Performance counters can be included with an application when it is installed or can be pro grammatically created using the .NET Framework.
performance counter
policy assertion policy expression
A specific requirement or setting.
Grouping of one or more policy assertions.
A set of requirements or settings associated with a given Web ser
vice or services. The two target areas that policy frameworks are generally con cerned with are cryptography and digital signatures.
policy framework
An XML Web service proxy represents a class that is generated and used to communicate with a Web service.
proxy
A proxy object is used to represent another object. In terms of .NET remoting, a proxy object is created for marshal-by-reference server-activated remote objects.
proxy object
remote method
A method that processes on a machine different from the one that
called it. remote object activation Before a client can create an instance of a remote object,
the object must be activated. The .NET Framework provides two modes of activation: server activation and client activation. Server-activated objects can be SingleCall or Singleton. serialization Process of converting an object into a stream of bytes so that it can be
written to another source. setup project Created with Visual Studio, setup projects are used to generate installer
(.msi) files that can be used to distribute an application. Simple Object Access Protocol (SOAP) The communication protocol used for XML
Web services. SoapSuds The SoapSuds utility ships with the .NET Framework 2.0 and is used to
extract metadata from a remote object and use the metadata to re-create a remote object.
Glossary
691
A sponsor is generally a client application that registers to be able to extend the lease duration, or lifetime, of a remote object.
sponsor state
Represents the ability to maintain data values between method calls and thus avoid the necessity of passing all variables in as parameter values.
stress testing Process of simulating an actual workload against a server for the pur
pose of determining threshold levels for specific applications. Computer that leads the world in processing capabilities and is able to handle an abundance of tasks at very fast speeds.
supercomputer
Also known as private key encryption. This method necessitates that the same key that is used to sign a message must be used to decrypt it as well. Generally considered to be less secure than public key methods because the private key has to be distributed.
symmetric algorithm
synchronous A way to call a method that happens sequentially, in the order in which
the method was called. If your program calls method A and then calls method B, method B is not called until method A returns. Used to represent the default settings and formats used when building a new project with Visual Studio. The template can be used to load a structure for your new project and can even include certain files to get you started.
template
A digital imprint corresponding to a specific time at which a given action occurred. In general, these values should be set automatically by the system without user interaction.
timestamp
COM+ gives developers more control over their applica tions by allowing configurable transaction isolation levels.
transaction isolation levels
Using a transport such as Secure Sockets Layer (SSL), a cli ent’s certificate is obtained at run time.
transport layer security
Shortened version of the identifier that represents a resource available on the intranet or Internet. For remoting, this URI is used on the server side to uniquely identify a remote object. The URL, which is more commonly recognized, is used by the client.
Uniform Resource Identifier (URI)
Web method
A method of a Web service.
An application that allows you to transfer data over Hypertext Transfer Protocol (HTTP) and Simple Object Access Protocol (SOAP).
Web service
A specialized XML grammar used to define exactly what goes into a Web service method.
Web Services Description Language (WSDL)
692
Glossary
Web setup project A Web setup project is used to easily deploy and configure an
ASP.NET Web application. WS-*
Commonly used acronym that references all of the evolving Web Services Stan dards, which encompass Security, Reliable Messaging, and Transactions in loosely coupled systems. The markup language used to represent messages sent and received by Web services.
Extensible Markup Language (XML) XML Infoset
A data model for an XML document.
Index A access control lists (ACLs), 132, 600
AcknowledgementQueue property, 606
AcknowledgeType property, 579
Acknowledgment property, 606
ACLs (access control lists), 132, 600
ACT (Application Center Test), 99
element, 425
Action property
SoapDocumentMethodAttribute class, 17
SoapRpcMethodAttribute class, 19
element
client-activated objects, 203, 208
description, 155, 157, 196
ActivatedClientTypeEntry class, 134
ActivatedServiceTypeEntry class, 134
activation mode (remote objects), 178, 201
Activator object, 209–210, 212
Active Directory directory service
authenticating messages, 621, 625
custom policy assertions, 422
hosting environment, 222
message queues, 571
MSMQ support, 567
UsernameToken, 498
Actor property
SoapReceiver class, 461
SoapService class, 465
actor/role attribute (Header element), 56, 496
Add Counters dialog box, 244
add element
configuring WSE router applications, 484–485, 492
enabling dynamic discovery, 114
registering SOAP receivers, 458
soapExtensionTypes element, 369
Add New Project dialog box, 116–117, 228
Add or Modify Policy Friendly Name dialog box, 403
Add Reference dialog box, 74, 177
Add Web Reference dialog box, 28–29, 270, 281–282
ADO.NET, 513
AfterDeserialize stage (SOAP), 73, 85
AfterSerialize stage (SOAP), 73, 85
aliases for namespaces, 356
AllowAutoRedirect property (HttpWebClientProtocol),
96
allowCustomSqlDatabase element (sessionState), 108
allowTestRoot attribute ( element), 499
anonymous authentication, 404, 408, 451
AnonymousForCertificate security token, 499
AnonymousOverX509 security token, 499
API (application programming interface), 355
App_code directory, 5
App.config file, 366, 406
App_data directory, 5
element
child elements, 156–158, 162
description, 153, 156, 194
ApplicationAccessControl attribute, 538
ApplicationActivation attribute, 512, 520, 595
Application Center Test (ACT), 99
application domains
defined, 127
.NET remoting support, 171
passing by reference, 132
registering channels, 131, 145
remoting support, 139
Application Event Log, 488
ApplicationID property (RemotingConfiguration), 141
ApplicationName attribute, 521, 525
ApplicationName property (RemotingConfiguration),
141–142
Application object, 93–94, 99, 101
application programming interface (API), 355
Application property (WebService), 8
ApplicationQueuing attribute, 536
applications
ASP.NET. See ASP.NET applications
console. See console applications
library, 519
object construction, 515
remote server. See remote server applications
remoting. See remoting applications
remoting client. See remoting client applications
remoting events, 336
server, 519
serviced components, 558–559
Web service. See Web service applications
application URLs, 170–171
ArgumentException, 307
.ashx file extension, 458
.asmx file extension
copying projects, 115
Service help page and, 106
storing public methods, 15
WebService processing directive, 7
Web services and, 5, 31, 33
693
694
ASP.NET applications
WSE routers, 484
ASP.NET applications
.ashx file extension, 458
configuration file support, 152
creating Web setup projects, 228–235, 263
hosting remote objects, 130, 139, 164, 224, 237, 263
specifying names, 142, 156
assemblies
adding references, 356–358
assigning strong names, 520
deploying remote objects, 225–226, 237
for serviced components, 511, 555–556
Web setup projects, 229
assembly attribute ( element), 158
assembly manifest, 520
assembly names, 8, 144, 511
assertions. See policy assertions; turnkey security
assertions
asymmetric algorithm, 412, 439, 450
AsyncCallback object, 325, 334, 347
AsyncDispatchMessage method, 146
asynchronous communications
ChannelServices class, 146
delegates and, 311, 347
determining if call has finished, 320–322
message queues, 569
polling, 319
queued components, 516
remote objects, 128, 209
remoting methods, 309–311, 327–334
sending/receiving messages, 567, 588
Web methods, 272–279, 289–292
ATM (automated teller machine) cards, 380
attachments, sending, 466–468, 479
Attach To Process dialog box, 240–241
attributes. See also specific attributes
adding to serviced components, 525
implementing security on serviced components, 537–
541
JIT activation, 533
object construction, 534–535
object pooling, 533
private components, 535
queued components, 536–537
services without components, 542–544
System.Transactions namespace, 544–545
transactions, 526–532
WebService processing directive, 7–8
Authenticated property, 622, 627
AuthenticateToken method, 423–424
authentication
anonymous, 404, 408, 451
AnonymousOverX509 security token, 499
certificate, 405, 408, 451
custom policy modes, 408, 451
defined, 621
message queues, 621
for messages, 620, 622, 624–625, 634–637
SOAP messages, 56, 381
username, 404, 408, 451
UsernameOverTransport security token, 498
Windows, 405, 408, 451
WS-Security specification, 379, 388
AutoComplete attribute, 514, 553
automatic transaction processing, 514
B bandwidth for .NET remoting, 303
Bare value (SoapParameterStyle), 46, 54
BeforeDeserialize stage (SOAP), 73, 77, 85
BeforeSerialize stage (SOAP), 73, 77, 85
Begin method, 285–290, 293
BeginInvoke method
delegates, 317
IAsyncResult interface, 311, 320
parameters, 334
polling for completion, 322
polling using callback methods, 325
BeginPeek method, 589
BeginReceive method, 589
Berners-Lee, Timothy, 171
bidirectional messaging, 463–466, 479
binary formatter
channel support, 158, 172
HTTP channel support, 132, 145, 159
HttpClientChannel class, 173
IPC channel, 175
marshal-by-value object, 158
message queue transactions, 583, 585
TCP channel support, 131, 139, 158, 174
WSE Messaging, 457
BinarySecurityToken class, 421
Binding property
SoapDocumentMethodAttribute class, 17
SoapRpcMethodAttribute class, 19
bindings, 39, 46–48, 54
blocking, 286
Body element (SOAP), 43, 56
bring your own transaction (BYOT), 514
browsers, 27, 33, 486
BufferResponse property (WebMethod), 16
BYOT (bring your own transaction), 514
communication channels
C CA (certificate authority), 620, 627
.cab file extension, 525
CacheDuration property (WebMethod), 16
callback methods
defined, 286
delegates and, 289
polling and, 293, 324–327, 334, 347
CancelAsync method, 279, 293
Cancel method, 278
CanDeserialize method (XmlSerializer), 49
catch statement, 242
certificate authentication, 405, 408, 451
certificate authority (CA), 620, 627
certificates
defined, 495
external, 620
internal, 620
X.509. See X.509 certificates
ChainStream method (SoapExtension), 74, 76
ChangeQueuePermissions right, 600
element
description, 154, 156, 196
registering channels, 162
ChannelName property, 145
Channel property
SoapClient class, 463
SoapSender class, 459
channels. See communication channels
element, 153, 156, 196
Channels counter, 245
ChannelServices class, 145–146, 173
element, 154
Chaos transaction isolation level, 529
child elements, 156–158, 162, 369
Choose Client Authentication Method group, 404
Class attribute (WebService), 7–8
classes. See also specific classes
deploying remote objects, 225–226
object-oriented design adage, 276
proxy. See proxy classes
clear element, 369
element, 195
client-activated objects
activating remote objects, 131
class support, 134
configuring, 160, 203–205, 208
creating, 164
defined, 129, 139
overview, 182–183, 191
proxy support, 139
registering, 150
695
clientActor attribute, 502
client applications. See remoting client applications
ClientCertificates property (HttpWebClientProtocol), 96
element, 154, 158
client-side processing
activating remote objects, 131
adding references to assemblies, 356–358
debugging remoting applications, 239–241, 253
deploying remote objects to, 225–228
handling session state, 96–97
proxy classes, 282
remote object lifetimes, 255–256
remoting events, 336
SOAP headers, 60–61, 70
CLR (Common Language Runtime)
catch statement, 242
COM+ catalog and, 524
as COM replacement, 511
memory management, 255
RealProxy class, 170
reference support, 255
reference types, 255
remoting, 127
ServiceConfig class, 542
value types, 255
clr attribute ( element), 157
Code Access Security, 337
CodeBehind attribute (WebService), 7
COM+
adding ComVisible attribute to class, 519
adding default constructors, 517
attributes for serviced components, 525
defined, 511
JIT activation, 533
registering serviced components, 521–525
serviced components, 513–516, 552
Services Installation Tool, 90, 523
SOAP service, 512
transaction isolation levels, 512
COM (Component Object Model), 8, 511, 610
Common Language Runtime. See CLR (Common
Language Runtime)
communication channels
asynchronous. See asynchronous communications
configuring, 171–172, 197–201
configuring formatting, 158–159
HTTP channel. See HTTP channel
IPC channel. See IPC channel
overview, 191
registering, 129, 131, 139, 145–146, 150, 162
selecting, 131–132
selecting protocols, 458
696
compensating resource manager (CRM)
synchronous. See synchronous communication
TCP channel. See TCP channel
compensating resource manager (CRM), 512, 514
compilation errors, 239
Completed event, 277
CompletedEventHandler, 293
ComponentAccessControl attribute, 538
Component Object Model (COM), 8, 511, 610
Component Services management console
adding project references, 530
attributed configuration settings, 525
overview, 521–522, 553
security via, 561
Computer Management console
deleting message queues, 576
inspecting messages, 623
message properties, 633
message queue transactions, 582, 618
setting permissions on message queues, 598, 602
setting up message queues, 572, 574, 576
setting up rules, 610
ComVisible attribute, 519, 595
confidentiality, 379, 388
.config extension, 400–401, 486
element, 367
element, 153, 193, 367
configuration files
configuring activation mode, 201–205
configuring client applications, 193–197
configuring communication channels, 197–201
configuring versioning, 158
copying projects, 115
creating, 152–155
editing, 365
editing proxy classes, 361
initializing leases, 259–260
overview, 366–369
remote server applications, 161, 164
remoting section, 162, 200, 437
sessionState element, 108
soapExtensionTypes element, 377
Web service access, 104
Configure method (RemotingConfiguration)
description, 143
loading configuration files, 152, 162, 197, 208
parameters, 152
configuring
client-activated objects, 160, 203–205, 208
communication channels, 171–176, 197–201
formatting, 158–159
IPC channel, 160
policy files, 401–402
referral cache, 486–488
remote server applications, 147–150, 161, 164
remoting systems, 128, 153–155
security, 406–408
server-activated objects, 159, 201–203, 208
session state mode, 108–109
singleton objects, 160
SOAP extensions, 78–79, 85
soapExtensionTypes element, 377
SOAP messages, 39–53
versioning, 144, 150, 158
Web service applications, 109–110
Web service method, 16
Web services, 110
WSE router applications, 484–485
ConformsTo property (WebServiceBindingAttribute), 47
ConnectionGroupName property
(HttpWebClientProtocol), 96
console applications
hosting remote objects, 130, 139, 164, 237, 263
overview, 223
ConstructionEnabled attribute, 515, 534–535
Construct method, 515, 534
constructors, default, 517
content-based routing, 483
Context-Bound Classes Loaded counter, 245
Context-Bound Objects Alloc/sec counter, 245
Context property (WebService), 8
Context Proxies counter, 245
Contexts counter, 245
ContextUtil class, 514, 539, 552
contractRef element, 113
CookieContainer property (HttpWebClientProtocol),
96–97
cookieName element (sessionState), 108
cookies, session state, 96
Copy Files dialog box, 116
correlating messages, 606–610
CreateClientInputFilter method
(SecurityPolicyAssertion), 416
CreateClientOutputFilter method
(SecurityPolicyAssertion), 416
CreateObjectRef property (MarshallByRefObject), 133
CreateServerChannelSinkChain method
(ChannelServices), 146
CreateServiceInputFilter method
(SecurityPolicyAssertion), 415
CreateServiceOutputFilter method
(SecurityPolicyAssertion), 415
CreationTimeout value (ObjectPoolAttribute), 533
credentials. See security credentials
Credentials property (HttpWebClientProtocol), 97
CRM (compensating resource manager), 512, 514
CryptoAPI (Microsoft), 631
DLLs (dynamic link libraries)
cryptographic service provider (CSP), 631
cryptography, 412
.cs file extension, 115
CSP (cryptographic service provider), 631
CurrentLeaseTime property (lease object), 256
Custom Actions editor, 232
CustomErrorsEnabled method
(RemotingConfiguration), 143
CustomErrorsMode property (RemotingConfiguration),
141
customFormatterProperty attribute (
element), 159
custom policies
authentication for, 408, 451
basic encryption, 410–413
creating assertions. See policy assertions
decryption, 424
encryption with security tokens, 421–424
security token issuing service, 424–427
signing and encrypting message exchange, 427–438
UsernameToken class, 410
customProvider element (sessionState), 108
Custom value (mode element), 108
D Data Access Layer pattern, 526
element, 155
debugging
Debugging Not Enabled dialog box, 25
.NET remoting tracking services, 246–249
performance counters and, 243–245
remoting applications, 239, 249–253, 263
with RemotingException class, 242–243, 253
Service help page, 28
testing Web services, 25, 31
Toggle Breakpoint function, 26
Visual Studio 2005 Debugger, 239–241, 253, 263
Debugging Not Enabled dialog box, 25
decryption, 410, 424, 439
default constructors, 517
DefaultTimeout property (SoapClient), 463
Default value (SoapParameterStyle), 46, 54
delegates
asynchronously calling remoting methods, 311, 347
BeginInvoke method, 317
invoking Web methods, 289
null parameters, 286, 322
Web method signatures, 273
DeleteJournalMessage right, 600
DeleteMessage right, 600
DeleteQueue right, 600
deployment
697
.NET remoting, 222, 237
remote objects, 225–228, 237
Web service applications, 115–117
Web services, 117–119
DerivedKeyToken class, 421
Description property
WebMethod attribute, 16
WebServiceAttribute class, 9–10
deserialization, 49, 54, 73, 172
Deserialize method (XmlSerializer), 49
DesignMode property (WebService), 8
Destination property
SoapClient class, 463
SoapSender class, 459
element, 367
DidUnderstand property (SoapHeader), 62–63, 70
digital signature
attachments and, 466
creating policies, 383–388
defined, 620
encryption and, 439
message queuing, 622
MSMQ support, 621
nonrepudiation, 411
WSE support, 379–382
DIME (Direct Internet Message Encapsulation), 362, 466
Direction property (SoapHeader), 58–59, 70
Disabled transaction isolation level, 529
.disco file extension, 114
DisconnectedObject method (ITrackingHandler), 247
discovery files
copying projects, 115
defined, 112, 119
dynamic, 114, 119
static, 113, 119
Web references, 113
Web service support, 4, 112
discovery process, 170
discoveryRef element, 113
DiscoveryRequestHandler class, 114
DispatchMessage method (ChannelServices), 146
DispatchModel property
SoapReceiver class, 461
SoapService class, 465
displayName attribute
element, 196
element, 156
element, 195
element, 157
element, 195
Distributed Transaction Coordinator. See DTC
(Distributed Transaction Coordinator)
DLLs (dynamic link libraries)
698
docRef attribute
compiling projects, 225
copying projects, 115
service components, 511
setting references to, 495
Web references, 269
docRef attribute, 113
documentation, 107
Documentation value (protocols element), 105
Document value (Style attribute), 43, 54
-d switch (SoapSuds utility), 227
DTC (Distributed Transaction Coordinator)
BYOT, 514
message queues, 572
serviced components and, 510, 512
utilizing transactions, 528, 530
dynamic discovery files, 114, 119
dynamic link libraries. See DLLs (dynamic link libraries)
dynamic registration, 524, 552
E EmitConformanceClaims property
(WebServiceBindingAttribute), 47
EnableDecompression property
(HttpWebClientProtocol), 97
EnableSession property, 16, 99
encapsulation, 45–46, 54
Encoded value (Use attribute), 45, 54
encoding, parameter, 44–45, 54
encodingStyle attribute (Header element), 57
EncryptedKeyToken class, 421
encryption
defined, 450
digital signatures and, 439
for messages, 427–438, 631–638
overview, 410–413
with security tokens, 421–424
SOAP extensions and, 72
EncryptionRequired property, 632
End method, 285, 287, 293
EndInvoke method, 347
EndPeek method, 589
EndReceive method, 589
Enterprise Services. See also COM+
creating serviced components, 509, 511, 552
defined, 511, 561
ServiceConfig class, 542–544
usage recommendations, 2
enumeration (enum)
for messages, 602–606, 618
parameter encoding, 45
SOAP extensions, 74
Envelope element (SOAP), 42, 54, 56
Equals method
ChannelServices class, 146
RemotingConfiguration class, 143
SoapExtension class, 74
X509SecurityToken class, 495
XmlSerializer class, 49
Equals property (MarshallByRefObject), 133
EventArgs object, 289, 345
event handlers, 287, 337–338
events
handling for remote objects, 339–345
loosely coupled, 515
.NET remoting, 336–338
serviced components, 557
exception handling, 242–243, 307–308 express messaging, 577–578 Extensible Markup Language. See XML (Extensible Markup Language)
element, 400–401
element, 400–401
ExtensionType property (SoapExtenstionAttribute), 78
external certificates, 620
F Fault value (Direction property), 59, 70
fileName attribute
Configure method, 152
element, 408, 451
File System editor, 228–229
file transfer protocol (FTP), 362
File Types editor, 230
filters, 418–419, 441–448
"fire and forget," 289, 293, 306–308, 317
firewalls, 173–174, 302
element, 154, 158
formatting. See also binary formatter; SOAP formatter
configuring, 158–159
defined, 172
element, 154
RegisterChannel method, 150
FromMappings method (XmlSerializer), 49
FromTypes method (XmlSerializer), 49
FTP (file transfer protocol), 362
FullControl right, 600
G GAC (global assembly cache), 223, 356, 524
GC (garbage collector), 255–256
GenerateSerializer method (XmlSerializer), 49
GenericRead right, 600
GenericWrite right, 600
IIS (Internet Information Services)
GetAllMessages method (MessageQueue), 602–603, 618
GetChannel method (ChannelServices), 146
GetChannelSinkProperties method (ChannelServices),
146
GetHashCode method
ChannelServices class, 146
RemotingConfiguration class, 143
SoapExtension class, 74
X509SecurityToken class, 495
XmlSerializer class, 49
GetHashCode property (MarshallByRefObject), 133
GetInitializer method (SoapExtension), 75–76
GetLifetimeService class, 134
GetLifetimeService property (MarshallByRefObject), 133
GetObject method (Activator), 209–210, 212
GET protocol (HTTP), 40, 105, 109
GetQueue method, 589
GetQueuePermissions right, 600
GetQueueProperties right, 600
GetRegisteredActivatedClientTypes method
(RemotingConfiguration), 143
GetRegisteredActivatedServiceTypes method
(RemotingConfiguration), 143
GetRegisteredWellKnownClientTypes method
(RemotingConfiguration), 143
GetRegisteredWellKnownServiceTypes method
(RemotingConfiguration), 143
GetRequestPolicy method, 497
GetSignedTokenXML (X509SecurityToken), 495
GetSTRTransformXML method (X509SecurityToken),
495
GetType class, 134
GetType method
ChannelServices class, 146
RemotingConfiguration class, 143
SoapExtension class, 75
XmlSerializer class, 49
GetType property (MarshallByRefObject), 133
GetUrlsForObject method (ChannelServices), 146
GetXML method (X509SecurityToken), 495
GetXmlSerializerAssemblyName method
(XmlSerializer), 49
global assembly cache (GAC), 223, 356, 524
group attribute (), 368–369, 377
GUID (globally unique identifier), 487
H hashing, 410
Header element (SOAP), 43, 56–57, 70
HelloWorld method (Service), 6, 15
hit counters, 93–94
Home attribute ( element), 485
699
hosting
remote objects, 222–224, 237, 263
remote server applications, 129–130, 139, 164
href element (wsdlHelpGenerator element), 107
HTML (Hypertext Markup Language), 107
HTTP (Hypertext Transfer Protocol)
.ashx file extension, 458
ASP.NET applications, 130, 224
default port, 171
HttpWebClientProtocol class, 96
SOAP messages, 40
SOAP service, 516
WSE Messaging, 458, 461–462, 479
WSE routers, 485
HTTP channel
binary formatters, 132, 145, 159
configuring, 160
description, 132, 139
.NET Framework support, 172, 191
overview, 173–174, 197–198
registering channels, 145
SOAP formatters, 132, 139, 158, 224
WellKnownClientTypeEntry class, 178
HttpClientChannel class, 173–174, 197–198
HttpGet value (protocols element), 105
element, 458, 484–485
httpHandlers section (Machine.config), 114
HttpPostLocalhost value (protocols element), 105
HTTP POST protocol, 105
HttpPost value (protocols element), 105
HttpSoapRouter class, 496
HttpSoap value (protocols element), 105
HttpWebClientProtocol class, 96–97
Hypertext Markup Language (HTML), 107
Hypertext Transfer Protocol. See HTTP (Hypertext
Transfer Protocol)
I
-ia switch (SoapSuds utility), 227
IAsyncResult object
asynchronously calling remoting methods, 311, 320,
334
IsCompleted property, 285, 293, 334
Web methods, 285–290
IChannel interface, 197
id attribute ( element), 196
IDictionary type, 145
-id switch (SoapSuds utility), 227
if statement, 239
IIS (Internet Information Services)
ASP.NET application support, 130, 156, 224
buffering support, 16
700
ILease interface
configuration file support, 152
hit counters and, 93
hosting remote objects, 222, 224
HTTP channels, 173
referral cache, 486
soapExtensionTypes element, 368
SOAP services, 516
Web application support, 228
Windows service applications, 224
ILease interface, 259, 261, 263
IMessageQueue interface, 589
Imports statement, 177, 483
includeVersions attribute ( element), 159
inheriting
from ServicedComponent class, 517, 552, 561
from WebServicesClientProtocol class, 358–360, 363,
370–373
InitializeLifeTimeService class, 134
InitializeLifeTimeService method, 257, 261, 263
InitializeLifeTimeService property
(MarshallByRefObject), 133
Initialize method (SoapExtension), 75–76
InitialLeaseTime property (lease object), 257
InOut value (Direction property), 59, 70
InProc value (mode element), 108
instantiating
HttpClientChannel class, 173–174, 197–198
IpcClientChannel class, 176, 200–201
remote objects, 183–185
serviced components, 556
TcpClientChannel class, 174–175, 199
integrity
MSMQ authentication, 621
symmetric algorithms, 412
WS-Security specification, 379, 388
InterfaceQueuing attribute, 536
interfaces, 225–226, 317. See also specific interfaces
internal certificates, 620
InternalRemotingServices class, 134
Internet, 128, 458
Internet Engineering Task Force, 171
Internet Information Services. See IIS (Internet
Information Services)
element, 155, 157
element, 155, 157
intranets, 224, 458
In value (Direction property), 58, 70
IPC channel
configuring, 160
description, 132, 139
.NET Framework support, 172, 191
overview, 175–176, 200–201
registering channels, 145
WellKnownClientTypeEntry class, 178
IpcClientChannel class, 176, 200–201
IpcServerChannel class, 175
IsActivationAllowed method (RemotingConfiguration),
143
IsCompleted method, 322–324, 334, 347
IsCompleted property (IAsyncResult), 285, 293, 334
IsRemotelyActivatedClientType method
(RemotingConfiguration), 143
IssuedToken class, 421
IssueSecurityContextTokenRequest method, 425–427,
439
IsWellKnownClientType method
(RemotingConfiguration), 143
ITrackingHandler interface, 246–249
J JIT (just-in-time) activation, 511, 514, 533
journal queues, 571–572, 600
JustInTimeActivation attribute, 533
K Keberos ticket, 405
KerberosToken class, 381
Kerberos tokens, 380–381
keyfile, 520
L Language attribute (WebService), 7
Launch Conditions editor, 233
lease manager, 256
leaseManagerPollTime attribute ( element),
156, 194
LeaseManagerPollTime property (lease object), 257
lease objects, 256–261, 263
leaseTime attribute ( element), 156, 194
element
description, 153, 156, 194
modifying lease objects, 259
lifetimes for remote objects, 182, 203, 255–261
Lightweight Transaction Manager (LTM), 532, 553
listeners, 336, 345, 589
Literal value (Use attribute), 44, 54
LoadXML method (X509SecurityToken), 495
localhost, 171
Location property (WebServiceBindingAttribute), 47
logic errors, 239
loops, 239
loosely coupled events, 515
LTM (Lightweight Transaction Manager), 532, 553
methods
M Machine.config file
enabling dynamic discovery, 114
file location, 107
overview, 107, 110
referral cache, 486
remoting section, 152, 162
sessionState element, 108
wsdlHelpGenerator element, 107
machine dead-letter queue, 572
machine journal queue, 572
machineName attribute ( element), 157
machine transactional dead-letter queue, 572
makecert utility, 625
marshal-by-reference process
defined, 191
deploying remote objects, 170, 214, 225–226
proxy objects, 169
remoting events, 338
server-activated objects, 178
MarshalByRefObject class, 127, 132–133, 139
marshal-by-value process
defined, 191
deploying remote objects, 169, 214, 225
overview, 132
proxy objects, 169
server-activated objects, 178
versioning, 158
Marshal class, 595
MarshaledObject method (ITrackingHandler), 247
MaxPoolSize value (ObjectPoolAttribute), 533
memory management, 255
Message class, 574, 577, 617
message layer security, 498
MessageName property (WebMethod), 16
MessageQueueAccessRights, 600
MessageQueue class
deleting message queues, 576
GetAllMessages method, 602–603
overview, 617
ResetPermissions method, 599
sending objects, 589
SetPermissions method, 599
setting up message queues, 574
Message Queue Information Service (MQIS), 620
message queues. See also MSMQ (Microsoft Message
Queuing)
asynchronous communications, 569
correlating messages, 606–610
creating, 610–612
deleting, 576–577
digital signatures, 622
701
listening asynchronously, 589
MSMQ support, 588
overview, 570–572 peeking/enumerating messages, 602–606 reading messages, 586–587 rules and triggers, 610
sending messages to, 577–578 setting permissions, 597–602, 618
setting up, 572–577
MessageQueueTransaction, 580, 617
MessageQueueTransactionType, 580, 582
messages/messaging. See also MSMQ (Microsoft Message
Queuing) aging, 578–579 asynchronous communications, 588
authenticating, 620, 622, 624–625, 634–637
bidirectional, 463–466, 479
channel support, 172
correlating, 606–610 deleting, 588
encrypting, 631–638 enumerating, 602–606, 618
express, 577
HTTP channel, 173
inspecting, 623
one-way, 459–462, 479
peeking, 602–606 reading from queues, 586–587 receiving, 570, 616–617 recoverable, 577–578 sending, 570, 577–578, 613–615 sending attachments, 466–468, 479
sending objects, 589–594 sending using queued components, 595–597 serviced components and, 512
signing, 620–623, 625–627 SOAP. See SOAP messages synchronous communication, 588
as transactions, 580–585 validating, 627–630, 638
webServices element, 104
WSE. See WSE Messaging Message Transmission Optimization Mechanism. See MTOM (Message Transmission Optimization Mechanism)
element, 467
metadata
defined, 56, 70
from remote objects, 226, 237
serviced components, 511, 561
methods
callback. See callback methods one-way, 17–20
702
Microsoft Base Cryptographic Provider
public. See public methods
remote. See remote methods
in remote objects, 183–185, 225
serviced components, 557, 559
Web. See Web methods
Microsoft Base Cryptographic Provider, 631
Microsoft CryptoAPI, 631
Microsoft Management Console. See MMC (Microsoft
Management Console)
Microsoft Message Queuing. See MSMQ (Microsoft
Message Queuing)
Microsoft Transaction Server (MTS), 511, 582
Microsoft Web Application Stress Tool, 484
Microsoft.Web.Services3 namespace, 483, 495
Microsoft.Web.Services3.Security.Tokens namespace,
421, 498
Microsoft Windows Installer (MSI) package, 524–525, 552
MinPoolSize value (ObjectPoolAttribute), 533
MMC (Microsoft Management Console)
Component Services, 521–522
registering serviced component, 552
setting up message queues, 572
SOAP services, 516
mode attribute ( element), 157, 195
mode element (sessionState), 108–110
MQIS (Message Queue Information Service), 620
.msi file extension
registering serviced components, 525
setup projects, 117, 228, 234–235
MSI (Microsoft Windows Installer) package, 524–525, 552
MSMQ (Microsoft Message Queuing)
authenticating messages, 620–622
encryption support, 631, 638
hosting environment, 222
message queuing support, 570
overview, 567, 617
queued components, 515
synchronous communications, 588
tracking properties, 606
MTOM (Message Transmission Optimization
Mechanism)
data transfer, 469, 471–479
sending attachments, 466–468, 479
WSE support, 362–363
element, 467
MTS (Microsoft Transaction Server), 511, 582
mustUnderstand attribute (Header element), 56, 62
N name attribute
element, 194
element, 196
element, 400
Name property (WebServiceAttribute), 9–10
Name property (WebServiceBindingAttribute), 47
Namespace property
WebServiceAttribute class, 9–10
WebServiceBindingAttribute class, 47
namespaces, 173, 177, 356
name spoofing, 520
.NET Framework
communication channels, 172, 191
COM+ Services support, 513
cryptographic support, 412
.NET remoting tracking services, 246–249, 253, 263
performance counters, 244, 253, 263
remote object lifetimes, 255
remoting support, 139
Services Installation Tool, 90, 523
SoapSuds utility, 225–228, 237
System.Configuration namespace, 365
transaction support, 513
WCF support, 354
new keyword, 131, 209, 212
New Web Site dialog box, 4, 11, 482
nonrepudiation, 411, 621
NotSupported transaction isolation level, 529
null parameters, 286, 322
O -oa switch (SoapSuds utility), 227
ObjectHandle class, 134
ObjectPool attribute, 533
object pooling, 511, 514, 533
objects
client-activated. See client-activated objects
lease, 256–261, 263
remote. See remote objects
sending via messages, 589–594
server-activated. See server-activated objects
serviced components, 515, 534–535
single call. See single call objects
singleton. See singleton objects
sink, 158. See singleton objects
sponsor, 256
objectUri attribute ( element), 157, 195
ObjRef class, 134
ODBC (Open Database Connectivity), 530
-od switch (SoapSuds utility), 227
Off value (mode element), 108
OneWay attribute
exception handling, 308
"fire and forget" functionality, 317
overview, 347
proxy classes
polling Web methods, 289–293
remoting events, 337
remoting methods, 303, 306–308
one-way messaging, 459–462, 479
one-way methods, 17–20
OneWay property
SoapDocumentMethodAttribute class, 17–18, 22
SoapRpcMethodAttribute class, 19, 22
Open Database Connectivity (ODBC), 530
Open Web Site dialog box, 110, 115
Out value (Direction property), 58, 70
P parameter encapsulation, 45–46, 54
parameter encoding, 44–45, 54
ParameterStyle property
(SoapDocumentMethodAttribute), 18
partitionResolverType element (sessionState), 109
passing by reference, 132
PasswordOption enumeration, 423–424
Path attribute ( element), 485
Patterns and Practices group (Microsoft), 412
PeekCompleted event, 589
peeking messages, 602–606
PeekMessage right, 600
Peek method, 589
performance considerations
for encryption, 631
express messaging, 578
recoverable messaging, 578
state management, 99
WSE routers, 482
performance counters, 243–245, 253, 263
Performance Monitor utility, 243–245
permissions, message queues, 597–602, 618
PINs (personal identification numbers), 380
Pipeline property
SoapClient class, 463
SoapReceiver class, 461
SoapSender class, 459
SoapService class, 465
PlatformNotSupportedException, 532
element, 400
element, 400–401, 408
PolicyAssertion class, 400, 413, 439, 496–497
policy assertions
adding, 400, 402, 404–406
creating custom, 413–421, 439
X.509 token and, 495–502
policy cache file, 400
policy expression, 408, 451
policy file. See also custom policies
703
adding policy assertions, 402, 404–406
configuring, 401–402
creating, 400–402, 497, 502
creating manually, 401
defined, 400
identifying policies, 400
structure of, 400
using, 406
policy framework, 399
polling
asynchronous calls, 319, 334
for completion, 322–324, 347
defined, 279
using callback method, 324–327, 347
Web methods, 284–285, 293
port attribute ( element), 157
portName attribute ( element), 157
port numbers
HTTP default, 171, 173
Visual Studio support, 27, 106
POST protocol (HTTP), 40, 105, 109
PreAuthenticate property (HttpWebClientProtocol), 97
element, 155, 158
priority attribute
element, 196
element, 368–369, 377
Priority property (SoapExtenstionAttribute), 78
privacy, 411–412
PrivateComponent attribute, 535
private components, 515, 535
private keys
MSMQ support, 631
symmetric algorithms, 412, 439, 450
X.509 certificates, 381
private queues, 571, 574
ProcessID property (RemotingConfiguration), 141
ProcessMessage method (SoapExtension), 74–77, 85,
443–444
ProcessRequestMessage method, 484, 492
projects
adding references, 177, 281
adding Web services, 281
setup. See setup projects
Web service, 4–6, 11–13
WSE support, 356, 362, 374, 376
Properties dialog box, 229, 515, 598
protocols element (webServices), 104–105, 109
element, 154
proxy classes
client-side processing, 282
delegates, 273
editing, 360–362
method call return types, 275–276
704
proxy objects
Web references, 270, 282, 358, 360
WSE support, 363
proxy objects
defined, 130, 139, 191
overview, 169–170
remote object lifetimes, 256
synchronization, 516
Proxy property (HttpWebClientProtocol), 97
-p switch (SoapSuds utility), 228
public keys
AnonymousForCertificate security token, 499
asymmetric algorithms, 412, 439, 450
MSMQ support, 631
X.509 certificates, 381
public methods
applying WebMethod attribute, 15, 22, 33
creating, 15, 20
testing Web services, 24
Web service support, 22
public queues, 571
publishing Web services, 112–113, 115
Q queued components
sending messages, 595–597
serviced components, 515–516, 536–537, 556
queues
accessing, 511
journal, 571–572, 600
machine dead-letter, 572
machine journal, 572
message. See message queues
private, 571, 574
public, 571
R RAM (random access memory), 578
ReadCommitted transaction isolation level, 529
ReadUncommitted transaction isolation level, 529
ReadXml method (SecurityPolicyAssertion), 417
RealProxy class, 170
ReceiveCompleted event, 589
ReceiveJournalMessage right, 600
ReceiveMessage right, 600
Receive method, 589
ReceiveSecurityFilter class, 418, 420, 443, 445, 448
recoverable messaging, 577–578
ref attribute
element, 156, 196
element, 159
ReferenceEquals class, 134
ReferenceEquals method
ChannelServices class, 146
RemotingConfiguration class, 143
SoapExtension class, 75
ReferenceEquals property (MarshallByRefObject), 133
references. See also Web references
adding, 356–358, 363, 374, 376
CLR support, 255
lease objects and, 261
to projects, 177
to remote objects, 177, 225
for serviced components, 517, 555–556, 559
element, 488, 499, 502
referral cache, configuring, 486–488
regenerateExpiredSessionID element (sessionState), 109
RegisterActivatedClientType method
(RemotingConfiguration), 144, 182–183
RegisterActivatedServiceType method
(RemotingConfiguration), 144, 150
RegisterChannel method (ChannelServices), 135, 145–
146, 150
RegisterTrackingHandler method (TrackingServices),
246
RegisterWellKnownClientType method
(RemotingConfiguration), 144, 178–181
RegisterWellKnownServiceType method
(RemotingConfiguration)
description, 144, 150
remoting support, 135, 142
registration
client-activated objects, 150
communication channels, 129, 131, 139, 145–146,
150, 162
dynamic, 524, 552
queues, 574
remote objects, 142
server-activated objects, 142, 150, 162
serviced components, 521–525, 552
single call objects, 142
singleton objects, 142
SOAP receivers, 458
Registry editor, 230
Regsvcs.exe (Service Installation Tool), 523, 552
Remote Calls/sec counter, 246
remote methods
accessing, 209–212
call asynchronously, 309–311
calling, 183–185
calling asynchronously, 309–311, 327–334
calling synchronously, 304–305
one-way calls, 306–308
remote objects
activating, 130–131, 176–178, 191, 201
RemotingException class
calling methods, 183–185, 317
classes and, 225, 240
client-activated objects, 182–183
communication channels, 131, 145
configuring client applications, 171–172
configuring versioning, 144, 150, 158, 162
creating, 132–135, 305
creating client instances, 169–171, 209
deploying, 225–228, 237
handling events, 339–345
hosting, 164, 222–224, 237, 263
instantiating, 183–185
lifetime management, 182, 203, 255–261
passing by reference, 132
references to, 177, 261
registering, 142–144
server-activated objects, 178–181
types, 129, 139
versioning, 144, 150, 158, 162
Remote Procedure Call (RPC), 43, 588
remote server applications
candidates for, 128
configuration examples, 159–160
configuring formatting, 158–159
configuring programmatically, 147–150, 164
configuring using configuration files, 161, 164
configuring versioning, 144, 150, 158
creating, 136–139
creating configuration files, 152–155
element, 156–158
hosting, 129–130, 139, 164
marshal-by-value process, 132
registering communication channels, 129, 131, 139,
145–146, 150
selecting communication channels, 131–132
specifying names, 142
remoting
ASP.NET applications, 224
bandwidth consumption, 303
calling methods asynchronously, 309–311, 327–334
calling methods synchronously, 304–305
channel support, 131, 171
configuring versioning, 144
connecting distributed components, 168
console applications, 223, 237
debugging applications, 239–241
defined, 139, 164
discovering application URLs, 170
events, 338
firewalls and, 302
HTTP channels, 173
implementing/responding to events, 336–338
Internet and, 128
705
invoking remoting methods, 311–316
loosely coupled events, 515
marshal-by-value support, 132
mechanics of calling, 303
overview, 127–129
performance counters, 245
remoting applications, 222, 237
setting elements, 153–155
soapsuds utility, 516
tracking services, 246–249, 253, 263
usage recommendations, 2
WCF support, 267
Windows service applications, 224
remoting applications
client. See remoting client applications
creating Web setup projects, 228–236
debugging, 239, 249–253, 263
deploying remote objects, 225–228
hosting remote objects, 222–224
.NET remoting deployment, 222, 237
.NET remoting tracking services, 246–249, 263
performance counters, 243–245, 253
remote object lifetimes, 255–261
RemotingException class, 242–243, 253, 263
server. See remote server applications
SIF and, 221
Visual Studio 2005 Debugger, 239–241, 253, 263
remoting client applications accessing remote methods, 209–212 activating remote objects, 176–177 adding references to assemblies, 356–358 application URLs, 170–171 calling remote object methods, 183–185 client-activated objects, 182–183 configuring activation mode, 201–205 configuring communication channels, 171–176, 197–201
configuring using configuration files, 193–197, 207
creating, 185–191, 205–207
creating client instances of remote objects, 169–171
server-activated objects, 178–181
RemotingConfiguration class
client-activated objects, 182–183
description, 150, 164
loading configuration files, 152
.NET remoting support, 197
public methods, 142–144
public properties, 141
server-activated objects, 178–181
System.Runtime.Remoting namespace, 133–134, 141
RemotingException class
debugging remoting applications, 242–243, 253, 263
System.Runtime.Remoting namespace, 134
706
RemotingServices class
RemotingServices class, 133–134
RemotingTimeoutException class, 135
remove element, 369
Renew method (ILease), 259, 261, 263
renewOnCallTime attribute ( element), 156, 194
RenewOnCallTime property (lease object), 257
RepeatableRead transaction isolation level, 530
RequestElementName property
SoapDocumentMethodAttribute class, 18
SoapRpcMethodAttribute class, 19
RequestEncoding property (HttpWebClientProtocol), 97
RequestNamespace property
SoapDocumentMethodAttribute class, 18
SoapRpcMethodAttribute class, 19
element, 425, 439
Request Security Token (RST) message, 424
element, 426, 439
Request Security Token Response (RSTR) message, 424
RequestSoapContext property
UserNameToken object, 382, 388
WebServicesClientProtocol class, 360, 363
Required transaction isolation level, 529
RequireMtom property
SoapClient class, 463
SoapSender class, 459
RequiresNew transaction isolation level, 529
ResetPermissions method (MessageQueue), 599
ResponseElementName property
SoapDocumentMethodAttribute class, 18
SoapRpcMethodAttribute class, 19
ResponseNamespace property
SoapDocumentMethodAttribute class, 18
SoapRpcMethodAttribute class, 19
ResponseSoapContext property (WebServicesClientProtocol), 360, 363
Result property (EventArgs), 289
revocationMode attribute ( element), 499
element, 487
element, 486
element, 487
element, 487
Rijndael class, 633
element, 487
role-based security, 511, 516, 537–541
RouterPolicy class, 497
routing, 483. See also WSE routers
RPC (Remote Procedure Call), 43, 588
RPC value (Style attribute), 43, 54
element, 487
element, 486
element, 486
element, 487
element, 487
RST (Request Security Token) message, 424
RSTR (Request Security Token Response) message, 424
runtime errors, 239
element, 487
S schemaRef element, 113
schemas, 193, 207
Schools Interoperability Framework (SIF), 220–221
Secure Sockets Layer (SSL), 130, 424, 498
security. See also encryption
access control lists, 132
Code Access Security, 337
configuring, 406–408
custom policies. See custom policies
digital signatures, 379
hashing, 410
message filters, 441
message layer, 498
.NET remoting deployment, 224
role-based, 511, 516, 537–541
serviced components, 537–541, 561
signing messages, 620–623, 625–627
transport layer, 498
turnkey assertions, 395, 400, 417
WSE Messaging, 458
WSE policies, 399–402, 404–406
WSE routers, 481, 494, 500–502
WSE support, 362, 395, 397–398
element, 499
SecurityCallContext class, 539, 552
SecurityContextTokenService class, 425–426, 439
security credentials
adding, 494–497
UsernameOverTransport, 498
UsernameToken, 498
verifying, 499–500
WSE routers and, 494, 502
X.509 certificates, 495–497
security identifier (SID), 620
SecurityPolicyAssertion class, 400, 413–417, 439
SecurityRole attribute, 538
SecurityToken class, 421–422
element, 423
security tokens, 421–427
SecurityTokenService class, 425
Select Item In Project dialog box, 232
SenderCertificate property, 625, 638
SenderId property, 622
SendHashed value (PasswordOption), 424
Send method, 577, 589
SendNone value (PasswordOption), 424
SID (security identifier)
SendPlainText value (PasswordOption), 424
SendRequestResponse method, 464
SendSecurityFilter class, 419–420, 443, 446, 448
Serializable attribute, 345
Serializable transaction isolation level, 529–530
serialization
message, 172
XML, 49–50, 54, 73
Serialize method (XmlSerializer), 49
server-activated objects
configuring, 159, 201–203, 208
creating, 164
overview, 178–181, 191
proxy support, 139
registering, 142, 150, 162
types, 129, 139
server applications, 519. See also remote server
applications
ServerException class, 135
Server property (WebService), 8
element
configuring formatting, 158
description, 154
server-side processing
activating remote objects, 131
debugging remoting applications, 239–241, 253
deploying remote objects to, 225
remote object lifetimes, 255–256
serviced components, 512
element, 155, 157, 195
serviceActor attribute, 502
Service.asmx file, 5, 7, 15
Service class, 6, 9
ServiceComponent class, 538
ServiceConfig class, 542–544
ServicedComponent class, 517, 552, 561
serviced components
accessing properties, methods, events, 557, 559
adding attributes, 525–545
adding instances, 556
adding references, 517, 555–556
assemblies, 511, 555–556
building, 546–552
compensating resource manager, 512
COM+ Services, 511–516
consuming, 555–557, 561
creating, 509, 511, 517–520
declaring and instantiating, 556
Distributed Transaction Coordinator, 510, 512
JIT activation, 511, 514, 533
messages and, 512
metadata, 511, 561
MSMQ support, 595
object construction, 515, 534–535
object pooling, 511, 514, 533
private components, 515, 535
queued components, 515–516, 536–537
referencing, 517, 555–556, 559
registering, 521–525, 552
security, 537–541, 561
server-side processing, 512
ServiceConfig class, 542–544
SOAP services, 512, 516
System.Transactions namespace, 532, 544–545
transactions, 511–512, 526–532
using in applications, 558–559
Web services, 512
serviceDescriptionFormatExtensionTypes element
(sessionState), 109
serviceDescriptionFormatExtensionTypes element
(webServices), 104
Service help page
debugging support, 28
defaults, 106
disabling, 107
protocols element, 105
SOAP messages, 39, 42
testing Web services, 24
webServices element, 104
wsdlHelpGenerator element, 107
Service Installation Tool (Regsvcs.exe), 523, 552
Service method help page
SOAP messages, 40, 54, 87
test Web service, 25–26
Service Oriented Architecture (SOA), 457
Session object, 93, 95, 99–102
Session property (WebService), 9
sessionState element, 108–110
session state mode, 108–109
SessionState property
SoapClient class, 463
SoapSender class, 459
SetAbort() method, 514
SetComplete() method, 514
SetPermissions method (MessageQueue), 599–600
SetQueueProperties right, 600
Setup.exe file, 117
setup projects
ASP.NET applications, 224
copying, 115
defined, 115
deploying Web services, 117–119
Web, 228–237, 263
Windows executable applications, 223
Windows service applications, 224
SID (security identifier), 620
707
708
SIF (Schools Interoperability Framework)
SIF (Schools Interoperability Framework), 220–221
Simple Object Access Protocol. See SOAP (Simple Object
Access Protocol)
single call objects
activating remote objects, 131
configuring, 159
creating, 164
defined, 129, 139, 178, 191, 201
registering, 142
singleton objects
activating remote objects, 131
configuring channels, 160
creating, 164
defined, 129, 139, 178, 191, 201
registering, 142
sink objects, 158
sinks, 172
Site property
HttpWebClientProtocol class, 97
WebService class, 9
skiMode attribute ( element), 499
Snapshot transaction isolation level, 530
Sn.exe utility, 520
SOA (Service Oriented Architecture), 457
SOAP (Simple Object Access Protocol)
ASP.NET applications, 130
channel support, 132, 139
configuring messages, 17, 22
serviced components, 512, 516
testing Web services, 25
versioning for marshal-by-value objects, 158
Web services, 3, 13
webServices element, 105
WSE support, 363, 483
soap12 element prefix, 42
SoapBindingUse enumeration, 45
SoapClient class, 463, 479
SoapDocumentMethod attribute
bindings for Web methods, 48
formatting SOAP messages, 43, 46
overview, 54
SoapDocumentMethodAttribute class
configuring SOAP messages, 43
formatting SOAP messages, 22, 87
public properties, 17–18
soap element prefix, 42
SoapEnvelope class, 460, 464
SoapException, 289
SoapExtensionAttribute class, 78–79, 85
SoapExtension class, 72, 74–75
soapExtensionImporterTypes element (webServices), 105
soapExtensionReflectorTypes element (webServices), 105
SOAP extensions
configuring, 78–79, 85
creating custom classes, 74–78
implementing, 80–84
overview, 72–74
soapExtensionTypes element
adding child elements, 369
attribute usage, 368
child elements, 369
configuring, 377
description, 105, 367
IIS support, 368
inheriting from WebServicesClientProtocol class,
370–373
overview, 365–369
specifying groups, 369, 377
specifying priority, 369, 377
SoapFilter class, 443–444, 448
SOAP formatter
ASP.NET application support, 130, 224
channel support, 158, 172
element, 157
HTTP channel support, 132, 139, 158
HttpClientChannel class, 173
IPC channel, 175
marshal-by-value object, 158
System.Runtime.Remoting namespace, 135
SoapHeader attribute
Direction property, 58–59, 70
Web methods, 70
SoapHeader class, 57–58
SoapHeaderException, 62
SOAP headers
adding custom classes, 57–59
client-side processing, 60–61, 70
encryption and, 413
handling unknown, 62–63, 70
implementing custom, 63–69
Kerberos tokens, 381
metadata, 70
overview, 56–57, 87
security tokens, 425
Web methods, 57, 61–63, 70
WSE support, 360, 363, 484
SoapHttpClientProtocol class, 360, 363
SoapHttpRouter class, 483
element, 155, 157
SOAP messages. See also WSE Messaging
authenticating, 388
bindings for Web methods, 48
configuring bindings, 46–47, 54
customizing, 39
System.Web.Services.Protocols namespace
digital signatures, 380–381
encryption support, 412, 421
filtering, 418–419, 441–446
formats, 42–44
headers in, 56–57
message layer security, 498
parameter encapsulation, 45–46
parameter encoding, 44–45
policy assertions, 413
security credentials, 494–500
security tokens, 424
Service help page, 39
Service method help page, 40
SOAP extensions and, 73
UsernameToken class, 498
WSE routers, 484, 488, 492
WSE security, 395
XML serialization, 49–50, 73
SoapMessageState enumeration, 74, 85
SoapParameterStyle enumeration, 45
SoapReceiver class, 458, 461–462, 479
SoapRpcMethod attribute, 43, 45, 54
SoapRpcMethodAttribute class
configuring SOAP messages, 43
formatting SOAP messages, 87
public properties, 17, 19, 22
SoapSender class, 459–460, 479
SoapService class, 465, 479
SoapServices class, 135
soapsuds utility, 516
SoapSuds utility (.NET Framework), 225–228, 237
SoapVersion property (SoapClient), 463
SoapVersion property (WebService), 9
SoapVRoot property (ApplicationActivation), 512
sponsor objects, 256
sponsorshipTimeout attribute ( element),
156, 194
SponsorshipTimeout property (lease object), 257
sqlCommandTimeout element (sessionState), 109
sqlConnectionString element (sessionState), 109
SQL Server
hosting environment, 222
performance counters, 244
Windows service applications, 224
SQLServer value (mode element), 108
SSL (Secure Sockets Layer), 130, 424, 498
standardization, importance of, 354
stateConnectionString element (sessionState), 109
state management
Application object, 93
client-side cookies, 96
configuring session state mode, 108–109
709
performance implications, 99
singleton objects, 201
in Web services, 97, 99–101
stateNetworkTimeout element (sessionState), 109
StateServer value (mode element), 108
static discovery files, 113, 119
storeLocation attribute ( element), 499
stress testing tools, 99
strictBinding attribute ( element), 159
strong names, 520
Style attribute (Body element), 43, 54
supercomputers, 128
Supported transaction isolation level, 529
symmetric algorithm, 412, 439, 450
SyncDispatchMessage method (ChannelServices), 146
synchronization, 511, 516
synchronous communication
calling Web methods, 269–272
listening for messages, 589
.NET remoting, 304–305
queued components, 516
sending messages, 567, 588
syntax errors, 239
System.Configuration namespace, 365
System.Diagnostics namespace, 244
System.EnterpriseServices namespace, 511, 517, 532
System.Messaging namespace, 574, 583, 588, 617
System namespace, 5
System.Runtime.InteropServices namespace, 519
element, 153, 194
System.Runtime.Remoting.Channels namespace, 173
System.Runtime.Remoting.Messaging namespace,
306–307
System.Runtime.Remoting namespace, 133–135,
141, 171
System.Runtime.Remoting.Services namespace, 246
System.Transactions namespace
attributes, 544–545
overview, 532, 552, 561
element, 367
System.Web namespace, 6, 367
System.Web.Services.Description namespace, 45
System.Web.Services namespace
attributes and members, 8
one-way messaging support, 461
overview, 6, 483
security credential support, 495
SOAP extensions, 74
Web service support, 101
System.Web.Services.Protocols namespace
classes supported, 17
overview, 6, 22
710
System.Web.Services.Protocols.SoapExtension namespace
parameter encapsulation, 45
SOAP messages, 39, 43, 46, 87
System.Web.Services.Protocols.SoapExtension
namespace, 72, 85, 87
System.Web.Services.Protocols.SoapHeader namespace,
56–57, 70
System.Xml.Serialization namespace
SOAP messages, 39
XmlSerializer class, 49, 54, 87
T TakeQueueOwnership right, 600
TCP (Transmission Control Protocol)
ASP.NET applications, 130
WSE Messaging, 457–458, 461, 479
TCP channel
binary formatters, 131, 139, 158
client-activated objects, 182
configuring, 160
description, 131, 139
.NET Framework support, 172, 191
overview, 174–175, 198–199
registering channels, 145
WellKnownClientTypeEntry class, 178
TcpClientChannel class, 174–175, 199
TcpServerChannel class, 174
templates, Web service projects, 4–5
testing
stress testing tools, 99
Web services, 24–31, 33
timeout element (sessionState), 109
Timeout property (HttpWebClientProtocol), 97
TimeToBeReceived property, 579
TimeToReachQueue property, 579
Toggle Breakpoint function, 26
element, 367
ToString class, 134
ToString method
ChannelServices class, 146
RemotingConfiguration class, 144
SoapExtension class, 75
XmlSerializer class, 49
ToString property (MarshallByRefObject), 133
Total Remote Calls counter, 246
TrackingServices class, 246–249
Transaction attribute, 529–530, 552
transaction isolation levels, 512, 529–530
TransactionOption property (WebMethod), 17
transactions
automatic processing, 514
BYOT, 514
compensating resource manager, 514
defined, 513
peeking messages, 602–603
sending messages, 580–586
serviced components, 511–512, 526–532
Transmission Control Protocol. See TCP (Transmission Control Protocol)
transparent proxies, 170, 191
transport layer security, 498
try/catch blocks, 305, 574
turnkey security assertions, 395, 400, 417
two-way messaging, 463–466, 479
type attribute
element, 196
element, 156
enabling dynamic discovery, 114
element, 159
, 423
element, 157
element, 368
element, 158
element, 195
TypeEntry class, 135
typeFilterLevel attribute ( element), 159
TypeId property
SoapDocumentMethodAttribute class, 18
SoapExtensionAttribute class, 78
SoapRpcMethodAttribute class, 19
WebServiceAttribute class, 10
WebServiceBinding Attribute class, 47
TypeName property, 144
-types switch (SoapSuds utility), 227
U Uniform Resource Identifier. See URI (Uniform Resource Identifier)
Uniform Resource Locators (URLs), 170–171, 191, 282
UnmarshaledObject method (ITrackingHandler), 247
UnregisterChannel method (ChannelServices), 146
UnregisterTrackingHandler method (TrackingServices),
246
UnsafeAuthenticatedConnectionSharing property
(HttpWebClientProtocol), 97
Unspecified transaction isolation level, 530
URI (Uniform Resource Identifier)
RegisterWellKnownServiceType method, 142
URLs and, 171
WSE Messaging, 458
WSE routing, 483, 492
Web references
url attribute
element, 195
element, 195
Url property (HttpWebClientProtocol), 97
URLs (Uniform Resource Locators), 170–171, 191, 282
Use attribute (SOAP), 43–45, 54
UseAuthentication property, 622
UseDeadLetterQueue property, 579
UseDefaultCredentials property
(HttpWebClientProtocol), 97
UseEncryption property, 632
useHostingIdentity element (sessionState), 109
useIPAddress attribute ( element), 157
Use property
SoapDocumentMethodAttribute class, 18
SoapRpcMethodAttribute class, 19
UserAgent property (HttpWebClientProtocol), 97
user IDs, 95
User Interface editor, 231
username attribute ( element), 486
username authentication, 404, 408, 451
UsernameOverTransport security token, 498
UsernameToken class
custom policy assertions, 410, 422–423
decryption and, 424
digital signatures, 380, 382
encryption with security tokens, 421
overview, 498
UsernameTokenManager class, 423–424
User property (WebService), 9
using statement, 177, 483
-u switch (SoapSuds utility), 228
V
validating messages, 627–630, 638
.vb file extension, 115
verifcationMode attribute ( element), 500
Verify method (X509SecurityToken), 495
VerifySignedTokenXML method (X509SecurityToken),
495
verifyTrust attribute ( element), 500
version attribute ( element),
194
versioning remote objects, 144, 150, 158, 162
Visual Studio
copying projects, 115
creating serviced components, 511
dynamic discovery files, 114
port numbers, 27, 106
Web service projects, 11–13
WseConfigEditor3 tool, 401
711
Visual Studio 2005 Debugger, 239–241, 253, 263
.vsdisco file extension, 114
W W3C (World Wide Web Consortium), 43, 171
WCF (Windows Communication Foundation), 267,
354
Web browsers, 27, 33, 486
Web.config file
App.config file and, 366
configuring WSE router applications, 484, 492
copying projects, 115
custom policy assertions, 423
disabling documentation, 107
loading configuration files, 152
overview, 366
policy files, 406
registering SOAP receivers, 458
sending attachments, 467
Web services accessing, 104
webServices element, 105, 107, 109–110
wsdlHelpGenerator element, 107
WSE routers, 488, 502
X.509 certificates, 500
WebMethod attribute
attaching to public methods, 15, 22, 33
default page display, 106
Description property, 39
testing Web services, 24, 28
WebMethodAttribute class, 6, 483
Web methods
Begin method, 285–290
calling, 280–281
calling asynchronously, 272–279, 290–292
calling synchronously, 269–272
IAsyncResult return type, 285–290
invoking, 269, 289
OneWay attribute, 306
polling, 284–285, 293
Service help page support, 39
Service method help page, 87
SoapBindingUse enumeration, 45
SOAP extensions, 78–79
SoapHeader attribute, 70
SOAP headers, 57, 61–63, 70
specifying bindings, 48
XML serialization, 54
WebMethods framework, 7–10, 33
Web references
adding to projects, 281
discovery files, 113
712
Web service applications
dissecting, 270 keeping current, 271 proxy classes, 270, 282, 358, 360 setting, 28–29 SOAP headers, 61 Web methods, 269 Web service support, 295 Web service applications configuring, 109–110 copying, 116 deploying, 115–117 distributed application methods, 3 handling session state, 99 WebService attribute, 9, 13, 33 WebServiceAttribute class, 9–10 WebServiceBinding attribute, 39, 47, 87 WebServiceBindingAttribute class, 47, 54 WebService class accessing objects, 93 overview, 8–9, 13, 33 System.Web.Services namespace, 6 WSE routers, 483 Web service methods, 15–19, 31 WebService processing directive, 7–8, 13 Web service projects, 4–6, 11–13 Web services accessing configuration files, 104 adding to projects, 281 .asmx page, 106 calling remoting methods, 317 calling unilaterally, 289–290 channel support, 132 configuring, 110 consumers of, 28–30, 98 creating, 3–10 creating public methods, 20, 22 defined, 13, 33 deploying, 117–119 discovery files, 112, 119 discovery process, 170 distributing client applications, 29 dynamic discovery files, 114, 119 handling session state, 96–97, 99–101 hosting remote objects, 130 Kerberos tokens, 381 message filters, 441 method signatures, 282 MTOM support, 466, 469, 471–479 overview, 3–4 publishing, 112–113, 115 removing documentation, 107 security policies, 399–402, 404–406
serialization/deserialization, 54 serviced components, 512 SOAP extensions, 72 SOAP headers, 60–61, 70 SSL connections, 498 static discovery files, 113, 119 testing, 24–31, 33 usage recommendations, 2 WCF support, 267 WebMethods framework, 7–10 Web references, 295 WSE Messaging, 455, 458, 462, 479 WSE routers, 455, 481–484, 492, 494 WSE support, 358, 363 WS-I Basic Profile support, 47, 87 XML support, 295 WebServicesClientProtocol class, 358–360, 363, 370–373 webServices configuration element descendants, 104–105, 109 overview, 104, 110, 367–368 Web.config file support, 105, 107 Web Services Description Language. See WSDL (Web Services Description Language) Web Services Enhancements. See WSE (Web Service Enhancements) WebServicesExtension class, 484 Web Services Interoperability Organization, 39, 46 Web setup projects, 228–237, 263 WelKnownClientTypeEntry class, 135 WelKnownServiceTypeEntry class, 135 element configuring, 208 configuring versioning, 158 description, 155, 157, 195 registering server-activated objects, 162 server-activated objects, 203 WellKnownClientTypeEntry class, 178 Windows authentication, 405, 408, 451 Windows Communication Foundation (WCF), 267, 354 Windows executable application, 130, 139, 164, 223, 237, 263 Windows service application hosting remote objects, 224, 237, 263 Visual Studio 2005 Debugger, 239 Windows services, 130, 139, 164 World Wide Web Consortium (W3C), 43, 171 Wrapped value (SoapParameterStyle), 46, 54 WriteMessage right, 600 WS-Addressing specification, 363 WSDL (Web Services Description Language) contractRef element, 113
ZIS (Zone Integration Server)
deploying remote objects, 226
disabling file generation, 107
SOAP messages, 40
WebServiceAttribute class, 10
webServices element, 104
WSE support, 363
wsdlHelpGenerator element (webServices), 105, 107
WSE (Web Service Enhancements)
adding references, 356–358, 363, 374, 376
adding to projects, 362, 374, 376
digital signatures, 379–388
editing proxy class, 360–362
encryption support, 412
inheriting from WebServicesClientProtocol class, 358–
360, 370–373
installing correct version, 356
messaging and routing, 455
overview, 363
setting up, 355
soapExtensionTypes element, 365–373
Web service policy, 399–402, 404–406
WseConfigEditor3 tool, 401–402, 406–408 WSE Messaging. See also WSE routers
one-way messaging, 459–462, 479
overview, 455, 479
security credentials, 494–500
selecting communication protocols, 458
sending attachments, 466–468, 479
SOA support, 457
two-way messaging, 463–466, 479
WSE routers
adding security, 500–502
configuring applications, 484–485
configuring referral cache, 486–488
creating, 489–492
creating applications, 482–484
overview, 455, 481–482, 492
security credentials, 494–497, 502
WSE Security Settings Wizard, 404, 406
WSE Settings 3.0 tool, 401–402, 406–408
WS-I Basic Profile, 39, 46, 54, 87
WS-Policy specification, 399
WS-SecureConversation specification, 363
WS-Security specification, 360, 363, 379, 405
WS-Trust specification, 363
X
element, 499–500 X.509 certificates
adding security credentials, 494–497, 502
digital signatures, 380–381
verifying security credentials, 499–500
X509SecurityToken class, 421, 495
xcopy command, 223
XML (Extensible Markup Language)
channel support, 132, 172
configuration file support, 152
File System editor, 229
message queue transactions, 582
MSMQ support, 515
policy files, 401
referral cache, 486
remoting recommendations, 128
sending attachments, 466
Web methods, 269
Web service support, 3–5, 295
WSE Messaging, 457
WSE support, 363
xml attribute ( element), 157
XmlAttributes class, 50
XmlAttributesOverrides class, 50
XmlElement attribute (XmlSerializer), 39, 49
XmlElementAttribute class, 50, 87
XML Infoset, 40
xmlns attribute
contractRef element, 113
element, 400
XML Schema Definition (XSD) schemas, 113
XML serialization, 49–50, 54, 73
XmlSerializer class, 49–50, 54, 87
XSD (XML Schema Definition) schemas, 113
Z ZIS (Zone Integration Server), 220
713