100% found this document useful (1 vote)
7 views

Visual Studio Extensibility Development: Extending Visual Studio IDE for Productivity, Quality, Tooling, Analysis, and Artificial Intelligence 2nd Edition Rishabh Verma pdf download

The document provides information on various ebooks related to Visual Studio and programming, including titles like 'Visual Studio Extensibility Development' and 'Getting Started with Visual Studio 2022.' It includes links to download these resources from ebookmass.com. The document also contains details about the authors, ISBN numbers, and copyright information.

Uploaded by

zeermeziou
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
7 views

Visual Studio Extensibility Development: Extending Visual Studio IDE for Productivity, Quality, Tooling, Analysis, and Artificial Intelligence 2nd Edition Rishabh Verma pdf download

The document provides information on various ebooks related to Visual Studio and programming, including titles like 'Visual Studio Extensibility Development' and 'Getting Started with Visual Studio 2022.' It includes links to download these resources from ebookmass.com. The document also contains details about the authors, ISBN numbers, and copyright information.

Uploaded by

zeermeziou
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 71

Visit https://ebookmass.

com to download the full version and


browse more ebooks or textbooks

Visual Studio Extensibility Development: Extending


Visual Studio IDE for Productivity, Quality,
Tooling, Analysis, and Artificial Intelligence 2nd
Edition Rishabh Verma

_____ Press the link below to begin your download _____

https://ebookmass.com/product/visual-studio-extensibility-
development-extending-visual-studio-ide-for-productivity-
quality-tooling-analysis-and-artificial-intelligence-2nd-
edition-rishabh-verma/

Access ebookmass.com now to download high-quality


ebooks or textbooks
We believe these products will be a great fit for you. Click
the link to download now, or visit ebookmass.com
to discover even more!

Getting Started with Visual Studio 2022: Learning and


Implementing New Features 2nd Edition Dirk Strauss

https://ebookmass.com/product/getting-started-with-visual-
studio-2022-learning-and-implementing-new-features-2nd-edition-dirk-
strauss/

Visual Studio Code Distilled: Evolved Code Editing for


Windows, macOS, and Linux - Third Edition Alessandro Del
Sole
https://ebookmass.com/product/visual-studio-code-distilled-evolved-
code-editing-for-windows-macos-and-linux-third-edition-alessandro-del-
sole/

Hands-On Visual Studio 2022: A developer's guide to new


features and best practices with .NET 8 and VS 2022 for
maximum productivity, 2nd Edition Hector Uriel Perez Rojas
https://ebookmass.com/product/hands-on-visual-
studio-2022-a-developers-guide-to-new-features-and-best-practices-
with-net-8-and-vs-2022-for-maximum-productivity-2nd-edition-hector-
uriel-perez-rojas/

Simple and Efficient Programming with C#: Skills to Build


Applications with Visual Studio and .NET 2nd Edition
Vaskaran Sarcar
https://ebookmass.com/product/simple-and-efficient-programming-with-c-
skills-to-build-applications-with-visual-studio-and-net-2nd-edition-
vaskaran-sarcar/
Simple and Efficient Programming with C# : Skills to Build
Applications with Visual Studio and .NET 2nd Edition
Vaskaran Sarcar
https://ebookmass.com/product/simple-and-efficient-programming-with-c-
skills-to-build-applications-with-visual-studio-and-net-2nd-edition-
vaskaran-sarcar-2/

Visual Studio Code Distilled: Evolved Code Editing for


Windows, macOS, and Linux 3 / converted Edition Alessandro
Del Sole
https://ebookmass.com/product/visual-studio-code-distilled-evolved-
code-editing-for-windows-macos-and-linux-3-converted-edition-
alessandro-del-sole/

Artificial Intelligence for Dummies 2nd Edition John Paul


Mueller & Luca Massaron

https://ebookmass.com/product/artificial-intelligence-for-dummies-2nd-
edition-john-paul-mueller-luca-massaron/

Engineering Intelligent Systems: Systems Engineering and


Design with Artificial Intelligence, Visual Modeling
Barclay R. Brown
https://ebookmass.com/product/engineering-intelligent-systems-systems-
engineering-and-design-with-artificial-intelligence-visual-modeling-
barclay-r-brown/

Visual Complex Analysis: 25th Anniversary Edition Tristan


Needham

https://ebookmass.com/product/visual-complex-analysis-25th-
anniversary-edition-tristan-needham-2/
Visual Studio
Extensibility
Development
Extending Visual Studio IDE for
Productivity, Quality, Tooling, Analysis,
and Artificial Intelligence

Second Edition

Rishabh Verma
Visual Studio Extensibility
Development
Extending Visual Studio IDE
for Productivity, Quality, Tooling,
Analysis, and Artificial Intelligence
Second Edition

Rishabh Verma
Visual Studio Extensibility Development: Extending Visual Studio IDE for
Productivity, Quality, Tooling, Analysis, and Artificial Intelligence
Rishabh Verma
Hyderabad, India

ISBN-13 (pbk): 978-1-4842-9874-9 ISBN-13 (electronic): 978-1-4842-9875-6


https://doi.org/10.1007/978-1-4842-9875-6

Copyright © 2024 by Rishabh Verma


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Smriti Srivastava
Development Editor: Laura Berendson
Editorial Project Manager: Jessica Vakili
Cover designed by eStudioCalamar
Cover image by Omid Moradi on Unsplash (www.unsplash.com)
Distributed to the book trade worldwide by Springer Science+Business Media New York, 1 New York Plaza,
Suite 4600, New York, NY 10004-1562, USA. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail orders-ny@
springer-sbm.com, or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole
member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc
is a Delaware corporation.
For information on translations, please e-mail [email protected]; for reprint,
paperback, or audio rights, please e-mail [email protected].
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available to
readers on GitHub (https://github.com/Rishabh-V/Visual-Studio-Extensibility-Development-2). For more
detailed information, please visit https://www.apress.com/gp/services/source-code.
Paper in this product is recyclable
To my wonderful, loving, and caring wife Neha.
To our precious son, Ram, whose joyful giggles, adorable cuteness,
and boundless curiosity fill our hearts with love and wonder.
And to the dedicated scientists at ISRO whose remarkable
achievements inspire us to reach for the stars and beyond.
Table of Contents
About the Author��������������������������������������������������������������������������������������������������� xiii

Acknowledgments���������������������������������������������������������������������������������������������������xv
Introduction�����������������������������������������������������������������������������������������������������������xvii

Who This Book Is For����������������������������������������������������������������������������������������������xix

Chapter 1: Basics Primer������������������������������������������������������������������������������������������ 1


Why Should I Extend Visual Studio?���������������������������������������������������������������������������������������������� 1
Compiler���������������������������������������������������������������������������������������������������������������������������������������� 3
What Is Software Development Kit (SDK)?������������������������������������������������������������������������������������ 5
Managed Extensibility Framework (MEF)�������������������������������������������������������������������������������������� 6
XML and JSON������������������������������������������������������������������������������������������������������������������������������ 9
Serialization and Deserialization������������������������������������������������������������������������������������������������� 11
Revisiting Visitor, Abstract Factory, and Factory Design Patterns����������������������������������������������� 13
Design Pattern����������������������������������������������������������������������������������������������������������������������� 13
Factory Method Pattern��������������������������������������������������������������������������������������������������������� 13
Abstract Factory�������������������������������������������������������������������������������������������������������������������� 14
Visitor Pattern������������������������������������������������������������������������������������������������������������������������ 15
MSBuild Basics��������������������������������������������������������������������������������������������������������������������������� 17
What Is Code Compilation?���������������������������������������������������������������������������������������������������� 17
What Happens When We Say That We’re Building the Code?������������������������������������������������ 17
How Do We Use MSBuild in Visual Studio?���������������������������������������������������������������������������� 17
async await��������������������������������������������������������������������������������������������������������������������������������� 19
.NET Compiler Platform (Roslyn)������������������������������������������������������������������������������������������������� 28
Summary������������������������������������������������������������������������������������������������������������������������������������ 35

v
Table of Contents

Chapter 2: Getting Started�������������������������������������������������������������������������������������� 37


The Setup������������������������������������������������������������������������������������������������������������������������������������ 37
Creating Your First Visual Studio 2022 Extension����������������������������������������������������������������������� 37
Open Packaging Convention������������������������������������������������������������������������������������������������������� 46
VSIX��������������������������������������������������������������������������������������������������������������������������������������������� 50
Grokking the Structure of a Boilerplate Extension���������������������������������������������������������������������� 51
VSIXAnatomyPackage.cs File������������������������������������������������������������������������������������������������ 52
References���������������������������������������������������������������������������������������������������������������������������� 57
Properties������������������������������������������������������������������������������������������������������������������������������ 57
Anatomy of Extension����������������������������������������������������������������������������������������������������������������� 58
Examining the Files��������������������������������������������������������������������������������������������������������������� 58
Examining the Other Parts of the Extension�������������������������������������������������������������������������� 64
How Does Visual Studio Discover and Load an Extension?�������������������������������������������������������� 65
Summary������������������������������������������������������������������������������������������������������������������������������������ 70

Chapter 3: Extending Visual Studio������������������������������������������������������������������������ 73


Know Your IDE – Visual Studio 2022 User Interface�������������������������������������������������������������������� 73
Visual Studio Extensibility Model������������������������������������������������������������������������������������������������ 78
Extending Menus and Commands����������������������������������������������������������������������������������������� 83
Tools Menu Extension������������������������������������������������������������������������������������������������������������ 83
Running the Code���������������������������������������������������������������������������������������������������������������� 100
The AsyncPackage Abstract Class��������������������������������������������������������������������������������������� 102
FAQs������������������������������������������������������������������������������������������������������������������������������������������ 108
Summary���������������������������������������������������������������������������������������������������������������������������������� 112

Chapter 4: Developing Your First Extensions�������������������������������������������������������� 115


Extensions to Aid Development of VS Extensions��������������������������������������������������������������������� 115
Visual Studio Extension to Perform Search������������������������������������������������������������������������������� 118
Starting the Extension��������������������������������������������������������������������������������������������������������� 120
Adding a Command to the Menu����������������������������������������������������������������������������������������� 126
Adding an Icon and Keyboard Support�������������������������������������������������������������������������������� 128

vi
Table of Contents

Writing the Search Functionality����������������������������������������������������������������������������������������� 132


Testing the Extension���������������������������������������������������������������������������������������������������������� 138
Tool Window Extension to Show DTE Object����������������������������������������������������������������������������� 150
Starting the Extension��������������������������������������������������������������������������������������������������������� 150
Adding a ToolWindowPane�������������������������������������������������������������������������������������������������� 152
Writing the Extension���������������������������������������������������������������������������������������������������������� 153
Running the Extension��������������������������������������������������������������������������������������������������������� 163
Summary���������������������������������������������������������������������������������������������������������������������������������� 166
Class References���������������������������������������������������������������������������������������������������������������������� 167
DTE�������������������������������������������������������������������������������������������������������������������������������������� 167
Document Interface������������������������������������������������������������������������������������������������������������� 170
TextSelection����������������������������������������������������������������������������������������������������������������������� 171
DialogPage�������������������������������������������������������������������������������������������������������������������������� 175
ToolWindowPane����������������������������������������������������������������������������������������������������������������� 176

Chapter 5: Developing Real-World Extensions����������������������������������������������������� 179


Visual Studio Extension to Display Notifications����������������������������������������������������������������������� 180
Starting the Extension��������������������������������������������������������������������������������������������������������� 182
Displaying the Infobar��������������������������������������������������������������������������������������������������������� 184
Running the Extension��������������������������������������������������������������������������������������������������������� 194
Displaying Other Notifications��������������������������������������������������������������������������������������������� 196
Visual Studio Extension to Generate Code�������������������������������������������������������������������������������� 199
Starting the Code Generating Extension������������������������������������������������������������������������������ 201
Generating the Code������������������������������������������������������������������������������������������������������������ 203
Running the Extension��������������������������������������������������������������������������������������������������������� 212
Summary���������������������������������������������������������������������������������������������������������������������������������� 216
Class References���������������������������������������������������������������������������������������������������������������������� 217
Infobar Type System������������������������������������������������������������������������������������������������������������ 217
Code Generation Types�������������������������������������������������������������������������������������������������������� 222

vii
Table of Contents

Chapter 6: Developing Real-World Extensions for Visual Studio Editor��������������� 227


Visual Studio Editor������������������������������������������������������������������������������������������������������������������� 228
Editor Subsystems��������������������������������������������������������������������������������������������������������������� 230
Editor Features�������������������������������������������������������������������������������������������������������������������� 235
Editor Extensibility�������������������������������������������������������������������������������������������������������������������� 239
Diagnostic Analyzer with Code Fix�������������������������������������������������������������������������������������� 241
Writing a Diagnostic Code Analyzer with Code Fix�������������������������������������������������������������� 245
Code Refactoring Extension������������������������������������������������������������������������������������������������������ 272
Coding the Extension����������������������������������������������������������������������������������������������������������� 275
Testing the Refactoring������������������������������������������������������������������������������������������������������� 279
IntelliSense������������������������������������������������������������������������������������������������������������������������������� 282
IntelliCode��������������������������������������������������������������������������������������������������������������������������������� 287
Enhance Visual Studio Using ChatGPT�������������������������������������������������������������������������������������� 288
Summary���������������������������������������������������������������������������������������������������������������������������������� 298
Class References���������������������������������������������������������������������������������������������������������������������� 300
Text Model Subsystem�������������������������������������������������������������������������������������������������������� 300
Content Types���������������������������������������������������������������������������������������������������������������������� 303
Text View Types������������������������������������������������������������������������������������������������������������������� 303
Diagnostic Analyzer������������������������������������������������������������������������������������������������������������� 304
AnalysisContext������������������������������������������������������������������������������������������������������������������� 305

Chapter 7: Snippets, Templates, and More…������������������������������������������������������� 309


Code Snippets��������������������������������������������������������������������������������������������������������������������������� 309
Anatomy of a Code Snippet������������������������������������������������������������������������������������������������� 316
Developing and Distributing Code Snippets������������������������������������������������������������������������ 318
Project and Item Templates������������������������������������������������������������������������������������������������������ 324
Connected Services������������������������������������������������������������������������������������������������������������������ 332
Debugging��������������������������������������������������������������������������������������������������������������������������������� 343
Summary���������������������������������������������������������������������������������������������������������������������������������� 346

viii
Table of Contents

Chapter 8: Continuous Integration and Hosting���������������������������������������������������� 349


Visual Studio Marketplace�������������������������������������������������������������������������������������������������������� 350
Publishing Extension to Visual Studio Marketplace������������������������������������������������������������������ 354
Continuous Integration and Continuous Deployment���������������������������������������������������������������� 363
Private Galleries������������������������������������������������������������������������������������������������������������������������ 381
Anatomy of a Private Gallery����������������������������������������������������������������������������������������������� 381
Creating Private Galleries���������������������������������������������������������������������������������������������������� 385
Consuming Private Galleries������������������������������������������������������������������������������������������������ 387
Summary���������������������������������������������������������������������������������������������������������������������������������� 390

Chapter 9: Tips and Tricks������������������������������������������������������������������������������������ 393


Tips and Tricks�������������������������������������������������������������������������������������������������������������������������� 393
VSIXManifest Metadata Values�������������������������������������������������������������������������������������������� 393
Correct Target Version��������������������������������������������������������������������������������������������������������� 395
Packaging and Updating the Extension������������������������������������������������������������������������������� 396
Use Extensibility Essentials 2022 Extension����������������������������������������������������������������������� 397
Find or Assign Keyboard Shortcut to Commands���������������������������������������������������������������� 398
Run a Command������������������������������������������������������������������������������������������������������������������ 399
Make Use of KnownImageMonikers������������������������������������������������������������������������������������ 400
Coding Is Easier with IntelliCode����������������������������������������������������������������������������������������� 402
Async Package and Background Loading��������������������������������������������������������������������������� 402
Use async All the Way���������������������������������������������������������������������������������������������������������� 403
Make Use of Analyzers�������������������������������������������������������������������������������������������������������� 403
Get a Service����������������������������������������������������������������������������������������������������������������������� 403
Provide a Service����������������������������������������������������������������������������������������������������������������� 404
Make Use of Options Page��������������������������������������������������������������������������������������������������� 404
Localize the Extension��������������������������������������������������������������������������������������������������������� 404
InstalledProductRegistration Attribute��������������������������������������������������������������������������������� 404
Consider to Use Ngen for Better Performance�������������������������������������������������������������������� 405
Reset Experimental Instance����������������������������������������������������������������������������������������������� 406
Rule-Based UI Context��������������������������������������������������������������������������������������������������������� 406
Use Syntax Visualizer���������������������������������������������������������������������������������������������������������� 406

ix
Table of Contents

Look at Sample Extensions������������������������������������������������������������������������������������������������� 407


Add Sound Effects��������������������������������������������������������������������������������������������������������������� 407
Digitally Sign Your Extension����������������������������������������������������������������������������������������������� 408
Create a VS Extension Pack������������������������������������������������������������������������������������������������� 409
Use the Checklist����������������������������������������������������������������������������������������������������������������� 410
Visual Studio Performance Manager����������������������������������������������������������������������������������� 411
Measure the Performance Impact of Your Extension on Visual Studio�������������������������������� 412
Live Code Share������������������������������������������������������������������������������������������������������������������� 412
Quick Launch/Search���������������������������������������������������������������������������������������������������������� 413
Close Tool Window��������������������������������������������������������������������������������������������������������������� 413
Use EditorConfig File����������������������������������������������������������������������������������������������������������� 414
Peek Definition�������������������������������������������������������������������������������������������������������������������� 414
Customize Scrollbar������������������������������������������������������������������������������������������������������������ 414
Conditional Breakpoints, Tracepoints, and Data Breakpoints���������������������������������������������� 415
Code Editing Shortcuts�������������������������������������������������������������������������������������������������������� 416
Make Use of Snippets���������������������������������������������������������������������������������������������������������� 416
Make Use of Code Map�������������������������������������������������������������������������������������������������������� 417
Use IntelliTest to Write and Maintain Better Tests��������������������������������������������������������������� 417
Programmatically Attach or Break the Debugger in Your Code������������������������������������������� 418
C# Interactive Window��������������������������������������������������������������������������������������������������������� 418
Paste Special for XML and JSON����������������������������������������������������������������������������������������� 419
Go to All������������������������������������������������������������������������������������������������������������������������������� 420
Improve Solution Load Performance����������������������������������������������������������������������������������� 421
Improve Navigation�������������������������������������������������������������������������������������������������������������� 421
Remove and Sort usings������������������������������������������������������������������������������������������������������ 422
Use Toolbox�������������������������������������������������������������������������������������������������������������������������� 422
Use Extensibility Templates������������������������������������������������������������������������������������������������� 423
Tap On to Events������������������������������������������������������������������������������������������������������������������ 423
Activity Log�������������������������������������������������������������������������������������������������������������������������� 425
GitHub Examples and Documentation��������������������������������������������������������������������������������� 425
GitHub and Visual Studio����������������������������������������������������������������������������������������������������� 426
Migrate Visual Studio 2019 Extensions to Visual Studio 2022��������������������������������������������� 426

x
Table of Contents

Share Feedback with Microsoft������������������������������������������������������������������������������������������� 426


Ask the Experts������������������������������������������������������������������������������������������������������������������� 427
Visual Studio YouTube Channel�������������������������������������������������������������������������������������������� 428
Tips on Twitter��������������������������������������������������������������������������������������������������������������������� 429
Subscribe to Blogs�������������������������������������������������������������������������������������������������������������� 430
Visual Studio Code�������������������������������������������������������������������������������������������������������������������� 431
Useful Visual Studio 2022 Extensions��������������������������������������������������������������������������������������� 432
The Future of Visual Studio Extensibility����������������������������������������������������������������������������������� 434
Summary���������������������������������������������������������������������������������������������������������������������������������� 435

Index��������������������������������������������������������������������������������������������������������������������� 437

xi
About the Author
Rishabh Verma is a Microsoft Certified Professional and
currently serves as a Senior Developer Relations Engineer
at Google India, where he contributes to the development
of Google Cloud’s C# SDK. With a background in electronic
engineering, he boasts over 15 years of hands-on experience
in hard-core development within the .NET technology stack.
Rishabh is driven by his passion for creating tools, Visual
Studio extensions, and utilities aimed at boosting developer
productivity.
His areas of interest include the .NET Compiler Platform (Roslyn), Visual Studio
extensibility, code generation, and .NET Core. Rishabh is an active member of the
.NET Foundation and has previously authored books on .NET Core 2.0, .NET Core
3.1, and Visual Studio Extensibility Development before undertaking this revision. He
occasionally blogs at https://rishabhverma.net/. His Twitter ID is @VermaRishabh
and his LinkedIn page is www.linkedin.com/in/rishabhverma/.

xiii
Acknowledgments
I would like to express my heartfelt gratitude to Microsoft and the Visual Studio team for
creating the wonderful Visual Studio IDE, a tool cherished and utilized by millions of
developers every day. Without them, we wouldn’t have been here discussing this.
I extend my sincere thanks to Google for providing me with generous paternity leave,
allowing me the time to write this book and share my knowledge.
Special appreciation goes to Mads Kristensen, my Visual Studio extensibility guru!
This work would not have been possible without him. It is by means of his blogs, talks,
videos, and extensions that I have learned about Visual Studio extensibility.
I am deeply grateful to my reviewer, Damien Foggon, for his meticulous review and
proofreading. He painstakingly combed through the entire content, offering corrections,
enhancements, and edits that have greatly improved this book.
A solid support system at home is the foundation of every achievement. I want to
express my heartfelt thanks to my parents Smt. Pratibha Verma and Shri R. C. Verma and
my brother Rishi Verma for their unwavering support and boundless energy.
I owe a special debt of gratitude to my son, Ram, and my wife, Neha. They sacrificed
countless weekends and provided unwavering support, helping me meet my deadlines.
This book is as much their accomplishment as it is mine.
Last, but certainly not least, I want to thank my acquisitions editor, Smriti
Shrivastava, for granting me with this incredible opportunity to share my knowledge and
contribute to the community. Heartfelt appreciation to my project coordinator, Shobana
Srinivasan, who worked patiently and persistently alongside me.

xv
Introduction
Welcome to the latest and most comprehensive edition of Visual Studio Extensibility
Development, thoughtfully updated for Visual Studio 2022. We are glad to have you join
us in our journey of learning Visual Studio Extensibility.
Our journey begins with a solid foundation in the essential concepts to extend Visual
Studio, encompassing crucial data structures and design patterns. This introduction
ensures that you feel at ease as we navigate through the depths of extensibility. This
introductory section is designed to provide you with the confidence and clarity needed
to fully embrace the content that follows.
Next, we’ll dive into the setup process, preparing the perfect launchpad for your
exploration of the extensibility realm. You’ll be introduced to the boilerplate extension,
gaining insights into the structure and anatomy of a Visual Studio extension. Discover
how Visual Studio seamlessly discovers and loads these extensions, setting the stage for
your own development endeavors.
Our journey continues as we unravel the intricate extensibility model of Visual
Studio. You’ll become well acquainted with the Visual Studio SDK, a vital tool in your
extensibility toolkit. Armed with this knowledge, you’ll embark on the creation of a basic
extension, crafting custom commands that can be seamlessly integrated into the code
window, tool menu, and solution explorer.
We’ll then explore how to develop an extension that empowers users to search
code within the search engine of their choice. You’ll learn how to leverage the Options
dialog to customize the extension according to user preferences. Dive into the world of
notifications in Visual Studio and discover how to effectively communicate with users.
You’ll also master the development of an extension that generates C# POCO classes from
JSON and how to leverage extensions to develop a Connected Service.
Our journey takes us to the heart of Visual Studio – the code editor. Here, we’ll
create code analyzers, implement light bulb-style code fix suggestions, and develop
code refactoring extensions. You’ll unlock the potential to extend IntelliSense, providing
custom code suggestions and completions. You also learn to harness the might of AI as
we integrate it into our extension, enabling developers to review, explain, and optimize
code seamlessly and making their development experience better.

xvii
Introduction

We’ll delve into the development of extensions that distribute code snippets,
enhancing developer productivity and ensuring the correct usage of APIs. You’ll also
gain expertise in creating Project Item and Project templates.
Explore the process of publishing an extension to the Visual Studio Marketplace,
making your creation accessible to the wider developer community. Our journey
continues with an in-depth look at deploying extensions using continuous integration.
As we conclude, we’ll unveil a treasure trove of invaluable tips and tricks for
navigating Visual Studio like a pro. Discover a curated selection of indispensable
extensions that can supercharge your development workflow. You also learn about the
future of Visual Studio Extensibility and the new out-of-process extensibility model that
is out now in preview version.
By the time you close the final chapter of Visual Studio Extensibility Development,
you will possess the expertise to develop, debug, customize, and publish an extension.

xviii
Who This Book Is For
This book is meticulously crafted for individuals who are truly passionate about software
development and aspire to unlock the full potential of Visual Studio. Whether you’re
a seasoned developer with years of experience under your belt or embarking on the
exciting journey of coding for the first time, our comprehensive approach caters to every
skill level. Developers, programmers, engineers, architects, instructors, innovators,
students, and technology enthusiasts, all leveraging the power of the Visual Studio IDE,
will find immense value in these pages.
My dedicated editorial team and I have invested considerable effort to provide you
with the most comprehensive and accurate information. However, should you have any
constructive suggestions or feedback regarding the content of this book, I would greatly
appreciate it if you could reach out to me at [email protected]. Your insights will help
us continue to enhance and improve this valuable resource.

xix
CHAPTER 1

Basics Primer
This chapter marks the beginning of our journey toward learning and developing
Visual Studio (VS) extensions. To pave this path, we will provide a quick refresher
of the fundamentals that will be required through the book and are prerequisites
for developing Visual Studio extensions. This chapter will act as a primer for the
fundamentals and can be skipped by the reader if they are well versed with the topics
covered here.
Before we delve into the fundamentals, the first and foremost question that comes to
mind is this: “Why should I extend Visual Studio?” So let us first answer it.

Why Should I Extend Visual Studio?


Why should I bother extending Visual Studio IDE?
I have heard this question many times and have seen numerous software developers
asking this very pertinent question. So, why are we here? Visual Studio is a great
integrated development environment (IDE) and makes the developer very productive
in coding, developing, debugging, and troubleshooting. Then, why should I even bother
extending it? Well – there are numerous reasons to do so. A few of the top ones are the
following:

• Customize Visual Studio to suit your needs and environment.

• To avoid repetitive or tedious work. With extensions, it can be done


just by a click of a button.

• Do things faster, as it is something that can increase your


productivity. It can be in the form of a snippet, or a tool to generate
a GUID (globally unique identifier), or code analysis, or code
refactoring, or a project/item template, or anything else that can get
the developer’s job done faster. There are numerous extensions that
can make even extension development faster!
1
© Rishabh Verma 2024
R. Verma, Visual Studio Extensibility Development, https://doi.org/10.1007/978-1-4842-9875-6_1
Chapter 1 Basics Primer

• Higher-quality development: There are a few great examples of


extensions like Roslyn analyzers, StyleCop, FxCop, CodeMaid, and
ReSharper, to name a few, which help the developer to identify the
issues while coding. This avoids unnecessary bugs in the future, and
the code can be compliant to coding standards, resulting in better
quality.

• Enforce policies or settings across teams. There are extensions that


can help you get code consistency and uniformity even across a large
team. For example, a check-in policy extension can ensure that each
code check-in has a work item associated with it and has 0 StyleCop
and FxCop violations. Without this, the code would not check in.

• Extending Visual Studio is a great learning opportunity. Developers


can gain deep insights into the inner working of a complex IDE like
Visual Studio and understand coding and architecture patterns and
improve their C# and .NET knowledge.

• Visual Studio extensibility allows developers to contribute to open


source extensions and/or collaborate on projects that can improve
the overall experience for the community.

• To foster innovation and experimentation, developers can explore


new ideas and leverage cutting-edge technologies to extend
Visual Studio. With the recent fast-paced development in the field
of artificial intelligence (AI), there are lots of opportunities to
experiment and innovate with AI-driven extensions. The AI-based
extensions can automate repetitive tasks, enhance code analysis,
review, provide intelligent code completions, and much more. We
will explore this bit in the upcoming chapters.

• Of course, fame and fortune: You can either contribute to the


community by sharing your great extension in the marketplace for
free or monetize it and charge a fee from consumers to use it. You get
a name, fame, and can also make some money, if you create great
extensions.

2
Chapter 1 Basics Primer

• It would be cool if… Mads Kristensen is one of the most popular


extension writers in the Visual Studio Marketplace with 125+
extensions to his credit. In one of his talks on Visual Studio
extensibility, he explained how he thinks about a new Visual Studio
extension and framed it beautifully: “It would be cool if…”

There are numerous great extensions for Visual Studio for improving developer
productivity, quality, refactoring, editors, and controls available in the Visual Studio
Marketplace: https://marketplace.visualstudio.com/. As of today, there are more
than 12.8K extensions in the marketplace with more than 45 million downloads and
counting.
Let us now start our quest of brushing up on the fundamentals.

Compiler
Let’s start with the fundamental definition of a compiler. A compiler is a software that
translates a computer program written in a high-level programming language, which
are easier for humans to understand (like C#, Java, etc.) language into a low-level
language or binary code that computers can execute. High-level languages resemble
human-readable languages like English, which low-level languages consists of 0s and 1s,
understood by the computer processors.
Now, there is another important thing that is called CPU architecture. The CPU
processing the instructions may be a 32-bit processor (x86) or a 64-bit processor (x64).
The memory space and the instruction set vary for both of these architectures. An
x64 processor has a 64-bit address and memory space and hence can work on larger
memory addresses. They also have a few new instructions as optimizations for faster
execution. Therefore, for proper utilization of the processor, the right-processor specific
machine codes should be generated. This presents a challenge that if a developer builds
the code, on one hand, in the x86 architecture of CPU and ships the software, it would
work well in both x86- and x64-based systems, but it would not be making optimal use of
the x64 processor. On the other hand, if a developer builds the code on an x64 processor,
it will not work on x86 processor-based systems.

Note Visual Studio 2022 is a x64-based application. Until Visual Studio 2019, it
was x86-based application.

3
Chapter 1 Basics Primer

For a C# .NET-based application, this is not generally an issue, as .NET compiler


compiles the code into Microsoft Intermediate Language, or MSIL, which is independent
of processor architecture. At the first time of execution, this MSIL is converted into the
platform architecture-specific machine code. To leverage this, we can choose the .NET
project platform (in project properties) as “Any CPU.”
The high-level flow of how the C# code executes in a machine is depicted in
Figure 1-1.

Figure 1-1. C# code execution flow

As an example, here is a computer program that does an operation of displaying a


message on a console. It is written in the C# language using a code editor. It is a sample
program of printing “Hello World!” text on a console:

using System;

namespace BasicsPrimer
{
    class Program
    {
        static void Main(string[] args)

4
Chapter 1 Basics Primer

        {
            Console.WriteLine("Hello World!");
        }
    }
}

This code will print the desired text on the console if run on a computer. The only
problem we’ll face is that a computer doesn’t understand this code. It understands only
binary language of 0s and 1s. So, we must convert this program into binary language
so that the computer can understand and run it. The compiler converts the code into
MSIL. When executing the program, .NET Common Language Runtime (CLR) does
a just-in-time (JIT) compilation of this MSIL into machine-specific code, which the
microprocessor understands and then executes the converted machine code to display
“Hello World!” on the console window as shown in Figure 1-2.

Figure 1-2. Hello World!

While writing extensions, we will come across the term Visual Studio SDK, so let us
discuss what SDK means.

What Is Software Development Kit (SDK)?


A software development kit (SDK), as the name implies, is a collection of tools designed
to facilitate software development. To better understand it, let us first understand the
concept of a development kit.
A kit refers to a set of essential tools for creating something (e.g., a carpenter’s kit
contains tools like a hammer, chisel, etc., to make furniture). Similarly, in software
development, we require a comprehensive toolset or development kit, known as
software development kit, or SDK. An SDK typically includes DLLs and libraries that
support, assist, and streamline the development process with a specific development
environment.
5
Chapter 1 Basics Primer

For instance, when developing an application on the .NET platform, we would need
the .NET SDK. The SDK encompasses various components, including but not limited to:

• Common Language Runtime (CLR) required for running/debugging


applications during development

• Base Class Library (BCL) DLLs to use built-in functions of .NET


Framework, etc.

Different SDKs will offer different content depending upon what the developer will
require while developing software using that particular SDK.
Let’s explore another relevant example related to the subject matter covered in
this book. To develop Visual Studio extensions, you need to use the Visual Studio SDK
(VSSDK). When you add the relevant workloads (covered in the next chapter) during
Visual Studio installation, you’re essentially installing the SDK required to develop
Visual Studio extensions. We will discuss Visual Studio SDK through this book, while
developing the extensions, and also delve into its components, as needed.
Visual Studio offers a high level of extensibility, and most of this extensibility is based
on the extensibility framework known as Managed Extensibility Framework (MEF). Let’s
now delve into MEF and understand the fundamentals.

Managed Extensibility Framework (MEF)


To understand Managed Extensibility Framework (MEF), we need to understand the first
two parts of its name, that is, “Managed” and “Extensibility.” Let us understand these
terms one by one:

• Managed: Any code that runs under the context of Common


Language Runtime (CLR) is called managed code.

• Extensibility: A way of extending the features/behavior of a class,


component, framework, tool, IDE, browser, etc. is called extensibility.

Now let’s see the formal definition of MEF taken from the official Microsoft
documentation page:
The Managed Extensibility Framework or MEF is a library for creating
lightweight, and extensible applications. It allows application developers
to discover and use extensions with no configuration required. It also lets

6
Chapter 1 Basics Primer

extension developers easily encapsulate code and avoid fragile hard depen-
dencies. MEF not only allows extensions to be reused within applications,
but across applications as well.
MEF was shipped by the .NET Framework team with version 4.0 to make an add-in-
or plug-in-based extensible application easily on .NET Framework. MEF is an integral
part of .NET Framework 4.0 and above, and it is available wherever the .NET Framework
is used. You can use MEF in your client applications, whether they use Windows Forms,
WPF, or any other technology, or in server applications that use ASP.NET.
The fundamental and simplified theory of MEF is that an application is composed
of parts. So, an application can be extended by exporting parts, importing parts, and
composing parts, without a need for configuration. MEF provides
• A standard for extensibility
• A declarative, attribute-based programming model
• Tools for discovery of parts implicitly, via composition at runtime
• A rich metadata system

The assembly System.ComponentModel.Composition provides the MEF. Just


importing this namespace would enable us to use MEF. Let us see the high-level basic
architecture of MEF (Figure 1-3).

Figure 1-3. MEF basic architecture


7
Chapter 1 Basics Primer

An MEF component called a part declaratively specifies its dependencies, called


imports, as well as its capabilities, called exports. When a part is created, the MEF
composition engine satisfies its imports from the other parts that are available. Because
of the declarative model (attributes), the imports and exports can be discovered at
runtime, without depending on hardly coupled and referenced assemblies or error-­
prone configuration files. MEF allows the application to discover parts via metadata.
An application leveraging MEF declares imports for its dependencies, for example,
in a constructor or in a property, and may also declare exports that can be used to
expose service to other parts. This way, component parts are also extensible. A diagram
depicting the high-level working of MEF is shown in Figure 1-4. The host application can
have several catalogs and parts. A catalog contains the parts (exports as well as imports).
There are several types of catalogs, like Directory catalog, Assembly catalog, Type catalog,
etc. Each part has some dependencies that are decorated with Import or ImportMany
attributes. This way they advertise their dependencies and requirements. There are some
parts that expose services. They are decorated with Export or ExportMany attributes and
provide or fulfill the service. Then there is an MEF container that takes the MEF catalog
and composes the parts if there are matching exports and imports.

Figure 1-4. MEF working

Visual Studio is highly extensible and makes extensive use of MEF to extend
its various components. All the editor extensions, code analyzers, code refactoring
extensions, etc. that we will develop in later chapters will make use of MEF and we will
need to decorate the classes that we write to extend with an Export attribute or other
attributes derived from Export attributes.

8
Chapter 1 Basics Primer

For a quick recap on MEF, I would highly recommend the readers to read this
good documentation by Microsoft at https://docs.microsoft.com/en-us/dotnet/
framework/mef/.
Please note that Visual Studio extensions can be built using .NET Framework.
However, please be aware that .NET Core is not supported for extension development in
Visual Studio as of writing this edition.
While writing extensions, we will come across a vsixmanifest file, which is an
XML file; and while publishing the extension to the marketplace, we will be creating
a publishManifest file, which is a JSON file, so for the benefit of new and beginner
developers, let us have a quick tour of XML and JSON.

XML and JSON


XML and JSON are the two most common data formats for exchanging information over
the Internet. Let us recap them one by one.
XML stands for Extensible Markup Language. It is a markup language like Hypertext
Markup Language (HTML). It is self-descriptive in nature. The very famous SOAP
protocol used in service-oriented architecture (SOA) also uses XML format to define its
Web Services Description Language (WSDL). We will see while developing Visual Studio
extensions that the vsixmanifest file that defines the extension metadata is an XML. Let
us see a sample XML file:

<?xml version="1.0" encoding="utf-8"?>


<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/
developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/
vsx-schema-design/2011">
  <Metadata>

    <Identity Id="VarToStrongType..b0eb46a5-106e-44f0-ad4a-bb66f19335a8"
Version="1.0" Language="en-US" Publisher="rishabhv"/>
    <DisplayName>VarToStrongType</DisplayName>

    <Description xml:space="preserve">This is a sample code refactoring


extension for the .NET Compiler Platform ("Roslyn").</Description>
  </Metadata>

</PackageManifest>

9
Chapter 1 Basics Primer

This is a sample XML showing Visual Studio extension’s package manifest.


You can read about XML in greater detail on the World Wide Web Consortium’s
official page: www.w3.org/XML/.
JSON stands for JavaScript Object Notation. This data format was first introduced
in the front-end/web world. Douglas Crockford of JavaScript: The Good Parts fame is
considered to be the man behind the fame of JSON format. It is an efficient data transfer
format and better than XML. As of today, it is being used in all back-end technologies
equally. While developing modern web applications, we will see that most application
configurations are now JSON based, including in ASP.NET Core. While developing Visual
Studio extension pack, we will see that it makes use of JSON.
Key points to know about JSON syntax are the following:

• Data is in name/value pairs.

• Data is separated by commas.

• Curly braces hold objects.

• Square brackets hold arrays or collections.

• Values must be one of the following data types:

a. A string

b. A number

c. An object (JSON object)

d. An array

e. A Boolean

f. Null

Here is how a typical JSON format data looks:

{
   "name":"Sachin",
   "age":46,
   "city":"Mumbai"
}

10
Chapter 1 Basics Primer

Let us do a quick dissection of this example to understand it better:

"name" is a key
"Sachin" is a value
"name":"Sachin" is a tuple

Visual Studio makes extensive use of serialization and deserialization while


persisting the files and in various other places; let us have a quick recap.

Serialization and Deserialization


Before discussing serialization and deserialization, let’s understand why it is required in
the first place.
We live in the world of the Internet where computers talk to each other and share
data. When you call a method of a web service using a SOAP or REST protocol, some
data gets shared between the client PC and the server. This data sharing among
computers happens via network cables. The data sharing over wire between two
processes running on different PCs requires the data to be converted into a format that
can be transferred over wire, and then at the receiver’s end, this formatted information
should be reconstructed back to the data. This, in essence, is the concept of serialization
and deserialization.
So, in the context of data storage or data sharing, serialization is the process of
translating data structures or object states into a format that can be stored or transmitted
over wire so that it can be reconstructed to its original form at a later point in time.
Deserialization is just the opposite of serialization. Serialization happens on a source
machine. Deserialization happens on a remote/target machine. Figure 1-5 summarizes
the process of serialization and deserialization.

11
Chapter 1 Basics Primer

Figure 1-5. Serialization and deserialization

If you use a Windows operating system and have ever hibernated your system,
it serves as an example of serialization. When you hibernate, the operating system
serializes the state of your machine and persists it in disk. When you boot the system
again, the operating system checks the disk and deserializes the data to restore the state
of your machine, so you resume from where you left off.
For any .NET project that involves JSON-based data exchange, Newtonsoft.Json
NuGet package is one of the popularly used packages. This library contains various
classes in which you can serialize or deserialize JSON data to and from your domain
model objects.
I would encourage you to learn more about it on its website here: ­www.newtonsoft.
com/json/help/html/SerializingJSON.htm.
Visual Studio and its extensions make extensive use of known and popular design
patterns. A few of the commonly used design patterns are visitor design patterns while
working with Roslyn syntax trees, singleton design patterns in initializing the custom
command, abstract factory in menus, and so on. Let us revisit few of the important
design patterns.

12
Chapter 1 Basics Primer

 evisiting Visitor, Abstract Factory, and Factory


R
Design Patterns
Design Pattern
Design patterns are standardized and reusable solutions to common problems in
software design. They are also referred to as Gang of Four (GoF) design patterns, as they
were initially defined by a group of four authors way back in 1994. All the design patterns
are divided into three broad categories as shown in Table 1-1.

Table 1-1. Design Patterns


Creational design patterns Behavioral design patterns Structural design patterns

Abstract factory Chain of responsibility Adapter


Builder Command Bridge
Factory method Interpreter Composite
Singleton Iterator Decorator
Prototype Mediator Façade
Memento Flyweight
Observer Proxy
State
Strategy
Template method
Visitor

Out of this huge list, we’ll be discussing only three design patterns that are going to
be used in this book.

Factory Method Pattern


Factory method pattern (a.k.a. factory design pattern) is a creational design pattern, that
is, it is related to object creation. It defines an interface for creating an object but lets
the classes that implement the interface decide which class to instantiate. The factory
method lets a class defer instantiation to subclasses.
13
Chapter 1 Basics Primer

An increasingly popular definition of factory method is a static method of a class that


returns an object of that class type. But unlike a constructor, the actual object it returns
might be an instance of a subclass. Unlike a constructor, an existing object might be
reused in place of creating a new object. Unlike a constructor, factory methods can have
different and more descriptive names.

Abstract Factory
Abstract factory is also a creational design pattern, that is, it is related to how objects
are created in your application. It provides an interface for creating families of related
or dependent objects without specifying their concrete classes. This pattern is generally
used in the creation of menus.
Abstract factory pattern implementation provides a framework that allows us to
create objects that follow a general pattern. So, at runtime, an abstract factory is coupled
with any desired concrete factory, which can create objects of a desired type.
Let us see the definition given by the Gang of Four (GoF) for an abstract factory
pattern:

• AbstractFactory: Declares an interface for operations that create


abstract product objects

• ConcreteFactory: Implements the operations declared in the


AbstractFactory to create concrete product objects

• Product: Defines a product object to be created by the corresponding


concrete factory and implements the AbstractProduct interface

• Client: Uses only interfaces declared by AbstractFactory and


AbstractProduct classes

Thus, the abstract factory provides interfaces for creating families of related or
dependent objects without specifying their concrete classes (Figure 1-6).

14
Chapter 1 Basics Primer

Figure 1-6. Abstract factory design pattern

Note The Gang of Four published a seminal design patterns book in 1994. It’s a
good place to start to learn more: Design Patterns: Elements of Reusable Object-­
Oriented Software (Addison-Wesley, 1994).

Client application creates a concrete implementation of the abstract factory and


then uses the generic interfaces to create the concrete objects that are part of the family
of objects. The client does not know or care which concrete objects it gets from each of
these concrete factories since it uses only the generic interfaces of their products.

Visitor Pattern
Visitor pattern is one of the behavioral design patterns. It is used when we have to
perform an operation on a group of similar kinds of objects. With the help of a visitor
pattern, we can move the operational logic from the objects to another class.
There are important parts of a visitor pattern that we need to know:

1. A method called “Visit,” which is implemented by the visitor and is


called for every element in the data structure

2. Visitable classes providing “Accept” methods that accept a visitor

Now let us understand the various design components involved in this pattern with
the help of the UML diagram shown in Figure 1-7.

15
Chapter 1 Basics Primer

Figure 1-7. Visitor design pattern

• Client: The Client class is a consumer of the classes of the visitor


design pattern. It has access to the data structure objects and
can instruct them to accept a Visitor to perform the appropriate
processing.

• Visitor: This is an interface or an abstract class used to declare the


visit operations for all the types of visitable classes.

• ConcreteVisitor: For each type of visitor, all the visit methods


declared in abstract visitor must be implemented. Each visitor will be
responsible for different operations.

• Element: This is an interface that declares the accept operation.


This is the entry point that enables an object to be “visited” by the
visitor object.

• ConcreteElementA and ConcreteElementB: These classes implement


the Element interface and define the “accept” operation. The visitor
object is passed to this object using the “accept” operation.

16
Chapter 1 Basics Primer

A great benefit of Visual Studio being extensible is that we can plug in our code to
the various solution and build events to take action when an event occurs. A few of the
events of interest for developers are related to build. Visual Studio makes use of the
MSBuild engine behind the scenes to build the code, so let us refresh the fundamentals
of MSBuild.

MSBuild Basics
Before we talk about MSBuild, we should first understand the difference between a
compilation process and a build process.

What Is Code Compilation?


Compilation is the process through which your language compiler validates the syntax of
your code whether it is right or wrong. If it is right, then compilation says it is okay or else
it throws compilation errors.

 hat Happens When We Say That We’re Building


W
the Code?
Build is the process through which a tool packages the compiled code and creates output
files on disk, for example, EXE, DLL, etc.
So, MSBuild is a build tool that performs the packaging task in Visual Studio
after your .NET or C++ code has been compiled successfully by respective language
compilers.

How Do We Use MSBuild in Visual Studio?


It is very simple. Once you’ve opened any project supported by Visual Studio, go to
the Build menu and click the “Build Solution” option as shown in the screenshot in
Figure 1-8. The same happens when you build, rebuild, or debug your code via Visual
Studio. That’s all you need to do. Thereafter, Visual Studio does everything required to
compile and build the project.

17
Chapter 1 Basics Primer

Figure 1-8. Visual Studio build menu

Whenever you build a project in Visual Studio, it happens in the following


mentioned steps:

1. Compilation of source code

2. Packaging of compiled code

Visual Studio (VS) acts as the orchestrator in this process. It controls both the
compiler and MSBuild. VS first asks the compiler whether the current code is compilable
or not. If the compiler says yes, then VS asks MSBuild to trigger the build process to
generate the build output binaries.
MSBuild tool comes preinstalled when you install Visual Studio, and it works in
background without your knowledge. You can also use it from the command line once
you’ve installed Visual Studio on your computer machine.
If you don’t have Visual Studio installed (e.g., in your build server where your
CI pipeline will be building the code for your extension), then you’ll have to install
either .NET software development kit (SDK) or Microsoft Build tools separately to get
the MSBuild EXE, which is the starting point to run MSBuild. As of today, MSBuild is
available as an extension in Visual Studio Code as well if you want to build any code and
package using MSBuild.

18
Chapter 1 Basics Primer

To know about the internals of MSBuild, I would encourage you to follow its open
source repository hosted on GitHub – https://github.com/microsoft/msbuild.
In modern programming, asynchrony is the part of mainstream coding and should
not be an afterthought. Writing extensions is no different. While writing extensions, we
will make use of asynchronous loading of packages and use async APIs for better and
efficient usage of threads. To that end, let us revisit async await.

async await
async await makes up the language features in C# language that help developers to do
asynchronous programming easily. How? Well, C# 5 (.NET Framework 4.5) introduced
keywords async and await, so that developers can write async methods directly.
Since, it’s a language feature exposed via keywords, the burden of complicated code is
offloaded from the developer to the compiler. With async await keywords, a developer
can just write an async method and the compiler takes the responsibility of writing the
complex code behind the scenes and optimizes it as well. Therefore, async await is also
called “syntactic sugar.” Let’s create our first async method using async await keywords
and understand it’s working. To do so, first let us write a synchronous code and then
convert it to the async method:

       private static void DownloadData(string url, string path)


       {
           // Create a new web client object.
           using (WebClient client = new WebClient())   //1
           {
               // Add user-agent header to avoid forbidden errors.
               client.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT
10.0; WOW64)"); //2

               // Download data from url.


               byte[] data = client.DownloadData(url);  //3

               // Write data in file.


               using (var fileStream = File.OpenWrite(path))  //4
               {
                   fileStream.Write(data, 0, data.Length); //5

19
Chapter 1 Basics Primer

               }
           }
       }

We have a simple DownloadData method that takes two arguments of type string,
namely, url and path. The code is straightforward and self-explanatory, by means of
comments, but let’s go through it to set the foundation for async await. Each line of the
program is marked with a comment for clarity.
1. We create a new WebClient object. WebClient provides APIs for
sending and receiving the data from a web resource using HTTP
requests and responses.

2. The user-agent header information of HttpRequest is set.

3. The DownloadData method of the client is called with the URL


as a parameter. This method is synchronous and may take some
time to complete. The executing thread will block and wait until
the statement completes successfully or encounters an error.
Eventually, a result would be obtained and it would be stored in a
local variable named data of type byte[].

4. We have the data downloaded from the URL, so we want to save


this data in a file path. So, we create a new FileStream object,
passing the path as a parameter.

5. We invoke the Write method on the FileStream object and write


the downloaded data to the file.

Since both WebClient and FileStream implement IDisposable, we have wrapped


their object creation code inside the using block, which would ensure that once the
object is no longer used, the memory of these objects is reclaimed by the CLR via
garbage collection (GC).
C# is a high-level language. The code that we write in C# is for the application layer.
For the same reason, it is more or less independent of the type of computer hardware,
and anything that we write in C# undergoes multiple transformations before they
get converted into assembly language that the CPU understands and processes. C#
doesn’t communicate to hardware directly. In the async sample program with method
DownloadDataAsync, we have two instances where we need to communicate with the
computer hardware to do the job. Generally, a programmer need not understand these

20
Chapter 1 Basics Primer

low-level details, and only knowing to use the APIs correctly is sufficient. However,
understanding these fundamentals can help us appreciate the benefits that async await
brings to the table.
In line #3, we call the DownloadData method on the web client object, which is
synchronous. The DownloadData method downloads the data from the specified URL
and returns it as a byte array. Depending on factors like size of data, network speed,
and other computer configuration parameters, it may take a while for this method to
complete.
Now, consider this scenario in an ASP.NET Core or ASP.NET application. When this
method is executed, the framework allocates one of the ThreadPool threads to handle
the request. The thread executes the code until it reaches the DownloadData method
call. Behind the scenes, the call goes from managed code (C# .NET) to the native code.
The native code would talk to the hardware and instruct it to download the data from
the specified URL. During this time, the thread allocated by ThreadPool in the managed
code has nothing to do but just wait and wait. Sometime in the future, the hardware
would finish its job and return the data to native code, which would in turn return the
data in byte [] to the managed code. An operation in which a thread’s primary task is
just to wait for the operation is the I/O-bound operation. This indeed is an I/O-bound
operation. Under the hood, a CLR thread pool makes use of an I/O port to schedule the
threads for I/O operations. These threads are referred to as I/O completion port (IOCP)
threads. A similar thing happens in line #5 as well. Here the data is written to the hard-­
disk drive of the computer, which is an I/O operation, and during this time, as well, the
managed thread is just sitting idle and waiting!
Since the code is running in a web application, it is common to expect a scenario in
which a burst of requests arrives at the server. ThreadPool would allocate a thread per
request, so depending upon the number of requests, we may have a large number of
threads trying to execute this code; and like we saw earlier, there would be a period of
time in which all of these threads would just sit and wait for the data to be downloaded
and returned back to it. Later, the data would be fetched and returned to the thread.
Even in this case, depending upon the number of cores in the server, only that many
threads would at the best be able to run concurrently and others would just wait for the
context switch to happen. Recall that context switches are expensive, and so we have
been following highly expensive observations in the preceding code:

• We are unnecessarily allocating a thread per request. (Threads are


expensive.)

21
Chapter 1 Basics Primer

• The thread spends a considerable amount of time doing nothing and


just waiting for an I/O operation to complete. (Wasting resources.)

• When the data returns, since we have many threads (more than CPU
cores), the threads would compete for the context switch to happen
to continue further processing. (Context switches are expensive.)

• This wasting of resources is happening twice in the method. See line


#3 and line #5.

Due to the preceding reasons, the synchronous I/O operations are not scalable, and
we may soon reach the memory and CPU limits as we are wasting or not utilizing the
resources optimally. This is assuming we have enough threads in the ThreadPool, or else
there may be other serious issues like thread exhaustion due to ThreadPool throttling
or an HttpRequest getting queued. We will see how leveraging asynchronous methods
via async await would solve this issue and enable the path for making highly scalable
solutions. Before we dive into the async version of the preceding code, let us quickly see
how we can invoke the code earlier from a console app.
To call this method from the console app, we need the following lines of code:

    static void Main(string[] args)


    {

            // Set the url to a website from which content needs to be


downloaded.
            string url = " https://www.apress.com/in/apress-open/
apressopen-titles";

            // Path where downloaded data needs to be saved.


            string path = "C:\\Rishabh\\download.txt";
            // Call the method.
            DownloadData (url, path);
    }

Upon executing this code, the data would be downloaded from the specified URL
and dumped into the file name download.txt in the specified location. This code is
simple and executes synchronously.
Let’s convert our DownloadData method into an asynchronous method, leveraging
async await keywords. The rewritten method would look like this:

22
Chapter 1 Basics Primer

        private static async Task DownloadDataAsync(string url,


string path)
        {
            // Create a new web client object.
            using (WebClient client = new WebClient()) //1
            {
                // Add user-agent header to avoid forbidden errors.
                client.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT
10.0; WOW64)"); //2

                // Download data from url.


                byte[] data = await client.DownloadDataTaskAsync(url); //3

                // Write data in file.


                using (var fileStream = File.OpenWrite(path)) //4
                {
                    await fileStream.WriteAsync(data, 0, data.Length); //5
                }
            }
        }

Pretty simple, right! The following changes are worth noting in this rewritten
asynchronous method:

1. Though it may not always be the case, there is no change in the


number of lines of code from the synchronous version of the method.

2. There is a new access modifier async added to the method definition.

3. The return type of method has changed from void to Task, though
keeping the return type as void would have compiled as well.
But it is highly NOT recommended to code that way. We will talk
about this later in our discussion of exception handling.

4. We have changed the method name from DownloadData to


DownloadDataAsync to indicate that this method is asynchronous.
Although there is no hard-and-fast rule like this, it is
recommended to have an async suffix in the method names that
are asynchronous, just to make it easier for API consumers as well
as for maintenance and readability.
23
Chapter 1 Basics Primer

5. The two important operations where data was getting


downloaded, and downloaded data was being written to files, now
have an await keyword before their invocation, and they make
use of an async version of methods instead of their synchronous
method counterparts.

With just these few changes, our synchronous method has been changed to an
asynchronous method. This is the USP of the async await keywords that it makes
writing asynchronous methods easier than ever. Though there is a lot that happens
behind the scenes, abstracted away from the developer, the compiler does all the hard
part and makes the life of the developer easy. The calling method will also undergo a
change that we will see a little later.
Based on this description, we can devise a simple step-by-step technique to convert
any synchronous method to an asynchronous method and they are the following:

• Introduce the async keyword in the method definition.

• Replace the return type of the method according to Table 1-2.

Table 1-2. Return Types for async Method


Synchronous method Return Type Async method Return Type

T Task<T>
void Task
void void (only for top-level event handlers, like button click)

Add an async suffix in the method name to declare to the world that the method is
asynchronous.
Inside the method, look for method invocations that have asynchronous versions
available (end with async and have task-based return types). If yes, use the async version
with the await keyword.
Okay! We have the async version of method. But, how is it better than the
synchronous version of the method we saw earlier? Let’s see the line-by-line execution
of code to understand this. Like earlier, we have the line number appended as a suffix in
each line of code.

24
Chapter 1 Basics Primer

1. We create a new WebClient object. WebClient provides APIs for


sending and receiving the data from a web resource using HTTP
requests and responses. (It is the same as the synchronous version.)

2. The user-agent header information of HttpRequest is set. (It is the


same as the synchronous version.)

3. The DownloadDataTaskAsync method of the client is called with


the URL as a parameter. This method is asynchronous and is
prefixed with an await keyword. This is where the compiler will
play a part. To simplify and make it comprehensive, the thread
executing this code would return to the caller method upon
encountering the await keyword. If it’s a GUI application, and the
method is invoked from a top-level event handler, then the main
thread will return to process the message pump and hence the UI
will remain responsive. If it’s a server-side code and ThreadPool
thread is executing it, then this thread will return to the caller
function and hence remain available for further processing
(instead of sitting there and waiting!). In the future, when the
DownloadDataTaskAsync method completes its work and returns
the data in byte[], ThreadPool may allocate the same or different
thread to resume the method from the same place and continue
with the rest of the code. In this sense, async await enables the
ThreadPool threads to return to the caller method (top-level
awaits may return the thread to the pool) and enter the method
multiple times (as many times as await appears).

4. We have the data downloaded from the URL, so we want to


save this data in a file path. So, we create a new FileStream
object, passing the path as a parameter. (This is the same as the
synchronous version.)

5. We invoke the WriteAsync method on the FileStream object and


await it to write the downloaded data to the file. This will have the
same behavior as we discussed in step #3. Basically, the compiler
transforms the method using async await into a state machine,
where thread can enter multiple times. This way threads remain
free because they are used optimally. They are freed up and return

25
Chapter 1 Basics Primer

to the caller upon encountering the await statement and can be


used elsewhere, increasing scalability and minimizing resource
wastage. Therefore, methods using async await make the code
more scalable and are highly recommended to be used in the
server-side applications as well as in GUI-based applications to
keep the UI responsive.

Tip To grasp the fundamental of async await, I suggest thinking of the await
keyword as the ContinueWith construct. The compiler transforms the code
after the await statement inside a ContinueWith construct. As soon as an
await keyword is encountered, the executing thread returns to the caller. Upon
completion of that statement, a thread executes the code wrapped inside the
ContinueWith construct. This can be on a different thread or the same thread
depending upon if ConfigureAwait(false) is used or not used, respectively.
This happens for all await statements.

Let’s have a look at the next code using async await. Please pay special attention to
the numbered steps.

Figure 1-9. async await control flow


26
Chapter 1 Basics Primer

In Figure 1-9, the high-level steps of the execution flow are marked. Let’s discuss
these steps to understand the control flow.
We know that our Main method is async as we added an async modifier in the Main
method definition. As we will see in the next section, when a method is marked with an
async modifier, the compiler transforms the method’s code into a type that implements a
state machine. The executing thread continues until it encounters an await keyword and
then returns to the caller.
In our case, the main thread enters the Main method (the entry point) and starts
executing the code. It continues to execute the code until it encounters the await
statement, marked as step 2.
The main thread passes the url and path parameters and invokes the
DownloadDataAsync, which is also asynchronous and is awaited. Inside the
DownloadDataAsync method, a Task object is created and returned to the Main method.
At this point, the await keyword wires up the callback method ContinueWith on this
returned Task object and passes the method that resumes the state machine and then
the main thread returns from the Main method.
The DownloadDataAsync method would run on the main thread until it encounters
its first await statement. This can be seen by printing the Thread.CurrentThread.
ManagedThreadId before and after await statements in the Main as well as in
DownloadDataAsync methods.
Upon encountering an await statement like await client.DownloadDataTaskAsync,
a Task object is created and returned to the DownloadDataAsync method. The await
keyword wires up the callback method ContinueWith on the Task object, and the thread
returns back to DownloadDataAsync.
Sometime later, the HttpClient will complete downloading the data from the URL,
and a ThreadPool thread will notify the Task object, which would result in the activation
of the callback method ContinueWith and the thread would resume the method from the
await statement.
Now, the DownloadDataTaskAsync method of HttpClient could have completed the
task successfully or may have encountered a network error. All these status checks are
done by the compiler-generated code behind the scenes, and the method execution
continues on the ThreadPool thread, which will then create a FileStream and call its
WriteAsync method. Again, the await operator calls a ContinueWith on the task object
returned from WriteAsync method passing in the callback method name to resume the
method, and the thread returns from DownloadDataAsync method again.

27
Chapter 1 Basics Primer

After some time, the write operation would complete. A ThreadPool thread will
notify the completion and the thread will resume the DownloadDataAsync method
until its completion and return to the Main method. The compiler will generate the
code to ensure that Main method knows that the DownloadDataAsync method is now
complete and it has no further await statements. This is done by marking the status of
Task returned from DownloadDataAsync method as Completed. The thread then waits at
Console.ReadLine() waiting for a user enter to exit the console.
This concludes our quick refresher on async await. In the next section, we will see
.NET Compiler platform and conclude this chapter.

.NET Compiler Platform (Roslyn)


Until not so long ago, C# and VB compilers used to be black boxes for developers. With
the advent of .NET compiler platform (Roslyn), this changed and now developers have
compiler as a service, which they can use to extend the compiler and display custom
warnings and errors and build amazing developer tools. .NET compiler platform is built
upon several APIs and services. Visual Studio extensibility for code fixes, refactoring, and
light bulb-style code actions is provided by the.NET compiler platform.
Figure 1-10 displays the high-level architecture of the .NET compiler platform.

Figure 1-10. .NET Compiler platform architecture

There are three main layers in the .NET compiler platform:

28
Chapter 1 Basics Primer

• Compiler APIs: This layer provides an object model that holds the
syntax and semantic information exposed at each phase of the
compiler pipeline. This layer exposes the immutable syntax trees,
symbols, code files, options, and assembly references. There is a layer
of extensibility above this layer which can be used to tap on to the
diagnostics and scripting APIs.

• Workspaces APIs: This layer exposes the object model that holds the
information of solutions. Workspaces APIs can be used to perform
code analysis, formatting across the solution.

• Feature APIs: This layer exposes the APIs to perform code analysis
fixes and refactoring.

The .NET compiler platform has opened the door for the plethora of opportunities
like the following:

• Enforcing best practices and standards, for example, StyleCop,


FxCop, and code analyzers

• Code-aware libraries

• Code generation

• Scripting (interactive window of Visual Studio is an example)

It is also the right time to state that Visual Studio 2022 makes use of the .NET
Compiler platform, and the code editor is built on top of the .NET Compiler platform.
To leverage the .NET compiler platform in your project, you need to add a NuGet
package Microsoft.CodeAnalysis, which is a superset of all the assemblies.
This is a huge topic and deserves a book in itself to do full justice. Here, we will just
present a quick overview so that the reader can understand and get started with the .NET
compiler platform.
There are primarily two types of analysis that you can perform on code:

• Syntax analysis: In this case, we make use of the compiler APIs.


We parse the source code and get a Syntax tree represented by
Microsoft.CodeAnalysis.SyntaxTree. This represents the lexical
and syntactic structure of the code. Once we have a syntax tree, we
can get the compilation unit root and all the other nodes that are its
descendants.

29
Other documents randomly have
different content
members."
"And very stupid of it, if you ask me," Liane retorted. "See that he
gets a card, will you."
"You are much too gracious, Liane; I shall have so little use for a
guest-card—"
"What are you talking about, Michael? Guest-card! I should say not. I
am proposing you for membership. It costs nothing when one is
properly introduced. Eh, Theodore?"
"As mademoiselle says . . . If Monsieur Lanyard will be so kind as to
let me have his address . . ."
With a shrug, Lanyard gave in. After all, it didn't matter. . . . And
when he had duly been entered in the club register, Theodore
escorted the newly fledged member to the foot of the stairs, upon
which Liane Delorme was picturesquely waiting, and there turned
both over to the guidance of a highly polished sub-altern.
Wide doorways on the first landing disclosed a chain of rooms
dedicated to the rites of jazz, liquid, instrumental, terpsichorean.
Calculated to remind a crusading clergyman of Belshazzar's Feast,
they reminded Lanyard of almost any Broadway restaurant at
midnight.
On the second landing, however, a break in the dance music below
made audible the heartless laughter of an ivory ball coquetting with a
roulette wheel behind one closed door, while a waiter emerging from
another room permitted a glimpse of a private supper party at the
peak of its lead, an interior tolerably Hogarthian.
Lanyard exchanged amused glances with Liane. "Busy little club," he
commented, "but wants rechristening—Clique's far too conservative—
should be known as the Liberal."
At the rear end of the hall another door admitted to a prettily
furnished supper room, where a table was being laid and, in coolers
on a side-table, several bottles of champagne were enjoying their last
rest. Requesting the waiter in attendance to open one of these, Liane
shrugged out of her wrap—which Lanyard took, though he kept his
overcoat on by way of pointing an intention to stop for a few minutes
only—and having made herself at ease upon the club fender of an
open fire, clinked her glass to Lanyard's.
"To you, my too-long lost friend, and to me—to a friendship that has
known too many interruptions and must henceforth know fewer."
He toasted with cool ambiguity: "To a rapport more complete."
With professional ease the waiter faded from their knowledge; and
the woman dimpled bewitchingly, patting the broad seat of the
fender.
"Come, sit by my side, Michael: let us talk."
"With all the pleasure in life," he assented, placing himself at a
discreeter distance than she had designated—"on one condition, my
dear Liane: none of your artfulness."
"Michael!" she reproached, delighted—"you don't trust me?"
"Really, you read one's mind."
"Don't be alarmed, my old one." She made a face to match her tone
of mocking reassurance. "I was mad about you once, I don't deny;
but that was long ago. Besides, you little know me if you think it
likely I would lay myself open to be scorned another time."
"I little know you," Lanyard conceded, "whatever I may think; and
I've got the quaintest notion, Liane, that the less I learn about you
the more likely I am to enjoy ordinary peace of mind. Be a good
child, now; treat me as you would a father, not as you might a
prospective papa. Tell me: what the deuce is your little game?"
"'Game'?" she repeated, petulant. "Michael, my dear! your manners
aren't as good as they were when your morals were worse."
"Admit that you didn't ask me up here to amuse yourself with
innocent flirtation."
"That is true."
"Admit, then, I am pardonably curious."
"Well! if you will have the truth . . . When I got over being foolish
about you, Michael . . . How long ago it seems!"
"A good half-year."
"I found I was still fond of you. When all's said about that sad affair,
you know, it was I who was rather a devil, and you who were rather
a dear. I owe you for more than one good turn I never did anything
to deserve."
"I wish I might think your associates in that adventure had come out
of it as well disposed."
"That absurd Monk, that clown Phinuit! Why bother your head about
such canaille?"
"And what has become of the precious pair?"
Plump but pretty shoulders described a gesture of indifference. "I
know nothing of them since that day when last you saw us all
together. I was out of patience with them then—as I think you
guessed. When you dismissed us, I sent them packing. And you?"
Lanyard, smiling, shook his head, and the woman cheerfully
consigned reminiscences to the grave of those dead yesterdays
where they belonged. "Tell me now about yourself."
"What is there to tell?"
"Much, monsieur. You are a mystery."
"I am flattered . . ."
"That's all blague," the woman scoffed. "You know I'm interested in
all you do. I've just told you so, and why." She endured his quizzical
scrutiny with a frank and friendly countenance, more entertained
than irritated by his mistrust. "Surely, my dear! you've not been
misbehaving so badly you need hesitate to confide in me."
"But a little while ago you were telling me my life was dull."
"You don't find it so?"
"You might the tale of it. Tastes differ."
"One is to infer your conduct has been good?"
"Irreproachable—by certain standards."
"Mine?" Liane twinkled—"or yours?"
"Yours certainly, since I hesitate to bore you."
"But you are provoking! And not at all polite." Lanyard looked
apologetic and said nothing. "Very well, then! if you won't answer
when I ask you prettily, I presume I shall have to tell you all I know
about yourself."
Lanyard pricked up his ears. "The little bird again?"
She solemnly nodded. "It is industrious; every day it brings me news
of this and that."
"And it tells you what of this?"
"Enough to make you what I styled you a moment ago: a mystery."
"Is it permitted to ask, how a mystery?"
"Assuredly. To begin with: It is now six months since you settled
down, apparently to vegetate in this dry climate."
"You distrust appearance?"
"Always when so far out of character. It is not like Michael Lanyard to
become static all at once. But here you live quietly, in the cheapest
decent lodgings, you have no callers, you write few letters, you see
no friends—but one—and spend no money on yourself; only when
you are seen in public with Madame de Montalais you seem
indifferent to expense. You see—?"
"I see one thing plainly: that it were well to put salt on the tail of that
little bird and wring its damned neck."
"But you do not see that this is, in one of your history, questionable
conduct? It is too much like reversion to your old days, when you
lived solitary and worked alone, making the name of the Lone Wolf
famous in Europe by following out your theory that a thief to be
successful should have no friends to betray him."
"But today!" Lanyard remonstrated—"the source of this astonishingly
detailed and accurate information about my modest habits can hardly
have failed to assure itself that they are all well within the law."
"On the surface. As were those of Michael Lanyard, the world-known
Parisian connoisseur of art before the War. But the cunning that made
it possible for the Lone Wolf to maintain that disguise, unsuspected
by the keenest criminal investigators of the Continent, has not
necessarily failed with years. To the contrary: what you did once you
should be able to do again, with even greater success, since you are
now older, less hot-headed, more astute. Let me tell you, my dear
friend!" the woman concluded with an unmistakable note of
earnestness: "they have great respect for your abilities, those who
are interested in you today."
"It seems, then," said Lanyard after a reflective pause, "I have to
thank you for a warning."
"I would be an ungrateful wretch did I fail to give it, who owe you my
life twice over at least."
"I think we may call that debt cancelled if you'll answer one
question."
"No questions!" A jewelled hand flashed a sign of refusal. "I have
said more than was wise as it is."
He persisted: "You won't tell me—?"
"Ask me nothing, my friend," Liane Delorme begged. "But use your
wits; they will tell you more than I dare, perhaps—fond as I am of
you, Michael—they are more to be trusted. Remember, with women
like me self-interest is ever at work. Perhaps it may be that the
pleasure of seeing you tonight has made me for once self-forgetful,
another time may find me less indiscreet."
"I will be careful," Lanyard said gravely, "not to expect too much . . ."
With equal gravity she responded: "Then you will be wise."
"And now," he concluded, rising, "your friends can't be much longer;
I mustn't put them to the trouble of kicking me out."
Liane put out a hand and caught his. "But I wish you to stay. I
promise you will be welcome. My friends will be delighted. One of
them in especial I am anxious you should know. You will find him well
worth your while, one of the most interesting men in New York, quite
a social power in his way."
"In his way—?"
"A quiet way, my friend, but a very real one."
There was more meaning in her eyes than in her words. Lanyard
hung in doubt. Impossible to misread the sincerity of her desire to
have him stay on. But her motive?
He had delayed too long. Voices sounded in the hallway, the gay
accents of a woman predominating. Then the door opened; five
people entered.
III
The first was a pretty young thing, piquantly fair and petite, with
glowing face and merry eyes, at sight of whom Lanyard felt
warranted in breathing an invocation to his prophetic soul. For now, it
seemed, chance or predestination was making good that
presentiment to which he had confessed during supper at the Ritz.
This brilliant little shape of life in the dark rectangle of the doorway
had been conspicuously one of that party whose forbidding host had
excited the aversion of Eve de Montalais and, in himself, half-formed
forebodings. The man at whom she was so gayly gurgling over her
shoulder, who wore both topper and grin at the doggish slant which
becomes the author of an amusingly improper wheeze, was the little
chap of the weazened wise mask whom Lanyard privately reckoned
court jester to the Sultan of Loot. The latter in very person bulked in
the shadowy background provided by the corridor, a presence vast
but vague, betrayed by the baleful burning of fire opals as a
thunderhead on a summer's night may remain more sensed than
seen till a glimmer of lightning lends definition to its loom. Behind
lurked a fourth, a figure still more indefinite. And in the rear a gleam
picked out the hairless poll of Theodore, inclined at a servile angle.
Discovering Liane Delorme all at once, the lady on the threshold
registered rapture, then ran to her with glad hands extended, her
slight little body bearing an extravagant wrap of Russian sables with
a grace as dainty as a fay's. Lips that didn't need paint to point their
pretty contours bubbling joyously—"Darling Liane! You luscious thing!
How we've missed you!"—she precipitated herself into Liane's arms
and printed inconsiderate kisses upon that studiously composed
complexion. When she permitted Liane to disengage and present
Lanyard, he received an almost disconcertingly cordial smile and a
tiny hand on which blazed in insolent beauty what he rated at first
glance the most exquisite emeralds he had ever seen, who in his day
had been somewhat an amateur of emeralds.
"Mr. Lanyard!"—Liane's introduction had been effected in English—"I
am so glad to know you. It seems to me Liane knows all the
interesting people—and nobody else."
"One trusts very truly you will not find need tonight to revise that
recommendation," Lanyard returned, bowing low over the little hand.
He added with an enquiring inflexion, because he wasn't sure of
having caught the name aright: "Mrs. McFee . . ."
"Mrs. Folliott McFee," Liane supplied with an accent on the Folliott
that supplemented something to this sense: 'Surely you must know
that magic name!'
All the same, Lanyard didn't.
"Folly for short," laughed Mrs. McFee—"Folly to my friends." Then she
gave a small make-believe shriek because the sable robe was being
lifted from her shoulders by the gentleman of the carven
countenance. "Peter Pagan! how you startled me . . . You know Peter
Pagan, of course, Mr. Lanyard: everybody does."
"Business of initiating you to the inner circle of certified somebodies,
Mr. Lanyard," quoth Mr. Pagan solemnly, shaking hands, and leaving
Lanyard with a feeling that no man had a right to look like that if he
couldn't extemporize more tellingly.
But Liane had dropped a hand upon his sleeve and was drawing him
aside to be made known to the Sultan of Loot.
"Mr. Morphew: Mr. Lanyard . . . You must become good friends, you
two who are both such good friends of mine."
This impressive figure of the immobile and livid face and the hooded
eyes, this Mr. Hugh Morphew, met Lanyard with a manner subtly
allusive beneath a show of non-committal courtesy. His smile was
grave, reticent and fugitive, a solitary cat's-paw flawing the surface of
plumbless deeps; his few words were carefully chosen and cast in
polished periods by an orotund voice: he was honoured to make the
acquaintance of Mr. Lanyard and hoped that he, as a friend of
Mademoiselle Delorme, would be so very good as to become one of
their number for the remainder of the evening . . . But in the cast of
his eye, the clasp of his hand, in an undertone his accents had as he
pronounced these perfunctory phrases, there was meaning intended
to be seized by Lanyard only, and which the latter interpreted much
to this effect: 'We have been waiting a long time for this meeting,
you and I. But patience: all in good time we will come to understand
each other perfectly.' . . .
To this finesse Lanyard returned no acknowledgement of any sort.
Indeed, he contrived to appear unconscious of it, to interpose an
amiably modest manner between the scrutiny of those inquisitive but
illegible eyes and a nature anything but easy to impress. He had lived
so long in this world, in the course of a busy life had had so much to
do with pretentiousness, that secretly, and the innuendoes of Liane
Delorme to the contrary notwithstanding, he inclined to suspect Mr.
Morphew of being a pompous fraud, a character of the utmost
commonplaceness skulking behind the consequential false front of a
jerry-built personality. He might be mistaken; but for the present the
best he was disposed to grant Mr. Morphew was suspended
judgement.
Moreover, at the moment, Folly McFee was demanding his attention
on behalf of one Mr. Mallison, another whom Lanyard remembered
having noticed at the Ritz.
This final introduction was transacted without casualties but without
eliciting crows of ecstasy from either party. Mr. Mallison, indeed, was
unaffectedly off-hand in his attitude, he didn't care a damn who knew
that, to him, Mr. Lanyard was an interloper, an upstart, nobody in
particular. A gesture for which Lanyard was grateful since it enabled
him to reciprocate the sentiment that shaped it without feeling remiss
in the matter of everyday urbanity.
Tall and gracefully made, Mr. Mallison aired evening clothes and hair
of a lustre seldom to be observed this side of the cinema screen. His
speech had the tune of the educated English, or something nearly
resembling it, his manners were silky and sulky, he practised a furtive
smile down his nose as if he knew something but wouldn't tell, he
had mastered a killing trick or two of the eyes for use in talking to
women. And when it transpired, on the word of Folly McFee, that
Mally tango'd quite too divinely, one felt that one needed to know no
more. . . . A person of importance, if you asked Lanyard, solely as he
might upon occasion shine with incandescence borrowed from the
genius of Mr. Morphew, upon whom Mallison seemed assiduous to
fawn in season and out.
Having offered the apology for his intrusion which custom prescribed
and accepted the equally conventional assurance that all hands were
ravished to have the privilege of welcoming one so well sponsored,
Lanyard settled down to use his wits, as Liane had recommended,
and find out for himself what this party was all about; if, indeed, it
was 'about' anything more unusual than mankind's native
predisposition to make light of whatever laws there be.
Certainly, if its members had foregathered at the Clique Club for any
purpose other than the desire to drink forbidden wine upon premises
of unholy repute, it wasn't at first blush apparent. Nobody was
hungry, every soul present having sat through a supper elsewhere
and earlier. On the other hand, everybody was famously thirsty with
the exception of Mr. Morphew, who was alleged never to drink, and
Lanyard who, having sampled it, didn't frightfully care for the Clique
cellar. But all of a sudden Folly McFee, in whom artificial exhilaration
was mounting apace, announced that she craved sure-enough
excitement. Whereupon at a sign from Morphew the cloth was
whisked away and the green baize of a card-table disclosed; whose
top manipulation of a hidden catch reversed, bringing to light a small
layout for roulette, complete but for chips and the metal wheel to fit
in the bowl. These being supplied by Theodore, Mr. Morphew
announced that he would stand the first trick as banker and croupier
in one, and that white chips would cost one dollar apiece and the sky
would be the limit; Mrs. McFee produced an impressive roll of bills
from a jewelled mesh-bag and bought chips with a free hand; while
Liane Delorme, Mallison, and Pagan purchased more conservatively
but still eagerly.
But Lanyard, when Morphew's heavy-lidded eyes turned his way,
shook his head: "Thanks; but if you don't mind I'll just look on."
"O Mr. Lanyard!" Folly McFee remonstrated—"and you look like such a
good sport."
"You see how deceitful I am," Lanyard pointed out. "Let this be a
lesson to Folly, not to trust appearances."
"But really, my friend!" Liane observed reproachfully—"you are no
longer the man you were."
"I have always made it a rule not to gamble without money in
pocket."
"But I will let you have any amount you want."
"You are too good, Liane. Another rule I have all my life observed is
never to gamble with borrowed money."
"Your credit is good, Mr. Lanyard," Morphew tersely put in.
"Rule Number Three: Never play on credit . . . I am deeply sensible
of your courtesy, Mr. Morphew, but really I will be most grateful if you
will permit me to sit by and look on merely. The novelty of seeing
myself in such a rôle at a roulette table will be compensation enough
for the self-denial."
"As you prefer . . ." Morphew politely gave in. But before long he
made occasion to exchange with Liane a look clouded with meaning,
which Lanyard wasn't supposed to see and which, so far as anybody
else knew, he didn't, who was busy just then refilling Folly McFee's
glass and making amused response to the coquetry with which the
flushed and laughing face turned up to his was instinct.
All the same, Lanyard wasn't missing much that went on, Life had too
well trained his faculties to overlook nothing that fell within their
range and to be wary of dismissing as necessarily negligible the most
minor and incidental details of any affair. He was beginning now to
experience glimmerings, to perceive that this curious post-midnight
party was 'about' something after all. Even before intercepting that
mute consultation of eyes he had felt tolerably satisfied that a
community of interests existed between at least three of those
present, that Liane, Morphew and Pagan were playing prearranged
parts in complete mutual sympathy. It was just possible that Mallison,
too, was privy to their confidence; but one rather doubted that,
Mallison impressed one as more likely to prove a tool, a pawn, a
wage-loyal henchman, than a peer of this interesting confederation.
The arguments he had adduced in his endeavour to make Eve
understand that he was not a man of the sort she ought to marry
began to seem inspired. Liane had never brought him here simply to
gratify a vagrant whim. Neither had her half-veiled hints been idly
uttered, concerning those nameless acquaintances of hers who were
taking such a profound if gratuitous interest in Lanyard, and the one
whom she most wanted him to meet, either Pagan or Morphew
unquestionably, and who was "quite a social power . . . in a quiet
way." Because the woman was well-disposed, for old sake's sake she
had chosen to warn him, if in her own oblique fashion, to be on his
guard with those two in whose minds, Lanyard hadn't any manner of
doubt, the project for some time had been forming of inveigling him
into some shady sort of association with them, for purposes of their
own in the last degree questionable.
Undoubtedly they had taken a good deal of pains to inform
themselves as to Lanyard's circumstances. How they expected to be
repaid for their trouble remained for him to find out. Hardly out of his
pocket; knowing as much as Liane had revealed, they probably knew
more, even that the debacle of his unregenerate days had left him
without resources other than the half-pay attaching to an extended
leave of absence from the British Secret Service, and that the not
inconsiderable cost of squiring about New York a woman of fashion
had brought him to a pass where he might no longer refuse to face
the prospect of being unable to pursue that sweet association for
sheer inability to finance it—he who had been accustomed to waste
money away as freely as in more spacious times he had been wont to
appropriate it! A plight the more painful in that it was one he couldn't
possibly confess to the woman he loved. He had gone tonight as far
in that direction as pride would let him. . . .
Since, then, it was manifestly not pence they wanted of him, this
precious pair, this Morphew and this Pagan, it followed that they
wanted something less tangible but probably in the upshot more
profitable, something which they might have found themselves in a
position to require of him if he could have been induced to play
roulette on credit and had lost—as he made no doubt he would have
lost. Setting aside all question of the honesty of the wheel which
Morphew's huge hands were manipulating with notable deftness, the
observation and experience of this inveterate gambler of other days
had convinced Lanyard that luck seldom or never favours him to
whom its smile is a matter of life or death.
Not that he conceived the game to have been planned with any idea
of inducing him to play and lose, his attendance had come about too
fortuitously. To believe that was to believe Liane had foreseen that he
would be marching down Fifth avenue at half an hour after midnight
and had deliberately arranged to have her cab skid and land her on
the kerb a dozen paces ahead of him.
No: by every sign acceptable to a fairly sophisticated intelligence,
tonight's affair had been plotted for the sole if highly problematic
benefit of Mrs. Folliott McFee. Not in all likelihood for the purpose of
fleecing her at a friendly little game, though she was punting with
feverish imprudence, broadcasting her bets and losing very
considerable sums without perceptible care. Lanyard was prepared to
credit Messrs. Morphew and Pagan with capacity for any degree of
knavery; but their evident affluence and their association with Liane
Delorme inclined him to believe that they were in this instance up to
some mischief at least a cut above crooked gambling. Liane,
thorough-paced rip that she was, had in the course of a highly
chromatic career feathered her nest too warmly to be reduced to the
rôle of tout to a brace of common sharpers.
What, then, could their purpose be with this engaging and indiscreet
young person? If only one knew a little more about Mrs. Folliott
McFee it might be easier to guess.
In the absence of such specific information, a study of her as she was
tonight would do no harm, might quite possibly prove rewarding.
Indisputably a fascinating creature. Divested of her sables, disclosed
partially in but largely out of a flimsy piece of impudence which the
cynical Rue de la Paix had fashioned to serve as an evening gown,
she cut a figure the most sprightly and sightly heart could wish: an
animated miniature of extreme loveliness, abandoning herself to the
spirit of play with the heedless vivacity of a charming child; drinking a
bit more than she should, perhaps, while she watched her stakes
unfailingly fall to the lot of the croupier's rake, but plaguing Mallison
with a lightly malicious wit that struck him speechless and left him
more than ever sulky, bartering pungent banter with Mr. Peter Pagan,
cheeking the taciturn Morphew till he smiled perforce his rare
begrudged smiles, and never for an instant forgetting that Lanyard
was likewise an unattached and personable male; and all with a
delicate air that robbed her most flagrant audacities of any
suggestion of poor taste and made her seem strangely out of place in
that ring of hard and selfish faces, in that overheated private room of
an establishment whose every purpose was illicit, in that demoralizing
atmosphere drenched with perfume of wine and scent of perfumed
flesh . . . Strangely out of place, appealingly helpless for all her
bravado: a child among thieves and worse . . .
But it were a thankless job to waste solicitude upon her: if Folly
couldn't take care of herself, nothing was more certain than that the
way to earn her abiding dislike was to try to take care of her. In New
York, as every elsewhere in the haunts of men of means beyond their
needs or native ability to spend with good grace, no novelty at all
inheres in the spectacle of such flighty young women, amusement-
mad and gifted with too much freedom from responsibility, going
devious ways with dubious guides. And the worst of it is, as a general
rule it's nobody's business but their own.
Now in course of time, when a waiter entered with yet another cooler
wherein two more bottles were luxuriously cuddled in cracked ice, the
open door admitted stimulating strains of the orchestra downstairs;
and forthwith Folly McFee concluded she'd had enough of roulette, at
least temporarily.
"Perfectly damn' rotten luck!" she declared, pushing back her chair
and jumping up. "I'm for a dance, maybe that will change it. Who
wants to take me down for this tango? Mally——?"
"You can't have Mally," Liane Delorme informed her with serene
decision. "You've had him all evening at the Ritz. It's my turn now.
Take Peter Pagan: he's a better match for you, dear."
"Pick on somebody your own size," Pagan paraphrased, leaving his
place with an alacrity that forestalled Lanyard's intended response to
the glint of invitation in the eyes which Folly promptly had turned his
way. "If you refuse me, Folly, you doom me to dance with Liane; and
that always makes me feel like an enterprising tug waltzing the
Mauretania round the North River."
Liane retorted with one of those characterizations so dear to the
Parisian heart, a deadly insult but absolutely meaningless when
rendered into English; and Pagan proved a certain lack of finish in his
cosmopolitan education by merely looking blank as he mentally
translated her remarks. After which he bowed cheerfully to the
traducer of his lineage and ambled off with Folly's hand under his
arm; while Liane rose and playfully tweaked Mallison out of his chair
by an ear, to his indignation, for he had been winning and naturally
wanted to go on playing as long as his luck lasted.
"It isn't that I really want to dance," she coolly explained to Morphew
and Lanyard as she haled Mallison to the door, "but simply to give
you two time to get acquainted . . ."
Morphew lumbered heavily after her and set the spring-lock by way
of providing against interruption. "Intelligent woman, Liane," he
approved, unsmiling, as he returned to his chair.
"As to that, monsieur, one is entirely of your mind."
Lanyard helped himself to a cigarette and looked civilly receptive
under the weight of Morphew's direct and thoughtful stare.
"Odd," that one considered, "we never happened to meet before this,
Mr. Lanyard."
"Think so?"
"Noticed you about town often enough."
"But does not the fact that our paths have sometimes crossed prove
we travel widely different courses?"
"I'm not so sure . . ."
"Not——?" Lanyard murmured, lifting the brows of polite surprise.
"I've got a notion, if the whole truth were known, you and I would
find we were travelling in much the same direction . . . in the dark."
"Monsieur does much travelling in the dark?"
"Guess you know what I mean," Morphew's gravity was lightened by
a twinkle of genial cunning. "When I say 'in the dark,' I mean, of
course, the side of our lives we like to keep covered up."
"This is most interesting," Lanyard protested with animation. "You are
going to tell me about that side of your life which you like to keep
covered up?"
"No fear." The twinkle broadened into a grin. "Guess I'll let you guess
at that, same as I have to guess at yours."
"I hope very truly monsieur does not so waste his time. I can assure
him, if his guesswork were to flood with light every nook and by-way
of my life, what he would see would not entertain him."
The lines running from Morphew's nostrils to the corners of his mouth
took on a sardonic set. "I doubt that, Mr. Lanyard."
"My ways of life are very quiet."
"I believe you. Still, I doubt I'd be bored."
"Possibly not," Lanyard conceded. "One is able to judge only by what
one has seen of you in public, monsieur; which leads one to believe
your interests centre by choice in light-hearted young people, not
sober-sided, steady-paced elderlies like myself."
"Oh! as to that, I take folks as I find them," Morphew alleged. "And I
find 'em all interesting, one way or another. Now yourself . . ."
"But I do assure you I am not at all interesting."
"Point of view," Morphew contended. "I'll say you've had an
interesting life."
Lanyard gave a good-natured shrug. "After all, it is the only life I
have . . . But monsieur, I am sure"—his manner grew moderately
pointed—"would find it tiresome."
"I don't," Morphew bluntly countered.
"Then I am honoured—I presume—to learn you have concerned
yourself in respect of my modest self."
"I know a lot about you," Morphew admitted—"past and present."
"Yet you tell me you think my present mode of life intriguing!"
"Intensely."
Lanyard laughed. "Monsieur will pardon my suggesting that his
sources of information, however busy, are unreliable if they have led
him to believe my small affairs worthy of his attention."
"Point of view again." Morphew dismissed argument with a flirt of a
massive hand. "Be that as it may: I've been anxious to meet you to
ask you to help me answer a certain question."
"Indeed?"
"Perhaps it would be more nearly right to call it a problem in
psychology."
"I am all attention."
"It's like this . . ." Morphew had resumed his customary guise of
profound solemnity. "What I want your expert opinion on, Mr.
Lanyard, is the question of whether it's possible for a man . . . say
he's a friend I'm taking a personal interest in . . . a man who built up
a pretty warm criminal reputation for himself, when he was younger,
and then hit the sawdust trail apparently for keeps . . . Whether it's
possible for such a man to keep going straight in the face of every
possible incentive to set up shop again as a master crook."
"Such incentives as——?" Lanyard enquired with every symptom of
intelligent interest in a hypothetical instance.
"Well! let's suppose this man I've got in mind, this friend of mine, has
fallen for a woman who's got everything, social position, any amount
of coin, all that sort of thing. Say she's in love with him, too, and they
want to get married. But my friend is broke, or next thing to it; and
he's got a touchy sense of honour—sometimes reformed crooks have,
you know—so he can't marry the woman, because that would make
him look like a fortune-hunter if she ever found out he hadn't a red
cent; and he can't let on to her he's stoney, because then she'd insist
on marrying him to support him, and he'd feel like a yellow pup; and
he can't do a quiet fade-out, either, because then she'd think he
hadn't been on the level with her, and that would break her heart.
That leaves him where? He's got to have coin to go on with, and the
only way to get it is for him to remember some of the things he's
been trying to forget. He's living in a city where there's more money
and loot lying round loose to be picked up for the taking than any
place else in the world, and where police protection against burglary
and highway robbery is a positive joke, where a good fat safe is
cracked or a hold-up pulled off every other day, and ninety-nine times
out of a hundred the crook's never caught. So you see our friend has
just what I said he had, every temptation to come back strong in the
housebreaking line, and practically nothing to fear—except maybe
that the woman he's crazy about will tumble sometime to how he's
getting his dough. And that's the problem that's been puzzling me,
Mr. Lanyard: What's our friend going to do? . . . What would you do?"
Lanyard thoughtfully ground out the fire of his cigarette in an ash-
tray and got up. "I imagine," he said quietly, "your anonymous friend
would do precisely what I mean to do, Mr. Morphew. He would gee
well weary of tedious beating about the bush, but at the same time
would remind himself that the obligations which devolve upon a
guest constrain him to overlook, for the present, a piece of damnable
impertinence. He would for that reason take his hat and coat and
stick—as you see me taking mine—and finally his departure—as I
shall take mine, monsieur, pausing only to advise you . . ."
Lanyard stood over Morphew, plunging a stare ugly with anger into
the apathetic and unreadable eyes of his host. "At the first sign, Mr.
Morphew," he said, "of any disposition on your part to meddle further
in my affairs, either in person or through an agent, I will seek you
out, wherever you may try to hide, and break this stick, or a stouter
one, over your contemptible back. Be advised: hands off!"
He waited an instant to hear what Morphew might have to say to this
defiance; but since the man said nothing, made no sign of any sort,
his huge body betrayed his mind by not so much as the stir of a
finger or the wince of an eye, Lanyard at length wheeled on a heel
and went to the door. Only then, as his hand closed on the knob,
Morphew spoke, employing the same conversational tone he had all
along employed.
"One moment, Mr. Lanyard. It may interest you to know I own this
joint. When I got up to shut that door a while ago, I gave Theodore
the high-sign. Ever since then four of our waiters, the toughest
rough-necks on the payroll, have been stationed in the hall. If you try
to leave without my say so, you'll be badly beaten up; and if you try
any rough stuff in here, my finger's on the push-button that will call
them in . . . I am not done talking with you yet, my friend. So now, if
you'll attend to me and keep your temper in hand, I'll show you just
where you stand."
He rested, watching Lanyard with no perceptible emotion in his bleak,
pale eyes; and when, after momentary consideration, Lanyard turned
back from the door, the man resumed with the same minatory
composure, leaning forward with an arm on the table and rapping out
his points with a thick forefinger.
"Whether you've gone back to thieving or not, Lanyard, I don't know
yet. I guess you have. If you haven't, you've thought of doing so.
Whether or not, you've got to come to me. I've got you"—Morphew
turned his hand palm up and closed the fingers slowly into a
tremendous fist—"there! You can marry your Mrs. de Montalais as
soon as you like, but only with my consent; and you won't get that
for nothing. If you're back at your old game, you'll come across to
me, fifty-fifty. If you marry the woman for her money, my share will
be half of all you squeeze out of her."
"And"—Lanyard's fingers were itching to bury themselves in that fat
throat and shake the beast till he cried for mercy—"and if I refuse?"
"I'll advertise you to all New York—or anywhere else you try to live
with your wife—as the Lone Wolf back at his old dodges. I'll prove
you committed every burglary of any size this Town has known in the
last three months; and if that isn't enough, I'll plant others on you.
You'll come across to me, my dear sir, or go up the River for life."
"Such being the case," said Lanyard, shortening his grip on his stick,
"I think I would as willingly go up for manslaughter—if killing a
blackmailer comes under that head."
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookmasss.com

You might also like